Animated Sinusoidal Cardiods

I think I just made up a thing. Usually when I think that, it just means fewer than a few hundred people have thought about it before me, so who knows.

Let’s start with cardioids. A cardioid is a heart-shaped curve. One way to create a cardiod is to roll a circle around another circle of the same size, tracing the path of a single point on the moving circle. Like so:

https://commons.wikimedia.org/wiki/File:Cardiod_animation.gif

I discovered another neat way to create a cardioid while checking out the math art challenge.

#MathArtChallenge Day 7: Cardioids!

In this method, you divide a circle into an arbitrary number of points around the radius. Then, for each point n, you draw a line from point n to point n*2. Point 1 to 2, point 2 to 4, point 3 to 6, etc.

Here’s some JavaScript/Canvas code showing this in action:

context.translate(400, 400);
const radius = 350;
const res = 100;
const slice = Math.PI * 2 / res;
const mult = 2;

context.beginPath();
for(let i = 1; i < res; i++) {
let a1 = slice * i;
let a2 = slice * i * mult;
context.moveTo(Math.cos(a1) * radius, Math.sin(a1) * radius);
context.lineTo(Math.cos(a2) * radius, Math.sin(a2) * radius);
}
context.stroke();

And here’s what that gives you:

You’ll notice in the code that I’ve divided the circle into 100 points, which is is rather low-res. If I up that to 360, we get something nicer:

So I’m calculating the points by getting two angles, a1 and a2, calculating those with slice * i and slice * i * mult as described above. slice being a full circle divided by res and mult equals 2 for now.

   let a1 = slice * i;
let a2 = slice * i * mult;

What if I change that to mult = 3 instead?

Or, mult = 4 ?

You see that for each multiplier, m, you get m-1 nodes in the cardioid. Let’s just go crazy and see what happens when we set res to 1440 points and mult to 25:

Here’s the code for those of you following along at home:

context.translate(400, 400);
const radius = 350;
const res = 1440;
const slice = Math.PI * 2 / res;
const mult = 25;

context.lineWidth = 0.25;
context.beginPath();
for(let i = 1; i < res; i++) {
let a1 = slice * i;
let a2 = slice * i * mult;
context.moveTo(Math.cos(a1) * radius, Math.sin(a1) * radius);
context.lineTo(Math.cos(a2) * radius, Math.sin(a2) * radius);
}
context.stroke();

All very interesting, but I wanted to start changing things up even more. I decided that rather than using a simple circle, what if I varied the radius of the circle with a sine wave? Here’s the code I came up with:

context.translate(400, 400);
const radius = 300;
const res = 1440;
const slice = Math.PI * 2 / res;
const mult = 5;
const waves = 6;

context.lineWidth = 0.25;
context.beginPath();
for(let i = 1; i < res; i++) {
let a1 = slice * i;
let a2 = slice * i * mult;
let r1 = radius + Math.sin(a1 * waves) * 100;
let r2 = radius + Math.sin(a2 * waves) * 100;
context.moveTo(Math.cos(a1) * r1, Math.sin(a1) * r1);
context.lineTo(Math.cos(a2) * r2, Math.sin(a2) * r2);
}
context.stroke();

First I created a waves constant that controls how many sine waves will go around the circle. Then an r1 variable that is based on radius, multiplied by the sine of a1 * waves times 100. And an r2 variable based on a2 * waves. So for each point, it’s radius will get larger and smaller as they progress around the circle. The result (setting mult back to 5):

You can get all kinds of interesting shapes by varying how many nodes and how many waves and the size of the waves and the resolution.

Of course, I had to have a go at animating these. The first idea was to vary the height of that radial wave. Here, it’s going back and forth from -80 to +80:

I’m not going to give the source for the animation examples, because it was written in another system entirely, but if you’ve followed along so far, you’ll be able to figure it out.

Next, I thought about varying the phase of that radial wave, so that the wave itself seemed to be animating around in a circle. This produced some really striking animations. I’ll close the article by posting animations for 2, 3, 4, 5 and 6 wave animated sinosoidal cardiodids. Enjoy!

On the Road to Becoming an Audiophile, Part I

Over the past several months, I have been on the road to becoming an audiophile. The saying says something about the journey being more important than the destination. In this case, I totally agree. In fact, I’m fairly certain that I don’t even want to become an audiophile. But taking the first few steps towards improving the quality of my audio experience has increased my appreciation and enjoyment of the music I listen to.

Of course, appreciation and enjoyment are very subjective things. I can say for sure that during the times of my life when I was most into music, the quality of audio equipment I was using was often pretty poor. That didn’t matter. Simply having better equipment and media doesn’t mean that you’ll enjoy it more. But in my case, diving into this subject has been the impetus for me to listen to way more music and get more into it than I have been in quite some years.

The way I see it, high quality music playback is made up of three points:

  1. High quality playback equipment (players, amplifiers, converters).
  2. High quality media (music files).
  3. High quality output devices (speakers, headphones).

Any one of these can be a weak link in the chain. If you have a crappy player, it doesn’t matter what your media is or what you’re listening to it on. If you have crappy, low quality mp3 files, your hardware can’t make up for that. And you can have perfect media on a perfect system, but if you have crappy headphones, it’s gonna sound like crap.

