diff --git a/.plans/mockups/project-history-archive-first-2026-07-03.svg b/.plans/mockups/project-history-archive-first-2026-07-03.svg deleted file mode 100644 index 9f85d92..0000000 --- a/.plans/mockups/project-history-archive-first-2026-07-03.svg +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - History cleanup mockup: same pane, but bulk archive is first-class - Proposal keeps the current revision-card pattern, then adds a same-pane archive mode for selecting multiple rows at once. - - - - 1. Main History pane enters archive mode without leaving the current UX - - < Back - PROJECT REVISIONS - - - Show - - - - - Past 7 Days - Past 14 - Past 30 - Archived - - Archive… - - - - Pattern Demo - Renamed to Pattern Demo - Jun 27, 10:12 AM - - Restore... - - Copy... - - - - Pattern Demo - 3 entities added - Jun 27, 10:01 AM - - +3 more changes - - Restore... - - Copy... - - - Archive mode stays inside the current pane and current cards. - The only archive entrypoint is the pane-level control, so cleanup stays bulk-first instead of duplicating row actions. - - Cancel - - Archive Selected - - - 2. Archive dialog uses the current sidebar/dialog language - - - Archive 2 revisions? - Selected rows - - - • Pattern Demo · Renamed to Pattern Demo - • Pattern Demo · 3 entities added - Archived rows remain available in Archived History for restore or copy. - - - Cancel - - Archive - - - 3. Why this fits better - - - 1 - The current History pane already teaches users - “row card + action buttons + dialog.” - Bulk archive matters, so the right compromise is a same-pane mode, not one-by-one cleanup. - - - Style contract kept - • same pane shell - • same filter tabs - • same revision card structure - • same action-button rhythm, with one added archive footer - - - Deliberate omission - This proposal still avoids turning the pane into a generic management table. - Bulk archive is supported, but only through a lightweight mode layered onto the existing history cards. - - - diff --git a/.plans/mockups/project-history-archived-view-2026-07-03.svg b/.plans/mockups/project-history-archived-view-2026-07-03.svg deleted file mode 100644 index f5f9e9a..0000000 --- a/.plans/mockups/project-history-archived-view-2026-07-03.svg +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - Archived History mockup: same pane, same cards, delete only here - Archived is a sibling state of the existing History pane. It can reuse the same lightweight selection mode for bulk maintenance. - - - - 1. Archived is a pane state, and can support bulk cleanup too - - < Back - PROJECT REVISIONS - - - Show - - - - - Past 7 Days - Past 14 - Past 30 - Archived - - - - Pattern Demo - Renamed to Pattern Demo - Archived Jun 29 - - Restore... - - Copy... - - Delete... - - - - Pattern Demo - 3 entities added - Archived Jun 28 - - +3 more changes - - Restore... - - Copy... - - Delete... - - - Archived rows still use the same preview, teaser, and action rhythm. - If the user wants to prune several archived items, the same lightweight selection mode can drive `Delete Selected`. - - Cancel - - Delete Selected - - - 2. Delete dialog exists only on archived rows - - - Delete 2 archived revisions? - Selected rows - - - • Pattern Demo · Renamed to Pattern Demo - • Pattern Demo · 3 entities added - These will no longer be available for restore or copy. - Use Restore or Copy instead if you are unsure. - - - Cancel - - Delete Permanently - - - 3. Why this matches the existing UX better - - - 1 - Archived is just another filter-like pane state, - not a brand new subsystem or admin page. - Bulk deletion can reuse the same mode pattern established by bulk archive. - - - Key consistency points - • same `behavior-block` card feeling - • same teaser/details pattern - • same Restore/Copy buttons - • bulk delete only where the user has already narrowed intent - - - Important non-goal - This proposal does not try to make history cleanup powerful first. - It tries to make it feel like a natural extension of the current pane first. - - - diff --git a/.plans/project-history-archive-workflow-proposal-2026-07-03.md b/.plans/project-history-archive-workflow-proposal-2026-07-03.md deleted file mode 100644 index c6ca04f..0000000 --- a/.plans/project-history-archive-workflow-proposal-2026-07-03.md +++ /dev/null @@ -1,271 +0,0 @@ -# Project History Archive Workflow Proposal - -Date: 2026-07-03 - -Related mockups: -- `.plans/mockups/project-history-archive-first-2026-07-03.svg` -- `.plans/mockups/project-history-archived-view-2026-07-03.svg` - -## Goal - -Reduce clutter in the visible Project History list while staying close to the current History revisions UX. - -This proposal intentionally avoids introducing a new admin-style surface or a new visual language for history rows. - -It does introduce a bulk-archive path, because archiving one row at a time is not sufficient for the actual cleanup use case. - -## UX constraint - -The proposal should feel like an extension of the current `Project Revisions` pane: - -- same `Project Tree -> Manage -> History` entry -- same `PROJECT REVISIONS` pane framing -- same `Past 7 / 14 / 30` compact filter controls -- same revision card pattern - - row button previews the revision - - teaser/details expansion remains the same - - action buttons stay on the card -- same dialog style already used for restore/copy/retention prompts - -## Recommendation - -Use a two-state model inside the existing History pane: - -1. Main History - - shows the current visible revision narrative - - keeps existing `Restore...` and `Copy...` - - uses a pane-level `Archive...` action as the cleanup entrypoint - - does not expose permanent delete - -2. Archived History - - is a sibling state of the same pane, not a separate product area - - renders archived rows using the same revision card pattern - - keeps `Restore...` and `Copy...` - - adds `Delete...` only here - -## Why this is the better fit - -The previous draft drifted too far from the current UX because it introduced: - -- selection mode -- bulk-first cleanup controls -- a more “management console” feeling - -That is not how the current history pane behaves today. - -The tighter fit is: - -- same card layout -- one additional pane state -- one explicit archive-selection mode inside the same pane -- dialogs that look like the ones already in the sidebar/history flows - -## Proposed workflows - -### Workflow A: Archive from the main History list - -Primary path: - -1. Open `Project Tree -> Manage -> History` -2. Click `Archive…` -3. Select one or more visible revision rows -4. Click `Archive Selected` -5. Confirm in an archive dialog - -Result: - -- the selected revisions disappear from the default visible History list -- they become available in Archived History -- the main list gets less noisy without destroying recoverability - -### Workflow B: Switch to Archived History - -Primary path: - -1. Open `Project Tree -> Manage -> History` -2. Click `Archived` - -Result: - -- the same pane switches from active-history rows to archived-history rows -- the same card design remains in place -- the user stays inside the same mental model and layout - -### Workflow C: Delete from Archived History - -Primary path: - -1. Open `Archived` inside the History pane -2. Use the same archive-selection pattern if deleting several rows, or `Delete...` on a single row -3. Confirm in a permanent delete dialog - -Result: - -- destructive cleanup remains possible -- but only after the user intentionally entered the archived state - -## Proposed UI changes - -### Main History pane - -Keep: - -- back button -- `PROJECT REVISIONS` title -- `Past 7 / 14 / 30` filters -- revision card layout -- row click to preview -- teaser/details expansion -- `Restore...` -- `Copy...` - -Add: - -- compact `Archived` switch near the existing date filters -- compact `Archive…` entry action that switches the pane into archive-selection mode -- archive-selection affordance on each visible revision card -- sticky footer actions while archive-selection mode is active: - - `Cancel` - - `Archive Selected` - -Do not add: - -- per-row archive buttons on the main list -- inline delete on the main list -- a separate archive-management toolbar - -### Archived History pane state - -Keep: - -- same pane shell -- same revision card design -- same row preview affordance -- same detail teaser/expansion pattern - -Change: - -- title or sublabel clarifies the archived state -- card actions become `Restore...`, `Copy...`, `Delete...` -- archived bulk maintenance may reuse the same selection-mode pattern when needed - -## Proposed labels - -Main History: - -- `Archived` -- `Archive…` -- `Archive Selected` -- `Keep in History` -- `Cancel` - -Archived History: - -- `Back to History` -- `Restore...` -- `Copy...` -- `Delete...` -- `Delete Permanently` - -Avoid in the main list: - -- `Delete` -- `Remove` -- `Clear` - -## Dialog behavior - -### Archive dialog - -Tone: - -- thoughtful but not severe - -Suggested message shape: - -- “Archive this revision from the main History list?” -- “The selected revisions will still be available in Archived History for restore or copy.” - -Actions: - -- `Cancel` -- `Archive` - -### Delete dialog - -Tone: - -- explicit and irreversible - -Suggested message shape: - -- “Delete this archived revision permanently?” -- “This cannot be undone.” -- “Restore or Copy are safer if you are unsure.” - -Actions: - -- `Cancel` -- `Restore Instead` optional if desired -- `Delete Permanently` - -## Relationship to current retention - -This proposal complements the existing retention dialog rather than replacing it. - -Current retention behavior already handles: - -- stale revisions by age -- archive/delete decisions at History entry time - -This proposal adds: - -- user-driven archive for clutter reduction on still-visible rows -- a concrete archived-state UI for rows that were archived intentionally or by retention flows - -## Data/behavior expectations - -Archive should: - -- remove the selected rows from default visible History -- preserve restore/copy behavior -- preserve summary/detail semantics -- preserve grouping semantics for grouped revisions - -Delete should: - -- only be reachable from Archived History -- remove the archived row from storage and recovery paths -- avoid dangling revision/event references - -## Tests to prefer - -Unit/integration: - -- entering archive-selection mode does not change the normal row-preview behavior until a row is explicitly toggled for selection -- archiving visible rows removes them from main History visibility -- archived rows appear in the archived History view model -- archived rows still support restore/copy -- delete is not exposed in main History view model -- delete removes archived rows only after confirmation -- grouped rows can be archived in one action without breaking event/revision linkage - -E2E: - -- main History shows archive-selection mode and not delete -- multiple visible rows can be archived in one pass -- switching to `Archived` keeps the same pane feel and shows archived rows -- archived rows can be restored/copied -- delete is available only in Archived History - -## Bottom line - -The best fit for the current UX is not a new cleanup system. - -It is a minimal extension of the existing revision-card workflow: - -- `Archive…` enters a same-pane selection mode for bulk cleanup -- `Archived` as a sibling pane state -- `Delete...` only on archived cards - -That accommodates the real bulk-archive use case without turning the history pane into a one-off GUI. diff --git a/.plans/ux-checklist-workflow-simplification.md b/.plans/ux-checklist-workflow-simplification.md deleted file mode 100644 index f4e097c..0000000 --- a/.plans/ux-checklist-workflow-simplification.md +++ /dev/null @@ -1,90 +0,0 @@ -# UX Checklist — Workflow Simplification (Intuitive → Fewer Steps → Shorter Pointer Travel) - -Goal: reduce “many ways to do the same thing” so there is one obvious, simplest path for each common task, and keep related controls co-located to minimize *shorter pointer travel distance*. - -This checklist is intentionally concrete: for each major task it defines a **recommended single obvious path**, plus what to **delete / merge / rename** so the editor stops offering multiple competing ways to do the same thing. - -Source of truth for naming: `.plans/editor-workflows-inventory.md`. - -## 0) Single Obvious Path (by major task) - -- Selection (single): **A1** (canvas click; Entity List click stays as parity). -- Selection (multi): **A2** (marquee + Shift-add; Entity List Shift/Ctrl-add stays as parity). -- Rename item: **A4** (inline rename in Entity List); context “Rename…” should route into A4. -- Group: **A5 → Group…** (Selection Actions menu; one consistent “Group…” that always prompts for name) + shortcut routes into same prompt. -- Ungroup sprites: **A5 → Remove from formation** (not “Ungroup”, avoid multiple verbs). -- Dissolve formation: **A5 → Dissolve formation**. -- Import any asset: **A20** (Assets Dock only). -- Place new sprite from asset: **A21** (drag asset to canvas). -- Replace sprite’s asset: **A21** (drag asset onto sprite) + visible affordance so it’s discoverable. -- Background image assignment: **A21** (drag to Background Layers) or **A29** (Inspector picker as secondary). -- Music assignment: **A21** (drag to Scene Music) or **A30** (Inspector picker as secondary). -- Local YAML round-trip: **A23/A24/A25** (Viewbar YAML controls; cloud stays cloud-only). -- Cloud YAML round-trip: **A52/A53** (Cloud panel; local file controls stay in Viewbar). -- Toggle Edit/Play: **A7** (Tab as primary; button as parity). -- View navigation: **A8/A9** (Space+drag / MMB drag; wheel zoom; Viewbar buttons as parity). -- Grid snap: **A10** (Ctrl/Cmd+G as primary; button as parity). -- Formation authoring: **W2/W3** (create/tune in Inspector + direct manipulation). -- Actions/Events authoring: **W14** (**Actions/Events** panel is the only “discover → create handler → edit steps” surface; no separate Attached Actions UI). -- History cleanup: **A31b → A31c → A31d/A31e** (browse current revisions, enter archive mode for bulk clutter cleanup, use Archived for destructive pruning only). - -## 1) Selection + Grouping / Ungrouping - -- [x] **Keep (primary):** Selection bar `…` menu (**A5**) for all selection actions (Group / Remove from formation / Dissolve / Delete / Duplicate / Create formation from…). -- [x] **Keep (parity):** keyboard shortcuts (e.g. Ctrl/Cmd+Shift+G) route into the same UI + naming semantics as A5 (opens Group… prompt). -- [x] **Delete / merge:** - - [x] Remove “Create Group” button variants that aren’t in A5 (top-right “Create Group”, inline buttons, etc.). - - [x] Remove Inspector grouping entrypoints that duplicate A5 (Ungroup/Dissolve/Delete buttons removed from Group inspector). -- [x] **Rename (terminology standardization):** - - [x] Replace “Ungroup” labels (for sprites) with **Remove from formation**. - - [x] Replace “Dissolve group” labels with **Dissolve formation** (keep “formation” consistently across UI). -- [x] **Style contract check:** near-cursor actions stay near-cursor; grouping actions are not in Inspector. - -## 2) Asset Import + Assignment - -- [x] **Keep (primary):** Assets Dock import (**A20**) for images/spritesheets/audio/fonts. -- [x] **Keep (primary):** drag-drop assignment (**A21**) for: - - [x] Create new sprite (drop on canvas), - - [x] Replace sprite asset (drop on sprite), - - [x] Assign background image (drop on Background Layers), - - [x] Assign scene music (drop on Scene Music). -- [x] **Delete / merge:** - - [x] Remove direct “Import” entrypoints from `SpriteImportPanel` as a competing importer; keep only Assets Dock “Advanced…” using `SpriteImportPanelView`. - - [x] Fold/remove `AudioLibraryPanel` (removed; Assets Dock remains the audio import surface). -- [x] **Add affordance (discoverability):** - - [x] Dragging an image/spritesheet over a sprite shows a replace/create hint tooltip (canvas drag hint). - -## 3) YAML Round-trip (tight local loop) - -- [x] **Keep (primary, local files):** Viewbar YAML controls (**A23/A24/A25**). -- [x] **Keep (project-scope parity):** Project Tree `Manage` provides `Import YAML` / `Export as YAML` for project-level file operations. -- [x] **Keep (primary, cloud):** Cloud panel (**A52/A53**) for cloud load/save only. -- [x] **Delete / merge:** - - [x] Cloud panel must not add “Open local YAML” actions; cloud and local remain separated to avoid duplicate workflows. - -## 4) Viewport Navigation Consistency - -- [x] **Fix copy:** Viewbar instructions match implementation (A8): `Space + drag` or `middle mouse drag`. -- [x] **Optional discoverability:** on-canvas hint shows while Space is held (“Pan mode: drag to move view”). - -## 5) Missing / Under-supported Workflows - -- [x] **Add workflow:** Convert/relink asset Embedded ↔ Path after import (project-level). - - [x] Add `Relink…` action on asset row in Assets Dock. - - [x] Keeps the same assetId so existing references remain intact. - -## 6) Audit Pass (to confirm simplification worked) - -- [x] For each major task (group, remove from formation, dissolve formation, import asset, place asset, replace asset, YAML loop local, YAML loop cloud, audio, input maps, actions/events), confirm: - - [x] There is **one primary path** that is discoverable. - - [x] Secondary paths (shortcuts) are consistent with the primary path, not separate behaviors. - - [x] The path keeps UI interactions **co-located** (short pointer travel) where possible. - -## 7) History Cleanup - -- [x] **Keep (primary):** bulk archive from inside `Project Revisions`, not from a separate management surface. -- [x] **Keep (secondary):** `Archived` as a sibling history state in the same pane. -- [x] **Delete / merge:** - - [x] Keep permanent delete out of the main active-history view. - - [x] Reuse the revision-card pattern and existing dialog language instead of inventing a new history table/admin UI. -- [x] **Primary path rule:** clutter reduction uses archive first; destructive pruning happens only after switching to `Archived`. diff --git a/.repo-memory/product-memory.md b/.repo-memory/product-memory.md index 2154bd4..186762e 100644 --- a/.repo-memory/product-memory.md +++ b/.repo-memory/product-memory.md @@ -1,77 +1,46 @@ # PhaserForge Product Memory -This file is the compact source of truth for product-wide behavior that should survive across features, refactors, and bug fixes. +Compact durable rules that should survive refactors and feature work. -If a change conflicts with this file, update this file in the same turn or explain why the behavior is intentionally changing. - -## Read Order - -For feature work or bug fixes, read in this order: - -1. `AGENTS.md` -2. `.repo-memory/product-memory.md` -3. `.repo-memory/regression-playbook.md` -4. Relevant scoped `AGENTS.md` -5. Relevant tests and implementation -6. Relevant top-level `.plans/*` file only when the task needs current workflow context or an active proposal - -Use `.plans/archive/` only as historical context after checking current tests and implementation. - -## Durable Product Invariants +## Durable Invariants ### Editor interaction - The editor should have one obvious primary workflow for common tasks. -- Near-cursor actions should stay near-cursor unless there is an explicitly approved workflow reason to move them. +- Near-cursor actions should stay near-cursor unless there is an approved workflow reason to move them. - Editor copy, hints, shortcuts, and gestures must match actual behavior. - Pixel-authored geometry such as entity positions, trigger rects, and hitbox rectangles should round to integer pixels unless a field is intentionally continuous. -- Pixel-art sprite textures should load with nearest-neighbor filtering; global Phaser config is not sufficient if runtime texture loads can still default to linear filtering. +- Pixel-art textures should use nearest-neighbor filtering on runtime loads, not just global Phaser config. ### Persistence and history - User work should survive reloads, tab close/reopen, and normal app restarts. -- The latest valid IndexedDB-backed project head wins over stale cached snapshots or legacy localStorage project state. -- History and persistence changes should preserve both data and the user-visible ability to recover/restore recent work. -- Restore sequencing is a product contract: workspace selection, active-project selection, project dispatch, scene load, and visible stabilization must happen in a consistent order. +- The latest valid IndexedDB-backed project head wins over stale cached snapshots or legacy localStorage state. +- Restore sequencing is a product contract and must remain stable. - Project history should preserve user intent across reload/rebuild, not just restoreable state. ### Serialization and project data - Project serialization should round-trip without semantic drift. - Backward compatibility for persisted project data matters unless the task explicitly changes the contract. -- Canonicalization helpers and migration code are part of the product contract, not just implementation detail. -- Legacy project formats should be canonicalized into current structures instead of leaking old keys/meanings forward. +- Legacy project formats should canonicalize into current structures instead of leaking old meanings forward. ### Cross-surface consistency -- If the same concept appears in canvas, inspector, scene graph, docs, and tests, behavior and terminology should agree across all of them. -- A fix in one surface is not complete if another surface can silently reintroduce the same bug class. +- If the same concept appears in canvas, inspector, scene graph, docs, and tests, behavior and terminology should agree. +- A fix in one surface is incomplete if another surface can silently reintroduce the same bug class. -### Action-time intent over later inference +### Action-time intent -- When the editor knows the user’s intent at action time, prefer storing that semantic meaning directly instead of re-inferring it later from diffs or rebuilt state. -- New heuristics should usually be fallback-only; recurring user-visible narrative bugs are often a sign that semantic meaning should be captured earlier. +- When the editor knows user intent at action time, prefer storing that semantic meaning directly instead of re-inferring it later. -## Where Detailed Truth Lives +## Reference Surfaces - Workflow specifics: `.plans/editor-workflows-inventory.md` - Workflow simplification decisions: `.plans/ux-checklist-workflow-simplification.md` -- Exact regression coverage: tests +- Exact behavior guarantees: tests - Active workflow/proposal notes: top-level `.plans/` -- Historical proposals and mockups: `.plans/archive/` - -## Truth Precedence - -1. Tests and implementation -2. `AGENTS.md` -3. `.repo-memory/` -4. Top-level `.plans/` -5. `.plans/archive/` ## Update Rule -Update this file when a change does any of the following: - -- introduces a new durable product rule -- changes a previously stable user-facing behavior -- resolves a recurring regression class by clarifying what must stay true +Update this file only when a change introduces or clarifies a durable product rule. diff --git a/.repo-memory/regression-playbook.md b/.repo-memory/regression-playbook.md index 8c4dfdf..22dd714 100644 --- a/.repo-memory/regression-playbook.md +++ b/.repo-memory/regression-playbook.md @@ -6,78 +6,44 @@ Use this file to keep previously solved bug classes from drifting back in. 1. Identify the bug class, not just the symptom. 2. Find the narrowest existing invariant in tests, product memory, or workflow docs. -3. Add or tighten tests before implementation when practical. -4. Fix the product if the behavior is wrong. -5. Redesign the test if the bug is really flaky coverage rather than broken behavior. -6. Record any new durable rule in `.repo-memory/product-memory.md`. +3. Add or tighten tests first when practical. +4. Fix the product if behavior is wrong. +5. Redesign the test when the failure is flake rather than product behavior. +6. Record a new durable rule in `.repo-memory/product-memory.md` only if it will matter again. ## Common Regression Classes -### Persistence / reload regressions +### Persistence / reload -- Risks: reload, reopen, snapshot selection, stale cache precedence, local/cloud divergence. -- Preferred coverage: - - unit tests for reducers/helpers/history logic - - targeted Playwright reload/reopen coverage for user-visible recovery flows -- Strong invariants to prefer: - - latest active head restores after reload/reopen - - legacy localStorage project YAML does not silently win over the durable store - - restore sequencing does not transiently materialize the wrong project and make it durable +- Risks: stale cache precedence, reload/reopen recovery, local/cloud divergence. +- Preferred coverage: reducer/helper tests plus targeted Playwright reload/reopen checks. -### Workflow regressions +### Workflow -- Risks: a previously simplified path gains duplicate entrypoints, extra steps, or mismatched labels. -- Preferred coverage: - - store/helper tests where logic changed - - scene/e2e tests for the primary user path - - workflow doc updates when the flow materially changes +- Risks: duplicate entry points, extra steps, mismatched labels, inconsistent primary path. +- Preferred coverage: shared logic tests plus E2E on the primary user path. -### Geometry / rendering regressions +### Geometry / rendering -- Risks: fractional pixel geometry leaks back into authored state, or global render settings silently re-enable blur. -- Preferred coverage: - - reducer/unit tests for integer-authored geometry normalization - - bootstrap/runtime tests for crisp-render defaults +- Risks: fractional authored geometry, blurry sprite rendering, inconsistent pixel scaling. +- Preferred coverage: reducer/unit tests plus runtime/bootstrap tests. -### Serialization / migration regressions +### Serialization / migration -- Risks: semantic drift after save/load, legacy compatibility breaks, canonicalization mismatch. -- Preferred coverage: - - round-trip unit tests - - migration fixture tests -- Strong invariants to prefer: - - parse legacy shapes, serialize canonical shapes - - preserve optional metadata that users can see or rely on later +- Risks: save/load drift, canonicalization mismatch, legacy compatibility breaks. +- Preferred coverage: round-trip and migration fixture tests. -### History narrative regressions +### History narrative -- Risks: user-visible history summaries or grouping drift after reload, compaction, coalescing, or rebuild. -- Preferred coverage: - - unit tests for history-event/revision helpers - - targeted E2E for reload/reopen narrative preservation -- Strong invariants to prefer: - - preserve action-time summaries such as specific rename/resize intent - - do not let specific summaries degrade into generic “edited scene/project” text after rebuild +- Risks: summaries/grouping drift after reload, compaction, or rebuild. +- Preferred coverage: helper tests plus targeted E2E for reload/reopen preservation. -### Cross-surface regressions +### Cross-surface -- Risks: fix lands in one UI surface but not another, or one code path bypasses the fix. -- Preferred coverage: - - at least one test for the underlying shared logic - - one integration test on the user-facing path most likely to drift - -## Choosing Memory vs Plan vs Test - -- Put durable repo-wide rules in `.repo-memory/product-memory.md`. -- Put active feature proposals or current workflow notes in top-level `.plans/`. -- Put superseded, partial, or historical design notes in `.plans/archive/`. -- Put executable behavior guarantees in tests. -- If the lesson came from repeated fixes, confirm it against tests or recent top-level plans before promoting it into repo memory. -- Transcript archive evidence and archived plans can help identify repeated bug classes, but tests and current product docs remain the final source of truth. +- Risks: a fix lands in one surface but not another. +- Preferred coverage: one shared-logic test and one user-facing integration path. ## Keep It Small -- If a lesson will matter again, add one short rule. -- If it only mattered for one feature rollout, keep it in the relevant `.plans/` file. +- Add one short rule per bug class, not a list of historical symptoms. - Prefer updating an existing rule over adding a near-duplicate rule. -- Prefer naming one bug class with 2-3 strong invariants over listing every historical symptom. diff --git a/AGENTS.md b/AGENTS.md index e0264ad..0961bc9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,108 +1,57 @@ # AGENTS.md for phaserforge -## Project Guidelines +## Read Order -### Read Before You Act -For feature work or bug fixes, read the smallest useful set of files in this order: +For feature work or bug fixes, read the smallest useful set in this order: 1. `AGENTS.md` 2. `.repo-memory/product-memory.md` 3. `.repo-memory/regression-playbook.md` 4. Relevant scoped `AGENTS.md` 5. Relevant tests and implementation -6. Relevant top-level `.plans/*` file only when needed for current workflow context or an active proposal +6. Relevant top-level `.plans/*` only when current workflow context or an active proposal matters Use `.plans/archive/` only for historical context after checking current tests, implementation, and repo memory first. -The goal is to keep durable repo memory compact and reusable, while leaving detailed feature history in plans and executable guarantees in tests. +## Core Rules -### TDD Requirement -All phases and implementation changes should be TDD-driven. Each gesture or editing behavior starts with store/helper tests, then scene-level interaction tests where practical, then implementation. Maintain comprehensive test coverage for reducers, helpers, and integrations. +- TDD first: store/helper tests, then scene/integration tests where practical, then implementation. +- Before reporting any code change complete, run the required verification for that change type. +- `arcadeactions/` is reference-only. Do not modify it. +- Do not change the default Playwright worker count from `3` in `playwright.config.ts`. +- Tests and implementation are the latest ground truth. `.repo-memory/` holds compact durable rules. Top-level `.plans/` holds the small active workflow/proposal surface. -### Completion Verification (E2E Required; Must Be Non-Flaky) -Before reporting any **code** changes (including new code) as completed, run the required E2E checks for the type of change and ensure they pass with **zero flakes**. +## Verification -#### Local E2E policy (what `npm dev test:e2e` means) -Locally, **only after making GUI changes**, run **Chromium smoke** E2E tests: -- GUI changes include anything under `src/editor/**`, `src/App.tsx`, or `src/phaser/EditorScene.ts` (and any other user-visible UI/editor workflow changes). -- Treat running `npm dev test:e2e` locally as: “run Playwright E2E smoke on Chromium only”. - - Implementation detail: run `npm run test:e2e -- --project=chromium --grep @smoke` (equivalently `PW_PROJECTS=chromium npm run test:e2e -- --grep @smoke`). +- GUI/editor changes under `src/editor/**`, `src/App.tsx`, or `src/phaser/EditorScene.ts` require local Chromium smoke: + - `npm run test:e2e -- --project=chromium --grep @smoke` +- Non-GUI changes should prefer unit/integration coverage and run E2E when user-visible behavior is affected. +- If fixing a browser-specific Playwright failure, also run that same local Playwright project or spec before declaring the fix complete. +- If a direct product fix fails to remove an E2E flake more than twice, redesign the test to use a less brittle invariant. -For non-GUI-only changes (server, data, helpers, etc.), prefer unit/integration tests and run E2E only when the change reasonably impacts editor behavior, app boot, or user-visible flows. +## Editor Workflow Policy -Important: GitHub Actions CI is configured to fail on flaky E2E tests. The bar for completion is: -- All E2E tests pass, and -- No E2E test is marked flaky (in any shard / browser / retry path). +These rules apply to `src/editor/**`, `src/App.tsx`, and `src/phaser/EditorScene.ts`. -#### Local Repro Requirement (When Fixing a Specific Browser Failure) -When addressing a reported E2E failure that is tied to a specific browser/project (e.g. `[edge]`, `[webkit]`, etc.), the agent MUST run that same Playwright project locally (at least the failing spec) as part of verification before declaring the fix complete, in addition to the baseline local E2E policy for the change (e.g. Chromium smoke for GUI changes). - -WebKit local note for this Ubuntu 26.04 setup only: -- This is a machine-specific workaround for an Ubuntu 26.04 environment. Do **not** assume other developers or CI need it. -- Prefer the normal Playwright project invocation first on other machines. Only use the fallback below if native local WebKit repro is blocked by Ubuntu 26 host/runtime mismatches. -- `npm run test:e2e:webkit -- ` uses the current repo's Ubuntu 26 native-workaround path. -- `npm run test:e2e:webkit:docker -- ` is the preferred fallback on this machine when Docker is available, because it avoids most of the Ubuntu 26 native WebKit dependency churn. -- The repo-local `.playwright-lib-compat/` shim directory exists only to bridge Ubuntu 26 SONAME mismatches (`icu`, `xml2`, `jxl`) for this setup. Treat it as an environment workaround, not a cross-machine standard. - -Non-code-only changes (docs, plans, mockups, etc.) do not require an E2E run. If E2E cannot be run (environment/tooling constraints), explicitly say so and report results of the closest equivalent verification performed. - -#### Flake Policy (Fix vs Test Redesign) -When addressing an E2E failure: -- First, weigh whether a **direct product fix** is appropriate, or whether the test should be **redesigned to be less brittle** (prefer stable user-visible invariants over timing/cursor/style assumptions). -- If a direct product fix has been attempted and has failed to eliminate the flake **more than twice**, the agent **MUST redesign the test** to be less brittle (and keep coverage meaningful). - -### ArcadeActions Reference Only -The `arcadeactions` directory is for reference only. Do not modify or add files to it. Use it to understand formations, actions, and arrange functions, but all changes must stay within `phaserforge`. For expandability, rely on external config files and editor-side logic. - -### Playwright Workers Default (Do Not Change) -Do not change the default Playwright worker count in `playwright.config.ts`. The default must remain `3` (overridable only via `PW_WORKERS`). - -## Editor UX / Workflow Policy - -These rules apply to any changes under `src/editor/**`, `src/App.tsx`, or `src/phaser/EditorScene.ts`. - -### Priorities (in order) +Priorities: 1. Intuitive primary workflow 2. Fewer total steps 3. Shorter mouse pointer travel distance -4. Style consistency (match established editor patterns) - -### Significant Change Confirmation (ask before implementing) -Ask the user to confirm before implementing any change that is likely to: -- Significantly change a workflow (primary entrypoint, gesture/shortcut, selection semantics, moving controls across panes, or adding a second way to do the same task). -- Introduce, remove, or materially alter a style contract (examples: paired inputs become stacked; context menus added/removed/moved; actions moved from near-cursor surfaces to inspector/toolbar). - -When asking for confirmation, include: -- Workflow(s) impacted (use `.plans/editor-workflows-inventory.md` names when available). -- Current vs proposed primary path (brief steps). -- Entry points added/removed/merged (buttons/menus/shortcuts/gestures). -- Expected change in steps and pointer travel. -- Style contract impacted (what rule changes and why). - -### Style vs Workflow Tie-break -If an established style would be violated but the user may benefit from a simpler/shorter workflow, pause and ask which to prioritize before implementing. Provide 1–2 alternatives that preserve style. - -### Documentation Update (only when workflows materially change) -If a workflow is added/removed/meaningfully altered, update: -- `.plans/editor-workflows-inventory.md` -- `.plans/ux-checklist-workflow-simplification.md` (only if decisions/checklist need updating) - -## PhaserForge code navigation rule -For PhaserForge architecture work, use Serena first to locate and inspect relevant symbols before reading whole files. - -Common targets: -- Phaser scene/editor classes -- action graph / behavior graph code -- serialization/deserialization logic -- command, selection, drag/drop, and undo/redo systems -- integration points between the visual editor and runtime actions +4. Style consistency -Do not scan the repo broadly first. Use Serena to identify the smallest relevant set of files and symbols, then read those files as needed. +Ask the user to confirm before implementing a change that materially changes: +- a primary workflow, entry point, gesture, shortcut, or selection model +- an established style contract such as where actions live or how paired controls are laid out -## Repo Memory Rule +When confirming, include: +- impacted workflow names from `.plans/editor-workflows-inventory.md` when available +- current vs proposed primary path +- entry points added/removed/merged +- expected impact on steps and pointer travel +- style contract affected -Use `.repo-memory/product-memory.md` for durable product invariants that should survive future refactors and feature work. +If a workflow materially changes, update `.plans/editor-workflows-inventory.md` and update `.plans/ux-checklist-workflow-simplification.md` only when the checklist/decision record itself changed. -Use `.repo-memory/regression-playbook.md` for recurring bug classes and where their guardrails belong. +## Code Navigation -Do not turn `.plans/` into the canonical source of product truth. Tests and implementation are the latest behavior truth, `.repo-memory/` holds compact durable rules, top-level `.plans/` holds the small active workflow/proposal surface, and `.plans/archive/` is historical context only. +For architecture work, use Serena first to locate the smallest relevant symbol set before reading files broadly. diff --git a/guardrails/gui-workflow-guardrails/AGENTS.md b/guardrails/gui-workflow-guardrails/AGENTS.md index 5aba6a1..80ca83b 100644 --- a/guardrails/gui-workflow-guardrails/AGENTS.md +++ b/guardrails/gui-workflow-guardrails/AGENTS.md @@ -1,26 +1,10 @@ -# AGENTS.md — GUI Workflow Guardrails (Root) +# GUI Workflow Guardrails -This repo is a *template kit* for enforcing workflow quality in GUI projects. +Template reminder only: -## Priorities (in order) 1. Intuitive primary workflow 2. Fewer total steps -3. Shorter mouse pointer travel distance -4. Style consistency (match established UI patterns) - -## Significant Change Confirmation (template rule) - -Before implementing a change that *significantly changes* an existing workflow or would violate an established style pattern: - -- Ask the user to confirm: - - workflows impacted (atomic/composite names if present) - - current vs proposed primary path (brief steps) - - entrypoints added/removed/merged (buttons/menus/shortcuts/gestures) - - expected impact on steps + pointer travel - - the style rule being broken (and why) -- Offer 1–2 alternatives that preserve style if there’s a tradeoff. - -## Progressive disclosure - -Keep root rules short. Put detailed style and interaction contracts in scoped `AGENTS.md` files near the code they govern. +3. Shorter pointer travel +4. Style consistency +Keep root rules short. Put detailed behavior contracts in scoped `AGENTS.md` files near the code they govern. diff --git a/src/editor/AGENTS.md b/src/editor/AGENTS.md index 9f0e171..9a3c346 100644 --- a/src/editor/AGENTS.md +++ b/src/editor/AGENTS.md @@ -1,35 +1,28 @@ -# Editor Rules (Workflows + Style Contract) +# Editor Rules Scope: `src/editor/**` -These rules enforce editor UX priorities while designing mockups and implementing UI changes. +## Priorities -## UX Priorities (in order) 1. Intuitive primary workflow 2. Fewer total steps 3. Shorter mouse pointer travel distance -4. Style consistency (match established editor patterns) +4. Style consistency with the existing editor -## Workflow Discipline +## Workflow Rules -- Prefer **one obvious primary path** per task. Avoid adding new entrypoints for an existing task unless it replaces another or has a clear reason (accessibility/discoverability/keyboard parity). -- When introducing new interactions, define/update the **atomic workflow** first (A##), then reference it in any composite workflows (W##) in `.plans/editor-workflows-inventory.md` when applicable. -- If a change materially affects user workflows, ensure documentation updates per root `AGENTS.md`. +- Prefer one obvious primary path per task. +- Avoid adding a second entry point for an existing task unless it replaces another path or has a clear accessibility/discoverability reason. +- If a change materially affects a workflow, update `.plans/editor-workflows-inventory.md`. -## Style Contract (must follow unless explicitly approved) +## Style Contract -- **Paired inputs are side-by-side:** conceptual pairs (X/Y, W/H, rows/cols, startX/startY, spacingX/spacingY, etc.) should be rendered in a two-column row (existing grid-2 pattern) rather than stacked line-by-line. -- **Near-cursor actions stay near-cursor:** selection/object actions should live in near-cursor surfaces (selection bar/context menu) before adding inspector/toolbar buttons. -- **Context menu parity:** if comparable canvas/editor objects support right-click actions, new comparable objects should too (or the deviation must be confirmed). -- **Reuse established panel patterns:** prefer existing foldouts, compact button styles, selection pills, inline menus, and validated numeric inputs rather than introducing novel layout patterns without reason. +- Paired controls stay side-by-side using existing two-column patterns. +- Near-cursor actions stay near-cursor before adding inspector or toolbar actions. +- Comparable objects should keep context-menu parity unless the user approves a deviation. +- Reuse existing foldouts, compact buttons, inline menus, and validated numeric inputs before inventing a new pattern. -## Style vs Workflow Tie-break - -If following a simpler/shorter workflow would violate an established style contract, pause and ask the user which to prioritize. Provide 1–2 alternatives that preserve style. - -## Testing (when behavior changes) - -For workflow-affecting behavior changes, follow the project TDD requirement: -- Store/helper tests first -- Scene-level/e2e tests (Playwright) where practical for the primary path +## Tests +- Follow TDD. +- Add scene/e2e coverage for the primary user path when workflow behavior changes. diff --git a/src/editor/EditorStore.tsx b/src/editor/EditorStore.tsx index 032810c..ac422d3 100644 --- a/src/editor/EditorStore.tsx +++ b/src/editor/EditorStore.tsx @@ -19,7 +19,6 @@ import { } from '../model/types'; import { createEmptyProject, createEmptyGameScene } from '../model/emptyProject'; import { - deriveWorldSpriteSize, deriveWorldUnitsFromNaturalPixels, getProjectPixelsPerUnit, normalizeProjectPixelsPerUnit, @@ -2210,6 +2209,7 @@ function reapplyProjectPixelScaleToMatchingSprites( const previousPixelsPerUnit = getProjectPixelsPerUnit(previousProject); const nextPixelsPerUnit = getProjectPixelsPerUnit(nextProject); if (previousPixelsPerUnit === nextPixelsPerUnit) return nextProject; + const scaleRatio = previousPixelsPerUnit / nextPixelsPerUnit; let scenesChanged = false; const scenes = Object.fromEntries( @@ -2220,16 +2220,11 @@ function reapplyProjectPixelScaleToMatchingSprites( const resolved = resolveEntityDefaults(entity); if (!resolved.asset) return [entityId, entity]; - const previousWorldSize = deriveWorldSpriteSize(previousProject, resolved.asset); - const nextWorldSize = deriveWorldSpriteSize(nextProject, resolved.asset); - if (!previousWorldSize || !nextWorldSize) return [entityId, entity]; - if (resolved.width !== previousWorldSize.width || resolved.height !== previousWorldSize.height) return [entityId, entity]; - entitiesChanged = true; return [entityId, { ...entity, - width: nextWorldSize.width, - height: nextWorldSize.height, + width: Math.max(1, Math.round(resolved.width * scaleRatio)), + height: Math.max(1, Math.round(resolved.height * scaleRatio)), }]; }), ); diff --git a/src/editor/Inspector.tsx b/src/editor/Inspector.tsx index 3992ed4..f3917ce 100644 --- a/src/editor/Inspector.tsx +++ b/src/editor/Inspector.tsx @@ -582,36 +582,11 @@ function EntityInspector({ /> -
- - -
{naturalSpriteSize && projectScaledSpriteSize ? ( <>
Natural Size: {naturalSpriteSize.width}×{naturalSpriteSize.height} px
Project Scale: {projectPixelsPerUnit} px/unit
World Size: {projectScaledSpriteSize.width}×{projectScaledSpriteSize.height} units
-
- -
) : (
Original (natural): {baseWidth}×{baseHeight} px
@@ -681,21 +656,6 @@ function EntityInspector({
Natural Size: {naturalSpriteSize.width}×{naturalSpriteSize.height} px
Project Scale: {projectPixelsPerUnit} px/unit
World Size: {projectScaledSpriteSize.width}×{projectScaledSpriteSize.height} units
-
- -
) : (
Original (natural): {baseWidth}×{baseHeight} px
diff --git a/src/phaser/AGENTS.md b/src/phaser/AGENTS.md index 5f7150b..f9d2897 100644 --- a/src/phaser/AGENTS.md +++ b/src/phaser/AGENTS.md @@ -1,32 +1,30 @@ -# Canvas / Gesture Rules (Workflow + Style) +# Canvas / Gesture Rules -Scope: `src/phaser/**` (especially `EditorScene.ts`) +Scope: `src/phaser/**`, especially `EditorScene.ts` + +## Priorities -## UX Priorities (in order) 1. Intuitive primary workflow 2. Fewer total steps 3. Shorter mouse pointer travel distance -4. Style consistency (match established editor patterns) - -## Significant-by-default changes (confirm before implementing) - -Treat changes as significant and ask the user to confirm before implementing if they touch: -- Selection behavior (single/multi/marquee), clearing selection, delete semantics -- Drag/move/duplicate gestures (Alt-duplicate), snapping behavior, bounds handle behavior -- Pan/zoom/fit/reset controls or shortcuts -- Mode toggling (Edit/Play) shortcuts or surfaces -- Right-click context menu behavior on canvas objects - -## Canvas Style Contract +4. Style consistency -- **Context menu parity:** if most interactive canvas objects expose right-click actions, new comparable objects should participate in the same context menu system rather than relocating actions to inspector/toolbar by default. -- **Affordances stay consistent:** maintain hover/cursor feedback patterns for new interactive objects to match existing canvas interactions. +## Confirm First -## Copy must match behavior +Ask the user before changing: +- selection semantics +- drag/move/duplicate gestures +- snap behavior or bounds handles +- pan/zoom/fit/reset controls or shortcuts +- mode toggles +- right-click canvas behavior -If gestures/shortcuts change, update any user-facing copy/hints that describe them so instructions remain accurate. +## Canvas Contract -## Tests (when behavior changes) +- Comparable interactive canvas objects should participate in the same context-menu system. +- Hover, cursor, and interaction affordances should match existing canvas behavior. +- If gestures or shortcuts change, update any user-facing hints/copy that describe them. -For gesture/interaction changes, add/update Playwright tests where practical to cover the primary workflow path. +## Tests +- Add or update Playwright coverage for primary gesture paths when interaction behavior changes. diff --git a/tests/editor/editor-store.test.ts b/tests/editor/editor-store.test.ts index 99102fd..13550ae 100644 --- a/tests/editor/editor-store.test.ts +++ b/tests/editor/editor-store.test.ts @@ -95,7 +95,7 @@ describe('EditorStore reducer', () => { expect(clamped.project.pixelsPerUnit).toBe(1); }); - it('recomputes existing asset-backed sprite sizes when they still match the prior project scale baseline', () => { + it('rescales existing asset-backed sprites across the project when pixels per unit changes', () => { const state = { ...seededState(), project: { @@ -164,8 +164,8 @@ describe('EditorStore reducer', () => { const scene = next.project.scenes[next.currentSceneId]; expect(scene.entities.auto.width).toBe(32); expect(scene.entities.auto.height).toBe(32); - expect(scene.entities.custom.width).toBe(40); - expect(scene.entities.custom.height).toBe(40); + expect(scene.entities.custom.width).toBe(20); + expect(scene.entities.custom.height).toBe(20); }); it('mirrors a project rename into the publish title only when the publish title is empty', () => { diff --git a/tests/editor/entity-inspector.test.tsx b/tests/editor/entity-inspector.test.tsx index 47d9a33..cce9195 100644 --- a/tests/editor/entity-inspector.test.tsx +++ b/tests/editor/entity-inspector.test.tsx @@ -126,6 +126,8 @@ describe('Entity inspector', () => { expect(markup).toContain('2 px/unit'); expect(markup).toContain('World Size'); expect(markup).toContain('32×32 units'); - expect(markup).toContain('Use Project Scale'); + expect(markup).not.toContain('Use Project Scale'); + expect(markup).not.toContain('sprite-size-width-px-readonly'); + expect(markup).not.toContain('sprite-size-height-px-readonly'); }); });