Notes from a year of building keyboards

← Back to Kevin's homepagePublished: 2021 March 7

The electronics design and fabrication technologies available to motivated individuals today is incredible. Compared to even just 6 years ago when I made a cell phone, we amateurs now have access to powerful CAD/CAM, low-cost/qty PCB assembly, sorta-usable free EDA software, powerful new embedded languages, and a huge corpus of tacit knowledge on YouTube.

I’ve spent the last year exploring this frontier by building wireless mechanical keyboards. I’ve designed a dozen PCBs, written bare-metal microcontroller firmware in three languages, and commissioned or fabricated myself a ton of parts from aluminum, acrylic, Corian, resin, and fabric:

A bunch of keyboards

This page isn’t a tutorial or comprehensive reference on any particular technical topic (though I’ll link to my favorites below). Rather, it’s a rough diary and reflection on the process. My hope is that:

  1. it gives you a flavor of the overall experience and demystifies the work between “idea” and “functioning prototype”
  2. you’ll discover at least one weird trick that you can apply to your own projects

If you have ideas, questions, or think I can help with your creative explorations, feel free to send me an email.

Motivation: Why keyboards?

I’ll start with a little secret: I don’t care much about keyboards. Most of my typing is on an 11" Macbook Air from 2013, though my fingers sometimes grace client-provided hardware like Dell laptops, IBM/Lenovo ThinkPads, and newer Macs with those butterfly keyboards that Twitter/HN people got real mad about. They’re all fine, really.

I first learned of the custom keyboard scene when I convinced a friend to sell his keyboards for $1,668, but personally never developed any burning desire to acquire (or bring into existence) a keyboard the way my friend and his fans did.

Rather, keyboards appeal to me as a playground of design constraints and technical challenges:

While these three domains — electronics, physical design/fabrication, and firmware — are all interesting to me on their own, they become even more fascinating combined together.

It’s immensely satisfying, for example, to find optimizations and novel product functionality by synthesizing knowledge across these disciplines:

As a problem space, keyboards have a “low floor and high ceiling”.

Finally, as a long-time web developer I’m attracted to the minimalism of embedded hardware products. Application code running in a web browser is subject to the whims of operating system schedulers, JavaScript JITs, and millions of lines of “system” code running underneath. Working in such a complex environment, it’s easy to develop a learned helplessness around performance, understandability, and even determinism.

While surely some of this is “grass-is-greener” thinking — yes, I’m aware of cosmic rays, bad solder joints, and thermal variation — I’ve found it an enjoyable change of pace to switch from StackOverflow comments and ever-changing dependencies to bare-metal code (mostly mine) running on physical hardware (also mine) that I can power-cycle instantly, documented by 1000-page datasheets which discuss worst-case timing guarantees in microseconds.

Retrospective overview + timeline

My original product concept was a “split ergonomic travel keyboard”, but I ended up spending far more time on technical pursuits and process development than I did getting a tightly-scoped product out the door. However, I managed to complete three functional prototypes:

v1

V1 keyboard

My initial focus was on maximally compact mechanical keyboard. I chose a 5x5 grid (no real reason) of Kailh’s low-profile “Choc” switches and selected components that would fit between the stems of the switches on the PCB backside.

This keyboard involved a lot of personal firsts: Using KiCAD, designing an nRF52-based board and firmware, designing a battery protection and charging circuit (my first use of a P-type MOSFET), drawing footprints for a mid-mount USB connector, etc.

In hindsight I’m amazed it all actually worked on the first revision, and I’m still tickled that I sourced custom, adorable-sized 2 x 13 x 80 mm lithium polymer cells ($200 for 50pcs from Battsys).

This v1 PCB worked great as a platform on which to develop firmware and refine my understanding of the Bluetooth low energy (BLE) and USB protocols (as exposed via Nordic Semiconductor’s SDK — I’m not yet ambitious enough to bit-bang the radio antenna myself).

The “Split Apple”

Split Apple keyboard

As soon I paired with a computer and actually tried using the v1 split keyboard , I realized I couldn’t be bothered to re-learn how to type on 50 ortholinear keys. So, for the next iteration, I decided to just split of Apple’s keyboard layout.

