Onyx Nova Pro update

Back in March I wrote a review of the Onyx Boox Nova Pro Ereader: https://www.bit-101.com/blog/2019/03/onyx-nova-pro-ereader/

Now, nearly 5 months later, I thought it would be good for a quick update.

tldr: I still love it. Like, really love it.

Details:

PDF reading

I’ve had more of a chance to consume PDF content on the device. As mentioned in the first review, most PDFs are utterly unreadable on a 6″ Kindle. Because each page has a fixed layout, when rendered full screen on a 6″ screen, the text is generally way too small. On a Kindle, you can zoom in and scroll around, but it was always way more painful than it’s worth.

On the 7.8″ screen, things are much better, but it’s still a bit too small for full page reading. I’ve eyed the Onyx Boox Note Pro, which has a 10.3 inch screen and would be amazing for this purpose. But at $599, I don’t think I’m going that route. The plus point is that the Onyx software has some great PDF reading features that actually makes even the 7.8″ screen functional for reading PDFs. It can automatically crop to the width or the height of the actual text on the page, perfectly getting rid of the extraneous margins. This allows most PDFs to be zoomed in enough to be workable. It also allows for different layouts. For example, if you have a document with two columns, you can set the reader view to that and you can see the first column zoomed to width – the top half anyway. Press next page and you see the bottom half of the first column, then the top right, bottom right, and onto the next page. I’ve read some things this way and it’s very workable.

PDF reflow options

Drawing / Sketching / Notes

I don’t use this feature a ton, but I still love it. Plenty of times that I’m trying to work out something or help my daughter with math or programming and it’s great to sketch out ideas or work out some formulas. And I’ve used it quite a bit for sketching notes of things I might want to build (physically or in software).

Content Management

Nothing much new here other than saying my system continues to work really well. My Calibre library is in Dropbox and all de-DRMed, so I can access it on any device, including on Android using another ereader app. I’m currently using Moon+ reader, which works really well if I’m somewhere without the Nova Pro and want to read a few pages of something. You don’t get the syncing like you would on Kindle apps/devices, but that’s fine.

The UI

The device had the v2.0 firmware when I got it. Shortly after that it got v2.1 and since then v2.1.2. The first update had huge UI improvements, and v2.1.2 brought a bunch of bug fixes and stability improvements. Other than the UI having so many features that the learning curve is fairly steep, I have no real complaints about it at this point.

Battery Life

In my first review I said that I had the power options set up to completely shut down the device after one hour of sleeping. I thought this was saving a ton of battery life, but I switched over to letting it stay powered up 100% of the time to avoid the 30-40 second startup time, and I don’t see a huge loss of battery time. I get many days to a week of battery life. I don’t really know, because I’ll just plug it in at night when I go to sleep if it’s under, say, 60%. Also, it charges really fast. There have been times I plugged the reader into my computer to transfer some files and do some other file management and noticed that the battery jumped 10% or so after just that short time being plugged in. In general, battery life is just a non-issue.

Android Apps

Not a huge change there. Pocket, Instareader, Dropbox are still my go-to apps. I did start using IAReader as well, syncing it to Dropbox. My workflow for that is if I see something in a book I want to save or use elsewhere, I can copy it, open IAReader and paste it into a document. As long as the Nova Pro is on line, that text is then available from wherever else I have Dropbox installed.

I’ve also tried the Moon+ reader Android app. Many Onyx users swear by it. It’s nice, and has some great additional features that the built in reader does not have, but it hasn’t totally won me over yet.

Onyx Nova Pro Ereader

Check out my update to this post, after using the Nova Pro for more than 4 months: https://www.bit-101.com/blog/2019/08/onyx-nova-pro-update

Let’s talk about ereaders. And first, let’s talk about Kindles.

I got my first Kindle in April 2009. Almost exactly 10 years ago. Goddaaaaamn, time flies. I didn’t buy into the whole Kindle hype at first. But I decided to try out the Kindle 2, skeptically. And I was hooked. I wound up buying several Kindles over the years, upgrading not at every new version, but every 2-3 years. I got the PaperWhite 4 late last year – as soon as it was available for preorder. And I loved it. Then I started thinking about getting the Oasis 2, mainly for the screen size. Most Kindles have stuck with the 6″ screen, whereas the Oasis went up to 7″. But the Oasis 2 is already pretty old, so I was waiting to see what might come out later this year.

And in the meantime, started looking around at other solutions. A couple of lines of alternative ereaders caught my eye:

Likebook and Onyx Boox

They both make several different models. E-ink, a lot of large screen sizes, and, most interestingly, with a stylus for sketching or taking notes. They also run a version of Android, which means you can install additional apps on them. Oh, and yeah, they are $$$$$. Way more than Kindles in general.

After researching what was available, I went for the newly released Onyx Nova Pro. Sadly, currently unavailable at this time on Amazon, but I think you can get it straight from Onyx, and other sources. You might have to dig around. [It’s back in stock.]

This has a 7.8″ display, larger than the Kindle Oasis, which is one of the first things I was looking for. The screen is beautiful, high dpi, front lit with two colors of LEDs which you can control independently or sync them for a neutral light.

Reading Books

It has a built-in ebook reader which supports a ton of file formats: PDF, ePub, MOBI, Doc, Docx, Docm, TXT, DjVu, FB2, HTML, CHM, AZW, AZW3, FBZ, ODT,PRC, RTF, SXW, TRC , JPG, PNG, BMP, TIFF, CBR, CBZ.

Compare that to the Kindle, which supports AZW3, AZW, TXT, PDF, MOBI, PRC. Anything else has to be converted to one of those formats.

Your reading experience can be customized to an amazing degree. Seriously, after two weeks, I’m still learning what you can do. Fonts, light temperature, boldness of text, text encoding, indentation, columns, text direction, text contrast, image contrast, line spacing, paragraph spacing, vertical margins, horizontal margins. The Kindle has some of that, but not nearly to the same degree. You can have several books open at once, in tabs. You can do text-to-speech. You can customize what happens when you tap any area of the screen, setting up different actions for each of nine screen zones. It does timed auto page turns and does a grid preview of either one, four, or nine pages at a time, plus table of contents as a sidebar.

Rather than the arbitrary Kindle “location” numbers, it always gives you the total pages and current page based on one page being one screenful of text. Of course this changes if you change the font size. And to be honest, it’s a little bit janky. It’s often a page or two off, but in general, it’s a fine estimate and easier to understand then Kindle’s locations.

Quick note about PDFs: while the Kindle supports PDFs, the 6″ screen size makes 95% of PDFs completely unreadable. The extra screen real estate on the Nova pretty much handles that. It’s also got a ton of other PDF-specific tools that I haven’t mentioned, that make things a lot easier, such as auto-cropping of margins to make reading PDFs even better.

For PDFs, you can use the stylus to draw or write directly on the PDF. For other formats, you can choose the side note feature, which opens the doc in split-screen landscape mode, one side for the book, one side for you to scribble on.

It has built-in dictionaries and you can add others and switch between them easily. Unlimited highlighting and notes, with different types of highlighting and underlining.

I could go on. It’s overwhelming. But overall, it’s just a great reading experience as well. The screen size and resolution, lighting, all the formatting options and navigation just make it a joy to read books on.

The Stylus

The other main thing that made me buy this was the stylus. Or in reality, the Wacom drawing layer that lets you draw on the screen with the stylus.

