clone

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

docs(openspec): specify Gift layout acceptance

Dami committed 40959f5
commit
40959f5f1070b2d96ff5aa6a37a83df09f02d73e
parent
fb6b325f117a66a690fcee5509e7ca5da6cf3d3a
author
Dami <dami.etoile@gmail.com>
5 files changed, +153 -0
Aopenspec/changes/fix-gift-card-layout/.openspec.yaml2+
Aopenspec/changes/fix-gift-card-layout/design.md54+++++++++++++++++++++++++++++
Aopenspec/changes/fix-gift-card-layout/proposal.md26++++++++++++++
Aopenspec/changes/fix-gift-card-layout/specs/game-stage/spec.md56++++++++++++++++++++++++++++++
Aopenspec/changes/fix-gift-card-layout/tasks.md15++++++++
A openspec/changes/fix-gift-card-layout/.openspec.yaml +2 -0
A openspec/changes/fix-gift-card-layout/design.md +54 -0
@@ -0,0 +1,54 @@
1+## Context2+3+Gift is rendered on a canvas from `src/scenes/gift.js`. The current card derives preview and action positions from fixed offsets inside a centered card, so a desktop shared-pack preview can consume the same vertical region as the action buttons. Mobile cards also need independent vertical placement because the available width and height are smaller.4+5+## Goals / Non-Goals6+7+**Goals:**8+9+- Define separate content, preview, metadata, actions, and hint regions within the card.10+- Keep every action visible and inside the card at desktop and mobile sizes.11+- Keep button hit targets at least 44 CSS pixels high and preserve keyboard selection order.12+- Make collision mode use the same layout contract for Replace, Keep Both as a Copy, and Cancel.13+- Verify the shared URL Gift path and reduced-motion rendering.14+15+**Non-Goals:**16+17+- Changing pack payloads, preview data, installation confirmation, or duplicate policy.18+- Reworking the designer's visual language, typography, or board art beyond placement needed to prevent overlap.19+- Adding a DOM layout fallback or a new UI dependency.20+21+## Decisions22+23+### Reserve the action region before sizing the preview24+25+Compute card geometry from viewport size, reserve the action stack and footer hint first, then fit title, metadata, and board preview into the remaining content rectangle. This keeps actions stable as level titles and preview boards vary. A purely fixed preview height was rejected because it can still collide on shorter desktop windows.26+27+### Use one responsive layout contract with stacked mobile actions28+29+Desktop may place the preview beside the action column when space allows; narrow cards SHALL stack preview above actions. Both modes use the same hit rectangles and minimum button height. Separate desktop and mobile implementations were rejected because they drift in keyboard and pointer behavior.30+31+### Keep preview clipping local to its content region32+33+Clip or scale only the board preview to its assigned rectangle. Text metadata and action labels remain independently measurable and are never allowed to draw into the action region. Allowing the whole card to overflow was rejected because it hides controls and creates ambiguous pointer targets.34+35+### Test geometry as observable layout data36+37+Expose or inspect the scene's rendered button rectangles and assert containment, non-overlap, and viewport margins in unit tests. Browser checks then verify the visible shared URL Gift card and actual pointer/keyboard activation. Screenshot-only coverage was rejected because it does not prove hit target geometry.38+39+## Risks / Trade-offs40+41+- [Risk] Long pack names or level titles reduce preview space. → Fit text to its content region and preserve the action region as the highest priority.42+- [Risk] Very short viewports may not fit all content simultaneously. → Keep the card within safe margins, allow the content preview to scale or clip, and keep actions reachable in the scroll-free canvas scene.43+- [Risk] Desktop and mobile hit rectangles diverge. → Share action construction and assert keyboard/pointer parity in both layouts.44+45+## Migration Plan46+47+1. Update Gift geometry and drawing/hit testing together.48+2. Add unit regressions for desktop, mobile, collision, and reduced-motion layout.49+3. Run browser shared URL Gift checks at desktop and mobile widths.50+4. Roll back by reverting the scene geometry and tests; no persisted data migration is required.51+52+## Open Questions53+54+None for this focused fix. Final visual spacing remains subject to the existing designer reference review.
A openspec/changes/fix-gift-card-layout/proposal.md +26 -0
A openspec/changes/fix-gift-card-layout/specs/game-stage/spec.md +56 -0
@@ -0,0 +1,56 @@
1+## MODIFIED Requirements2+3+### Requirement: Workshop and Gift SHALL connect to the pack service4+The stage SHALL connect Workshop actions to the presentation-independent pack service hooks, support drag-and-drop `.cjs` preview/import, keep URL intake pending until Gift confirmation, and expose in-canvas feedback for success, validation errors, collisions, copy, export, and removal. Workshop SHALL have a prominent player-facing entry from Title and INDEX in addition to any Pause route, and entering it SHALL record the originating scene so Back returns there. Keyboard and pointer activation SHALL expose the same Workshop actions. Workshop and Gift layout SHALL follow the designer reference and remain separate from pack validation logic. Gift SHALL reserve a distinct action region after fitting its preview content, and every action SHALL remain visible, inside the card, and separated from the preview at desktop and mobile widths.5+6+#### Scenario: Workshop imports a trusted module7+- **WHEN** the player chooses Import or drops a `.cjs` file and confirms the trusted path8+- **THEN** the stage previews and installs it through pack-service hooks, then offers the new pack on INDEX9+10+#### Scenario: Duplicate pack uses explicit choice11+- **WHEN** a pack id already exists during Workshop or Gift installation12+- **THEN** the stage offers Replace, Keep both as a copy, or Cancel and does not silently mutate the registry13+14+#### Scenario: Pack errors are readable15+- **WHEN** validation fails with more than five details16+- **THEN** the stage shows the first five plain-language errors, an `and N more` summary, and a Copy details action17+18+#### Scenario: Gift shows a normalized preview and collision19+- **WHEN** a valid share or local module preview returns a pack that already exists20+- **THEN** Gift shows the pack name, author, level count, first-level preview, and `ALREADY HERE` with Replace, Keep both as a copy, or Not now choices before installation21+22+#### Scenario: Gift actions do not overlap the desktop preview23+- **WHEN** a shared pack Gift card is drawn at a desktop viewport24+- **THEN** the preview board and metadata stay within the content region, every action rectangle stays within the card's reserved action region, and no preview pixels or labels overlap an action hit target25+26+#### Scenario: Gift actions remain reachable on mobile27+- **WHEN** a shared pack Gift card is drawn at a narrow mobile viewport28+- **THEN** preview content scales or clips within its region, actions stack in order with at least 44 CSS pixels of height, and each action remains inside the safe card margins and viewport29+30+#### Scenario: Collision actions use the same safe layout31+- **WHEN** Gift enters `ALREADY HERE` collision mode at desktop or mobile width32+- **THEN** Replace, Keep Both as a Copy, and Cancel use distinct visible hit rectangles that do not overlap the preview or one another33+34+#### Scenario: Keyboard and pointer Gift actions agree after responsive layout35+- **WHEN** the player selects an action with keyboard input or activates its pointer rectangle36+- **THEN** both paths produce the same keep, later, replace, copy, or cancel result and preserve the existing confirmation behavior37+38+#### Scenario: Workshop is reachable from Title and INDEX39+- **WHEN** the player is on Title or INDEX and chooses the visible Workshop entry40+- **THEN** the stage opens Workshop directly without requiring a detour through Pause41+42+#### Scenario: Workshop keyboard and pointer actions agree43+- **WHEN** the player activates Workshop, Import, Play, Share, Export, Remove, or Back with either keyboard or pointer input44+- **THEN** both input paths produce the same action and feedback result45+46+#### Scenario: Back returns to the originating scene47+- **WHEN** the player enters Workshop from Title or INDEX and chooses Back48+- **THEN** the stage returns to that originating scene with its current selection and progress intact49+50+#### Scenario: Local Import Gift can return to Workshop51+- **WHEN** the player chooses Import in Workshop, previews a local `.cjs` pack, and chooses Not now or presses Escape in Gift52+- **THEN** the stage returns to Workshop with the existing pack selection and registry unchanged53+54+#### Scenario: Shared URL Gift can return to Title55+- **WHEN** the app opens with a valid shared `#pack=` URL and the player chooses Not now or presses Escape in Gift56+- **THEN** the stage returns to Title without installing the pack or changing the registry
A openspec/changes/fix-gift-card-layout/tasks.md +15 -0