clone

a browser grid puzzle game where you push words around to rewrite the rules of each level

Archive completed world-index navigation change

Dami committed 8639457
commit
8639457902c9e3e8a400514a56958972aab86467
parent
2c15b1dec0a0e2a1068a25057e283e25aa39534a
author
Dami <dami.etoile@gmail.com>
6 files changed, +138 -0
Ropenspec/changes/add-world-index-navigation/.openspec.yaml → openspec/changes/archive/2026-09-24-add-world-index-navigation/.openspec.yaml0
Ropenspec/changes/add-world-index-navigation/design.md → openspec/changes/archive/2026-09-24-add-world-index-navigation/design.md0
Ropenspec/changes/add-world-index-navigation/proposal.md → openspec/changes/archive/2026-09-24-add-world-index-navigation/proposal.md0
Ropenspec/changes/add-world-index-navigation/specs/world-index-navigation/spec.md → openspec/changes/archive/2026-09-24-add-world-index-navigation/specs/world-index-navigation/spec.md0
Ropenspec/changes/add-world-index-navigation/tasks.md → openspec/changes/archive/2026-09-24-add-world-index-navigation/tasks.md0
Aopenspec/specs/world-index-navigation/spec.md138++++++++++++++++++++++++++++++
R openspec/changes/add-world-index-navigation/.openspec.yaml → openspec/changes/archive/2026-09-24-add-world-index-navigation/.openspec.yaml +0 -0

No content changes.

R openspec/changes/add-world-index-navigation/design.md → openspec/changes/archive/2026-09-24-add-world-index-navigation/design.md +0 -0

No content changes.

R openspec/changes/add-world-index-navigation/proposal.md → openspec/changes/archive/2026-09-24-add-world-index-navigation/proposal.md +0 -0

No content changes.

R openspec/changes/add-world-index-navigation/specs/world-index-navigation/spec.md → openspec/changes/archive/2026-09-24-add-world-index-navigation/specs/world-index-navigation/spec.md +0 -0

No content changes.

R openspec/changes/add-world-index-navigation/tasks.md → openspec/changes/archive/2026-09-24-add-world-index-navigation/tasks.md +0 -0

No content changes.