I already mentioned being able to draw on PDFs. But more useful for me is the built-in notes app. Again, crazy options: fixed width pencil mode, or pressure-sensitive brush mode, a few simple shapes, erase entire lines or just portions, lasso tool – select, scale, rotate, move drawings, add text, OCR what you’ve written, choose line width and color (black, white, red, green blue – colors show up on exported PDFs). It comes with a bunch of templates – grids and lines of all shapes and sizes, calendars, todo lists, etc. Back up to Dropbox, OneNote or some other services. Each note can have multiple pages and you can organize notes into folders. Notes are natively saved as PDF files, but you can also export them as PNGs.

The quality of the notes app blew me away. Exceeded all my expectations. They look great, really smooth, zero lag. The pressure sensitivity is great. The feel of the pen on the surface is perfect. So much like just writing on paper. Notes only work with the pen, so palm rejection is just automatic

Again, I could go on about this feature forever. I really like it.

Things you won’t find, though, are things like zooming in and out or layers. It’s not a serious art tool, more for handwritten notes and quick sketches.

Android

To be honest, this aspect of the tablet I could have done without. But now that I have it, there are a few cool aspects. Although it has a built-in app store with a few staple apps, you can also add the Google Play Store and download anything that will work on Android 6. Really the only things I’ve found particularly useful are Pocket, Instapaper and Dropbox.

I mean, it comes with an email client, but you can also add Gmail. It has a full featured browser. You can install Youtube! And games. Yes, videos and animation in e-ink. It works and it fun to try out, but seriously… no. I have way to many other devices to hand that just do all those things much better.

You can also do audiobooks and play music via Bluetooth headphones or speaker. But again. I have other devices.

Oddly, you can also install other ereader apps, including the Kindle Android app, Nook, Google Play Books, etc. Personally, I use Calibre to manage my ebook library and put it directly on the device anyway. More on that next.

Content Management

I use Calibre to manage my ebooks. It handles just about any known format of ebook and does a good job of converting between formats. It has a plugin system and a rich ecosystem of plugins that deal with all kinds of things. One I use often is a metadata plugin that searches the internet for metadata and cover images for any book that is missing those.

I also use a DeDRM plugin so when I download my ebooks from Amazon, it strips the DRM from them and lets me read them anywhere, including the Nova. Is this legal? Probably not. Is it ethical? I feel like it is. I’m not uploading my books to sharing sites, or otherwise making them available to others. I buy books for my personal use, and I use them personally. But I want to have backup copies and want to read them on devices and apps that are not made by Amazon.

Another great thing is that when I connect the Nova to my computer with USB, Calibre recognizes it. I can then select whichever books I want and just say “Send to device” and they instantly appear there.

The Nova has 32 GB of storage, which is huge if you are just storing books there. Audiobooks, music, and manga will take up a lot more space, but that’s as much as the best Kindle has.

In the reading app you can view your whole library, filtered and sorted by various criteria, or toggle over to just recently active books, which is what I mostly use. You can also sort books into folders.

If you just want to shoot a single document over and you don’t have a USB cable to hand, the Nova has a wifi transfer mode. This launches a local server at an address something like 10.0.0.125:8083. You go there on your computer and you get a web page that allows you to select a file and then sends it over to the device. I use this often.

The Dropbox app is also super useful for accessing content on the device. And as mentioned before, I use the Pocket and Instapaper apps to save web articles and read them later on the Nova. It’s a pretty good experience.

The system also includes a simple but totally functional file manager that lets you move files around, rename, delete, create folders, all the usual stuff.

OK, the not-so-good parts…

The UI

As I’ve been saying, the number of options on this thing is overwhelming and I’m still learning all that is possible. The UI is not nearly as slick as the Kindle. In fact, it is very much a UI that some enthusiastic developers put together. In addition, all the software is created in China, and it’s created in Chinese. You can set the language to be English and you’ll be fine, but you will see some strange grammar here and there in the UI, and the occasional misspelling. The good news is that the firmware is under very active development. In fact, shortly after I got my Nova, they announced version 2.1 of the firmware. I was able to update easily and it brought a ton of improvements.

On the plus side, the system has been rock solid. It’s never once crashed or frozen up or done anything weird at all in the couple of weeks I’ve had it.

Battery Life

The Kindle advertises six weeks of battery life. When you drill in on that, that’s with no Bluetooth or wifi and 30 minutes of reading per day. Even then, I’d say that’s optimistic. In real life, you’ll probably get at least a couple of weeks on a Kindle charge though.

The Nova is a different story. It’s an Android device. But, that said, it’s pretty good at conserving power. I’ve gone a full weekend with a lot of reading and use and still wound up at 60-something percent. During the week, with a bit less use, I made it through four days and was down to 30-40% I think. So you’re talking days, not weeks. I’ve got a big USB charger next to my bed, so it’s easy enough to just plug it in before I go to sleep.

A Kindle just sleeps and when you want to read it just instantly wakes up. The Nova can do the same, but when it’s sleeping, it’s going to be using a lot more power than the Kindle would be. So there are two power settings. One will put the device to sleep after so many minutes of inactivity, another will turn it off after a certain time. Options are sleep after 3, 5, 10, 30 minutes or never. And power off after 15, 30, 60 minutes or never.

I have these set to sleep after 5 minutes and turn off after an hour. And with that, I get several days off a battery charge. You can disable the power off timer, but that’s going to affect the battery life. I haven’t experimented with that, so I’m not sure what the impact would be. The downside to turning it off is that it takes a little while to boot up. About 35 seconds. A bit of an annoyance, but since it stays on for an hour after your last activity, it’s livable.

And obviously if you install a lot of apps that are doing stuff in the background, that’s going to affect battery life. There is a power saver mode, which apparently throttles background app power use. I haven’t tested that much either.

Overall, with my current settings, I’m completely satisfied with the battery life at this point.

Price

The Onyx Nova Pro costs $299 USD. Plus tax, shipping, whatever. I threw in $40 for a case that does the auto-on/off when you open/close it, and has a holder for the stylus. That’s the same as a 32 GB Kindle Oasis without special offers. But SO many more features.

Update: The $299 was what I paid on Amazon, where it is currently not available. It will probably cost a bit more elsewhere. Hopefully Amazon will get some more soon.

Second Update: It’s back on Amazon, but currently $319.

More info

From the horses mouth: Onyx Book Nova Pro

Some video reviews:

Note: the first video shows the device running the older firmware, while the second shows the updated 2.1 firmware with many improvements.

Perlinized Hexagons

In my last post, Hexagons, I talked a bit about how cool hexagons are, and gave one method of creating a hex grid. I also used this image as a header:

This was a bit of a tease, as I didn’t show how to create such an image. But I promised I’d come back around and give some code for it, so here we go.

First, some refactoring

As I’m sure most of you guessed, this image uses Perlin noise, but you could use any other function to get different textures. Check out my articles on flow fields (parts one and two) for more ideas along these lines. I’ll also be using the same Perlin noise library mentioned in the second of those articles.

I’m going to take the basic code from the tiled hexagons in the last article and change it up a bit. Mainly all I’m doing here is removing the translation code and calculating each x, y drawing point directly. Here’s what that looks like:

const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
context.lineWidth = 0.5;

function hexagon(x, y, r) {
  let angle = 0;
  for(let i = 0; i < 6; i ++) {
    context.lineTo(x + Math.cos(angle) * r, y + Math.sin(angle) * r);
    angle += Math.PI / 3;
  }
  context.closePath();
}

const radius = 10;
const ydelta = Math.sin(Math.PI / 3) * radius;
let even = true;

for(let y = 0; y < 900; y += ydelta) {
  let offset = 0;
  let yy = y;
  if(even) {
    offset = radius * 1.5;
  }
  for(let x = 0; x < 900; x += radius * 3) {
    context.beginPath();
    hexagon(x + offset, y, radius);
    context.stroke();
  }
  even = !even;
}