Unfortunately, not all the necessary keycap sizes were available for Choc switches, so I had to make this one with taller Cherry MX switches. Rather than wait ~5 weeks for PCBWay assembly, I designed with parts from JLCPCB’s catalog (~1 week turnaround) and soldered myself the nRF52840 dongle.

Because JLCPCB doesn’t assemble USB connectors, the Split Apple also pushed me to implement wireless charging hardware and over-the-air firmware updates (with associated bootloader stack).

By this point I’d found an sign shop here in Taipei that was happy to same-day laser cut acrylic from PDF drawings, and I relied on them extensively for cheap and fast (about $5 per 150mm laser-cut acrylic part) material mock-ups while prototyping the keyboard’s “PCB + acrylic + acrylic” stack-up construction (an idea I stole from this PancakeLegend keyboard).

Because of the complexity of its layout (not just a 5x5 grid) and stacked-layer construction, the Split Apple forced me to develop a programmatic process to carry designs from keyboard-layout-editor.com (of course that’s a thing) to my PCB and mechanical CAD software. This process came in quite handy for all subsequent work.

The Atreus

Atreus keyboard

Atreus keyboard

In November I got access to a desktop CNC mill and immediately started exploring designs using Corian, an artificial stone-like material typically found in fancy kitchen countertops. I wanted to explore fabricating a small production run (~50 keyboards?) myself, so I machined Phil Hagelberg’s Atreus design as a prototype design, for a few reasons:

The production framing encouraged me to optimize my design for manufacture (minimize the number of setups and endmills), develop fixtures, and really dial in the feeds & speeds to maximize the material removal rate.

To keep the Atreus from slipping around a desk, I also investigated several silicone and polyurethane materials and mold design techniques.

Timeline

Materials

The r/MechanicalKeyboards subreddit loves anodized aluminum. Yes, amazing material: lightweight, strong, corrosion resistant, etc., etc. But also sorta boring — I mean, we can already buy those keyboards at the Apple store!

I’m much more interested in materials like leather, cork, Corian, and fabric.

Finding such materials and related tooling was difficult in the first few months after I moved Taiwan (I miss McMaster-Carr), but eventually I managed with a lot of legwork and Google Translate-mediated conversations.

I hoped leather might serve as a non-slip “bottom” that could be stitched around or glued to the v1 PCBs:

leather bottom

however the thick, already stiff leather became brittle after laser cutting (also, the smell!) and wasn’t actually very grippy (I suspect the v1 PCB is simply too light).

For the same application, I attempted to laser cut 6mm thick Ikea-hotplate-holder cork rounds, but only managed to start a small fire:

cork attempt

I did eventually find a 1mm cork fabric (not sure if it’s pure cork or includes binder) that could be cut easily, but it also wasn’t grippy enough to serve as a base.

I then explored attaching it to acrylic sheet and laser cutting keycaps. I’m not sure how it’d wear over time as a keycap (probably not well), but there may be other nice applications for a natural, compliant material (wrist rests?).

After cutting the first keycaps, it occurred to me that I could use the cork as visual texture by putting it underneath the acrylic. This turned out well, and inspired me to try a variety of fabrics:

fabric keycaps

Pro-tip: after laser cutting, use masking tape to keep all of the loose pieces together for easier removal from the machine.

I found that Super 77 (right) left a cloudy residue, and I had much better luck using, uh, whatever the stuff on the left is:

glue comparisons

To actually use these as keycaps, they need stems to mate with switches. Choc stems have a high aspect ratio, so I’m not sure the best way to make a “stem plate” onto which the fabric and acrylic could be attached.

FDM-printed plates probably won’t be strong enough (with layers parallel to the key face), but maybe resin prints might work? I did try machining keycap positives, but their stems broke when friction-fitting into the switches:

A plastic keycap and switch w/ snapped custom keycap stems stuck inside

A ball endmill / fillets might have helped reduce the stress. Of course the normal keycaps are produced via injection molding, though I honestly have no idea how metal molds are made for such high aspect ratio features since all I can imagine is chips fusing to and breaking endmills in the deep pockets of a mold negative. Maybe wire EDM?

