Skip to content

KN-86 Deckline — Prototype Architecture

This document describes the KN-86 Deckline prototype device. The prototype exists to validate the interaction model, the capability model, the Cipher voice, the C cartridge grammar, and the overall experience. The same hardware is also the current shipping target (Q4 2027). An earlier production direction targeting RP2350 / Pico 2 has been dropped and is archived — see docs/_archive/hardware/KN-86-Modern-Build-Specification.md.

Architecture: This document assumes the capability model described in KN-86-Capability-Model-Spec.md. nOSh is the orchestrator — it owns the mission board, economy, reputation, phase chain, and Cipher voice. Cartridges are capability modules loaded and managed by the nOSh runtime. The standalone cartridge model is retired.


Device: Pi Zero 2 W + Elecrow 7” IPS display (1024×600). nOSh runs as a Linux userspace application. Logical presentation: 80 columns × 25 rows at ~12×24 pixels per character.

Desktop emulator: SDL2 on macOS/Linux. Same nOSh C codebase, swapped platform layer. Primary dev environment.

  • The entire nOSh C codebase (cell engine, mission board, Cipher voice, capability system, save management)
  • The C cartridge grammar (nosh_cart.h, nosh_runtime.c, nosh_stdlib.c)
  • All game/program logic for every title
  • The .kn86 cartridge image format
  • Keycaps, switches, and key layout (Choc v1, MBK, same legends)
  • GBA SP hinges (work at both scales)
  • The desktop emulator is a third compile target using the same abstraction layer

ComponentDetails
Raspberry Pi Zero 2 WBCM2710A1, quad Cortex-A53 @ 1GHz, 512MB RAM, HDMI out, WiFi/BT
Elecrow 7” IPS display1024×600, HDMI input
ComponentDetailsNotes
Kailh Choc v1 switchesWhite (clicky), 30 + sparesSame as production device
MBK blank black keycaps34+Same as production device
GBA SP replacement hinges2Proven in the Penkesu, reusable knowledge for production
Adafruit PowerBoost 1000CUSB-C charging + 5V boostSame module the Penkesu uses — known good with Pi Zero
3.7V LiPo battery606090 or similar, ~3000mAhSame pouch cell form factor as production
Adafruit MAX98357AI2S DAC + ampAudio output — same module as production
28mm 8Ω 2W speakerRoundSame as production
3.5mm TRS switched jackPCB mount, stereoHeadphone out — same as production
3.5mm TRRS jackPCB mount, 4-poleLink port — same as production
QMK-compatible keyboard controller (Pro Micro, RP2040-class, or equivalent)Keyboard controller (per ADR-0018)Runs stock QMK firmware, communicates with Pi Zero over USB HID via an internal USB hub IC
1N4148 diodes30Key matrix
HDMI ribbon cable + adaptersRight angle + mini HDMI + 20cm ribbonPenkesu-style cable routing through hinges
PETG filament (black)1kg spoolEnclosure printing
M2 / M2.5 heat-set inserts + screwsAssortedAssembly hardware
ComponentWhy Not
Physical SPI flash cartridgesCartridge images load from SD card filesystem instead
Card edge connectorNo physical cartridge slot in the current build
TP4056 chargerPowerBoost 1000C handles charging on the Pi Zero path
Amber LED backlight modDisplay renders amber-on-black in software