Here’s what that gives us. Notice that I made the radius much smaller and stroked it instead of filling it.

Again, this all builds off of the last article. I had to remove the translation code because I need the exact x, y coordinates of every point of every hexagon, so I can feed that into a Perlin noise function to know how much to shift it.

Adding some noise

The Perlin function is going to make use of this library: https://github.com/josephg/noisejs. Feel free to add that to your project however you’d like. Or add a different noise function. It doesn’t really matter which one you use.

I need a function that’s going to take an x, y coordinate, calculate an offset based on Perlin noise, and return a new, shifted x, y coordinate. Since JavaScript doesn’t let us return multiple values, I’ll return and object with x, y properties. Here’s the function:

function perlinize(x, y) {
  const scale = 0.01;
  const strength = 20;
  const angle = noise.perlin2(x * scale, y * scale) * Math.PI;
  return {
    x: x + Math.cos(angle) * strength,
    y: y + Math.sin(angle) * strength,
  }
}

To revisit how a Perlin flow field works, we’re going to use 2-dimensional Perlin noise, feeding it an x, y value. Since the numbers we’re using will be in the hundreds or even thousands for pixel values, we’ll scale that down a bit with a scale value. This function returns a value from -1 to +1. Other Perlin noise functions sometimes return values from 0 to 1. Either will work just fine, but might need some tweaking. I take that value and multiply it by PI, which will give me a number from -PI to +PI. We’ll call that an angle in radians. In degrees, it would be -180 to +180. And we’ll use the sine and cosine of that angle to create an offset based with a customizable strength. Then, we return the original x, y coordinate + that x, y offset.

Now we just need to alter our code to use the perlinize function. I’ll just show the relevant function:

function hexagon(x, y, r) {
  let angle = 0;
  for(let i = 0; i < 6; i ++) {
    const p = perlinize(x + Math.cos(angle) * r, y + Math.sin(angle) * r);
    context.lineTo(p.x, p.y);
    angle += Math.PI / 3;
  }
  context.closePath();
}

And this is where this gets us.

Each hexagon still perfectly tiles because the Perlinized offset for each shared point of each hexagon should be exactly the same, at least down to an adequate degree of precision.

Shading

Now let’s add some shading. Basically we just want a grayscale value for each hexagon. To enhance the effect, the shading should be coordinated with the offset flow field values, so we’ll use the same Perlin noise settings. Here’s a function that will accomplish that:

function getShading(x, y) {
  const scale = 0.01;
  const value = (noise.perlin2(x * scale, y * scale) + 1) / 2;
  const shade = 255 - value * 255;
  return "rgb(" + shade + "," + shade + "," + shade + ")";
}

This takes an x, y coordinate and returns and rgb color string. Remember that this particular noise function returns -1 to +1. I’ll add 1 to that to have a range of 0 to 2, then divide by 2 to get 0 to 1. Then I’ll calculate a shade value by subtracting that normalized value by 255 and subtracting from 255. A bit convoluted, I know. This is all made a lot easier if you have a map range function. It would look something like this:

const n = noise.perlin2(x * scale, y * scale);
const shade = map(n, -1, 1, 255, 0);

To see how a map function would work, check out this video.

Finally, we just need to alter our drawing code to set the fill color based on the x, y of each hexagon, and do a fill before the stroke:

  for(let x = 0; x < 900; x += radius * 3) {
    context.beginPath();
    hexagon(x + offset, y, radius);
    context.fillStyle = getShading(x + offset, y);
    context.fill();
    context.stroke();
  }

And here is the result:

Summary

Don’t stop here. There are all kinds of variables and different rendering techniques to experiment with here. This is all just about taking two different concepts – hex grids and Perlin noise – and combining them in a creative way. This worked out pretty well, but there are an infinite other combinations waiting for you to discover.

Late breaking comment…

One thing I had in writing this but totally spaced out on while writing the article is that this code is extremely unoptimized. Every single x, y point here is calculated and then “perlinized” three times. OK, some of the ones on the edges only get calculated only once or twice, but you get the point.

Strategies for optimizing would probably involve creating a single point grid one time and then using a loop to draw using the pre-calculated points in that grid.

This is left as an exercise for the reader.™

Hexagons

I know what you’re thinking. I’m thinking it too. So let’s stop tiptoeing around the subject and just say it out loud:

Hexagons are freaking cool.

Oh… you weren’t thinking that? Oops. My bad. I just assumed. Must be just me. So let me state my case on why hexagons are so damn neat.

First, let’s get some definitions out of the way. A hexagon is a six-sided polygon. And just to be clear, the hexagon I’m talking about is the regular, convex polygon type of hexagon. Which is to say that all of its sides are the same length and all of its angles are the same (120 degrees).

Cool things about hexagons

  1. A hexagon is made up of six equilateral triangles. Each triangle is composed of three 60-degree angles, and three sides that are the same length, which is the radius of the hexagon.
  2. This means that each side of the hexagon is the same length as its radius.
  3. Hexagons are one of the three regular tessellations. That means you can take a bunch of hexagons and pack them together perfectly with no space left over. The only other two regular polygons you can do that with are squares and triangles. And in a sense a hexagon tiling and triangle tiling wind up being exactly the same thing. See #1 above.
  4. Hexagons appear pretty regularly in nature. The bounds of any snowflake, the cells of a beehive, basalt columns, the compound eyes of insects, the packing of bubbles, the cloud formations on the north pole of Saturn.

    By NASA/JPL-Caltech/Space Science Institute – http://www.nasa.gov/sites/default/files/pia18274_full.jpg, Public Domain, https://commons.wikimedia.org/w/index.php?curid=33952464
  5. When you tile hexagons, exactly six hexagons will surround every other hexagon. If you connect the center points of the six surrounding hexagons, you get another, larger hexagon.
  6. If you connect every other point of a hexagon to its center, you have a perfect isometric cube.

All of these points, and more, make hexagons a great shape to play with if you’re doing any kind of creative coding.

So, you want to draw a hexagon…

Now you’re saying, “Gosh, Keith. These hexagons sound wicked pissah! How can I draw one???” Well, let me tell you.

You need three parameters, the x, y position and a radius. You can also throw in a rotation parameter, but I’ll start without that. I’m going to do this in JavaScript, and assume there’s an 800×800 canvas element on the page with an id of “canvas”. You should be able to easily convert this code to whatever language you are working with.

const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");

function hexagon(x, y, r) {
  context.save();
  context.translate(x, y);
  let angle = 0;
  for(let i = 0; i < 6; i ++) {
    context.lineTo(Math.cos(angle) * r, Math.sin(angle) * r);
    angle += Math.PI / 3; // 60 degrees
  }
  context.closePath();
  context.restore();
}

context.beginPath();
hexagon(400, 400, 100);
context.stroke();


Run that, and we get a very nice hexagon. You can fill it instead of stroke it, make a bunch at different positions and of different sizes and colored differently. I’m not going to dive into the code there much, as it’s pretty simple.

Note, that I’m keeping it super simple here. You can optimize this, you can rework this, make it more reusable, make it draw regular polygons of any number of sides, pass in a rotation value and set angle to that instead of zero, and on and on. Maybe you want to pass in the context, or make the function a method of the context object. And you should do all of that. Or some of that. Or however much of that you want to do. But I’m in charge today, and we’re doing hexagons. And we’re doing them simple.

What about that tessellation stuff?