A openspec/specs/world-index-navigation/spec.md +138 -0
@@ -0,0 +1,138 @@
1+# world-index-navigation Specification2+3+## Purpose4+TBD - created by archiving change add-world-index-navigation. Update Purpose after archive.5+## Requirements6+### Requirement: Each registered pack SHALL own a world and INDEX sheet range7+The catalog and INDEX layout SHALL create one world record and one or more8+pack-owned sheets for every registered pack, including core. Sheets SHALL hold9+at most fifteen nodes, and a world with more than fifteen proofs SHALL continue10+onto another sheet in the same world. World order SHALL be core first, then11+bundled registration order, then imported install order. Layout SHALL NOT infer12+world identity from origin or a hard-coded pack ID list.13+14+#### Scenario: Bundled packs remain separate worlds15+- **WHEN** core, crossword, crate-works, and tidewater are registered in that16+ order as the approved default bundle17+- **THEN** the layout exposes four worlds in that order, with each pack's nodes18+ in its own sheet range and no bundled node assigned `worldId: core`19+20+#### Scenario: Example packs remain available through import21+- **WHEN** garden-basics or word-lab is imported22+- **THEN** it becomes its own world after the default bundle without changing23+ core, crossword, crate-works, or tidewater progress and order24+25+#### Scenario: A long pack continues within its own world26+- **WHEN** an imported pack has sixteen ordered proofs27+- **THEN** it receives two sheets with the same world ID, fifteen nodes on the28+ first sheet, and one node on the second sheet29+30+#### Scenario: Registration order survives replacement and forking31+- **WHEN** a bundled pack is replaced or an imported pack is forked32+- **THEN** replacement keeps the existing world position and the fork appends33+ as a new imported world without reordering other worlds34+35+### Requirement: World identity metadata SHALL use nonblocking W11 validation36+An optional `manifest.world` SHALL accept a glyph that is exactly one grapheme37+cluster counted with `Intl.Segmenter` at `granularity: 'grapheme'` and no more38+than 16 UTF-16 code units. Its tagline SHALL be at most 80 characters, contain39+no newline, use sentence case, and contain no `·` (U+00B7). Its accent SHALL40+be one of `you`, `push`, `stop`, `win`, `sink`, `defeat`, or `tick`. An invalid41+optional identity field SHALL add a nonblocking W11 note and fall back to the42+first palette glyph, no tagline, and the default `--fg` path. Invalid gameplay43+fields SHALL continue to reject the complete pack atomically.44+45+#### Scenario: Valid world metadata is exposed46+- **WHEN** a pack declares `{ glyph: '🌊', tagline: 'A wet proof.', accent: 'sink' }`47+- **THEN** the normalized catalog world exposes those values with the pack's48+ stable ID, author, origin, and registration order49+50+#### Scenario: Invalid world metadata keeps the pack playable51+- **WHEN** a pack declares `accent: 'glow'`, a multi-grapheme glyph, or an52+ overlong tagline53+- **THEN** registration succeeds with a W11 note, uses the fallback world54+ identity, and keeps the pack's gameplay and active-level data available55+56+#### Scenario: World tagline reports the middle-dot correction clearly57+- **WHEN** a tagline contains `·`58+- **THEN** the pack receives a W11 note saying `Tagline can't use ·; use a59+ comma or a dash.` and the normalized world has no tagline60+61+#### Scenario: Gameplay validation remains atomic62+- **WHEN** a pack has valid or invalid `manifest.world` metadata but an invalid63+ gameplay field64+- **THEN** the pack is rejected by the existing gameplay validator and is not65+ added to the catalog66+67+#### Scenario: A legacy pack receives defaults68+- **WHEN** an otherwise valid pack omits `manifest.world`69+- **THEN** registration succeeds and its world metadata uses the default glyph,70+ no tagline, and the default foreground path accent71+72+### Requirement: INDEX progress SHALL be scoped per world73+The INDEX view model SHALL expose the active world ID/number, world name, world74+completion count, total proof count, and current world-strip position. Solved75+state SHALL remain keyed by `{ packId, levelId }`. The opener of every world76+SHALL be available, later proofs SHALL unlock in order within that world, and a77+proof solved in one world SHALL not unlock or count toward another world.78+79+#### Scenario: Completion counts do not leak between worlds80+- **WHEN** one proof is solved in world `alpha` and none is solved in world `beta`81+- **THEN** alpha reports `1 / alphaTotal`, beta reports `0 / betaTotal`, and82+ beta's second proof remains locked behind beta's opener83+84+#### Scenario: Entering a world selects its local cursor85+- **WHEN** the player leaves world `alpha` after selecting its third proof and86+ later returns87+- **THEN** the INDEX restores alpha's saved cursor when it still exists, or88+ selects alpha's first available node, without changing the active proof in89+ another world90+91+### Requirement: INDEX SHALL navigate between worlds without wraparound92+The navigator SHALL map Q/E, gamepad LB/RB, and one two-finger horizontal swipe93+per gesture to one-world-left/right actions. Walking forward from a world's94+terminal path node SHALL enter the next world's first node; walking backward95+from the first node SHALL enter the previous world's terminal node. The first96+and last world boundaries SHALL be no-ops with existing blocked-navigation97+feedback. Intra-world sheet boundaries SHALL remain distinct from world98+boundaries.99+100+#### Scenario: Q and E switch one adjacent world101+- **WHEN** the active world is the second of three and the player presses Q102+ once, then E once103+- **THEN** the navigator enters world one, then world two, with one transition104+ per input and no proof move recorded105+106+#### Scenario: Outer boundaries do not wrap107+- **WHEN** the player presses Q in world one or E in world three108+- **THEN** the world and active proof remain unchanged and the navigator returns109+ a blocked-navigation indication110+111+#### Scenario: Path edges cross worlds in travel direction112+- **WHEN** the player walks right off the final path node of world one113+- **THEN** the cursor enters world two's first node; walking left from world114+ two's first node returns to world one's final node, without wrapping past the115+ first or last world116+117+### Requirement: INDEX SHALL provide a stable world presentation seam118+The INDEX scene SHALL consume a pure world view model containing world number,119+world count, name, glyph, tagline, accent, per-world completion, and strip120+position. The first entry into a world and Workshop PLAY SHALL emit a121+world-card request with origin `index` or `workshop`, at most once per world per122+session. The seam SHALL not change integer board coordinates or simulation123+state.124+125+#### Scenario: First entry requests a world card126+- **WHEN** the player enters an unvisited world from INDEX127+- **THEN** the scene emits one `world-card` request containing that world's128+ normalized identity and `origin: index` before settling on its sheet129+130+#### Scenario: Workshop PLAY requests the same card seam131+- **WHEN** the player chooses PLAY for an unvisited pack in Workshop132+- **THEN** the scene emits one `world-card` request with `origin: workshop`,133+ preserving the pack's first node and current simulation state134+135+#### Scenario: Re-entry does not replay the card136+- **WHEN** the player returns to a world whose card request was already settled137+ during the current session138+- **THEN** the world header view model updates without another card request