I’ve just launched Sequence8, a PICO-8 music sequencer toy.

Here’s a video:

You can play with it in the browser at https://billiam.itch.io/sequence8, or download prebuilt binaries.

The copy button will save your song to your clipboard so that you can keep and share them.

To import a song, just paste it in.

Shorter songs fit in a tweet, so if you make something you like, please share it with me!

I picked up PICO-8 in the enormous Itch.io bundle recently, and have been having a lot of fun with it. Sequence8 is my first PICO-8 game.

The platform’s built-in limitations help ensure that games stay small and (roughly) within scope. They can’t be too large in code length, or lexical tokens, nor in sprites, sound, or music. Audio is limited to four channels, the screen is 128px square, there are 16 colors.

Sequence8 is based on another project I never finished, built with Ruby and Gosu.

There, I was able to use several full sized audio samples of real instruments, and dynamically pitch them up. Visual effects could be handled with transparencies and complex masks. I used C libraries for fast quadtree performance for mouse events. Can’t really do any of that in PICO-8 (at least, I can’t).

Here’s some of the build process

Getting started

This is the first prototype. It can play sounds. The current beat scrolls by.

Initial prototype
Initial prototype

Here I’ve started adding the sprites for the background, scrub bar, and selected notes, and one of the only sprite animations.

I found this post invaluable when trying to work with PICO-8’s color palette.

Adding sprites
Adding sprites


Without the ability to bind a bunch of arbitrary keyboard shortcuts, I actually had to build out the UI for this as well, which took the vast majority of the project’s development time.

Challenges here were:

  • Adding mouse support and mapping screen pixels to UI elements,
  • having logical controller navigation for an irregular grid,
  • switching between mouse and controller input without breaking something
  • having a different number of notes for some instruments,
  • adding and removing bars of music (which also adds and removes UI elements)

I probably rebuilt the whole UI system 3 or 4 times, and I’m still not happy with it.

UI as tabs
UI as tabs

I think this didn’t work well because the tab as a UI concept implies nesting content underneath the tab, but I wanted to have more information about the other instrument tracks visible at once.

Here’s the mouse support. It’s mostly built on top of the controller support, so while the mouse has a pixel position, it also maintains a position within the UI grid, identical to controller handling.

Mouse support
Mouse support


I went through a few iterations for lighting effects. Originally, the song progress bar was represented by a full column of sprites, as well as some smaller sprites to both sides that would overlay the background to fake a glowing effect.

In this version, the notes light up for a moment after they’re played. This is handled with a palette swap, and redrawing pixels surrounding each note. It’s wildly expensive, but it looks nice, and fixes issues with static overlays on top of animated images.

Light fade effect
Light fade effect

I’m doing this in a pretty simplistic way. For a much more performant (and technical approach), here’s a really cool article:

Light fade effect failing to maintain 60fps
Light fade effect failing to maintain 60fps

In the end, I used a simpler approach, using one level of lighting off to the sides of the


I started on some particle effects to make the visuals a little more engaging, but ran into further performance issues there. I put together a simple profiler to help track down the specifics.


PICO-8, as a virtual console, has it’s own CPU limits distinct from the host system, and applies extra CPU cost to some operations.

The biggest takeaway here for me was: Limit expensive redrawing, limit deeply nested loops, limit overall particle counts (and make sure that count is up to date, and not from the last animation frame. Whoops)

I think these look nice still, but they’re big, slow and floaty, like each note is shaking down snow. Still nice, but I wanted a more explosive feel.

Big slow particles
Big slow particles

Here’s a less colorful, and more conservative version. Particles have more starting velocity, and fade faster.

Smaller particle effects
Smaller particle effects

Here’s the final version. Notable changes here:

  • Notes are always in front of the particles, and have a bit of an opaque outline around them, making them much more visible when a lot is happening on screen.
  • Two or three contrast frames at beginning of the particle burst, making it more distinct and poppy.