Given that some keyboard designs might have tight tolerances between keys/keycaps and the enclosure, I’d attach the stems to the fabric/acrylic first and laser cut the entire assembly together.

Thick acrylic gives a neat parallax effect, and I’m excited for inexpensive-yet-bling designs leveraging this effect with ENIG PCBs:

This prompted me to explore PCBs as a structural/aesthetic material; after all, what else can you custom specify at 200 micron tolerances and have delivered for literally $10?

I actually ordered a pile of 1mm thick boards just so I could stack them together to play with designs in 3D:

PCB blanks

Visually, silkscreen is the boldest color (designed to be seen), exposed ENIG copper the most baller (gold!), and more refined effects can be done by varying copper underneath soldermask or removing soldermask + copper entirely. (For example, see this Goyard lookin’ pattern.)

For thin PCBs, one could probably pull off neat translucency effects as well.

The tolerances of copper are tighter than silkscreen, but in my PCBWay board some copper features still got distorted and the silk/copper alignment isn’t great:

PCB close ups

I think dithering algorithms and other patterns based on varying-sized circles (can’t blur those!) might be very interesting here. See ditherpunk and beyond 1-bit.

PCB design

The last time I designed a PCB was back in 2014 (when I made a cell phone), using a friend’s copy of Altium. Returning six years later, I figured I’d try the open source KiCAD software (version 5), which I’d heard was finally usable.

This is, uh, only somewhat true — you can’t just fire up the software and learn by clicking around a consistent, documentation-at-the-point-of-need coherent interface like you can with Autodesk’s Inventor or Fusion 360.

But on the plus side KiCAD is free and open source, which means that once you learn the (many) quirks and features you’ll at least be able to use it in peace without forced upgrades or “our incredible journey” acquisitions taking away the tool entirely — I expect I’ll be able to open my designs in 20 years (perhaps running KiCAD 5 in a virtual machine), which is more than I can say for any of the web-based tools in this space.

KiCAD tips

Part selection GUI

It’s daunting to shop through the millions of parts on DigiKey when you’re not sure exactly what you need. Fortunately, JLCPCB only assembles from their much smaller part library. Unfortunately, JLCPCB’s website is slow and terrible, so instead consider downloading their parts library Excel File, converting that into a CSV via this script:

#!/usr/bin/env python

import xlrd
import csv
import re

re_px = re.compile(":([0-9.]+)")

with xlrd.open_workbook("JLCPCB SMT Parts Library(20210212).xls") as wb:
    sh = wb.sheet_by_index(0)
    px_idx = sh.row_values(0).index("Price")

    with open("parts.csv", 'w', newline="") as f:
        col = csv.writer(f)
        # write header
        labels = sh.row_values(0)
        labels.insert(px_idx, "Px")
        col.writerow(labels)

        for row in range(1, sh.nrows):
            vals = sh.row_values(row)
            m = re_px.search(vals[px_idx])
            px = m.group(1) if m else vals[px_idx]
            vals.insert(px_idx, px)
            col.writerow(vals)

# TODO, have python run this
print("""
sqlite3 parts.db << EOF
.separator ","
.import parts.csv parts
EOF
""")

and loading that CSV into a SQLite database so you can use DB Browser for SQLite as a super-fast local interactive search/GUI. Just need a 3.3V low dropout linear regulator? It’ll take 15s to find the most popular one — and it’s only $0.12!

A nice load sharing circuit

Here’s a nice circuit that allows you to run a microcontroller (VDD) from either battery or external power (VBUS):

The P-MOSFET cuts off the battery when USB’s 5V comes on VBUS. See this detailed article or explainer video.

I use 5.1kOhm for all my pull-downs because that specific value is needed anyway for USB-C’s CC lines.

Wireless modules

Nordic Semiconductor’s nRF52 family is quite popular for embedded bluetooth applications; low power ARM core, USB peripheral, built-in power regulator that can be attached directly to lipo batteries, and lots of great docs, examples, and open-source mindshare. I did not consider any other bluetooth solutions for my project.