Yeah, now let’s make a bunch of hexagons and stick them together perfectly to see them tile. With squares, this is really easy. Loop through on the y and x axes and draw a square at each point. With hexagons, it’s a bit trickier. There are certainly multiple ways to go about this. I’ll give you one method, but if you come up with something that fits your needs better, go for it.

First of all, note that with the hexagon we drew above, it’s a bit wider than it is tall. Here, I’ve draw lines from the center to each point of the hexagon.

We can see that the width is two times the radius. Simple. But the height is a bit less. Knowing a bit of trigonometry, we can figure out that the distance from the center to the top of the hexagon is the sine of 60 degrees times the radius. So the height of the hexagon is twice that.

Here’s a hex grid.

The main thing to note is that unlike a grid of squares or rectangles, each alternate row or column overlaps with the previous and next row or column. If you consider we have even rows and odd rows, the even rows are horizontally offset from the odd rows by 1.5 times the radius. To see that, consider the horizontal distance from the center of one hexagon to the center of one of the hexagons immediately to its left or right, but in an alternate row.

Within each row, the center-to-center horizontal distance between each hexagon is 3 times the radius. To see that, consider the distance from the center of one hexagon to the center of the hexagon directly to its left or right in the same row.

And vertically, each row is offset from the previous row by one half a hexagon height, or sin(60) * radius.

Knowing all of that, we can put together a double for loop that draws a grid.

const radius = 50;
const ydelta = Math.sin(Math.PI / 3) * radius;
let even = true;

for(let y = 0; y < 900; y += ydelta) {
  context.save();
  if(even) {
    context.translate(radius * 1.5, 0);
  }
  for(let x = 0; x < 900; x += radius * 3) {
    context.beginPath();
    hexagon(x, y, radius);
    context.stroke();
  }
  context.restore();
  even = !even;
}

I’ll walk through this code quickly. First we set the radius to whatever. 50 in this case. Then we calculate how far apart to place each row. We said that was sin(60) * radius. 60 degrees is PI / 3 radians. And I’ll set an even variable to true to know whether we are on an even or odd row.

Then we create a double for loop on y and x. I have an 800 pixel canvas, but I looped through to 900 on each axis so I didn’t wind up with any empty space on the right or bottom edges. The y loop increments by ydelta and the x loop increments by radius * 3, all as discussed above.

If we’re on an even row, I’ll translate the canvas by radius * 1.5. Note that I did a context.save() before that, and follow up with a context.restore() at the end of the loop.

Inside the inner x loop, I just draw the hexagon. And at the very end of the loop I set even to !even to make the next row be odd, meaning it will not get that horizontal translation applied.

And now you can make a hex grid. Of course, you can fill each hexagon instead of stroking it. If you used different colors, that works out well, but if you are using all the same color, they’re all going to blend in together. A trick to handle that is to reduce the radius you pass into the hexagon function like so:

context.beginPath();
hexagon(x, y, radius - 5);
context.fill();

This gives you a 10 pixel border between each hexagon (5 pixels on each side).

Another strategy for filling a space with hexagons is to start with a single hexagon at the center and draw six new hexagons around that one and continue out in rings from there.

Hexagons are also a common tiling pattern in various strategy games. In that case, you need a bit more logic to figure out which six tiles are adjacent to any given tile and how to move from one to the next. Beyond the scope of this tutorial.

But what about that cool image at the top with the warped, 3d-looking hexagons?

Yeah, that one is pretty neat, isn’t it? Try it for yourself. I’ll write up another article on how I did that soon.

2018 in Review

Here were are again… At the rate I’m going here, this blog will just be a collection of annual years in review.

Anyway, an interesting year. For most of my programming career, I’ve had my job and then my personal projects. This past year drew to a close, the day job took a lot more of my focus. In fact, for the last 2-3 months at least, I haven’t really had any big personal projects. Work has been taking most of my attention. That’s not a bad thing. I’ve taken on a new role, really a whole new career path at work and I’ve grown in so many ways. More on that later.

Personal Projects

As far as personal projects, I started the year being into the Rust programming language, but before too long I got way more into Go. As far as programming languages, Go has excited me more than anything else has in many years. It takes a lot of the strengths of many different languages. It’s a compiled, strongly-typed systems programming language, but at the same time it can be expressive enough to make it really fun to do creative coding with. As with Rust, I have been generating graphics with bindings for Cairo. Initially I was using go-cairo. But as that has seen very little actual work over the last couple of years, I wound up forking it and doing a lot of work on it myself, resulting in my own go-cairo. I also ported the bitlib library that I’ve used in other languages over to bitlib for Go or blgo.

GIFs
I created a lot of animated GIFs with the above setup. And a couple months of the year I led a gif-a-day kind of thing on twitter. #MayContainGifs and #GulyIsForJifs. These were great fun and it was really nice to have other people playing along.

Wine

I also did two side projects for other people in 2018. I was approached by the designer, Jenny Doll. She was working with the Anarchist Wine Company and wanted to create a series of generative, data-driven labels for a line of wines. Yes, please. The wines lines are called Anarchist, Philosopher, Rosé Against the Machine, and Conspiracy Theory. For each group, we took data relating to historical anarchists, philosophers, disruptors and conspiracy theories and worked them into a generative design. For example, a list of philosophers, their birth dates, date of death and some other key date in their life. These were interpolated into various “hot spots” on a square canvas. Then I used my Random Lissajous Web algorithm (one of the few techniques I can say with a good amount of confidence that I invented) and gave each data set some different parameters. The web also reacted in different ways to the aforementioned hot spots, and each set had a different color palette. In the end, the result is very abstracted from the original data. But damn, they looked cool once they wound up on the bottles.

Elixir

Another project came up at just about the same time and wound up being very similar. I was approached by Design Science UK to create some graphics for Elixir Europe, a community for European life science organizations. They needed images for their 2017 annual report. A full back/front cover spread and full page images for each section. They also wanted something like the Random Lissajous Webs, but in a way that represented the idea of each section of the report: platforms, communities, activities, governance. These again got pretty abstracted from the concepts. Essentially what I wound up doing was generating lots of different images with random parameters, picking ones that I liked and kind of matching them up with the section concepts. You can browse the actual publication here:

Both this and the wine project gave me some practice in creating high resolution images. This would have been a problem in my previous platform of choice, HTML/JS/Canvas. But generating these in Go worked out really great. The final challenge came a few months later. Elixir wanted a large banner for a conference they were presenting at. The banner would look something like this:

But the required dimensions were roughly 11 feet by 7 feet, at a resolution of 150 dpi! This wound up being so large that even Go/Cairo choked on it. I wound up having to render it in four different overlapping tiles and then stitch it back into one giant image.

Work

For the last almost two years, I’ve been working at Notarize. We do on-line notarizations. Not the sexiest thing in the world, but I think it’s a great example of taking some important function that has not really changed in centuries and bringing it into the modern world. In addition, we’ve extended the service so that we are able to do full mortgage closings completely on line. You can buy a house, without ever leaving your house. You can buy a house on your phone. I mean fully buy a house. Sign all the documents, get them notarized. Done deal. You own the house. The company is changing laws and revolutionizing the industry. When I started, I was the 7th engineer. At this point, there are nearly 40 of us in the engineering department alone.

That’s me, front and center with the blue shirt.

In November of 2017, I made the first big career jump in ages, becoming an engineering manager, and wound up managing something like 10-11 other developers. At the end of 2018, the person in charge of engineering gave notice. There was nobody in the wings to take over his duties and it’s not the kind of hire you get overnight. So, to make a long story short, I’m now the Director of Engineering of 38 engineers. Factually, I’m leaning heavily on one of the other managers, who is taking on about as much extra stuff as I am, but he didn’t want the title. I didn’t particularly want it, but I didn’t really want to see the position go unfilled. In short, I think (hope) I am better than nothing.