Final particle effects
Final particle effects

I recommend looking through (and supporting) this amazing pixel art resource: https://blog.studiominiboss.com/pixelart

CNC toolholders

While working on some other projects, I mocked these guys up real quick to help organize some of the tools and accessories I’m using with my CNC right now.

The design is simple, and they’re just carved in scrap 3/4” plywood, so recreating them if when tools change won’t be a big deal.

Eventually, I’m planning to have these in drawers instead, but it’s a good start.

Tool holder
Tool holder
Workholder holder
Workholder holder

To make an accurate profile for complex (mostly two-dimensional) parts, I took a photo zoomed in at a distance (to minimize perspective distortion), with a ruler visible.

This photo can be imported into Fusion 360 as a canvas, and the ruler used to calibrate it.

This is my first real CNC project, a cyclone dust separator.

There are lots of different versions of these floating around, but most use big box store five-gallon buckets, or larger garbage cans, but I wanted one that would fit comfortably underneath my CNC table and still have some capacity.

I settled on using a short, 10 gallon steel bucket

The lid and is made of 1” plywood, cut with a 1/4” endmill and a 90 degree chamfer bit. The baffle just redirects airflow, so only uses 1/2” plywood. It was also cut with a 1/4” endmill, but the extended section that contacts the wall of the bucket was tapered with a 1/4” ball end mill to match the slope of the bucket.

Lid after cutting on the CNC
Lid after cutting on the CNC
Baffle profile cut
Baffle profile cut
After trimming off tabs on the router table
After trimming off tabs on the router table

I’m using readily available schedule 40, 2” PVC pipes and fittings and 3d-printed this fitting to allow the pipe to pass through the lid at a 45° angle.

3D printed fitting
3D printed fitting

I installed the fitting using wood screws and caulk to seal it, and added a bead of caulk in the lip and smoothed it down. It kind of works, but a softer silicone caulk would have worked better.

3D printed fitting
3D printed fitting

I held the lid and baffle together with dowels, screwed in from the top and bottom. Here’s the assembled lid with baffle (upside down).

Lid assembled
Lid assembled
Fully assembled separator
Fully assembled separator

To connect the separator to my shopvac and hoses, I used 2” PVC, heated (agonizingly slowly) with a (tiny) heatgun until they could be formed over my hose fittings.

PVC vacuum hose adapter
PVC vacuum hose adapter

It works well, but I haven’t measured its efficiency. I’m not really seeing anything in the shopvac now though.


CNC tool setter

I had some keyboard switches left over from a previous project, and wanted a more convenient process for changing bits during a job.

Bit setter mountet to wasteboard
Bit setter mountet to wasteboard

This is a simple switch, wired in parallel with my touch plate, that is used before and after changing router bits.

When changing a bit, a macro offsets the Z height by the difference between the first and second tool length, and work can continue with the new bit.

This process is much faster than manual zeroing after changing bits, or using the touch plate. The tool can overshoot the switch’s trigger position slightly without damage, so the probe speed can be much faster than a touch plate, and it doesn’t require connecting the probe clip.

Additionally, if the original zero position has been carved away by the previous job, the tool setter can still be used.

It’s promising, but has some issues.

First, it has moving parts exposed to cnc dust and chips. I added a magnetic cover for it to help with that

Second, though it’s much lower profile than commercial options, it’s just about flush with the surface of my wasteboard. For surfacing, when I’m cutting off the edge, I’ve been pulling the cap off and taping it down. I’m planning to move it out in front of the wasteboard instead.

Third, repeatability isn’t amazing (around 0.02-0.04mm) because the 3d-printed button top I’m using isn’t a perfect fit on the switch, and the switch has some play as well. I’m looking to replace it with something with less play, but haven’t found the right thing yet.

3D printable files for it can be found here

CNC software and jogging

To drive the CNC, I’m currently using CNCjs, installed on a Raspberry Pi 3b+.