Unfortunately the higher-end Nordic chips (52840 and 52833) require laser-drilled “microvias” (0.15mm diameter) to access all their pins, which’ll raise the price of your PCBs to a few hundred bucks at least.

So for cheap 2-layer PCBs (more than sufficient for keyboards), you’ll want to use pre-assembled modules which break out the chips’ pins to larger pads and include many of the supporting components like high-frequency crystal, power inductors, etc.

If you just want to make a wireless keyboard, grab a nice!nano or nrfmicro hand-solderable hobbyist module.

If you’re constrained on space and/or are just dying to reflow solder, check out Fanstel modules and Raytac modules. Both can be purchased in small quantities directly from the manufacturer as well as in bulk from the usual suspects (Digikey, Mouser).

Note that Fanstel’s modules (example left) have more generous pinout spacing than Raytac’s (right):

nRF modules

Raytac’s pins have 0.4mm pitch, and JLCPCB’s 2-layer capabilities (0.13mm min track/spacing) mean you’ll need 0.39mm to escape the inner pins, so…do you feel lucky?

In a pinch, if you want to prototype something quickly with an easily available part, you can breadboard or hand-solder onto a PCB Nordic’s $10 “dongle”, which is also the most inconspicuous way to develop firmware on-device at a coffee shop:

dongle

I found using the dongle as a solder-on module worked well for my Split Apple design, modulo measuring the footprint. Shout out to the Taipei Hackerspace for letting me use their soldering station, which was quite productive despite (or perhaps because of?) its Blade Runner vibes:

Soldering station at Taipei Hackerspace

If you want to hand-solder something smaller, I had luck with Raytac’s $2 nrf52805 castellated edge module as part of my aircon controller.

Firmware

Developing the keyboard firmware was challenging for two primary reasons:

  1. Unlike my past embedded projects which were completely minimal and bare-metal, my keyboard firmware needed to interface with Nordic’s bluetooth stack

  2. My keyboard prototype hardware varied substantially — not only in terms of GPIO (which pins connect to which switches and LEDs; active-high vs. active-low) but also the switch sensing scheme (direct connections vs. a scanning matrix) and the underlying microcontrollers themselves (52833 on my v1 and devkit board, 52840 on the Split Apple and Atreus).

While there were some other challenges — notably understanding bootloaders, the code-signing firmware for updates via USB and Bluetooth, and logging/debugging effectively — those topics are fairly well-trodden and documented online (see embedded tips below).

I first started trying to write my firmware using Rust’s RTIC framework, but ran into trouble:

I had more success letting Nordic’s SDK be “in charge” of the build process and boot sequence (e.g., setting up interrupt vectors) and then calling out to my Rust firmware, which was compiled as a static library and simply linked against.

Rather than any fancy safe resource management scheme, I used mutable globals. YOLO:

pub static mut KEYBOARD_STATE: Option<KeyboardState> = None;
pub static mut LATEST_KEYS: Option<Packet> = None;

#[no_mangle]
pub extern "C" fn RTC2_IRQHandler() {
    let rtc2 = unsafe { &hw::Peripherals::steal().RTC2 };
    rtc2.events_tick.write(|w| w.events_tick().not_generated());

    unsafe {
        LATEST_KEYS = Some(read_keys());
    }
}

Aside from making me feel unsafe about everything, I also found that Rust made it quite complicated to loop over microcontroller pins and support conditional compilation for different hardware configurations.

Thus, I rewrote the firmware again (third time’s the charm!) in Zig, a much smaller language. This worked out swimmingly; see my thoughts on the complexity of Rust and Zig for more.

Interop gymnastics

While Nordic has a great SDK with a ton of examples, everything is written in C and I’d decided to play on hard-mode and write my firmware in Rust.

Calling out to a plain C function from Rust is not normally a big issue — it’s not painless (you must atone by writing unsafe a lot, especially when dirtying your immortal soul by touching pointers), but it’s doable. There are even nice tools like bindgen that’ll write boilerplate code for you.

