TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Show HN: Asciify, high-performance animated text art

6 pointsby TeffenEllisabout 2 years ago

1 comment

TeffenEllisabout 2 years ago
Hello Hacker News!<p>Asciify’s origin story begins with my attempts to use SVG’s more esoteric features like lighting effects and animations. If you’ve ever tried to make an animated SVG, you’re unfortunately familiar with just how slow they can perform even under modest designs.<p>Three.js to the rescue! Somehow their demos always ran at a smooth 60 FPS, and could render actual 3D graphics unlike the perspective-trickery I so often used in SVGs.<p>Despite the promise of a better tool, I was quickly humbled by a new domain of mysterious terminologies and fractals of OpenGL APIs. I still haven’t found a definition for a “normal” that feels intuitive. But I pressed on until I felt confident enough to put some simple scenes together. I tried some of the examples in their API documentation and discovered their ASCII effect.<p>It was pretty! And slow!<p>Maybe it was a feeling of gratitude or a sense of pride, but I knew it could be faster…and it only took me 3 weeks to crack the code.<p>It was simple at first. Their version used string concatenation. Could I use DOM nodes? Yes, but they’re slow to initialize. Could I use the same nodes and update their values? Okay that’s a bit faster. Maybe CSS grid could help with the layout. A marginally better FPS but what happens when I enable color? Slow! What if I make a diff from the previous frame buffer and do selective updates? Okay, now it’s fast but only on mostly static scenes.<p>The game changed when I moved my efforts to a canvas renderer. I discovered how I could pre-calculate each cell coordinate to optimize my frame rate, skipping the unchanged values. I could rethink how I perceived an array of RGBA values — height is just a derivative of width! And why are we using these expensive math operations when a bit shift could do the same thing? Let’s get rid of these string arrays and use 8 bit integers while we’re at it!<p>Did you know that Chrome’s Turbofan only optimizes `String.fromCharCode` when you use a 16 bit integer? Oh, the things I could tell you…<p>Eventually my efforts plateaued at a humble 30 FPS. The canvas `fillText` method is slow slow slow. This would’ve been the end, but I found a new inspiration while making the image upload demo. Drawing a single character is a lot like drawing an image buffer, so why don’t we pre-draw the ASCII characters to individual canvases? We could then call the much more performant `drawImage` method and consistently hit 60 FPS!<p>There’s more to this story that you can find in the Asciify source code, including the horrifying tales of reimplementing the color blending with alpha masks. The truth is that there are still optimizations to be found for someone brave enough to port this to WebGL. But I’m happy with the results and proud to share them with you.<p>I think that great artists can change how we see the world. Does that make coding an art? I certainly think so.