The system is currently headless, because I don’t have a dedicated laptop for it, and my CNC lives in my garage where it’s too cold to leave an LCD screen.

CNCjs is fine, and a good fit for this use case, but pretty clunky on a small screen, and lacks some of the features available in other gcode senders, like autoleveling, basic gcode generation for simple operations like facing, cancelable jogging, angle deviation probing…

I find jogging via the default web interface really uncomfortable. It’s very easy to hit the wrong button among the tightly packed buttons, and do something bad, like rapid moving to zero when things are in the way. I’d like to say I only did this once, but…

The other issue with jogging like this, particularly with a small screen is that button presses may be queued, and delayed, and then may execute in series unexpectedly. There’s also no real way to quickly cancel dangerous moves.

I saved myself some pain by enabling soft limits in GRBL, but I need to tune these better.

For small screen use, there’s a much better interface at https://github.com/cncjs/cncjs-shopfloor-tablet, which I used for a little bit. It too has some issues; It’s much better suited to a tablet display than a phone, and you cannot run macros from it.

I started down the path of making the interface more responsive, but stopped using it before finishing.

I also ran into this issue which drove me crazy for a few days before discovering that, if I left the interface open on my phone, and the phone went to sleep, whatever job was running would halt.

File uploading

To transfer gcode from my machine to the raspberry pi, I’m currently using https://github.com/efeiefei/node-file-manager to upload the gcode to the CNCjs watch folder. It would have been easy to set up network shares for this also.

I’ve also written (hacked together) a utility to upload gcode files to node file manager, as well as opening them in my default editor, and have set this utility as my Fusion 360 editor.

Now, these are automatically uploaded after post processing.

Utility can be found here: https://github.com/Billiam/upload-passthrough

Probing and other macros

I’m using a few macros right now.

One for XYZ probing using a touchplate, as well as two for a bitsetter are from here: https://github.com/cncjs/CNCjs-Macros

I duplicated the XYZ probe one and deleted a bunch of it to act as a Z-only probe, since I’ve been setting the Z-zero to my spoilboard away from my material, when I do full through cuts.

I’m also using one from this page to jog around the X/Y perimeter of loaded gcode: https://github.com/cncjs/cncjs/wiki/User-Guide

Jogging improvements

I dug up a wireless keyboard I’d forgotten about, the Logitech K400+.

I found this module for CNCjs which allows jogging with a wireless keyboard: https://github.com/cncjs/cncjs-pendant-keyboard, but I don’t have that specific one, and some of its special key mapping didn’t translate to mine.

I also found this one which supports smooth jogging while holding a key, as well as grbl jog cancelling. https://github.com/jheyman/shapeoko/tree/master/cncjs-pendant-keyboardreader

This one is more generic, but can’t work with my headless setup, as it requires the running application to maintain focus.

I’ve forked it here: https://github.com/Billiam/cncjs-pendant-keyboardreader

It now uses node-hid like cncjs-pendant-keyboard so it doesn’t require focus, and works with the Logitech K400 plus.

I have it set up to jog on X and Y with the arrow keys, Z axis via I and K in 0.1mm increments.

Ctrl + direction will move 10mm at a time.
Alt + direction will move 1mm at a time.
Shift + direction will move continuously in that direction until shift is released.

Ctrl + H will home the machine.

I’ve also added a few macros via keyboard:

Ctrl + P will run an XYZ probe
Ctrl + Z will just run a Z probe
Ctrl + 1 will initialize the bitsetter for the first tool
Ctrl + 2 will use the bitsetter for tool changes
Ctrl + Shift + Return will continue after pausing for toolchanges.

With an easier setup for jogging, I’m only using the default CNCjs interface on my phone to start jobs.

Eventually, I’d like to replace the keyboard with something more specialized, but most of the commercial ones I’ve seen aren’t compatible with GRBL.