Skip to content

Commit fc8cb1a

Browse files
Merge pull request #39 from ghostintheshell-192/feat/desktop-only
feat: RAID Sandbox is a desktop game — the mobile flow is removed (ADR-003)
2 parents c9b4358 + 28101f7 commit fc8cb1a

16 files changed

Lines changed: 256 additions & 546 deletions

.claude/rules/overview.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,28 @@ Spec-driven and incremental:
3131
- **YAML data files** (`data/`) — RAID levels, algorithms, components, challenges.
3232
Parsed in-browser via **js-yaml**, vendored in `vendor/js-yaml/` (not a CDN, and not
3333
an npm dependency — see `vendor/README.md`).
34-
- **Touch support**`touch-dnd.js` shims the HTML5 drag-and-drop API, which does not
35-
exist on touch devices.
3634
- **Zero runtime dependencies** — the headless node tests must not require YAML parsing.
3735

3836
## Architecture (source layout)
3937

4038
- `src/engine/``model.js`, `layout.js` (placement), `validator.js`
4139
- `src/sandbox/``canvas-controller.js`, `canvas-state.js`, `physical-controller.js`,
42-
`render.js`, `sidebar-accordion.js`, `touch-dnd.js`
40+
`render.js`, `highlight.js`, `drag-util.js`
4341
- `src/challenge/` — challenge mode
4442
- `data/` — YAML resource files (the domain data, extracted from `src/`)
4543
- `tests/` — headless node suites (`*.test.js`, run one at a time with `node <file>`)
4644
plus browser test pages (`*.test.html`, demos)
4745

4846
## Key Design Decisions
4947

50-
- **No stack change**: the bottleneck is *interaction* (touch gestures), not rendering.
51-
Canvas/WebGL/WASM would be a regression here; the shareable URL is the goal. Only
52-
sanctioned upgrade path is incremental **TypeScript via `@ts-check`** (zero runtime change) —
53-
in place since 2026-09-02 on the engine files (`jsconfig.json`, `src/engine/types.js`,
54-
`.development/automation/typecheck.sh`).
55-
- **Mobile flow inverted**: on touch, "tap a slot → it offers the pieces that fit"
56-
(inline), not "pick a piece, find it a home" — drag and scroll compete for the same gesture.
48+
- **No stack change**: the whole game has to travel as one link, with zero runtime
49+
dependencies, stay readable as source, and be type-checked without a toolchain.
50+
Canvas/WebGL/WASM would cost all four and buy rendering speed the game does not need.
51+
The only sanctioned upgrade path is incremental **TypeScript via `@ts-check`** (zero
52+
runtime change) — in place since 2026-09-02 on the engine files (`jsconfig.json`,
53+
`src/engine/types.js`, `.development/automation/typecheck.sh`).
54+
- **Desktop only** since 2026-09-05 ([ADR-003](../../.development/reference/decisions/003-desktop-only.md)):
55+
below 900px `index.html` shows a short notice and a link to the knowledge base. The
56+
inline picker survives the removal as click-to-build, next to drag-and-drop.
5757
- **License**: deliberately none for now (= full copyright). If revisited: AGPL-3.0 for
5858
code + CC BY-SA 4.0 for content.

.development/ARCHITECTURE.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ data/ (YAML) → engine/ → sandbox/ → DOM
1919
(constraint engine). This layer is what the headless suites assert against,
2020
and it must stay independent of the DOM for that to remain possible.
2121
- **`src/sandbox/`** — owns the DOM. Controllers (`canvas-controller.js`,
22-
`physical-controller.js`), state (`canvas-state.js`), rendering
23-
(`render.js`), and the touch shim (`touch-dnd.js`) that stands in for the
24-
HTML5 drag-and-drop API where it does not exist.
22+
`physical-controller.js`), state (`canvas-state.js`) and rendering
23+
(`render.js`). Desktop only (ADR-003): building is drag-and-drop plus the
24+
inline click-to-build picker.
2525
- **`src/challenge/`** — challenge mode, built on top of the same engine.
2626
- **`data/`** — YAML resource files, parsed in-browser. The headless tests do
2727
not read them: they must run with zero dependencies.
@@ -36,6 +36,7 @@ kernel rules and never regenerated from the engine.
3636