I’d used these tools successfully before, so I started by trying to write a Cargo build.rs build script to compile Nordic’s C SDK and generate bindings I could call from Rust.

Unfortunately, the Nordic SDK and Bluetooth stack are not plain C functions. The SDK is a lot of C, and it’s chock full o’ preprocessor-macros (Nordic’s BLE keyboard example has 1,177 #defines that configure the SDK).

The Bluetooth stack (the “softdevice”) is even more interesting: It’s a binary blob that you flash onto the microcontroller along with your program. When the microcontroller boots, the softdevice takes control of some hardware resources (like the radio and a timer) and registers some high-priority interrupt handlers before then jumping to your program.

This is pretty clever, as it allows the system to meet the strict timing requirements of Bluetooth Low Energy without burdening the application programmer with any responsibility. Your app can’t mess anything up: When a timing interrupt fires, the CPU will jump away from your app, run the necessary code within the softdevice, and jump back to executing your none-the-wiser app code. (The 100-page softdevice specification is actually a pretty good read.)

However, all this architectural fanciness depends on complex gymnastics in various linker scripts and conditional includes. Since someone seemed to have gotten far using Bindgen with the Nordic SDK, I figured it’d be worth giving a shot.

Sadly, despite a ton of pairing/debugging help from my friend Jake Donham, after more than a month of “change a flag and recompile everything” 10-minute iteration cycles and some truly horrific discoveries (llvm-objcopy sometimes drops segments when outputting IHEX!?!), I gave up in frustration.

Now, to be clear, this failure shouldn’t reflect poorly on Rust or its tooling — it’s more a reflection of the complexity of the domain and the best solution that Nordic engineers could build with a lingua franca programming language and tooling from the 1970’s.

I eventually landed on the much more obviously pragmatic (hindsight!) approach:

  1. Copy one of Nordic’s Makefile-based GCC example projects.

  2. Add Makefile targets to build the Rust code as statically-linkable library from C:

    .PHONY: RUST
    
    rusty/target/rusty.h: RUST
            cd rusty && cbindgen --crate rusty --lang c --output target/rusty.h
    
    rusty/target/thumbv7em-none-eabihf/release/librusty.a: RUST
            cd rusty && cargo build --release --no-default-features --features $(TARGET) --target "thumbv7em-none-eabihf"
    
    LIB_FILES += rusty/target/thumbv7em-none-eabihf/release/librusty.a
    INC_FOLDERS += rusty/target
    
  3. Just…call into the Rust code from the C main function:

    #include "rusty.h"
    
    int main() {
      //a bunch of code copied from a Nordic example app to setup softdevice, etc.
      my_main_loop_written_in_rust();
    }
    
  4. and from Rust call into C via manually-written bindings:

    fn sleep() {
        unsafe {
            extern "C" {
                fn nrf_pwr_mgmt_run();
                fn nrf_log_process();
            }
    
            while nrf_log_process() {} //process any logs before we go to sleep
            log("going to sleep");
            nrf_pwr_mgmt_run();
        }
    }
    

(Note: Since I started my adventure, a braver and presumably much more knowledgeable person has created nrf-softdevice, a Rust softdevice wrapper which might’ve helped here.)

Embedded Tips

Computer-aided design + fabrication

I’m always blown away when I use CAD tools; they make coding in Emacs feel like rubbing two sticks together in the dark. Inventor, SolidWorks, and Fusion 360, all great! (I’ll even forgive that last one for the hassle it gave me for daring to design a chair offline.) Check them out, get a spacemouse, and be amazed by computers again!

Building keyboards developed my fabrication skillset along two dimensions: a programmatic design workflow and designing fixtures for machining

Integrated design workflow

The V1 keyboard was just a plain circuit board which I laid out entirely in KiCAD.

This turned out to be frustrating even for that simple 5x5 grid layout. (E.g., there’s no way to combine footprints into a layer and “hide” them in KiCAD 5, so I was constantly accidentally selecting and moving switch footprints while trying to layout the other components.)

I realized that if I wanted to reliably position switches in more complex keyboard designs and match them to enclosures, I would need to do so programmatically.

Here’s the workflow I came up with:

  1. Design a keyboard layout on keyboard-layout-editor.com:

    Keyboard Layout Editor screenshot

  2. Convert KLE’s “raw data” JSON to a CSV (one row per switch; columns of switch number, switch size, x/y position, rotation, etc.)

  3. Use a KiCAD Python script to read this CSV and position switch footprints accordingly:

    I set the switch footprint origin to be the center of the switch (rather than pin 1), and positioned switch 1 at the PCB layout global origin. (This is important later so that DXFs from other programs can be aligned to this location and import in the correct position.)

  4. Write an Inventor script to position Sketch Blocks:

    Since I was exploring designs with material between the switches (flush with depressed keycaps), I used two sketches: One to cut the switch mounts, and another for to cut keycap surrounds.

    (Yes, I’m running a Python script in PowerShell against CAD software in a virtual machine on a 2013 Macbook Air with 8 GB of RAM; it’s is still more responsive than Slack.)

Because the KiCAD script in step #3 positions switches by identifier and Inventor is already parametric, I can reposition the switches at any time by simply re-running the scripts and everything would rebuild appropriately, even if other PCB components have been placed (KiCAD) or downstream geometric features created (Inventor).

Some miscellany:

Fixture design

Most of my machining experience has been on a small Desktop Shopbot (see my CNC + computer vision experiments), where I used clamps and a spoilboard for workholding.

While the CNC I managed to find here in Taipei is a more capable Roland MDX-540, it didn’t have much in the way of workholding besides the tapped holes of the aluminum machine bed.

I purchased a vise, manually zeroed the machine as best I could to the vise front inside corner:

CNC machine

(This photo is me backing up the vise origin coordinates.)

This vise worked great for my initial experiments, where I tried out various endmills, feeds, and speeds to maximize material removal speeds while maintaining an acceptable off-the-mill surface finish. I’d just line up by feel the front of the stock to the front face of the vise and make sure never to let the toolpath wander into negative X (I have — knock on wood — avoided crashing the machine thus far):

Nice looking Corian chips

Note that when machining you want chips, not dust, since the latter indicates pointless recutting of material which causes excess heat and reduces tool life; these Corian chips look nice to me!

Workholding became trickier when I got into machining full keyboards, however, because most of them:

Here’s I ended up doing:

  1. Mount the stock centered in the vise, lining up the front edge by feel with a measuring block pressed against the front of the vise. Zero the Z-axis to the top of the stock and machine the switch mounts all the way through;

  2. Flip the stock over, again using the measuring block to hold stock Y-axis alignment, and machine the other side. Because the Z-axis position hasn’t changed, the Z-axis distance between the PCB and the switches remains constant across stock material thickness variation.

  3. To machine the profile, I needed to lift the entire stock above the vise while maintaining it in a machine-calibrated x/y position. To do this, I used the CNC to machine a set of through-holes in a piece of construction lumber I found laying around (presumably Taiwan’s equivalent of a 2x4):

    These holes line up with the keyboard switch centers, so laser-cut acrlyic pieces can then be used for both alignment and clamping:

    (Since I’m constraining to a plane I ought to use just two pins and let the other clamps float in x/y but…also this is a mostly-flat piece of wood I found in a bucket, yeah?)

    On later iterations of this highly-advanced fixture, I added a screw in the side to act as a Y-axis stop against the front of the vise (for easy repeatability):

    In case none of the above made sense, here’s a video of toolpaths:

Mold design

As part of my background research I bought the $130 bluetooth, choc-switch NuPhy F1 keyboard (referal link), which has a cleverly designed base:

Orange NuPhy keyboard base

The inverted “T"s and horizontal protrusion lets the keyboard to rest on the aluminum areas between a MacBook’s keys, so you can place this keyboard directly on your open laptop (if you, presumably, absolutely cannot bear to touch Apple’s "butterfly switches”).

