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.
One Device, Two Compile Targets
Section titled “One Device, Two Compile Targets”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.
What’s Shared
Section titled “What’s Shared”- 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
Prototype Hardware
Section titled “Prototype Hardware”Already On Hand
Section titled “Already On Hand”| Component | Details |
|---|---|
| Raspberry Pi Zero 2 W | BCM2710A1, quad Cortex-A53 @ 1GHz, 512MB RAM, HDMI out, WiFi/BT |
| Elecrow 7” IPS display | 1024×600, HDMI input |
To Source
Section titled “To Source”| Component | Details | Notes |
|---|---|---|
| Kailh Choc v1 switches | White (clicky), 30 + spares | Same as production device |
| MBK blank black keycaps | 34+ | Same as production device |
| GBA SP replacement hinges | 2 | Proven in the Penkesu, reusable knowledge for production |
| Adafruit PowerBoost 1000C | USB-C charging + 5V boost | Same module the Penkesu uses — known good with Pi Zero |
| 3.7V LiPo battery | 606090 or similar, ~3000mAh | Same pouch cell form factor as production |
| Adafruit MAX98357A | I2S DAC + amp | Audio output — same module as production |
| 28mm 8Ω 2W speaker | Round | Same as production |
| 3.5mm TRS switched jack | PCB mount, stereo | Headphone out — same as production |
| 3.5mm TRRS jack | PCB mount, 4-pole | Link 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 diodes | 30 | Key matrix |
| HDMI ribbon cable + adapters | Right angle + mini HDMI + 20cm ribbon | Penkesu-style cable routing through hinges |
| PETG filament (black) | 1kg spool | Enclosure printing |
| M2 / M2.5 heat-set inserts + screws | Assorted | Assembly hardware |
Not Used in Prototype
Section titled “Not Used in Prototype”| Component | Why Not |
|---|---|
| Physical SPI flash cartridges | Cartridge images load from SD card filesystem instead |
| Card edge connector | No physical cartridge slot in the current build |
| TP4056 charger | PowerBoost 1000C handles charging on the Pi Zero path |
| Amber LED backlight mod | Display renders amber-on-black in software |
Architecture
Section titled “Architecture”Overview
Section titled “Overview”┌─────────────────────────────────────────────────────────────┐│ 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 as a Linux Application
Section titled “nOSh as a Linux Application”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.
Keyboard Architecture
Section titled “Keyboard Architecture”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.
| Component | Role |
|---|---|
| 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 |
Key Layout (30 keys)
Section titled “Key Layout (30 keys)”Left grid (4 rows, 3.5 key layout with EVAL spacebar):
QUOTE CONS NIL LAMBDA INFO CAR APPLY SYS LINK BACK CDR ATOM ╔════ EVAL ════╗ EQRow 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/software/runtime/input-dispatch.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.
Audio Architecture
Section titled “Audio Architecture”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.
Display Rendering
Section titled “Display Rendering”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 tallcharacter cell : 12 px wide × 24 px tall (80 × 12 = 960, 25 × 24 = 600)panel letterbox : 32 px horizontal per side, 0 px verticalscale 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/software/api-reference/grammars/character-set.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.
Boot Sequence
Section titled “Boot Sequence”- Pi Zero powers on. Pi OS Lite boots to console (no desktop environment).
- systemd launches nOSh as a service.
- nOSh initializes SDL2 fullscreen at 1024×600.
- nOSh initializes SDL_audio with emu2149.
- nOSh reads Universal Deck State from
~/.nosh/deckstate.bin. - Display:
KINOSHITA KN-86 DECKLINE / NOSH RUNTIME v2.1 / CIPHER ONLINE - Display: Operator handle, reputation, credits, registered capabilities.
- nOSh scans
~/.nosh/cartridges/for .kn86 images. - If cartridges found: display program list, await selection.
- 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.
nOSh Platform Abstraction
Section titled “nOSh Platform Abstraction”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.
// Displayvoid platform_display_init(void);void platform_display_present(const uint8_t *framebuffer);void platform_display_set_backlight(uint8_t level);
// Audiovoid platform_audio_init(void);void platform_audio_submit(const int16_t *samples, uint32_t count);
// Inputvoid platform_input_poll(KeyEvent *events, uint32_t *count);
// Savebool platform_save_write(const char *slot, const void *data, uint32_t size);bool platform_save_read(const char *slot, void *data, uint32_t size);
// Cartridgebool platform_cart_load(const char *name, CartridgeHeader *header, uint8_t *code, uint8_t *data);bool platform_cart_list(char names[][16], uint32_t *count);
// Timeuint32_t platform_ticks_ms(void);void platform_sleep_ms(uint32_t ms);Two Implementations
Section titled “Two Implementations”| File | Target | Display | Audio | Input | Cartridge |
|---|---|---|---|---|---|
platform_linux.c | Device (Pi Zero 2 W) | SDL2 → HDMI | SDL_audio + emu2149 | USB HID via SDL2 events | .kn86 files on SD card |
platform_sdl2.c | Desktop emulator | SDL2 window | SDL_audio + emu2149 | Keyboard 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.
Build System
Section titled “Build System”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└── MakefileBuild Targets
Section titled “Build Targets”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 imageWhat the Prototype Validates
Section titled “What the Prototype Validates”| Aspect | How the Prototype Tests It |
|---|---|
| Interaction model | All 30 keys, full CAR/CDR/CONS/NIL/ATOM/EQ grammar, LAMBDA recording, QUOTE bookmarks |
| Capability system | Mission board generation, cross-cartridge contracts, phase chain, cartridge swapping (menu-based) |
| Cipher voice | Sentence grammar engine output on boot, mission board, debriefs |
| C cartridge grammar | nosh_cart.h macros, cell definitions, event handlers, full ICE Breaker implementation |
| Sound design | emu2149 PSG synthesis, all system sounds, per-program audio through real speaker |
| 80×25 text mode | Full terminal layout, side-by-side panes, split-screen, all four launch title UIs |
| Link protocol | Two prototype decks connected via UART or WiFi TCP, symmetric and asymmetric play |
| Universal Deck State | Credits, reputation, cartridge history, cross-program integration, persistence across sessions |
| Null program | Procedural microfiction generation from accumulated career state |
What the Prototype Does NOT Validate
Section titled “What the Prototype Does NOT Validate”- 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.
Enclosure (Prototype Only)
Section titled “Enclosure (Prototype Only)”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.