apps that travel between tiny computers.
5 apps down, 11 devices across, 55 cells. Every one of them either runs that app's own C, one click away, or says plainly what is missing. Nothing below is a mockup and nothing below is a date somebody typed: the whole table is ledger.json, written by bun run ledger, which builds and replays every cell it claims. puck is a device-agnostic emulator, a set of self-contained device packs, and a set of portable app bundles.
A cell with a picture is a build that ran: emulator is the module rebuilt from the port's own source and its traces replayed, host is the same C compiled natively under address and undefined-behaviour sanitizers and diffed against it frame by frame, and silicon is how many real boards have run that port's trace and confirmed the frames. blind is whether an agent with no session context ported it from the pack folder alone. A cell with no port carries the mechanical verdict instead. Every mark folds a sentence: hover it, or open it, for the whole reason it says what it says.
| device packsreal firmware, in this repository | an author's own packnamed by their bundle, not carried here | silhouettesa device.json and nothing else, no firmware anywhere | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| RP2350-Touch-AMOLED-1.8368×448 | ESP32-S3-Touch-AMOLED-1.8368×448 | Web-Touch368×448 | tinydraw-esp32-s3-touch-amoled-18 | M5StickC-PLUS2135×240 · datasheet only | Feather-ESP32S2-TFT240×135 · datasheet only | LILYGO T-Display-S3170×320 · datasheet only | Pico Display Pack 2.0 on Pico 2320×240 · datasheet only | Watchy200×200 · datasheet only | M5Stack CoreS3320×240 · datasheet only | Waveshare ESP32-S3-Touch-LCD-2.8240×320 · datasheet only | |
| chrono A full-screen stopwatch: six seven-segment digits, two buttons, nothing else on screen. descriptor |
run it
nativenative, verified by pixel-exact frame diffs. Source: packs/rp2350-touch-amoled-18/firmware/apps/chrono.c. emulator PASS4/4 frame(s) matched host MATCH4/4 capture point(s) identical to the wasm build, sanitizers address, undefined |
run it
faithful portfaithful port, verified by pixel-exact frame diffs. Source: apps/chrono/ports/esp32-s3-touch-amoled-18/chrono.c. emulator PASS4/4 frame(s) matched host MATCH4/4 capture point(s) identical to the wasm build, sanitizers address, undefined |
run it on your phone
faithful portfaithful port, verified by pixel-exact frame diffs. Source: apps/chrono/ports/web/chrono.c. emulator PASS4/4 frame(s) matched host MATCH4/4 capture point(s) identical to the wasm build, sanitizers address, undefined |
not this app's target |
degradedchrono on M5StickC-PLUS2 (silhouette): degraded. The cost is stated: panel, 135x240 is under the 200x200 this app asks for, and above the 128x96 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here240x135 (this panel's 135x240, presented a quarter turn round), 16.7% of the panel painted, ghost buttons a, b, pwr. |
refusechrono on Feather-ESP32S2-TFT (silhouette): refuse. Refused because buttons: this device offers 1 button an app may use and this app needs 2; what they are for: key, start and stop, and it must feel instant; click, reset to 00:00:00, on a different control so it cannot be hit by accident. It would also cost: panel, 240x135 is under the 200x200 this app asks for, and above the 128x96 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here135x240 (this panel's 240x135, presented a quarter turn round), 14.4% of the panel painted, ghost buttons d0, and this panel is already landscape, so the host's own quarter turn puts the app across the device's short side rather than along it. |
degradedchrono on LILYGO T-Display-S3 (silhouette): degraded. The cost is stated: panel, 170x320 is under the 200x200 this app asks for, and above the 128x96 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here320x170 (this panel's 170x320, presented a quarter turn round), 16.4% of the panel painted, ghost buttons boot, io14. |
gochrono on Pico Display Pack 2.0 on Pico 2 (silhouette): go. Every dimension the app states is met by what the device declares. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here240x320 (this panel's 320x240, presented a quarter turn round), 16.0% of the panel painted, ghost buttons a, b, x, y, and this panel is already landscape, so the host's own quarter turn puts the app across the device's short side rather than along it. |
degradedchrono on Watchy (silhouette): degraded. The cost is stated: buttons, "UP" is a click standing in for the key this app wants (start and stop, and it must feel instant). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs, no page here200x200 (this panel's 200x200, presented a quarter turn round), 15.4% of the panel painted, ghost buttons up, down, menu, back. It ran, and there is no page for it here: this board declares a mono1 panel and the shared emulator only reads the 16-bit formats the real packs declare, so presenting it would mean pretending packs/web's own RGB565 framebuffer is this board's glass. |
gochrono on M5Stack CoreS3 (silhouette): go. Every dimension the app states is met by what the device declares. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here240x320 (this panel's 320x240, presented a quarter turn round), 16.0% of the panel painted, ghost buttons pwr, a, b, c, and this panel is already landscape, so the host's own quarter turn puts the app across the device's short side rather than along it. |
gochrono on Waveshare ESP32-S3-Touch-LCD-2.8 (silhouette): go. Every dimension the app states is met by what the device declares. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here320x240 (this panel's 240x320, presented a quarter turn round), 16.1% of the panel painted, ghost buttons boot, pwr. |
| fluidbox A particle liquid that sloshes and settles inside the device's own enclosure shape. descriptor |
run it
adaptationadaptation, verified by stated behavioral invariants, and its own port notes call it degraded. Source: apps/fluidbox/ports/rp2350-touch-amoled-18/fluid.c. emulator PASSall invariants held over 3 frame(s) host MATCH3/3 capture point(s) identical to the wasm build, sanitizers address, undefined |
run it
adaptationadaptation, verified by stated behavioral invariants, and its own port notes call it go. Source: apps/fluidbox/ports/esp32-s3-touch-amoled-18/fluid.c. emulator PASSall invariants held over 3 frame(s) host MATCH3/3 capture point(s) identical to the wasm build, sanitizers address, undefined |
run it on your phone
adaptationadaptation, verified by stated behavioral invariants, and its own port notes call it go. Source: apps/fluidbox/ports/web/fluid.c. emulator PASSall invariants held over 3 frame(s) host MATCH3/3 capture point(s) identical to the wasm build, sanitizers address, undefined |
not this app's target |
degradedfluidbox on M5StickC-PLUS2 (silhouette): degraded. It runs at 25 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (135x240 at one per 1268 px). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. It runs at 25 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (135x240 at one per 1268 px). runs here135x240, 3.8% of the panel painted, ghost buttons a, b, pwr. |
refusefluidbox on Feather-ESP32S2-TFT (silhouette): refuse. Refused because sensors: this app needs a vector sensor (gravity direction, read every step, so tilting the device pours the liquid) and the device declares none at all. It would also cost: buttons, "D0" is a click standing in for the key this app wants (reset the fluid to a settled block, one tap, no explanation). It runs at 25 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (240x135 at one per 1268 px). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. It runs at 25 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (240x135 at one per 1268 px). runs here240x135, 3.8% of the panel painted, ghost buttons d0. |
refusefluidbox on LILYGO T-Display-S3 (silhouette): refuse. Refused because sensors: this app needs a vector sensor (gravity direction, read every step, so tilting the device pours the liquid) and the device declares none at all. It runs at 42 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (170x320 at one per 1268 px). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. It runs at 42 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (170x320 at one per 1268 px). runs here170x320, 3.8% of the panel painted, ghost buttons boot, io14. |
refusefluidbox on Pico Display Pack 2.0 on Pico 2 (silhouette): refuse. Refused because sensors: this app needs a vector sensor (gravity direction, read every step, so tilting the device pours the liquid) and the device declares none at all. It runs at 60 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (320x240 at one per 1268 px). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. It runs at 60 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (320x240 at one per 1268 px). runs here320x240, 3.8% of the panel painted, ghost buttons a, b, x, y. |
refusefluidbox on Watchy (silhouette): refuse. Refused because panel: this app's colour carries information and the panel is mono1, which is not a colour one. It would also cost: buttons, "UP" is a click standing in for the key this app wants (reset the fluid to a settled block, one tap, no explanation). It runs at 31 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (200x200 at one per 1268 px). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. It runs at 31 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (200x200 at one per 1268 px). runs, no page here200x200, 3.8% of the panel painted, ghost buttons up, down, menu, back. It ran, and there is no page for it here: this board declares a mono1 panel and the shared emulator only reads the 16-bit formats the real packs declare, so presenting it would mean pretending packs/web's own RGB565 framebuffer is this board's glass. |
degradedfluidbox on M5Stack CoreS3 (silhouette): degraded. It runs at 60 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (320x240 at one per 1268 px). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. It runs at 60 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (320x240 at one per 1268 px). runs here320x240, 3.8% of the panel painted, ghost buttons pwr, a, b, c. |
degradedfluidbox on Waveshare ESP32-S3-Touch-LCD-2.8 (silhouette): degraded. It runs at 60 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (240x320 at one per 1268 px). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. It runs at 60 particles against the reference 130 (how many particles the fluid is made of), bound by panel area (240x320 at one per 1268 px). runs here240x320, 3.8% of the panel painted, ghost buttons boot, pwr. |
| tinydraw A full-panel finger-drawing canvas: variable-width antialiased ink, two-level zoom, one-stroke undo. descriptor |
run it
adaptationadaptation, verified by stated behavioral invariants, and its own port notes call it degraded. Source: apps/tinydraw/ports/rp2350-touch-amoled-18/tinydraw.c. emulator PASSall invariants held over 4 frame(s) host MATCH4/4 capture point(s) identical to the wasm build, sanitizers address, undefined |
run it
adaptationadaptation, verified by stated behavioral invariants, and its own port notes call it degraded. Source: apps/tinydraw/ports/esp32-s3-touch-amoled-18/tinydraw.c. emulator PASSall invariants held over 4 frame(s) host MATCH4/4 capture point(s) identical to the wasm build, sanitizers address, undefined ported blind 2026-09-02claude-sonnet ported tinydraw to esp32-s3-touch-amoled-18 on 2026-09-02 with no session context; given the pack folder, the app bundle, and docs/convention/ - no session context and no sibling port to copy from; bun run verify-bundle went green on the first run, with no correction from a person; 1 attempt; about 50 minutes. Recorded by hand in blind-ports.json, not computed here. |
run it on your phone
adaptationadaptation, verified by stated behavioral invariants, and its own port notes call it degraded. Source: apps/tinydraw/ports/web/tinydraw.c. emulator PASSall invariants held over 4 frame(s) host MATCH4/4 capture point(s) identical to the wasm build, sanitizers address, undefined |
not this app's target |
refusetinydraw on M5StickC-PLUS2 (silhouette): refuse. Refused because touch: this app needs 1 touch point(s) and the device declares 0. It would also cost: panel, 135x240 is under the 200x200 this app asks for, and above the 128x128 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. blankm5stickc-plus2 declares no digitizer (touch.points 0), and tinydraw demands 1 touch point(s), so there is nothing here that could ever answer a touch. the app compiled, instantiated and painted this 135x240 panel, and 100.00% of it is one single colour. That is what an app with nothing to show yet looks like, and it is also what an app drawing at coordinates outside this panel looks like: the PNG beside this line is the only thing that tells the two apart. |
refusetinydraw on Feather-ESP32S2-TFT (silhouette): refuse. Refused because buttons: this device offers 1 button an app may use and this app needs 2; what they are for: key, cycle the zoom level; click, undo the last stroke, on a different control so cycling zoom cannot erase work, and because touch: this app needs 1 touch point(s) and the device declares 0. It would also cost: panel, 240x135 is under the 200x200 this app asks for, and above the 128x128 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. blankfeather-esp32s2-tft declares no digitizer (touch.points 0), and tinydraw demands 1 touch point(s), so there is nothing here that could ever answer a touch. the app compiled, instantiated and painted this 240x135 panel, and 100.00% of it is one single colour. That is what an app with nothing to show yet looks like, and it is also what an app drawing at coordinates outside this panel looks like: the PNG beside this line is the only thing that tells the two apart. |
refusetinydraw on LILYGO T-Display-S3 (silhouette): refuse. Refused because touch: this app needs 1 touch point(s) and the device declares 0. It would also cost: panel, 170x320 is under the 200x200 this app asks for, and above the 128x128 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. blanklilygo-t-display-s3 declares no digitizer (touch.points 0), and tinydraw demands 1 touch point(s), so there is nothing here that could ever answer a touch. the app compiled, instantiated and painted this 170x320 panel, and 100.00% of it is one single colour. That is what an app with nothing to show yet looks like, and it is also what an app drawing at coordinates outside this panel looks like: the PNG beside this line is the only thing that tells the two apart. |
refusetinydraw on Pico Display Pack 2.0 on Pico 2 (silhouette): refuse. Refused because touch: this app needs 1 touch point(s) and the device declares 0. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. blankpico-display-pack-2 declares no digitizer (touch.points 0), and tinydraw demands 1 touch point(s), so there is nothing here that could ever answer a touch. the app compiled, instantiated and painted this 320x240 panel, and 100.00% of it is one single colour. That is what an app with nothing to show yet looks like, and it is also what an app drawing at coordinates outside this panel looks like: the PNG beside this line is the only thing that tells the two apart. |
refusetinydraw on Watchy (silhouette): refuse. Refused because touch: this app needs 1 touch point(s) and the device declares 0. It would also cost: buttons, "UP" is a click standing in for the key this app wants (cycle the zoom level). This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. blankwatchy declares no digitizer (touch.points 0), and tinydraw demands 1 touch point(s), so there is nothing here that could ever answer a touch. the app compiled, instantiated and painted this 200x200 panel, and 100.00% of it is one single colour. That is what an app with nothing to show yet looks like, and it is also what an app drawing at coordinates outside this panel looks like: the PNG beside this line is the only thing that tells the two apart. |
gotinydraw on M5Stack CoreS3 (silhouette): go. Every dimension the app states is met by what the device declares. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs herethe module's own emu_device() declares M5Stack CoreS3: 320x240, buttons pwr, a, b, c; the painted canvas is 320x240 device pixels, one per panel pixel; a synthetic drag changed the panel: 4.70% of pixels differ from before it, over the 0.5% floor. |
gotinydraw on Waveshare ESP32-S3-Touch-LCD-2.8 (silhouette): go. Every dimension the app states is met by what the device declares. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs herethe module's own emu_device() declares Waveshare ESP32-S3-Touch-LCD-2.8: 240x320, buttons boot, pwr; the painted canvas is 240x320 device pixels, one per panel pixel; a synthetic drag changed the panel: 4.51% of pixels differ from before it, over the 0.5% floor. |
| gameos A handheld game console shell: pick a game to launch a thermal gunner, a slot machine, or a swing-driven procedural golf course. descriptor |
run it
adaptationadaptation, verified by stated behavioral invariants, and its own port notes call it degraded. Source: apps/gameos/ports/rp2350-touch-amoled-18/gameos_port.c. emulator PASSall invariants held over 12 frame(s) host MATCH12/12 capture point(s) identical to the wasm build, sanitizers address, undefined |
run it
adaptationadaptation, verified by stated behavioral invariants, and its own port notes call it degraded. Source: apps/gameos/ports/esp32-s3-touch-amoled-18/gameos_port.c. emulator PASSall invariants held over 21 frame(s) host SANITIZERthe sanitized host build trapped on gameos-demo-esp32 (address, undefined): signed integer overflow: 1499045572 + 668265263 cannot be represented in type 'int' |
gogameos on Web-Touch (pack): go. Every dimension the app states is met by what the device declares. Unchecked: memory (this target declares no budget.ram.bytes, and nothing here invents one); tick (this target declares no budget.tickBudgetMs). A verdict is a comparison of two documents, never a prediction that the port runs. |
not this app's target |
refusegameos on M5StickC-PLUS2 (silhouette): refuse. Refused because panel: 135x240 is under the 184x224 this app can scale to, and because touch: this app needs 1 touch point(s) and the device declares 0. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here135x240, 66.1% of the panel painted, ghost buttons a, b, pwr. Compiled from its RP2350-Touch-AMOLED-1.8 port's own file: this app has no web-pack port of its own. |
refusegameos on Feather-ESP32S2-TFT (silhouette): refuse. Refused because panel: 240x135 is under the 184x224 this app can scale to, and because touch: this app needs 1 touch point(s) and the device declares 0, and because sensors: this app needs a vector sensor (GUNSHIP aims the reticle by tilt, the donor's own default aim mode) and the device declares none at all. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here240x135, 44.6% of the panel painted, ghost buttons d0. Compiled from its RP2350-Touch-AMOLED-1.8 port's own file: this app has no web-pack port of its own. |
refusegameos on LILYGO T-Display-S3 (silhouette): refuse. Refused because panel: 170x320 is under the 184x224 this app can scale to, and because touch: this app needs 1 touch point(s) and the device declares 0, and because sensors: this app needs a vector sensor (GUNSHIP aims the reticle by tilt, the donor's own default aim mode) and the device declares none at all. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here170x320, 62.8% of the panel painted, ghost buttons boot, io14. Compiled from its RP2350-Touch-AMOLED-1.8 port's own file: this app has no web-pack port of its own. |
refusegameos on Pico Display Pack 2.0 on Pico 2 (silhouette): refuse. Refused because touch: this app needs 1 touch point(s) and the device declares 0, and because sensors: this app needs a vector sensor (GUNSHIP aims the reticle by tilt, the donor's own default aim mode) and the device declares none at all. It would also cost: panel, 320x240 is under the 368x448 this app asks for, and above the 184x224 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs here320x240, 59.9% of the panel painted, ghost buttons a, b, x, y. Compiled from its RP2350-Touch-AMOLED-1.8 port's own file: this app has no web-pack port of its own. |
refusegameos on Watchy (silhouette): refuse. Refused because panel: this app's colour carries information and the panel is mono1, which is not a colour one, and because touch: this app needs 1 touch point(s) and the device declares 0. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs, no page here200x200, 60.0% of the panel painted, ghost buttons up, down, menu, back. Compiled from its RP2350-Touch-AMOLED-1.8 port's own file: this app has no web-pack port of its own. It ran, and there is no page for it here: this board declares a mono1 panel and the shared emulator only reads the 16-bit formats the real packs declare, so presenting it would mean pretending packs/web's own RGB565 framebuffer is this board's glass. |
degradedgameos on M5Stack CoreS3 (silhouette): degraded. The cost is stated: panel, 320x240 is under the 368x448 this app asks for, and above the 184x224 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs herethe module's own emu_device() declares M5Stack CoreS3: 320x240, buttons pwr, a, b, c; the painted canvas is 320x240 device pixels, one per panel pixel; a synthetic tap changed the panel: 59.43% of pixels differ from before it, over the 0.5% floor. Compiled from its RP2350-Touch-AMOLED-1.8 port's own file: this app has no web-pack port of its own. |
degradedgameos on Waveshare ESP32-S3-Touch-LCD-2.8 (silhouette): degraded. The cost is stated: panel, 240x320 is under the 368x448 this app asks for, and above the 184x224 it scales to: the layout comes out of the panel, so it fits, smaller. This target is unverified against silicon, so every number above came from a datasheet, not from a board. A verdict is a comparison of two documents, never a prediction that the port runs. runs herethe module's own emu_device() declares Waveshare ESP32-S3-Touch-LCD-2.8: 240x320, buttons boot, pwr; the painted canvas is 240x320 device pixels, one per panel pixel; a synthetic tap changed the panel: 87.91% of pixels differ from before it, over the 0.5% floor. Compiled from its RP2350-Touch-AMOLED-1.8 port's own file: this app has no web-pack port of its own. |
| aliceisjustplaying/tinydraw their repository reproduced from aliceisjustplaying/tinydraw@0c0b2d9 on 2026-09-02 |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. |
emulator PASS28/28 frame(s) matched built by aliceisjustplaying/tinydraw@000de0a, its own command: ./scripts/build-puck-wasm |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. build-failedaliceisjustplaying/tinydraw's bundle names no port source this pack could compile: a silhouette runs through packs/web, and this bundle declares no web port and no rp2350 port to borrow one from. |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. build-failedaliceisjustplaying/tinydraw's bundle names no port source this pack could compile: a silhouette runs through packs/web, and this bundle declares no web port and no rp2350 port to borrow one from. |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. build-failedaliceisjustplaying/tinydraw's bundle names no port source this pack could compile: a silhouette runs through packs/web, and this bundle declares no web port and no rp2350 port to borrow one from. |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. build-failedaliceisjustplaying/tinydraw's bundle names no port source this pack could compile: a silhouette runs through packs/web, and this bundle declares no web port and no rp2350 port to borrow one from. |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. build-failedaliceisjustplaying/tinydraw's bundle names no port source this pack could compile: a silhouette runs through packs/web, and this bundle declares no web port and no rp2350 port to borrow one from. |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. build-failedaliceisjustplaying/tinydraw's bundle names no port source this pack could compile: a silhouette runs through packs/web, and this bundle declares no web port and no rp2350 port to borrow one from. |
no verdictaliceisjustplaying/tinydraw's descriptor.md's Demands section carries no ```json demands block, so this app's requirements are prose only. Add one (docs/convention/app-bundle.md, "Demands are also machine-readable"); nothing here guesses at prose. build-failedaliceisjustplaying/tinydraw's bundle names no port source this pack could compile: a silhouette runs through packs/web, and this bundle declares no web port and no rp2350 port to borrow one from. |
A silhouette is a board nobody has written firmware for: one device.json with its numbers read off a datasheet and never measured against silicon, compiled against through packs/web so the app really runs at that panel size with those buttons. Last computed 2026-09-02.
Not a port: each device pack's own shipped app, plus the instrument's own minimal example firmware - every tile below links to it running live, the same as the cells above.
A bouncing square: the pack's own reference app, proving its band-render contract with nothing borrowed from another device.
The instrument's own minimal reference firmware: a 240x240 panel, two buttons (one with a long-press verdict), a shake sensor, and a scripted two-button chord. Not a device pack, not a ported app - the smallest complete emu_device() implementation, and where a new firmware author starts.
A self-contained folder for one target: real drivers, a real board's firmware, and a device.json descriptor the emulator reads at runtime. Nothing in the shared instrument names one device; every panel size and button comes from the pack itself. The browser is one of those targets, so a phone is a device pack too, and an app ported to it goes through the same verifier as an app ported to a chip.
An app is defined by its descriptor and traces, not by one implementation's source code: what appears on screen, every interaction, and separate requirements from preferences. A port starts with a verdict against the target pack, computed from those two documents, before any code is written.
app-bundle.mdEvery cell above is recomputed when its own inputs change, and reused when they do not. A faithful port replays its traces and compares frames pixel for pixel; an adaptation states behavioral invariants and gets checked against those; either way the shared harness decides, not a claim in a README.
decision 0012