This is a huge life change for me. It means I’m writing virtually no code at work anymore. And that’s OK. The me of a few years ago can’t believe that I’m saying it’s OK, but it is. We have a really high quality team of amazing developers here who are more than capable of cranking out code day and night. I’m focusing on process and code quality and keeping this crew of 40 evil geniuses happy and productive and not killing each other.

2019

Like last year, I’m not really making any specific resolutions, but I have some guidelines I’d like to focus on a bit better this year. I published these last year.

To summarize,

  1. Creation is greater than Consumption.
  2. Enlightenment is greater than Entertainment.
  3. Advice is greater than Authority.
  4. Commendation is greater than Condemnation.

I think I did pretty well on 3 and 4 last year. I don’t feel like I created enough in 2018 though. And what I created was more for entertainment than enlightenment.

So for 2019 I’m going to work on 1 and 2. I have two ideas for books that have been floating around in my head. One for several years. I’ve started these both a number of times. I plan to actually finish both of them this year. Watch this space for more details. I’d also like to publish more tutorials and articles. Maybe even some more videos. But let’s start with some more tutorial-based blog posts here.

I’m also doing less and less on “social media” these days. It’s become less and less social and more and more media. I left Facebook for good this year and it was one of the best things I did for myself. I’m about -this- close to closing my Instagram account. But I do follow some family members there, which is the only reason I’m keeping it at this point. I played with Mastodon a bit earlier in 2018, but despite all its promises of being a social media utopia, it’s not for me. So I’m down to Twitter as the only thing I really check on a regular basis. And I’m trying to do less and less there as well. Oh, no, wait. I’m also on Reddit regularly, though I don’t post a lot. Just the odd reply here and there, and my interests are constantly changing. To be honest, I miss the old days of forums. I’ve considered setting up some kind of creative coding forum or discourse. Something I will look more into this year, unless someone knows of a good one out there already. But for now, the guideline is going to be “tweet less, blog more”.

Speaking of guidelines, a few others I want to note for myself to try to follow in 2019 are John Maeda’s Four Rules from 1999:

  1. Don’t speak ill of others.
  2. Avoid passive aggressive behavior.
  3. Listen broadly, but don’t waffle on decisions.
  4. When in error — admit, apologize, move forward.

And while we’re at it, here’s a gem from Woody Guthrie – his resolutions from 1943. Holds up pretty well, IMO. I love the conditional on number 3. 🙂

Happy 2019 all!

tinpig 1.4.0 and sales pitch

For the past few weeks I’ve been putting a lot of work into an app called “tinpig“. It’s a tool for creating projects out of custom templates. I’ve described it in a previous post and the readme file details how to use it in depth, so I’m not going to go to much into that here.

This past weekend I got tinpig to version 1.4.0 and I think it’s pretty stable and feature complete in terms of what I envisioned for it. At this point, I’m mainly thinking about fleshing out some of the templates that can be used with it. So this post is kind of a sales pitch on why you might want to think about using it.

If you’re an app developer, you probably create a project and then work in that project day in / day out for weeks, months, maybe years. There’s a good chance that the project you’re working in now was created by someone you don’t even know.

But let’s say you’re also a “creative coder” as I know a lot of you reading this probably are. Maybe you create a project or two per week, or maybe you try to crank out something on a daily basis. Each time you want to create something new, you have to set up that project. This might involve making a folder, creating some files and other folders in that folder, editing those files, importing libraries, setting up build scripts etc.

Chances are, after you’ve done that a few times you’ve worked out some shortcuts. Maybe you started by copying an earlier project and then going into it and changing some stuff. Eventually maybe you came up with a master project that includes all the stuff you generally use, set up the way you like to set it up. You copy the master project, then go in and change a few things here and there, then you’re ready to start writing code.

Well, that almost exactly describes what tinpig does for you. A tinpig template is that master project. All those initial tweaks you make to the master before you start coding – the project name, date, whatever – those get put into the template as tokens and you have a chance to give them values when you create the project.

But now you can have multiple different kinds of projects, different languages and platforms, etc. all easily accessible and creatable without hunting around your hard drive. Type tinpig, choose a template, give it token values if needed, and you have a new project.

Another common use case is when you are learning something new. In fact, that’s where I, personally, am getting a lot of use out of my own app currently. I’m learning the Go language and have been working through some tutorials and books and just reading documentation and figuring stuff out. Every time I start a new chapter that has a new project type, and every time I want to try out a new feature, I just type tinpig and select my Go template. It has no custom tokens, so it just creates a new folder with a main go file in it. That file has a package, the start of an import section and a `main` function. All ready to start learning the new thing.

One more example – another way I’ve actually used the app a couple of times. Say you are an app developer as described in the beginning of this post. You’re working in a big, complex project. But you run into something that’s not working the way you think it should. You don’t know if it’s a bug in the project code, or maybe you just don’t understand how that language feature works. So you want to isolate the code in question and do a quick test of the feature all by itself.

I do mostly web development at my job. I have tinpig templates ready for HTML/JS, NodeJS and Webpack/React. I can fire up one of those projects in just a few seconds (a bit longer to install the dependencies on the Webpack one) and test out the feature I’m working on in isolation. When you’re done, delete the project and go back to your main work.

This is also useful for experimenting with some new language feature before adding it to your project. I’ve been doing some major refactoring on this web project and thought that React React render props might simplify things in this code I was working on. But I didn’t have a clear concept of how they worked. I fired up a Webpack/React project in about a minute, figured out how they worked, and went back to my main code to continue the refactor.

Anyway, that’s my pitch. I won’t lose any sleep if nobody uses tinpig other than myself, but it’d be nice to know that other people find it as useful as I do.

Introducing “tinpig”

Years ago, I was a big fan of Sublime Text as an editor. It’s a great general purpose editor. There was one thing I missed though. Prior to that, I had mostly worked in dedicated, language/platform IDEs. These always had a “new project” functionality. They knew how to set up a new project in the language they were dedicated to. Because Sublime is a general purpose editor, it couldn’t really supply that functionality, because every type of project is different.

So, I wrote a plugin called STProjectMaker, now, just ProjectMaker. This allowed you to create a template for whatever language/platform you wanted, and create a new project from within Sublime. It actually became fairly popular, with over 6000 installs.

But about four years ago, I stopped using Sublime Text. So I stopped working on the plugin. Issues and PRs and feature requests piled up. Recently Ben Felder asked if the project was still alive and if he could help out getting it into shape. He’s been doing a great job cleaning things up and has brought the project back to life again, which I’m really excited about, and very grateful for.

But, personally, I’m still not using Sublime. So this got me thinking about recreating the basic functionality as a standalone project. Last Friday I sat down and wrote up a list of features I wanted in such a tool. And one week later, yesterday, I released v1.0 of a project codenamed “tinpig”.

tinpig

The concept is pretty simple. You have templates, which are folders of files, potentially with replaceable tokens in them. You choose a template, specify a location and it copies the files over, replacing the tokens with values you define. Not rocket science.

There are other tools out there that are probably way more powerful. I think one of tinpig’s key features is its simplicity. The whole reason you would use a tool like this is to quickly spin up projects of different types. For prototyping, testing stuff, great for creative coding, etc. You don’t want to have to learn a whole new tool or templating language to do that. You can just create a project the way you like it, copy the files over into your templates directory and add a json file with a name and description, and you have a new template that lets you recreate that project anywhere you want within about 20 seconds.

But if you want, you can go in and add tokens and a few other power features to make the project even more powerful.