In the past few months, I’ve put attention on all three of these areas, trying out new playback equipment, upgrading my digital music library, and learning and trying different headphones (in ear monitors to be exact).

Actually, I went into this, not with the thought of becoming an audiophile, but just wanting a better way of organizing and accessing my existing music library. Of course, this led to a cycle of improving one of the above three points, and then seeing the shortcomings in the other two and upgrading those. This has definite potential to become one of those continuous loops of sinking more and more money into the next thing to get that extra 0.01% improvement in quality. I haven’t gone too far down this path and I’m pretty much happy with where I’m at and what I have at this point… though I can’t rule out one or two more purchases in the coming months. But after that, I’ll be totally happy. Really. Yeah… I might be in a tiny bit of denial.

Anyway, I plan on discussing each of the above points in future posts, defining some basic terminology, describing the paths I went down and pointing out what’s further on down the roads I have not traveled yet (yeah, “yet”). Again, I’m not an audiophile, and if I ever start referring to myself as such, someone please do an intervention. But learning more about this technology has been a lot of fun and I think I know enough to point out some practical basics to any newcomers.

Next up, I’ll talk about playback equipment – DACs and DAPs, etc. How I got into it, what I looked at, what I got, what else is out there, and what I’d think about getting in the future.

2019 in Review, and a new project

I don’t blog much these days, but usually do manage to get in a year-in-review post every December or January.

2019 was a tough year. Not bad, but lots of changes, lots of stress

Work

I’ve probably been more focused on work this past year than I have been in many years. To be honest, work has often been somewhat of “what I do in between my side projects” rather than the other way around. This year, the balance was very much the opposite. In fact, I had no real large side projects at all in 2019.

As mentioned in last year’s update, at the end of 2018 I became the Director of Engineering for Notarize. I took on this role with quite a bit of trepidation. I was actually offered the VP of Engineering role, but naively thought that taking on a lesser title would mean less responsibility and stress. In retrospect, it’s obvious that when you’re on top of the pyramid, it doesn’t really matter what title you go by. I could be the VP Eng or CTO or Director of Engineering or whatever else, and I’d still be doing what I’m doing now and stressing out just as much.

About three weeks into this new job, I got my first big challenge. We needed to do a significant, company-wide layoff, and I had to come up with a list of engineers to let go. Like, a dozen of them. I was very tempted to hand the list in containing just a single name – my own. But that wouldn’t have changed the outcome and would have just been taking the easy way out and giving the problem to someone else. We got through it, but it was one of the most painful things I’ve had to do in my career. Every one of the names on the list stuck me like a knife. They were all good people, many of them friends. I did what I could for each and every one of them, giving recommendations on LinkedIn, letting them know of other opportunities as they came up, and even acting as a personal/professional reference for several.

The rest of the year has gone a lot better. The remaining team members came together, got more focused and we’ve done some great work this year. We had two hackathons, agile training, a stability week, did some reorganization, sent people to some conferences, started warming up to the idea of having multiple remote engineers, and lots of other good stuff.

But there have been lots of ups and downs for me, personally. I’ve always tried to avoid management positions and remain a hands-on coder. That is all done. Apart from the occasional special projects, I’m not doing any regular coding at all. And I’m pretty much trying to figure out what I’m supposed to be doing day by day. It’s very different than being an engineer and having a project, feature or a bunch of tickets assigned to you. Every week, every day I have to decide what my job is going to consist of. It might be dealing with legal, personnel or code quality issues, coordinating requests across teams, arranging meetings and presentations or just about anything else. The panic points come when I’ve done everything that has been a pressing issue and I’m sitting there thinking, “now what the hell am I supposed to do???” And don’t talk to me about your imposter syndrome. You don’t want to know how bad mine is.

But overall it’s been great. A major learning and growing opportunity.

Other Projects?

Like I said, I haven’t really had any major public facing projects of any kind this past year. I still love geeking out over my multiple Thinkpads, trying different Linux distros, tweaking my home server and installing various media servers and other services on the home network and an external VPS and a few Raspberry Pis. Always tinkering with something.

But there has been one project slowly brewing, which I think I’m ready to make public…

bitbooks

I’ve been getting the urge to go back to writing books. I’ve written or contributed to about fifteen books with various different publishers. And a few years back I self-published Playing With Chaos. There are pros and cons to going through a publisher and self publishing.

And then there’s a third option that I have not tried yet – open source publishing. Enter bitbooks. I’ll be posting more about this soon, but basically, I’ll be creating books on github. Not a new idea, but one that appeals to me right now. You can check in any time and see the progress of any current books. When they are complete, they’ll be available in various finished formats – epub, mobil, azw3, pdf. Free as in freedom and free as in beer. They’ll have a Creative Commons license. No DRM. No charge to download or read, but I’ll set up ways to donate for those that find the material useful.

One part that I’m most excited about is that because of the open, flexible publishing format, I’ll be able to provide code samples in multiple languages. That’s one huge problem with coding books – they are almost always tied to a specific programming language. Of course, the text of the book and the examples given in the book will have to use a specific language, but I’ll be providing the actual code samples on github in multiple languages. And I’m hoping to get some community involvement as well, with people submitting examples in their own favorite languages as pull requests.

Again, more on this coming soon, but go ahead and check out the site and see what’s up there so far.


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.