3737
- [ADR-001: The RAID engine's type comes from which object it is, not where it sits](reference/decisions/001-engine-identity-not-position.md) `[high]` — Hardware vs. fake RAID is decided by which of two distinct engine objects sits on the control path (compute silicon vs. metadata-only chip), not by the engine's position relative to the PCIe bus; software RAID is the configuration where neither is present.
3838
- [ADR-002: The engine holds no domain facts — it reads them from data files](reference/decisions/002-the-engine-holds-no-domain-facts.md) `[high]` — The engine's code knows *how* to compose, recognize, validate and explain; it does not know *what* a backplane, a RAID-on-Chip or a RAID 5 is. Every domain fact — components, ports, verdicts, level shapes, disk minimums — lives in the YAML files and is read from there, so adding a capability is adding a file.
39+
- [ADR-003: RAID Sandbox is a desktop game — the mobile flow is removed](reference/decisions/003-desktop-only.md) `[medium]` — Below the desktop breakpoint the game is no longer offered. A phone or a narrow window gets a short page that says what RAID Sandbox is, that it needs a desktop browser, and points to the knowledge base — which stays readable on mobile. The touch shim, the mobile layout and the accordion palette go; the inline picker stays, as click-to-build on desktop. No mobile version is promised.
3940

4041
## Project Tree
4142

@@ -67,8 +68,6 @@ kernel rules and never regenerated from the engine.
6768
- `highlight.js` — RAID Sandbox: "what I am talking about is THAT one".
6869
- `physical-controller.js` — RAID Sandbox: physical layer (axis A) canvas controller.
6970
- `render.js` — RAID Sandbox: render + animate a placement grid (Phase 2b).
70-
- `sidebar-accordion.js` — collapse the palette into an accordion on narrow screens.
71-
- `touch-dnd.js` — touch shim for the HTML5 drag-and-drop API.
7271

7372
### tests
7473
- `algorithms-data.test.js` — validates the REAL algorithm YAML files in data/algorithms/. Run with: node algorithms-data.test.js (uses python3 + pyyaml to read YAML; this repo is zero-dependency and Node has no YAML parser, so ...

.development/CURRENT-STATUS.md

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ its own (`reference/engine-robustness-and-extraction.md` §8).
1919

2020
## Recent Milestones
2121

22+
- **Desktop only** ([ADR-003](reference/decisions/003-desktop-only.md), 2026-09-05):
23+
below 900px the game is no longer offered — `index.html` hides the canvases and shows
24+
a short notice saying what RAID Sandbox is, that it needs a desktop browser, and
25+
linking the knowledge base, which stays readable on a phone. No mobile version is
26+
promised, because none is planned. **What went**: `touch-dnd.js` (the drag-and-drop
27+
shim), `sidebar-accordion.js`, the ≤900px single-column flow and the
28+
`pointer: coarse` block in `sandbox.css`, the narrow-screen physical-layer fold and
29+
its toggle. **What stayed**: the inline picker, no longer a touch affordance but
30+
click-to-build next to drag-and-drop, and the base for the accessibility work
31+
(roadmap item 9). One tech-debt closes by deletion — the `touch-dnd.js` re-scope — and one is
32+
re-scoped: the physical layer's missing picker, now a desktop asymmetry at low priority. Every interface change from here is
33+
designed once, for one width - 2026-09-05
2234
- **Degenerate levels — what the player has, next to what they tried to build** (PRs
2335
#35#37, 2026-09-05, one day after the spec): the leaf level files declare
2436
`minDisksToRun` (with the kernel line) and `collapsesTo` (RAID 5 @2, RAID 6 @3,
@@ -145,13 +157,12 @@ decision.
145157
coloured by verdict, the ADR-001 lesson with no words. Start:
146158
`specs/planned/derived-controller.md` ("the dashed box is the verdict, drawn"),
147159
`engineNodeId` in the eval result, `highlight.js`. **M**
148-
5. **Technical queue****mostly closed 2026-09-05** (see the milestone): the level's
160+
5. **Technical queue****closed 2026-09-05** (see the milestones): the level's
149161
`reason` on success (PR #28), RAID 0+1 reads high (PR #27), the validator's last ids
150-
in code (PR #30), `algorithm-drop-ignores-class` (PR #24). Two items remain, both
151-
Valentina's: the physical layer's missing tap-to-picker
152-
(`tech-debt/physical-layer-canvas-has-no-touch-picker.md`) needs a triage in the
153-
browser first; `touch-dnd.js` re-scope now that tap-to-build ships — what "re-scope"
154-
means here is still hers to say. **S each**
162+
in code (PR #30), `algorithm-drop-ignores-class` (PR #24). The two remaining items
163+
were both about touch. ADR-003 answered them: ~~the `touch-dnd.js` re-scope~~ (the shim
164+
is gone), and the physical layer's missing picker re-scoped as a desktop asymmetry,
165+
low priority, to take up with item 9 (`tech-debt/physical-layer-canvas-has-no-touch-picker.md`).
155166
6. **Challenges on the physical axis** — the requirement vocabulary knows only the
156167
data metrics; add the RAID type ("must be hardware") and the physical-validator
157168
phase 2 rules (fake RAID limited to 0/1/5/10, mixed protocols, Storage Spaces).
@@ -167,7 +178,7 @@ decision.
167178
Start: `data/`, `data-loader.js` (a language prefix). **M**
168179
9. **Accessibility** — keyboard and screen-reader paths were never considered; for a
169180
teaching tool they matter. Start: an audit of `index.html` roles/labels, the
170-
drag-only interactions (tap-to-build already helps). **M**
181+
drag-only interactions. **M**
171182
10. **Extracting the game engine** — the decision this whole plan prepared: second
172183
domain (datacenter / network topologies / motor workbench), name, scope; then
173184
`git subtree` with history, never a copy. Start:
@@ -192,9 +203,6 @@ Small, any time:
192203

193204
See `.development/tech-debt/`:
194205

195-
- `physical-layer-canvas-has-no-touch-picker.md` — open (medium): the physical layer
196-
never got the tap-to-picker inversion; needs a triage in the browser first (roadmap
197-
item 5).
198206
- `canvas-nodes-are-unnamed.md` — open (medium): the canvas does not name the things
199207
the player builds (roadmap item 2).
200208
- `capacity-approximate-on-mixed-disks.md` — open (medium): usable capacity is
@@ -203,6 +211,8 @@ See `.development/tech-debt/`:
203211
writes as one disk, so RAID 0+1 gets `writeMult 0.5` and `writeClass medium` against
204212
1+0's `1` / `high`. Fixing it lets 0+1 satisfy the `database` challenge — a domain
205213
decision, taken on purpose, recorded there.
214+
- `physical-layer-canvas-has-no-touch-picker.md` — open (low, re-scoped by ADR-003): the physical
215+
layer has drag-and-drop only, the data layer also click-to-build; take up with item 9.
206216
- `automation-not-checked-on-windows.md` — open (low): hooks and dev scripts are
207217
tested only on the Linux workstation.
208218
- `nested-data-allocation-order.md`**mostly RESOLVED**. Per-span order is
@@ -213,9 +223,9 @@ See `.development/tech-debt/`:
213223

214224
## Notes
215225

216-
- **Test suite**: 17 headless node files in `tests/` — run each with `node <file>`, or all
226+
- **Test suite**: 19 headless node files in `tests/` — run each with `node <file>`, or all
217227
via `bash .development/automation/test.sh`; type check via `typecheck.sh`; plus
218-
browser test pages (`*.test.html`) and demos. Responsive/touch/accordion work is
228+
browser test pages (`*.test.html`) and demos. Drag-and-drop, picker and animation work is
219229
browser-only (guarded), does not touch the headless suite.
220230
- **Zero-dependency**: YAML parsed in-browser via js-yaml; node tests must not require
221231
YAML parsing at runtime.

.development/INDEX.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
- [nested-data-allocation-order.md](tech-debt/nested-data-allocation-order.md) — Tech debt — nested data-allocation order
5858
- [nvme-hardware-raid-unbuildable.md](tech-debt/nvme-hardware-raid-unbuildable.md) — NVMe disks can never reach `engine-roc` — Hardware RAID over NVMe is unbuildable
5959
- [nvme-software-raid-unbuildable.md](tech-debt/nvme-software-raid-unbuildable.md) — All-NVMe software RAID cannot be built — the recognizer demands an HBA the spec forbids
60-
- [physical-layer-canvas-has-no-touch-picker.md](tech-debt/physical-layer-canvas-has-no-touch-picker.md) — The Physical Layer canvas never got the mobile tap-to-picker inversion
60+
- [physical-layer-canvas-has-no-touch-picker.md](tech-debt/physical-layer-canvas-has-no-touch-picker.md) — The Physical Layer canvas has no click-to-build picker — drag is its only path
6161
- [physical-recognizer-does-not-walk-the-path.md](tech-debt/physical-recognizer-does-not-walk-the-path.md) — The physical recognizer checks presence and one edge, not the path
6262
- [ports-double-source-of-truth.md](tech-debt/ports-double-source-of-truth.md) — Component ports are defined twice, and the two environments read different copies
6363
- [power-loss-warning-promised-not-implemented.md](tech-debt/power-loss-warning-promised-not-implemented.md) — The power-loss warning is promised in the data and was never written
@@ -71,10 +71,11 @@
7171
- [refusal-points.md](reference/refusal-points.md) — Refusal points — where the game says no, and whether it says why
7272
- [unspoken-content.md](reference/unspoken-content.md) — Unspoken content — what the game knows and never says
7373

74-
### reference/decisions/ (2 files)
74+
### reference/decisions/ (3 files)
7575

7676
- [001-engine-identity-not-position.md](reference/decisions/001-engine-identity-not-position.md) — ADR-001: The RAID engine's type comes from which object it is, not where it sits
7777
- [002-the-engine-holds-no-domain-facts.md](reference/decisions/002-the-engine-holds-no-domain-facts.md) — ADR-002: The engine holds no domain facts — it reads them from data files
78+
- [003-desktop-only.md](reference/decisions/003-desktop-only.md) — ADR-003: RAID Sandbox is a desktop game — the mobile flow is removed
7879

7980
---
8081

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# ADR-003: RAID Sandbox is a desktop game — the mobile flow is removed
2+
3+
**Date**: 2026-09-05
4+
**Status**: Accepted
5+
**Impact**: medium
6+
**Summary**: Below the desktop breakpoint the game is no longer offered. A phone or a narrow window gets a short page that says what RAID Sandbox is, that it needs a desktop browser, and points to the knowledge base — which stays readable on mobile. The touch shim, the mobile layout and the accordion palette go; the inline picker stays, as click-to-build on desktop. No mobile version is promised.
7+
8+
## Context
9+
10+
The game was built for a wide canvas: drag disks, group them, set the two axes, watch
11+
the layout animate. Mobile support was added afterwards, in three steps:
12+
13+
- **June 2026** — a responsive pass: the palette wraps and collapses into an accordion
14+
under 900px, the physical layer folds away, the results panel flows below the canvases.
15+
- **June 2026**`touch-dnd.js`, a shim that fakes the HTML5 drag-and-drop events on
16+
touch (press-and-hold 180 ms, then drag), so the controllers work unchanged.
17+
- **July 2026** — the mobile flow inverted (PR #1): tapping an empty zone opens an inline
18+
picker of what fits there, because drag and scroll compete for the same gesture. It
19+
was validated in the browser by the author and a designer, and shipped.
20+
21+
Two things were never finished. The **physical layer** got no picker: on touch it is
22+
still the shim, the worst experience in the game
23+
(`tech-debt/physical-layer-canvas-has-no-touch-picker.md`). And the shim itself was
24+
flagged the day tap-to-build landed as *"largely redundant, possibly dead code — to
25+
re-scope"*, and stayed that way for six weeks because nobody could say what to keep.
26+
27+
Meanwhile every change to the interface is designed twice. The two boxes of the
28+
degenerate-levels work (2026-09-05) were laid out for the wide panel *and* for the
29+
single-column flow; the information icons and the knowledge-base rework ahead would be
30+
too. That is the real cost: not the code that exists, but the second target every future
31+
change has to hit.
32+
33+
The site has no audience yet — it has not been announced anywhere. There is nothing to
34+
lose by deciding now, and Search Console will say later how many phones ever arrive.
35+
36+
One more thing depends on this. `.claude/rules/overview.md` justifies the vanilla stack
37+
with *"the bottleneck is interaction (touch gestures), not rendering"*. Without touch,
38+
that sentence no longer carries the argument, and the stack has to be defended on the
39+
grounds that were always there too.
40+
41+
## Decision
42+
43+
**RAID Sandbox is a desktop game.** Below the desktop breakpoint (900px, the line the
44+
layout already used) `index.html` does not offer the canvases. It shows a short page:
45+
46+
- what the game is, in a few lines;
47+
- that it needs a desktop browser — stated plainly, with no "coming soon" and no
48+
mention of a mobile version, because none is planned and the project does not print
49+
promises it cannot keep;
50+
- a link to the knowledge base.
51+
52+
A shared `#build=` link opened on a phone lands on that page too, not on a broken
53+
canvas.
54+
55+
**The knowledge base stays readable on mobile.** It is the one page a phone visitor gets,
56+
and its rework (roadmap item 3) designs for that.
57+
58+
**What goes**: `touch-dnd.js`; `sidebar-accordion.js`; the mobile layout in
59+
`sandbox.css` (the ≤ 900px flow, the `pointer: coarse` sizing); the physical-layer
60+
fold-away where it exists only for narrow screens; the `pointer: coarse` and
61+
`(max-width: 900px)` branches in the controllers.
62+
63+
**What stays**: the inline picker. It was written *touch-first*, but it opens on click,
64+
and on desktop it is a second way to build — an empty zone offers what fits — next to
65+
drag-and-drop. It is not mobile code; it is the game's own answer to "what can go here",
66+
and the information icons will lean on the same idea.
67+
68+
## Rationale
69+
70+
- **One target.** Every interface change from here on is designed once, for the wide
71+
layout. That halves the cost of the roadmap's next three items.
72+
- **The mobile game was never whole.** Half of it (the physical layer) ran on a
73+
press-and-hold shim that fought the scroll. Finishing it meant a second picker and a
74+
second round of validation for a surface nobody has visited.
75+
- **Honesty over reach.** A page that says "this needs a desktop" is true. A half-working
76+
game on a phone teaches the wrong things about RAID and about the project.
77+
- **Reversible.** The removed code stays in the history (PR #1 and the June commits);
78+
the notice page is an afternoon. If Search Console ever shows a mobile audience worth
79+
serving, the decision is one revert and one conversation away.
80+
81+
## Consequences
82+
83+
- **One tech-debt closes by deletion, one is re-scoped.** The `touch-dnd.js` re-scope
84+
(roadmap item 5) is answered: the shim is gone. `physical-layer-canvas-has-no-touch-picker`
85+
loses its touch half but not its point — the data layer keeps a click-to-build picker
86+
and the physical layer has only drag, an asymmetry that matters for the accessibility
87+
work (item 9); it stays open at low priority under a truer title.
88+
- **Smaller surface**: two JavaScript files and the mobile section of the stylesheet go;
89+
the headless suites are untouched (none of this was ever loaded under Node).
90+
- **A phone visitor loses the game** and gets the knowledge base. Until the site is
91+
announced, that visitor is the author.
92+
- **The stack argument is restated** in `overview.md`: no build step and no framework
93+
because the whole game must travel as one link with zero runtime dependencies, be
94+
readable as source, and be type-checked without a toolchain — not because of touch.
95+
- **Accessibility (roadmap item 9) is unaffected**: keyboard and screen-reader paths are
96+
a desktop concern, and the click-to-build picker is a better base for them than drag.
97+
- **The knowledge base becomes the mobile front door**, which sets a requirement for its
98+
rework: readable on a phone, linked from the notice page.
99+
100+
## See also
101+
102+
- `.claude/rules/overview.md` — the stack decision, restated by this ADR.
103+
- `tech-debt/physical-layer-canvas-has-no-touch-picker.md` — re-scoped by this decision:
104+
no longer about touch, still about the physical layer having one build path.
105+
- `.memory-bank/2026-07-24-2135-mobile-tap-to-build-ci-branch-protection.md` (local) —
106+
the day tap-to-build shipped and the shim was first questioned.
107+
- [ADR-001](001-engine-identity-not-position.md), [ADR-002](002-the-engine-holds-no-domain-facts.md)
108+
unaffected: this decision is about the surface, not the engine.

0 commit comments

Comments
 (0)