┌─────────────────────────────────────────────────────────────┐
│ CAPABILITY MODULES (CARTRIDGES) │
│ .kn86 images loaded from SD card — phase handlers, │
│ cell defs, templates, Cipher domain vocab, save data │
├─────────────────────────────────────────────────────────────┤
│ nOSh APPLICATION (ORCHESTRATOR) │
│ Mission board · Phase chain · Economy · Cipher voice │
│ Cell engine · Display · Sound · Input · Save mgr │
├──────────────────┬──────────────────┬───────────────────────┤
│ GAME LOGIC │ AUDIO ENGINE │ DISPLAY ENGINE │
│ C cartridge │ emu2149 PSG │ SDL2 framebuffer │
│ grammar │ via SDL_audio │ → HDMI → Elecrow │
│ handlers │ 44.1kHz output │ 1024×600, amber │
├──────────────────┴──────────────────┴───────────────────────┤
│ LINUX (Raspberry Pi OS Lite) │
│ Pi Zero 2 W · SDL2 · ALSA · USB HID │
├─────────────────────────────────────────────────────────────┤
│ KEYBOARD (custom mech keeb per ADR-0018) │
│ QMK-compatible controller · QMK firmware · USB HID → hub │
└─────────────────────────────────────────────────────────────┘

nOSh compiles as a single Linux binary. It is not a desktop application with a window manager — it runs fullscreen on the framebuffer or via SDL2 with no window decorations, no cursor, no desktop environment. Pi OS Lite boots to console. nOSh launches on boot via systemd service. The operator never sees Linux.