Just thinking… I should make a tinpig template template. A meta template that makes setting up a template even easier… Sorry, got sidetracked.

Anyway, try it out. If you want. Let me know if it’s useful. Tell me how it could be better.

Oh, if you come up with a useful template, feel free to do a PR in the tinpig-templates repo. Or just chuck it over to me and I’ll put it in there.

Introducing bitlib-rs for Rust and Cairo

This article builds off my previous article, Intro to Cairo Graphics in Rust. In that, I briefly described how to install Rust and the Cairo graphics library and set up a Rust project using the cairo-rs bindings. With that article, and a bit of dedicated research on your own, you should have been able to start coding some drawings using the Rust programming language. In this article, I’m going to build on what I described there, and introduce my own library, bitlib-rs, that adds a bunch of new functionality on top of Cairo.

I used to do a lot of work in Flash. ActionScript. RIP. I had, at various times, built up libraries of additional drawing routines that made it easier to draw complex shapes, manipulate colors, etc. But for some reason I never got very organized with it back then.

Eventually, I switched over to JavaScript and started using Canvas to draw stuff. By that time, github was a thing, and I started creating libraries that actually stuck around. This culminated in my own bitlib JavaScript library that I personally used all the time. It’s got all kinds of advanced drawing routines, animation stuff, a bunch of math and geometry functions, a pseudo random number generator, and hard core color manipulation tools.

When I started working with Rust and Cairo, I wanted all that functionality to come over with me. So I got to work porting bitlib to bitlib-rs. This was a great way for me to learn Rust itself. 800-something lines of code I knew inside out, that had to be recreated in a totally different paradigm. With the added verbosity of the new language, pulling some other stuff in from some of my earlier JS libraries, and riffing on existing code with new functionality, I’m up to over 1,400 lines of Rust. It’s still very much a work in progress, and as of this writing, should be considered to be in a pre-alpha state. Functions might be broken. APIs might change. More stuff needs to be tested and documented. But there’s some good stuff in there.

Let’s start by adding bitlib-rs to a new project. Use cargo new to create a project. In the dependencies, add:

[dependencies]
bitlib = { git = "https://github.com/bit101/bitlib-rs.git" }

Normally, dependencies are added with a version number when they are registered with the crates dependency system. Since bitlib-rs is not there yet, you can just add it with the git url. Alternately, you could check out the project and add it via a path:

[dependencies]
bitlib = { path = "path/to/bitlib-rs" }

I use this method while I’m working on the library and want to see the latest changes in a test project.

Now, in your main.rs, add the following line at the top of the file:

extern crate bitlib;

Now you’re ready to use the various structs and methods in your code. But first, let’s get an idea of how bitlib-rs can make using Cairo easier. Let’s make a bare-bones application that draws a bunch of randomly sized, positioned and colored circles and saves it as a png.

extern crate cairo;
extern crate rand;

use cairo::{ Context, ImageSurface, Format };
use std::fs::File;
use std::f64::consts::PI;
use rand::random;

fn main() {
    let surface = ImageSurface::create(Format::ARgb32, 600, 600)
        .expect("couldn't create a surface, yo");
    let context = Context::new(&surface);    

    for _i in 0..1000 {
        let x = random::<f64>() * 600.0;
        let y = random::<f64>() * 600.0;
        let r = rand::random::<f64>() * 45.0 + 5.0;

        context.set_source_rgb(random::<f64>(),
                               random::<f64>(),
                               random::<f64>());
        context.arc(x, y, r, 0.0, PI * 2.0);
        context.fill();
    }

    let mut file = File::create("output.png").unwrap();
    surface.write_to_png(&mut file)
        .expect("Couldn't write to png");
}

It’s not too bad, but there are some points there that seem a bit painful to me to have to do over and over.

  • Creating the surface and context is wordy.
  • The random syntax is painful to do anything interesting with.
  • The color definition method is inadequate.
  • Shape definitions lacking.
  • Saving to png is wordy.

To contrast, here is the exact same program written using bitlib-rs:

extern crate bitlib;

use bitlib::canvas::{ Canvas, BitContext };
use bitlib::color::Color;
use bitlib::random::Random;
use bitlib::file::open;

fn main() {
    let canvas = Canvas::create(600.0, 600.0);
    let context = canvas.get_context();
    let mut rand = Random::new();

    for _i in 0..1000 {
        let x = rand.float(0.0, 600.0);
        let y = rand.float(0.0, 600.0);
        let r = rand.float(5.0, 50.0);
        context.set_source_color(&Color::random_rgb());
        context.fill_circle(x, y, r);
    }
    canvas.write("output.png");
    open("output.png");
}

Let’s go through it step by step. First, the creation of the surface and context. I always want to create both of these, in the exact same way. They are a pair. So I created a Canvas struct that encapsulates them. This now goes from:

let surface = ImageSurface::create(Format::ARgb32, 600, 600)
    .expect("couldn't create a surface, yo");
let context = Context::new(&surface);

to this:

let canvas = Canvas::create(600.0, 600.0);
let context = canvas.get_context();

You can count characters typed if you want. But for me, it’s just a lot less boilerplate to keep in my head. Canvas::create and get_context. Simple.

Next, the random syntax. The rand crate is very powerful, but can be a bit complex to use, especially if you want a seeded pseudo random number generator (PRNG). Using the simplest (non-seeded) version, you get this:

let x = random::<f64>() * 600.0;
let y = random::<f64>() * 600.0;
let r = random::<f64>() * 45.0 + 5.0;

I don’t really love having to specify the data type in angle brackets and doing the math to generate a range. So I encapsulated rand’s more complex PRNG functionality into bitlib::random::Random. You have to create the PRNG, and then you have various methods to get int ranges, float ranges, bools, etc.

let mut rand = Random::new();

and then…

let x = rand.float(0.0, 600.0);
let y = rand.float(0.0, 600.0);
let r = rand.float(5.0, 50.0);

Doesn’t save a whole lot of typing, but again, it’s much easier on the brain. At least on my brain.

Then there’s color management. Cairo-rs has two methods for setting color:

context.set_source_rgb(r, g, b);
context.set_source_rgba(r, g, b, a);

In these, each value is a normalized value (0.0 to 1.0). For those of us who are used to 0-255 integers and hex values for color, this can be hard to think with. So a large portion of bitlib-rs is devoted to powerful color methods. You create an instance of the Color struct with various methods such as:

Color::rgb(r, g, b);                 // values from 0.0 to 1.0
Color::rgba(r, g, b, a);             // values from 0.0 to 1.0
Color::rgb_int(r, g, b);             // values from 0 to 255
Color::rgba_int(r, g, b, a);         // values from 0 to 255
Color::from_int(0xffcc9966);         // single integer argb.
Color::from_string("#ffcc99");       // rgb with 100% opacity
Color::from_string("#80ffcc99");     // argb
Color::from_string("palevioletred"); // standard css color names
Color::grey(shade);                  // 0.0 to 1.0 shade
Color::grey_int(shade);              // 0 to 255 shade
Color::hsv(h, s, v);                 // h = 0.0 to 360.0. s, v = 0.0 to 1.0

Then the random color methods:

Color::random_rgb();                // what it sounds like
Color::random_grey();               // also what it sounds like
Color::random_grey_range(min, max); // min and max both 0.0 to 1.0
Color::random_hsv(hmin, hmax, smin, smax, vmin, vmax); // you get the idea

Finally, some hard-coded colors for black, white, red, green, blue, yellow, cyan, magenta:

Color::black();
Color::red(); // etc.

So, our randomly colored circles go from:

context.set_source_rgb(random::<f64>(),
                       random::<f64>(),
                       random::<f64>());

to:

context.set_source_color(&Color::random_rgb());

Two things to note here. One is that there’s a new method on context, set_source_color. I’ll get into how that happened in a moment. Also, this method takes a reference. So it’s &Color instead of just Color. This lets the context borrow colors rather than move them, so you can reuse a single color multiple times. It’s a Rust thing you need to understand early on.

Now, about that context. It’s got some drawing methods, sure. But they are pretty minimal. That’s fine. I’m a big fan of APIs being minimal but extendable. There are a lot of things I want to draw that are not simply lines, arcs, rectangles or bezier curves. But they can all be composed from those things.

One of the brilliant pieces of Rust is its trait system. You can think of a trait as an interface… kind of. It defines methods that should be on a struct that implements that trait. Just like an interface defines methods that should be on a class that implements that interface. But Rust allows you to implement the trait methods on other structs. Even structs you don’t own, like cairo::Context. With that, I was able to extend Context with a whole boatload of new methods that are indistinguishable from native methods. All you have to do is tell Rust that you want to use that trait. My trait is called BitContext, so you just have to say:

use bitlib::canvas::BitContext;

at the top of the file and you’re all set. This is why we now magically have a new method called context.set_source_color, when Context itself only has set_source_rgb and knows nothing at all about my custom Color module. I’ve also added a ton of custom shapes, so instead of using arc and fill:

context.arc(x, y, r, 0.0, PI * 2.0);
context.fill();

I can now just draw a filled circle:

context.fill_circle(x, y, r);

The BitContext trait has all kinds of other drawing methods on it. Methods to draw ellipses, rounded rectangles, various types of curves and paths, polygons, stars, heart shapes, grids, etc. They each have a simple version that creates a path, and fill as well as stroke variants where appropriate.

Finally, we get to the point of saving the drawing as a png. Normally, you need to create a file and set up error handling, and use that file in the surface.write_to_png method, again with more error handling.

let mut file = File::create("output.png").unwrap();
surface.write_to_png(&mut file)
    .expect("Couldn't write to png");

But with the Canvas struct, you can just call write, with the path.

canvas.write("output.png");
open("output.png");

Also notice the final line, which is a call to bitlib::file::open. This will open the file in whatever application is registered to open that kind of file. As of this writing, this is set up to work on Linux and MacOS. It’s a nice added touch that lets you create and display the image just by running the program.

In addition to all that, there are geometry and math modules that have a bunch of other useful functions in them. One thing to note is that almost all the methods in those modules work exclusively with f64 values – 64-bit floating point numbers. Many of them could be made generic, but because cairo-rs‘s drawing methods all take f64s, I decided to keep these methods using the same data type. That may change in the future.

You may have noticed that I kind of skimped on the error handling. In various places where errors need to be handled, I did the bare minimum of expect or unwrap, which will work fine when things work fine, but will crash the program (with a hopefully useful error message) if you, say, try to use a file you don’t have access to. For my purposes – writing programs that generate images – this is totally fine. To make it more robust, I’d probably want to pass those possible error conditions to the caller of the functions that are currently squashing those errors. That would make the whole system more complex to use and defeat the purposes of a lot of the shortcut methods I’ve created. If you plan on doing something more sensitive – writing an app that others are going to depend on, you’d want to not use these shortcuts, and actually handle the errors appropriately.

To recap, this whole library is in its very early stages. But I know that a lot of the people who follow me may be interested in learning something new like Rust and Cairo and if this code were to give someone a bit of a boost, and some sample code to get started, that would be great.

My Resolution Guidelines

So here’s the obligatory New Year’s Resolution post. I’m not going to tell you what my resolutions are, or what yours should be, but I have been mulling over some guiding principles for quite a while. These aren’t resolutions, per se. But they are guideposts I try to keep in mind personally when thinking about my resolutions, or in fact, whenever I’m taking any action.

So here you go, my four principles. These are all in the form of “X is greater than Y”. In each case, this does not mean that X is holy and Y is evil. It just means that when all else is equal, I would prefer to give preference to X over Y.

1. Creation is greater than Consumption.

If I have a chance to create something versus consume something that someone else has created, I like to focus on creating. Whether this means writing a blog post or tutorial, making a video, publishing some open source experiments, building an app or game, going down into the shop and doing some wood or metal working or even doing some home improvements, creating something either for myself or for someone else will always be priority for me.

This doesn’t mean that consumption is bad. Nothing wrong with some Netflix and chill. I do some casual gaming on Steam, etc. and I’m even thinking of getting a more decent gaming rig this year to try a few more serious games. But personally, I need to keep in mind that games and popular media can be traps.

Yeah, sometimes I find myself at the end of an evening, having done nothing more than surfing imgur, reddit, YouTube and my RSS feed all night. It doesn’t feel very good. Other nights, I pull myself away from the computer after working on some long post or open source library all evening, with my head full of plans on where to go with it next. The latter is far more fulfilling. To me. Personally.

2. Enlightenment is greater than Entertainment.

Whenever I create something that has nothing but entertainment value, I feel empty. I have a side site called Art From Code where I just post algorithmically generated images and occasionally animations. Every once in a while, I get back into it for a little bit. But it never lasts very long because it’s just me saying, “Look at this cool thing I made.” And maybe some other people come along and say, “Hey, I like that cool thing you made.” And it ends there. That’s really boring for me.

I guess that’s why artists like to go on and on about their visions and inspirations for various pieces. I’m convinced that a lot of that stuff is dreamed up after the pieces are complete, but I understand the sentiment to explain what’s behind a particular work. That’s why I prefer to do stuff with open source. Even with computer-generated art, I like to share the code that created the image. It’s not some pseudo-intellectual artist’s statement about a dream I had, it’s literally what I did that brought that image about.

Hopefully, by sharing that, someone else will have some similar idea pop into their head and they can go riff on it and do some creation of their own.

Of course, I often go further than just sharing the code, and wind up writing tutorials or books or doing videos or talks on how I did things. And nothing beats the feeling of someone emailing to thank me for some bit of info I passed on, with a link to some project they were able to do because of that. It always makes my day.

3. Advice is greater than Authority.

So many articles and tutorials are designed, I think, not so much to teach, but to build up the egos of the authors. You know the ones I’m talking about:

“Everything you know about ____ is wrong!”

“The right way to ____.”

“10 things you should be doing in ____.”

“You’re doing ____ all wrong.”

A lot of these are outright clickbait, designed to create controversy. Others are from people who have learned some stuff about some stuff and have taken it upon themselves to instruct the world on the right way to do that stuff. Apparently, by speaking like an authority, you become an authority. At least in your own mind. And often in the minds of those coming newly to a subject.

I’m not perfect, but I intentionally try to avoid such a tone whenever I’m writing an article or tutorial. I actually do word searches for words like “should” before publishing an article. It’s a word that often indicates that I’ve slipped into authoritarian mode. I’m not saying I forbid the use of the word in my writing, I just look extra close when I do find myself using it.

Now, obviously, there are times when you are explaining some process to an audience and there is a common pitfall you want to warn them about. Say there’s a situation where strategy A is going to cause them a big headache and strategy B is a much better solution. You could write:

“Don’t use strategy A! It’s wrong. Strategy B is the right way to do this.”

But now you’ve just stuck the reader with a fixed idea that strategy A is bad and strategy B is good, with no real understanding of why. They’ll probably go off and repeat this to others, with just as much authority. And just as little explanation. Alternately, you might want to write:

“You could use strategy A here, but if you do that, here’s what you’re going to run into… [explain the pitfalls] Instead, you might want to look at strategy B, which has these advantages in this situation… [explain the benefits]”

There are no stone tablets with right and wrong coding practices written on them. Or design practices, or really any other practices in any field. There are different ways of doing just about anything that can be done. Each of those ways will have its benefits and its disadvantages. What we call the “right” way is usually one of the ways where the benefits greatly outweigh the disadvantages. Rather than just dictating “right and wrong”, why not explain the details and let them decide? It’s more work, but I find it much more valuable.

4. Commendation is greater than Condemnation.

Everything I’ve talked about so far has mostly to do with things you create yourself. This last one has more to do with responding to things others are doing or have created.

Another easy way to stroke one’s own ego is to put down something that someone else has done. Apparently, some people feel that if they are able to criticize something, they must be better than that thing they are criticizing. They are able to see the flaws in the product that the author could not see. So we get movie and book reviewers who have never written anything other than movie and book reviews. Software and hardware reviewers who have never built anything real or virtual. And of course, political experts who have never been in charge of anything other than their own life (and have often failed miserably at that).

If you use some software or hardware that has a bug, it’s way too easy to write some scathing review about how the developers are a bunch of idiots. You feel justified. I used to do this all the time. I’m trying to get out of that. I’ve actually found that directly communicating to the developer or company and explaining the issue usually works far better. Not always, but often enough to be a much better first attempt. If I do wind up posting a bad review about anything, I try really hard to not let my emotions get too involved. And I try to remember that there are real people behind the product – developers or creators like me, who are not perfect, but generally aren’t idiots.

Along with this, I’ve made a real effort to commend those things I really like. If I use some software or device or service that I like, I’ll tweet about it, tell people about it, leave a positive review about it. Usually we are only driven to give feedback when something goes wrong and we get pissed off. If something just works the way we expected it to, we go on our happy way without another thought. So I’ve been trying to go back through my purchase histories now and then and do positive reviews for all the things I bought. Particularly for smaller companies, individuals, eBay sellers, etc., whose livelihood depends on positive word of mouth.

I’ll even sometimes send a personal note to the seller/creator if I particularly liked something I bought or used. I know the effect this has because people often do the same for my books, videos, tutorials, etc. and it always puts me in a good mood when I get one of those notes.

Rewarding positive behavior can be just as powerful as punishing bad. Sometimes a bit of both is needed. But if I had to focus on one, it would be the former.

Summary

There is a lot of negativity in the world. It’s tempting to fight back at bad things with more negativity. But if we do that we just have negative on top of negative. Someone somewhere needs to do something positive once in a while. All of the above are focused on adding some positivity back into the world, lifting others up in the hopes that they’ll do the same for me now and then.

Have a great new year!

2017 in Review

It’s that time of year when we look back to see how things have gone in the last year, what we accomplished, how well we stuck to our goals, any major changes – good or bad, and start making plans for the next year. All arbitrarily based on a calendar system someone made up centuries ago, but so be it. If there’s no natural origin point, make one up.

2017 was a year of massive change for me. I changed companies once and changed jobs twice. And to a large degree, I actually changed careers once. I abandoned one coding platform, ramped up on another one and started learning an entirely new one.

My Job and Career

When the year started, I was working at a company called Dreamsocket, doing mostly Android work, with some web work and helping out now and then on iOS. I’d been there nearly three years and learned a whole lot. It’s a small company that does way more work than you would imagine possible. Award-winning, high profile work. It was an honor to be part of a lot of those projects. But I was feeling the urge to move on. It was just a feeling. I hadn’t gotten to the point of actually looking for another job. But then Steff, a friend and former coworker at two different companies reached out and asked if I’d be interested in coming to have a chat where he was working.

The company was Notarize. They do on-line notarizations. Not too exciting, I thought. But sure, worth a chat. As it turned out, I wound up being impressed enough with the people and technology that I wound up accepting an offer and became part of the web team. It’s all React, with Relay and GraphQL. Rails backend. In other words, a whole bunch of technology I knew almost nothing about. The first couple of months were a struggle. Although I came on as a senior engineer, I felt like a total noob. But I eventually found my feet and got productive and feel like I’ve been doing pretty well in terms of helping shape the team’s best practices, improving processes, improving the build, etc.

The company has been growing fast. There were 6 developers before me. Now there are close to 30. A month or so after I started there, Steff became the Engineering Manager. As we continued to grow, we needed additional managers. In just about every company I’ve worked for in my career as a developer, I’ve had some kind of manager role offered to me. I’ve never been interested. I just wanted to code. At Notarize, it was different. I really liked the way Steff was defining the role. It aligned with what I really wanted to do – help other developers be successful. So I volunteered. It’s very different. Much less coding, but I’m really enjoying getting to know all the engineers more and helping align what they want to do with what the company needs to get done. I have 8 developers I’m working with. Soon to be more. Working with Steff has been great. We see most things eye to eye and have a lot of agreement on where we should be headed. So that’s my job and the start of my budding new career.

Personal Projects

In the last few years, I’ve done a lot of physical making of stuff. Woodworking, knife making, leather work, blacksmithing. It’s been great, but it’s taken a back seat this year. Mostly due to the new job, which has required learning a whole lot of new stuff. There’s also the commute factor. For the previous four years, I was working at home. At the end of the day, I’d just pop downstairs into the shop and do an hour’s work before dinner. Or even get something done in the morning before work. I’m starting to feel the urge to build something these days though. I’m planning to at least get down into the workshop and do some cleaning up and organizing before New Years, and hopefully get a few projects done in the coming year.

As for personal coding projects, at the beginning of 2017, I started a new BIT-101 Lab. This was kind of a revival of my earliest BIT-101 Flash-based experiments lab. I had hoped to continue the experiment-a-day for the full year, but the new job did impact that. I’d be coming home and learning about React and Relay and Ruby and Rails. I had a backlog of daily pieces which acted as a buffer for a while, but when those ran out, I didn’t have the time to continue doing more.

Eventually, as I stabilized in the new job, I started being a bit more relaxed after work and had the urge to learn something new. I’ve been coding graphics and animation in JavaScript and Canvas for years. I really felt it was time to learn a new language though. Two that I was really interested in were Rust and Go. I somewhat randomly chose Rust, and for the last couple of months, that has been consuming me. It at once feels very familiar, but is also so fundamentally different than any other language I’ve worked in. It’s been a real challenge, but not in any overwhelming sense. I’ve been able to get productive in Rust while I continue to learn its weird nuances. I’ve been porting over a lot of my JavaScript graphics libraries. I’ve discovered that porting code you are really familiar with is a great way to learn a new language. You know exactly what you are trying to do. You just need to know how to express that in the new language’s constructs. I’ve already published one article on what I’m doing, and have plans for more to come.

I haven’t gone deep into animation with Rust. I’ve been using Cairo graphics, which really just generates image files which I save to disk. I have got a setup going where I can very easily generate an image sequence and convert it into an animated gif. Eventually, I want to explore the Piston game engine. More for its interactive animation capabilities than actually creating games. But who knows where that will go.

Personal Life

Not a whole lot to report here. I’m a year older than I was last year, slowly working my way through my sixth decade on this planet. (No, that doesn’t mean I’m in my 60s. Do the math!) There’s a lot to be said for getting older though. As your own mortality becomes more real to you, a lot of BS falls away. A lot of things you used to fret over now seem silly. You start to focus on what’s really important. And you realize that what is important is an individual thing that nobody can define for you, and you can’t define for anyone else.

I guess I’ll just end on that existentially inspirational note. I’m honestly excited for what 2018 will bring!