Having never worked with silicone or polyureathanes before, I thought it’d be fun to try designing and fabricating a similar keyboard base.

For my first test, I created a mold by laminating together three laser-cut acrylic sheets and cast RTV #533 (27A Shore hardness) silicone from my Taipei Hackerspace friend:

A photo of a jar of silicone and mold

Unfortunately, it proved too viscous and jiggling the mold wasn’t sufficient to flatten things out, though doing so did attract the Hackerspace cat:

An adorable cat watching silicone polymerize.

In addition to the difficulty flattening, the cast part felt very, uh, gross. I’m not sure how much of this was due to the hardness and how much was an artifact of the smooth texture, but either way, it definitely wasn’t durable enough to serve as a keyboard base so I decided to try again with polyurethane.

I tried a 55A milky formulation (left; $10 for 1.2 kg) and a 65A clear formulation ($6 for 0.2 kg):

Polyurethane casting in acrylic molds

These were much easier to work with than silicone (much less viscous), but unfortunately the clear resin had an unhappy reaction with the acrlyic mold. (Yeah I overfilled the left one, but I definitely didn’t blow up the one on the right; I left it perfectly flat and it bubbled itself to that mess overnight.)

The 55A had a good hardness, but still felt a bit gross/sticky from having such a smooth surface. To alievate this, I decided to try casting it using a textured silicone mold (an idea I got from Sony’s PS5 microtextured controller).