Display: SDL2 renders an 80×25 character grid into a 960×600 logical framebuffer (80 × 12 px cell width, 25 × 24 px cell height per ADR-0014). The logical canvas is integer-scaled 1:1 onto the 1024×600 Elecrow panel with a 32 px horizontal letterbox per side and zero vertical letterbox. All pixels are amber (#E6A020) on black (#000000). The SDL2 window is fullscreen at 1024×600.

Audio: emu2149 (YM2149F PSG emulator) runs in an SDL_audio callback thread. Same library as the production device and the desktop emulator. 44.1kHz, signed 16-bit PCM, stereo output. Audio goes through HDMI to the display’s built-in speakers (if any) or through the MAX98357A via I2S on the Pi Zero’s GPIO.

Input: The keyboard is built as a custom mechanical keyboard per ADR-0018 — a QMK-compatible controller (Pro Micro, RP2040-class, or equivalent) on a custom-fab unified 30-key PCB (preferred) or modified split layout reconnected under a single keyplate (fallback). It runs stock QMK firmware and presents as a USB HID keyboard to the Pi Zero via an internal USB hub IC (TUSB2036 / FE1.1s / equivalent) on the interior plate. nOSh reads key events from /dev/input or SDL2’s event loop. The key matrix, debounce, and scan rate are handled by the controller — nOSh receives clean key-up/key-down events.

Cartridge loading: No physical cartridge slot in the prototype. Cartridge images (.kn86 files) are stored on the Pi Zero’s SD card. nOSh reads from a cartridges/ directory. A menu at boot lists available programs. Selecting one loads the .kn86 image into memory and initializes the cartridge’s handlers.

Cartridge swapping: Simulated. When a multi-phase mission requires a cartridge swap, nOSh displays the prompt (PHASE 2/3: DECRYPT PAYLOAD — REQUIRES SIGNAL), the operator selects the program from a menu (navigated with CDR/CAR/EVAL), and nOSh unloads the current cartridge and loads the new one. The phase chain serialization works identically to the production device — only the physical act of pulling a cartridge is replaced by a menu selection.

Save system: Save data writes to files on the SD card instead of flash sectors. The nOSh save API (nosh_save_write, nosh_save_read) abstracts this — cartridge code doesn’t know or care whether it’s writing to flash or filesystem.

Link port: UART serial over GPIO, same protocol as the production device. Alternatively, two prototype decks can link over WiFi using a TCP socket that carries the same UART packet format. WiFi link is prototype-only — production uses the 3.5mm TRRS cable.

Touch: Disabled. Do not install the touch driver. Do not connect the touch ribbon cable if it’s separate from the display ribbon. The keys are the interface.


The keyboard is electrically independent from the Pi Zero. It’s a self-contained USB HID device, built as a custom mechanical keyboard per ADR-0018.

ComponentRole
QMK-compatible keyboard controller (Pro Micro ATmega32U4, RP2040-class, or equivalent)Matrix scanner, debounce, USB HID output — exact part chosen at hardware bring-up per ADR-0018
30 × Kailh Choc v1 hot-swap switches (+ 5 spares)14 function keys + 16 numpad keys, in Mill-Max 0305 or Kailh hot-swap sockets
30 × 1N4148 diodes (+ 5 spares)Matrix anti-ghosting; SMD on the fabbed PCB
Custom-fab unified 30-key PCB (preferred, ADR-0018 Option B) OR split-layout PCB reconnected under a single keyplate (fallback, ADR-0018 Option C)8×4 matrix (30 populated, 2 empty) routed to the controller
Internal USB 2.0 hub IC (TUSB2036, FE1.1s, or equivalent)Fans Pi OTG out to the keyboard controller + cartridge bridge (ADR-0011); no external USB cables

Left grid (4 rows, 3.5 key layout with EVAL spacebar):

QUOTE CONS NIL LAMBDA
INFO CAR APPLY SYS
LINK BACK CDR ATOM
╔════ EVAL ════╗ EQ

Row 2 is the home row / WASD cluster: CAR (W), BACK (A), CDR (S), APPLY (D). EVAL is a 3U-wide bar spanning three columns on the bottom row. EQ sits to its right as a single-width key.

Right grid (4×4 phone-layout numpad + operator column):

1 2 3 ÷
4 5 6 ×
7 8 9 −
. 0 ENT +

Data grid is phone layout per ADR-0016 §5; see docs/ui-design/KN-86-Input-System-Architecture.md §1.

The QMK-compatible controller scans the combined 8×4 matrix (8 columns, 4 rows = 30 used, 2 empty) and sends USB HID keycodes to the Pi Zero through the internal USB hub IC. Stock QMK firmware maps the physical matrix positions to keycodes that nOSh recognizes; the only firmware contribution is the 30-key keymap file.

LAMBDA and QUOTE are handled by nOSh, not the keyboard firmware. The controller sends raw key events. Firmware-layer QMK features (tap-dance, layers, combos) are deliberately not used — nOSh’s input manager handles hold detection (LAMBDA 2-second hold for recording mode), key repeat, and all function key logic. The keyboard is dumb — it just reports which keys are pressed. SYS now handles cancel/abort operations: SYS held for 2 seconds triggers a hard disconnect, replacing the old ESC key. ATOM and EQ are runtime-level operations handled by nOSh’s cell engine.


The Pi Zero 2 W has limited native audio options. Two paths:

Path A — MAX98357A on GPIO I2S (preferred): The Pi Zero’s GPIO includes I2S pins (BCK, LRCK, DATA). The MAX98357A connects directly. This is the same DAC/amp module as the production device. Audio quality is clean digital. The speaker and headphone jack wire to the MAX98357A output.

Path B — HDMI audio (fallback): Audio goes through the HDMI connection to the Elecrow display. If the display has a speaker or audio out, this works with zero additional hardware. Quality depends on the display. Less control over volume and routing.

Path C — USB audio (backup): A cheap USB audio adapter on the Pi Zero’s USB port. Adds a dongle but guaranteed to work with ALSA.

Path A is preferred because it matches the production hardware. Same module, same wiring, same audio behavior. emu2149 outputs samples to an ALSA device backed by the I2S interface.


The prototype renders an 80×25 character grid into a 960×600 logical framebuffer, composited onto the 1024×600 Elecrow panel with a 32 px horizontal letterbox per side (ADR-0014):

logical canvas : 960 px wide × 600 px tall
character cell : 12 px wide × 24 px tall (80 × 12 = 960, 25 × 24 = 600)
panel letterbox : 32 px horizontal per side, 0 px vertical
scale pipeline : integer 1× throughout (same output on emulator and prototype)

Every character cell is exactly 12×24 pixels. The bitmap font uses Press Start 2P (Latin/Greek/Cyrillic) + CP437 (box drawing/block elements) stored as a 256-glyph bitmap atlas at native 8×8 (Layer 1); glyphs render 1× horizontal / 2× vertical, centered in the cell with 2/4 px padding. See docs/architecture/KN-86-Character-Set-and-Font-Architecture.md for the Unicode expansion path (Layer 2). A native 12×24 font cut is explicit follow-up work per ADR-0014.

Color: Every lit pixel is amber (#E6A020). Every unlit pixel is black (#000000). No other colors. The SDL2 renderer draws to a single surface at 1024×600 and presents it fullscreen.

Bitmap mode: The full 960×600 logical framebuffer is addressable for bitmap graphics (wireframe maps, network diagrams, sonar displays), per ADR-0014. The 32 px horizontal letterbox on each side of the 1024×600 Elecrow panel is invisible to cartridges. Line-drawing and shape primitives operate at the full logical pixel resolution.

Split-screen mode: Divides the 600px height between bitmap (top) and text (bottom), or vice versa. The split position is specified in pixel rows.

Refresh: Immediate. SDL2 presents frames at monitor vsync or uncapped. No perceptible latency between keypress and display update.


  1. Pi Zero powers on. Pi OS Lite boots to console (no desktop environment).
  2. systemd launches nOSh as a service.
  3. nOSh initializes SDL2 fullscreen at 1024×600.
  4. nOSh initializes SDL_audio with emu2149.
  5. nOSh reads Universal Deck State from ~/.nosh/deckstate.bin.
  6. Display: KINOSHITA KN-86 DECKLINE / NOSH RUNTIME v2.1 / CIPHER ONLINE
  7. Display: Operator handle, reputation, credits, registered capabilities.
  8. nOSh scans ~/.nosh/cartridges/ for .kn86 images.
  9. If cartridges found: display program list, await selection.
  10. If no cartridges: display > AWAITING MODULE

Boot time: Pi Zero cold boot to nOSh running is approximately 8–15 seconds depending on SD card speed. A splash screen or Kinoshita logo fills the wait.


The key to the multi-target strategy is that nOSh’s core logic never touches hardware directly. All platform-specific code lives behind an abstraction layer.

nosh_platform.h
// Display
void platform_display_init(void);
void platform_display_present(const uint8_t *framebuffer);
void platform_display_set_backlight(uint8_t level);
// Audio
void platform_audio_init(void);
void platform_audio_submit(const int16_t *samples, uint32_t count);
// Input
void platform_input_poll(KeyEvent *events, uint32_t *count);
// Save
bool platform_save_write(const char *slot, const void *data, uint32_t size);
bool platform_save_read(const char *slot, void *data, uint32_t size);
// Cartridge
bool platform_cart_load(const char *name, CartridgeHeader *header, uint8_t *code, uint8_t *data);
bool platform_cart_list(char names[][16], uint32_t *count);
// Time
uint32_t platform_ticks_ms(void);
void platform_sleep_ms(uint32_t ms);
FileTargetDisplayAudioInputCartridge
platform_linux.cDevice (Pi Zero 2 W)SDL2 → HDMISDL_audio + emu2149USB HID via SDL2 events.kn86 files on SD card
platform_sdl2.cDesktop emulatorSDL2 windowSDL_audio + emu2149Keyboard via SDL2 events.kn86 files on filesystem

platform_linux.c and platform_sdl2.c are nearly identical — the main difference is that the Linux version runs fullscreen with no window chrome and reads input from USB HID rather than a desktop keyboard mapping.

All nOSh core code (nosh_core.c, nosh_mission.c, nosh_cipher.c, nosh_cells.c, nosh_runtime.c, cartridge handlers) includes only nosh_platform.h. It never includes SDL2 or Linux headers directly.


kn86-nosh/
├── src/
│ ├── core/ # Platform-independent nOSh code
│ │ ├── nosh_core.c
│ │ ├── nosh_cells.c
│ │ ├── nosh_mission.c
│ │ ├── nosh_cipher.c
│ │ ├── nosh_runtime.c
│ │ ├── nosh_stdlib.c
│ │ └── nosh_cart.h # Cartridge grammar macros
│ ├── platform/
│ │ ├── platform_linux.c # Device (Pi Zero 2 W + SDL2)
│ │ └── platform_sdl2.c # Desktop emulator
│ ├── audio/
│ │ └── emu2149.c # YM2149F PSG emulator (vendored)
│ └── programs/ # Cartridge source code
│ ├── ice_breaker.c
│ ├── neongrid.c
│ ├── black_ledger.c
│ └── depthcharge.c
├── assets/
│ ├── font_8x8.bin # 8×8 bitmap font (emulator) scaled to ~12×24 on device
│ └── cipher_words.bin # Cipher voice word tables
├── cartridges/ # Built .kn86 images
├── CMakeLists.txt
└── Makefile
make device # Compiles for Pi Zero 2 W (ARM Linux, links SDL2)
make emulator # Compiles for desktop (native, links SDL2)
make cartridge NAME=ice_breaker # Builds a .kn86 image

AspectHow the Prototype Tests It
Interaction modelAll 30 keys, full CAR/CDR/CONS/NIL/ATOM/EQ grammar, LAMBDA recording, QUOTE bookmarks
Capability systemMission board generation, cross-cartridge contracts, phase chain, cartridge swapping (menu-based)
Cipher voiceSentence grammar engine output on boot, mission board, debriefs
C cartridge grammarnosh_cart.h macros, cell definitions, event handlers, full ICE Breaker implementation
Sound designemu2149 PSG synthesis, all system sounds, per-program audio through real speaker
80×25 text modeFull terminal layout, side-by-side panes, split-screen, all four launch title UIs
Link protocolTwo prototype decks connected via UART or WiFi TCP, symmetric and asymmetric play
Universal Deck StateCredits, reputation, cartridge history, cross-program integration, persistence across sessions
Null programProcedural microfiction generation from accumulated career state
  • Amber monochrome LCD aesthetics (prototype renders amber in software on a color IPS display)
  • Physical cartridge insertion/removal experience (cartridge images load from SD card during the prototype phase)
  • Final enclosure fit and finish

These are finish-out concerns for the production build-out of the same Pi Zero 2 W hardware.


Quick and functional. Not the final design.

  • Shell: Pelican 1170 Protector Case, black, off the shelf. Integrated hinge, ABS latches, molded rubber feet, watertight when closed — no fabrication of the shell itself.
  • Inset panels: 3D-printed in PLA or PETG on Prusa MK3S+ (material selection TBD during bring-up). Lid panel carries the Elecrow 7” display bezel; base panel carries the keyboard plate (30 Choc v1 switches), cartridge-slot retainer, and port cutouts.
  • Foam: Pelicanfoam is cut to seat the Pi Zero 2 W, PowerBoost 1000C, TP4056, amp, speaker, and LiPo in the base cavity and to cradle the display module behind the lid bezel. The Pelican shell is never machined.
  • HDMI ribbon and audio leads route along the Pelican hinge line between lid and base with service slack.
  • No cartridge slot in the enclosure (cartridges load from SD card).
  • No debossed wordmark, no cosmetic finishing on the inset panels — plain printed plastic over the off-the-shelf Pelican shell.
  • Port access: USB-C (charging via PowerBoost), 3.5mm headphone jack, 3.5mm link jack, SD card slot (accessible for swapping cards during development). Panel-mount pigtails pass through the Pelican wall via minimal drilled holes.

The enclosure can be rough. The Pelican shell handles the “ruggedized/watertight” half of the mechanical design for free; the printed insets just have to fit and hold components. Cosmetics are a production concern.