To make that, I machined an acrlyic positive on the CNC, tossed it in the laser cutter to texture with a fun pattern, and glued it to the bottom of a laser cut mold box (aside: MakerCase is an amazing single-serving-site), and filled that box with silicone:

Laser cut box with an acrlyic positive next to a cast silicone mold made from that box

This process was also supervised by the cat:

An adorable cat watching vacuum degassing a mold

The silicone climbed up the sides of the mold box, so to ensure the final mold would sit flat I had to cut off all the top edges. Then flipping upside-down and placing in a second laser-cut box (for mold support and to contain potential mess from my overfilling-tendencies) I cast the desired part:

polyurethane part

The larger textured area had significant entrapped bubbles and the final part still felt pretty sticky. If I tried this again, I’d look for a harder polyurethane mix.

A small production run?

I started exploring keyboards as a “something to do in arrival quarantine” project. I could design PCBs on my laptop and have them delivered to me by mail, no workshop required.

After the initial success of my v1 PCB, deciding to settle in Taiwan, and development of local fabrication capabilities, I considered doing a small production run. I’d spend a few weeks making ~10–50 keyboards, machining them on the CNC, casting polyurethane bases, doing final PCB component assembly (wireless modules and USB connectors), flash firmware, test, and ship to Reddit keyboard enthusiasts across the world.

This seemed like an achievable and potentially quite satisfying outcome to the year’s exploration.

I began gauging interest by posting photos to the Mechanical Keyboards subreddit and Discord. Having never done any sort of photography before (product or otherwise), I picked up a used DSLR and had a ton of fun playing around with camera settings, lighting, backdrops, etc. (Luke Ayer’s YouTube channel was the best “learn to product photography” resource I found, by far.)

Here are two example photos:

A fancy photo of a keyboard

A fancy photo of a keyboard

My greatest compliment was having someone on Discord mistake one of my photos for a render, which I quickly dispelled with damning evidence of the behind-the-scenes reality:

A keyboard being photographed in a chair on a kitchen table

However, as I spent a few weeks photographing form studies and fishing around Reddit for interest, I realized that, again, I simply don’t have strong feelings about keyboards — I didn’t feel that any of my designs were beautiful, ergonomic, or otherwise needed to exist beyond prototypes ¯\_(ツ)_/¯

Although it would indeed be hilarious to sell a few thousand dollars of keyboards to Reddit randos, I knew that the challenges of a 50-unit production run — assembling the nth board, navigating international battery shipping rules in Chinese, setting up a Shopify to collect payments, etc., etc. — would be difficult to overcome without either a love of keyboards or a masochistic burning desire to trade in my intellectually satisfying and financially lucrative computing career for the world of pain that is high-mix, low-volume, fashion-driven manufacturing.

So, while it’s possible that I’ll return to the world of keyboards in the future, after a year of exploration in this domain I’m content to let things rest and to focus on exploring other opportunities.