From 6ee01f76094eca6a1944f526a72b799ec0eba7e3 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Tue, 31 Mar 2026 01:10:12 +0200 Subject: [PATCH] auto-git: [add] AGENTS.md [add] Action [add] architecture.md [add] prompts.txt [add] roadmap.md [add] testing.md --- AGENTS.md | 506 +++++++++++++++++++++ Action | 0 architecture.md | 1101 ++++++++++++++++++++++++++++++++++++++++++++++ prompts.txt | 1113 +++++++++++++++++++++++++++++++++++++++++++++++ roadmap.md | 606 ++++++++++++++++++++++++++ testing.md | 649 +++++++++++++++++++++++++++ 6 files changed, 3975 insertions(+) create mode 100644 AGENTS.md create mode 100644 Action create mode 100644 architecture.md create mode 100644 prompts.txt create mode 100644 roadmap.md create mode 100644 testing.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..1e6f3adf --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,506 @@ +# AGENTS.md + +## Project identity + +This repository contains a browser-based brush/solid editor for creating lightweight interactive 3D scenes, plus a built-in browser runner for playing those scenes. + +The product goal is: + +- Hammer / TrenchBroom style spatial authoring +- modern browser delivery +- glTF asset import/export +- fast edit -> run iteration +- lightweight interactive runtime with spatial audio, navigation modes, and simple entity-driven logic + +This is not a general-purpose DCC. +This is not a full game engine. +This is a focused authoring + runtime tool for browser-delivered 3D spaces. + +--- + +## Product pillars + +1. **Brushes are sacred** + - Layout authoring must remain faster than Blender. + - Brush editing is a first-class workflow, not a legacy compatibility mode. + - The editor must feel immediate, precise, and grid-friendly. + +2. **Imported assets are first-class** + - glTF / GLB import must feel native. + - Imported meshes, materials, textures, and animations must coexist cleanly with brush-authored worlds. + - Imported assets complement brushes; they do not replace them. + +3. **The runner is built in** + - Every meaningful authoring step should be testable in-browser. + - Switching from edit mode to play mode should be nearly instant. + - The runner is part of the product, not a demo app. + +4. **Web-native sharing matters** + - Scenes should be easy to load, embed, preview, and eventually share by URL. + - The browser is a target platform, not a secondary export target. + +--- + +## Architectural stance + +When making design decisions, prefer: + +- plain three.js over unnecessary abstraction +- explicit data models over implicit scene graph state +- deterministic rebuilds over hidden mutations +- command-based editing over ad hoc state changes +- typed scene entities over free-form JSON blobs +- vertical slices over speculative infrastructure +- boring, maintainable code over cleverness + +The project uses: + +- React for application shell and editor UI +- three.js for viewport and runtime rendering +- a canonical editor document model independent of three.js +- command pattern for undo/redo +- runtime entity systems for navigation, triggers, audio, and interaction +- glTF / GLB as the main interchange asset format +- JSON as the canonical authoring format + +Do not collapse editor state into raw three.js objects. +Do not make the three.js scene the source of truth. +Do not make glTF the canonical editor save format. + +--- + +## Early binding decisions + +These defaults are intentionally fixed for the early slices unless a later slice explicitly changes them. + +### Coordinate system + +- world space is right-handed and **Y-up** +- `+X` is right, `+Y` is up +- scene units are meter-like and should be used consistently for movement, collision, and audio distances + +### Early repo shape + +- start as a single Vite app +- keep domain folders under `src/` +- do not introduce `/apps` + `/packages` or a monorepo split until the current code actually needs it + +### State ownership + +- do not use the React tree as the canonical state container +- keep canonical editor state in a thin external editor store/service +- React renders and dispatches commands; it does not own the document + +### Persistence + +- the canonical scene document is versioned from day one +- M0-M2 may use local draft persistence plus explicit JSON import/export +- when binary assets arrive, they must survive reloads via embedded data or project-scoped packaged storage +- never rely on ephemeral Blob URLs as the only persisted asset reference + +### Early brush defaults + +- Slice 1.1 box brushes are axis-aligned only +- arbitrary brush rotation is explicitly deferred +- canonical box face IDs are fixed and stable: + - `posX` + - `negX` + - `posY` + - `negY` + - `posZ` + - `negZ` +- `posY` is the top face and `negY` is the bottom face + +### Model placement + +- placed imported models are **model instances**, not typed entities +- keep model instances in a document collection separate from `entities` + +### Runtime interaction scope + +- keep trigger/action/target links explicit and typed +- do not activate actions for systems that do not exist yet +- add sound and animation actions only when those runtime systems are implemented + +### Early clipping scope + +- until a dedicated convex-brush slice exists, clipping must be constrained to results representable by currently supported brush kinds +- unsupported clip cases must fail clearly instead of inventing new hidden geometry rules + +--- + +## Non-goals + +Unless explicitly added to the roadmap, do not turn this project into: + +- a general CAD package +- a Blender replacement +- a multiplayer MMO editor +- a full node-based visual scripting environment +- a full physics sandbox +- a photoreal AAA renderer +- a React Three Fiber showcase +- an ECS research project + +We may add optional scripting, plugins, collaboration, or advanced baking later. +They are not v1 priorities. + +--- + +## Core product vocabulary + +Use these terms consistently: + +- **Document**: canonical editor state +- **Brush**: author-authored solid/primitive in canonical brush form +- **Face**: one editable surface of a brush +- **Material**: logical authoring material definition +- **Texture**: image resource backing material channels +- **Asset**: imported external resource, usually GLB/GLTF or audio and related media +- **Model Instance**: placed scene instance of an imported asset +- **Prefab**: reusable asset/entity package placeable in scenes +- **Entity**: typed scene object with runtime/editor semantics +- **Runner**: browser runtime that loads and plays scenes +- **Viewport**: editor rendering surface +- **Command**: undoable state transition +- **Tool**: editor interaction mode such as select, move, box-create, face-edit +- **Build**: deterministic transformation from document -> runtime scene data +- **Export**: transformation to external deliverables such as GLB + +Avoid vague terms like “object”, “thing”, “item”, or “component” when a more precise domain term exists. + +--- + +## Repo expectations for agents + +When working in this repo: + +1. Read: + - `AGENTS.md` + - `architecture.md` + - `roadmap.md` + - `testing.md` + +2. Respect the current vertical slice. + - Do not “prepare for future flexibility” by adding unnecessary systems. + - Implement the smallest coherent version that preserves the architecture. + +3. Preserve layering. + - `document` owns canonical state. + - `commands` apply valid state changes. + - `geometry` owns derived brush and collider generation. + - `viewport-three` renders editor state. + - `runtime-three` plays runtime state. + - `entities` owns typed non-brush scene objects. + - `assets` adapts external asset/audio/media formats. + - `serialization` persists canonical state. + +4. Do not bypass command infrastructure for editor mutations. + - If the user can do it in the editor, it should usually be represented as a command. + +5. If persisted schema changes, update compatibility explicitly. + - bump the document schema version when required + - add or update migrations + - add at least one migration or compatibility test + +6. Prefer explicit typing and explicit invariants. + - Avoid permissive `any`, loose maps, or magic strings when a discriminated union or typed schema is appropriate. + +7. Keep systems testable. + - Geometry generation should be testable outside the browser UI. + - Serialization should be round-trip tested. + - Runtime interactions should be testable through deterministic fixtures where possible. + +8. Keep browser concerns in mind. + - Gracefully handle pointer lock failure, audio unlock requirements, missing gamepads, and asset load failures. + - Avoid architecture that assumes native desktop privileges. + +--- + +## Code quality rules + +### General + +- TypeScript only +- strict typing enabled +- prefer pure functions for transforms/build steps +- isolate impure browser/three.js side effects +- no silent catch-and-ignore +- no dead feature flags without roadmap justification +- no hidden singleton globals unless explicitly part of infrastructure + +### Naming + +- use descriptive names +- prefer domain names over generic utility names +- avoid abbreviations unless they are standard and obvious +- function names should describe intent, not implementation detail + +Good: +- `buildRuntimeSceneFromDocument` +- `applyMaterialToSelectedFaces` +- `createBoxBrushCommand` + +Bad: +- `handleThing` +- `updateData` +- `doBuild` + +### File organization + +- small files where it helps clarity +- split by domain, not by arbitrary technical categories +- avoid giant “misc” or “utils” dumping grounds +- every folder should have a clear reason to exist + +### Comments + +- explain *why*, not what the code obviously does +- use comments to document invariants, constraints, and tricky browser behavior +- remove stale comments promptly + +### Error handling + +- fail loudly in development +- surface usable diagnostics in the editor UI +- never corrupt the document silently +- preserve previous valid state on failed builds where possible + +--- + +## Data model rules + +The canonical authoring state must remain independent from three.js scene graph objects. + +### Required separation + +Maintain these layers: + +1. **Authoring model** + - JSON-serializable + - versioned + - typed + - stable across runtime/editor rebuilds + +2. **Editor view model** + - three.js meshes, helpers, overlays, gizmos + - disposable and rebuildable + +3. **Runtime model** + - play-mode scene graph + - controllers, triggers, emitters, colliders, animation mixers + +Do not let editor-only helpers leak into the canonical document. +Do not store raw three.js objects inside canonical document state. + +### Brush rules + +- brushes are not stored as triangle soup +- face material assignments are per-face +- UV transforms are canonical editor data +- runtime mesh generation is derived data +- collision generation is derived data +- early boxes are axis-aligned and use fixed face IDs + +### Entity rules + +- entities must be typed +- entity schemas must be explicit +- entity defaults must be centralized +- entity validation must happen at document/build boundaries +- model instances remain separate from entities + +--- + +## Performance rules + +Performance matters, but premature micro-optimization does not. + +Priorities: + +1. editor responsiveness during common operations +2. deterministic rebuild behavior +3. predictable memory usage +4. runtime smoothness for modest scenes +5. export/build correctness + +When optimizing: + +- measure first +- optimize hotspots, not aesthetics +- document assumptions +- prefer algorithmic improvements over clever hacks + +Expected hotspots: + +- picking/raycasting +- brush rebuilds / CSG +- face highlighting +- large texture browser lists +- imported asset previews +- runtime trigger scanning if implemented naively + +--- + +## UX rules + +The editor should feel like a real authoring tool, not a tech demo. + +Prioritize: + +- fast selection +- robust snapping +- visible grid and transform feedback +- obvious active tool state +- low-friction material application +- quick play testing +- understandable errors + +Every new feature should answer: +- What does the user see? +- What does the user click/drag/type? +- How is failure communicated? +- How is the action undone? +- How is the result tested? + +--- + +## Vertical slice policy + +We build in vertical slices. +Each slice must deliver a complete, usable capability across all relevant layers. + +A good slice includes: +- document changes +- commands +- viewport behavior +- UI panel updates +- runner behavior if relevant +- persistence +- tests +- manual QA notes + +A bad slice is “just backend structure” or “just a partial UI”. + +Do not land architectural scaffolding that has no immediate use in the current slice. + +If a roadmap item is too large for one pass, split it into smaller end-to-end sub-slices instead of landing half-systems. + +--- + +## Typical slice shape + +For each slice, agents should aim to deliver: + +1. domain model changes +2. command(s) +3. viewport interaction/tooling +4. UI affordance +5. serialization support +6. runtime/build support if needed +7. tests +8. docs update if behavior changed materially + +--- + +## Decision heuristics + +When uncertain: + +### Prefer plain three.js over extra abstraction +Unless abstraction clearly simplifies repeated patterns. + +### Prefer canonical JSON over reusing runtime/export data structures +The editor’s needs are different from export/runtime needs. + +### Prefer typed entity schemas over generic script bags +Especially in early versions. + +### Prefer constrained capabilities that feel good over flexible capabilities that feel vague +Example: +- better to have one excellent box-brush tool than five half-working primitive tools + +### Prefer immediate usability over speculative extensibility +But preserve clean seams for future extensions. + +--- + +## What agents must not do + +Do not: + +- rewrite broad project structure without a strong reason +- introduce new framework dependencies casually +- add R3F because “we might want it later” +- introduce ECS because “games use ECS” +- over-generalize the entity system +- replace canonical brush data with raw mesh editing +- implement hidden magic behaviors without schema support +- remove tests to get green CI +- make visual changes without noting them in the slice summary +- ignore browser restrictions around input/audio + +--- + +## Required deliverables in implementation responses + +When making meaningful changes, include: + +1. what changed +2. why it changed +3. which files were added/updated +4. how to run/test it +5. known limitations +6. follow-up suggestions only if directly relevant + +If the environment prevents verification, state exactly what was and was not verified. + +--- + +## Definition of done for a slice + +A slice is done when: + +- the feature can be used end-to-end +- the feature is represented in canonical document data +- the feature can be saved and loaded +- the feature is test-covered appropriately +- the feature has manual verification notes +- the feature does not violate the architecture +- obvious failures produce usable diagnostics +- undo/redo works if the feature is editor-authored + +--- + +## Preferred stack unless changed deliberately + +- TypeScript +- React +- Vite +- three.js +- Vitest +- Playwright +- ESLint +- Prettier +- a small state store if needed +- minimal dependencies overall + +Add dependencies only when they clearly save time and complexity over building in-house. + +--- + +## Final instruction to agents + +Build the smallest coherent thing that feels real. + +The product should always trend toward: +- spatial immediacy +- authoring clarity +- browser-native practicality +- fast iteration +- strong foundations for brushes, assets, entities, and runner behavior + +If forced to choose, preserve the integrity of: +1. the canonical document model +2. the brush workflow +3. the edit -> run loop diff --git a/Action b/Action new file mode 100644 index 00000000..e69de29b diff --git a/architecture.md b/architecture.md new file mode 100644 index 00000000..7fa22708 --- /dev/null +++ b/architecture.md @@ -0,0 +1,1101 @@ +# architecture.md + +## Overview + +This project is a browser-based 3D scene authoring tool with a built-in runtime runner. + +It has two primary modes: + +1. **Editor mode** + - author spatial scenes using brush primitives, entities, materials, and imported assets + +2. **Runner mode** + - load and play those scenes in-browser using configurable navigation and interaction modes + +The architecture is designed to preserve old-school level-editor ergonomics while staying web-native and maintainable. + +--- + +## Architectural goals + +### Primary goals + +- fast and precise brush-based scene authoring +- modern browser runtime delivery +- native support for imported GLB/GLTF assets +- robust material/texture workflows +- instant edit -> play iteration +- deterministic save/load/build behavior +- clean separation between authoring model and runtime rendering + +### Secondary goals + +- embeddable runner +- future prefab ecosystem +- future collaboration support +- future scripting/plugin seams +- future export targets beyond the built-in runtime + +### Non-goals + +- replacing Blender +- becoming a full game engine +- full visual scripting in v1 +- photoreal renderer competition +- deeply general engine/editor abstractions before needed + +--- + +## Early binding decisions + +These decisions are intentionally fixed for the early slices so implementation chats do not invent different interpretations. + +### Coordinate system and units + +- world space is right-handed and **Y-up** +- `+X` is right and `+Y` is up +- scene units are meter-like and should be treated consistently by editor transforms, runtime movement, collision, and audio distance settings + +### Initial repo shape + +Start simple. + +Recommended initial layout: + +```txt +src/ + app/ + core/ + document/ + commands/ + geometry/ + viewport-three/ + runtime-three/ + entities/ + materials/ + assets/ + serialization/ + shared-ui/ +tests/ + unit/ + domain/ + geometry/ + serialization/ + browser/ + e2e/ +fixtures/ + documents/ + assets/ + exports/ +``` + +Do not introduce `/apps` + `/packages` or monorepo packaging until the current codebase actually needs it. + +### Canonical state ownership + +- keep canonical editor state outside the React component tree +- React renders state and dispatches commands +- a thin external editor store/service is the correct place for the document, selection, tool mode, and command history + +### Persistence strategy + +- version the canonical document from day one +- M0-M2 may use local draft persistence plus explicit JSON import/export for the document +- once binary assets are introduced, saved projects must keep them via embedded data or project-packaged storage +- never persist only ephemeral Blob URLs or runtime-only browser object references + +### Early brush representation + +The first supported brush kind is an axis-aligned box. +Do not support arbitrary brush rotation in Slice 1.1. + +Use stable face IDs: + +```ts +type BoxFaceId = + | "posX" + | "negX" + | "posY" + | "negY" + | "posZ" + | "negZ"; +``` + +`posY` is the top face and `negY` is the bottom face. + +Recommended early box shape: + +```ts +interface BoxBrush { + id: string; + kind: "box"; + center: Vec3; + size: Vec3; + faces: Record; + layerId?: string; + groupId?: string; +} +``` + +`size` values should be positive and non-zero. + +### Early UV representation + +Store actual UV transform values canonically per face. + +```ts +interface FaceUvState { + offset: Vec2; + scale: Vec2; + rotationQuarterTurns: 0 | 1 | 2 | 3; + flipU: boolean; + flipV: boolean; +} +``` + +In early slices, “fit to face” is a command that rewrites explicit UV values. +Do not persist a separate procedural fit flag yet. + +### Model instances vs entities + +Placed imported models are not typed entities. + +- imported assets live in the asset registry +- placed scene instances of those assets live in `modelInstances` +- typed runtime/editor objects such as `PlayerStart` or `TriggerVolume` live in `entities` + +### Trigger/action/target scope + +Keep interaction links explicit and typed. +Only activate actions for systems that already exist. + +- teleport/visibility actions can land before audio/animation systems +- sound actions should land with the audio slice +- animation actions should land with the animation slice + +### Clipping scope + +Until a dedicated convex-brush slice exists, clipping must stay constrained to results representable by the currently supported brush kinds. +If the first clip implementation only supports axis-aligned box brushes and principal-axis clip planes, that is acceptable. + +--- + +## System model + +The architecture is based on three major representations: + +### 1. Canonical authoring document + +The editor’s source of truth. + +Properties: +- JSON-serializable +- versioned +- typed +- deterministic +- independent of three.js runtime objects + +Contains: +- world settings +- brush definitions +- face UV/material assignments +- entity instances +- model instances +- interaction links +- asset references +- prefab references +- editor metadata +- layer/group structures if the current slice truly needs them + +### 2. Editor viewport representation + +A transient three.js rendering of editor state. + +Properties: +- rebuildable +- disposable +- optimized for interaction and visualization +- may include helpers, overlays, and selection visuals + +Contains: +- preview meshes +- wireframes +- selection outlines +- gizmos +- helper icons +- grids +- temporary tool feedback + +### 3. Runtime representation + +A play-mode representation derived from the document. + +Properties: +- optimized for navigation and interaction +- independent from editor overlays and helpers +- suitable for embedding and scene playback + +Contains: +- renderable meshes +- collision data +- runtime entities +- model instance runtime bindings +- trigger bindings +- animation mixers +- audio emitters +- navigation/controller systems + +These three representations must remain conceptually separate. + +--- + +## High-level module layout + +Keep the initial repo simple, but preserve domain boundaries in code. + +Recommended domain layout inside `src/`: + +- `core` +- `document` +- `commands` +- `geometry` +- `viewport-three` +- `runtime-three` +- `entities` +- `materials` +- `assets` +- `serialization` +- `shared-ui` + +Longer-term, this may evolve into `/apps` + `/packages` if real pressure appears. +Do not start there by default. + +--- + +## Module responsibilities + +## `core` + +Purpose: + +- shared domain types and low-level interfaces + +Contains: + +- IDs +- enums +- discriminated unions +- shared constants +- small foundational helpers + +Rules: + +- no React +- no DOM +- no three.js +- no serialization side effects + +Examples: + +- `BrushId` +- `EntityType` +- `MaterialId` +- `SceneVersion` + +--- + +## `document` + +Purpose: + +- canonical editor state model + +Contains: + +- root scene document +- typed records/collections +- validation entry points +- document migrations +- default factories +- invariants + +Rules: + +- must remain serializable +- no three.js object references +- should be testable in isolation + +Example structure: + +```ts +interface SceneDocument { + version: number; + world: WorldSettings; + materials: Record; + textures: Record; + assets: Record; + brushes: Record; + modelInstances: Record; + entities: Record; + interactionLinks: Record; +} +``` + +--- + +## `commands` + +Purpose: + +- explicit, undoable state transitions + +Commands mutate the document through controlled APIs. + +Examples: + +- create brush +- delete brush +- move brush +- resize brush +- assign material to selected faces +- place entity +- place model instance +- import asset reference +- change world settings + +Recommended command shape: + +```ts +interface Command { + id: string; + label: string; + execute(ctx: CommandContext): void; + undo(ctx: CommandContext): void; +} +``` + +Command context should expose: + +- current document +- selection +- services needed for mutation bookkeeping +- optional event hooks + +Rules: + +- editor-authored state changes should flow through commands +- commands must be deterministic +- commands should be replayable where practical +- commands must preserve document validity + +--- + +## `geometry` + +Purpose: + +- brush kernel and derived geometry generation + +Contains: + +- primitive definitions +- tessellation/build logic +- plane/face operations +- UV projection math +- snap/grid helpers +- collision mesh generation +- optional later clipping helpers + +This is one of the most critical modules. + +### Canonical brush representation + +Brushes should not be stored as raw triangle meshes. + +Preferred progression: + +#### Early v1 + +Explicit parametric primitives with per-face data: + +- box +- wedge/ramp +- cylinder prism +- stairs +- arch + +#### Later + +Plane-based convex solids and clipping-based editing. + +### Derived outputs + +From brush data, generate: + +- editor mesh +- pick mesh +- highlight mesh +- collision mesh +- runtime mesh +- export mesh + +These should be rebuildable from canonical brush data. + +--- + +## `viewport-three` + +Purpose: + +- render editor state and provide spatial interaction + +Contains: + +- editor three.js scene +- cameras +- grid +- picking +- transform gizmos +- editor overlays +- tool previews + +Responsibilities: + +- convert document selections/build results into visible editor objects +- handle hit testing +- manage editor cameras and view modes +- render helper visuals +- support high-frequency tool feedback + +Suggested internal subsystems: + +- `ViewportHost` +- `EditorSceneRenderer` +- `PickService` +- `CameraController` +- `GridRenderer` +- `SelectionOverlay` +- `ToolPreviewRenderer` +- `GizmoBridge` + +### Cameras + +Target minimum by milestone: + +- perspective in early slices +- top/front/side orthographic views when the viewport-layout slice lands + +--- + +## `runtime-three` + +Purpose: + +- play scenes in-browser + +Responsibilities: + +- load built runtime scene +- create player/controller +- evaluate interactions +- play animations +- manage audio +- expose embeddable runtime APIs + +### Major subsystems + +- `RuntimeLoader` +- `RuntimeScene` +- `ControllerManager` +- `InteractionSystem` +- `TriggerSystem` +- `AudioSystem` +- `AnimationSystem` +- `RuntimeUIBridge` + +### Navigation modes + +Initial modes: + +- first-person +- orbit visitor + +Later optional modes: + +- free-fly +- click-to-move +- click-to-teleport +- controller-supported variants where applicable + +These modes should share a common interface: + +```ts +interface NavigationController { + id: string; + activate(ctx: RuntimeContext): void; + deactivate(ctx: RuntimeContext): void; + update(dt: number): void; +} +``` + +--- + +## `entities` + +Purpose: + +- typed non-brush scene objects + +Entities bridge authoring and runtime behavior. + +Early entity types: + +- `PlayerStart` +- `SoundEmitter` +- `TriggerVolume` +- `Interactable` +- `TeleportTarget` + +Later entity types may include: + +- `Door` +- `Waypoint` +- `AmbientZone` +- `CameraZone` + +### Entity design rules + +- entities are typed +- entity schemas are explicit +- defaults live centrally +- runtime builders convert document entities into runtime objects +- editor icons/gizmos for entities are separate from runtime representation +- model instances remain separate from entities + +### Example schema + +```ts +type EntityInstance = + | PlayerStartEntity + | SoundEmitterEntity + | TriggerVolumeEntity + | InteractableEntity + | TeleportTargetEntity; +``` + +Avoid a generic “script blob” as the initial design. +Typed entities are easier to validate, render, test, and expose in UI. + +--- + +## `materials` + +Purpose: + +- authoring material registry and editor material behavior + +Contains: + +- logical material definitions +- material library metadata +- thumbnail info +- material categories/tags +- material-to-runtime conversion + +The editor material model should be a stable abstraction. +It does not need to map 1:1 to raw three.js materials internally. + +Example: + +```ts +interface MaterialDef { + id: string; + name: string; + shadingModel: "basic" | "standard" | "unlit"; + baseColorTexture?: TextureRef; + normalTexture?: TextureRef; + roughnessTexture?: TextureRef; + emissiveTexture?: TextureRef; + transparent?: boolean; + doubleSided?: boolean; + tags: string[]; +} +``` + +### Per-face editing + +A major design requirement: + +- per-face material assignment +- per-face UV controls +- quick apply workflow +- stable face IDs on canonical brushes + +--- + +## `assets` + +Purpose: + +- external asset and media import/export + +Contains: + +- GLB/GLTF loaders +- audio import helpers +- preview generation +- asset metadata extraction +- export assembly +- optional optimization integration + +### Asset principles + +Imported assets should become one or more of: + +- registered project assets +- placed model instances +- reusable prefab inputs +- material/texture records where useful + +Do not treat imported assets as opaque blobs forever. +Extract useful metadata and register them meaningfully. + +### Asset registry entries should capture + +- asset ID +- source name +- type +- stable persistence reference +- contained scene/nodes when relevant +- materials +- textures +- animations +- bounding box / dimensions if feasible +- import-time notes or warnings +- preview thumbnail if practical, but thumbnail generation must not block the import path + +### Imported asset placement + +There should be a clear distinction between: + +- asset record +- model instance +- prefab definition + +--- + +## `serialization` + +Purpose: + +- persistence of canonical authoring state + +Contains: + +- save/load functions +- migrations +- compatibility guards +- validation hooks +- round-trip checks + +### Canonical save format + +Use project JSON as the canonical save format. + +Reasons: + +- preserves editor semantics +- easy to version +- easy to diff +- easier to migrate than overloading glTF with editor-only metadata +- decouples authoring from runtime/export packaging + +### Migration rule + +Every persisted schema change must be accompanied by: + +- an explicit compatibility decision +- a version bump when needed +- a migration or compatibility test + +Suggested load flow: + +```ts +load -> detect version -> migrate stepwise -> validate -> use +``` + +Never silently reinterpret incompatible files. + +--- + +## `shared-ui` + +Purpose: + +- reusable React UI elements across editor and runner shells + +Contains: + +- inspector controls +- outliner items +- browser panels +- dialogs +- status bars +- toasts +- property editors + +This module should not own domain logic. +It should render state supplied by domain modules. + +--- + +## Application layout + +## `editor-web` + +Main responsibilities: + +- boot the editor app shell +- host React UI panels +- instantiate the editor viewport +- connect store/document/commands +- switch into play mode or launch runner context +- manage local persistence/import/export actions + +Suggested major areas: + +- toolbar or command bar +- viewport region +- outliner +- inspector +- material browser +- asset browser +- status / validation panel + +## `runner-web` + +Main responsibilities: + +- load a built or live scene +- initialize runtime systems +- expose navigation modes +- provide minimal UI overlay +- support embedding + +Long-term, the runner may exist both: + +- inside the editor for play mode +- as a standalone deployable viewer/player + +--- + +## State management + +Use a thin store for app/editor state orchestration. +Do not use the React tree as the canonical state container. + +Recommended separation: + +### Canonical/editor state + +- scene document +- selection +- tool mode +- command history +- active project persistence state + +### UI state + +- panel visibility +- focused inspector tabs +- search queries +- dialog state +- viewport mode/layout + +### Ephemeral viewport state + +- hover hit +- drag preview +- temporary gizmo state +- frame timing +- pointer capture state + +### Runtime ephemeral state + +- active controller +- playing sounds +- trigger occupancy +- animation playback state + +Keep ephemeral rendering and interaction state out of the serialized document. + +--- + +## Build pipeline + +The project has multiple “builds” conceptually: + +### 1. Frontend app build + +Standard web app bundling. + +### 2. Runtime scene build + +Transforms the document into runtime-usable data. + +### 3. Export build + +Transforms document/runtime scene data into external deliverables such as GLB or a packaged runner. + +These should not be conflated. + +### Runtime scene build stages + +Recommended conceptual pipeline: + +```txt +SceneDocument +-> validate +-> resolve assets/materials/entities/model instances +-> build brush meshes +-> build colliders +-> build runtime entity graph +-> assemble runtime scene package +``` + +### Export build stages + +```txt +SceneDocument +-> validate +-> build export scene graph +-> attach materials/textures/assets +-> emit GLTF/GLB or packaged output +-> optional post-process +``` + +--- + +## Validation + +Validation should exist at multiple boundaries. + +### Document validation + +Checks: + +- missing references +- invalid entity property values +- invalid material refs +- invalid brush params +- duplicate IDs +- unsupported schema versions + +### Build validation + +Checks: + +- unbuildable geometry +- unresolved assets +- incompatible runtime entity setups +- missing audio files +- invalid trigger targets + +### Runtime validation + +Checks: + +- controller mode availability +- audio unlock restrictions +- failed asset loads +- unsupported browser features where relevant + +Errors should surface clearly in the editor UI. + +--- + +## Selection and picking architecture + +Selection should not depend on raw scene traversal alone. +Use explicit mapping between visible pickable objects and domain IDs. + +Recommended approach: + +- maintain pick proxies or metadata bindings +- raycast against known pick layers +- convert hit -> domain selection result +- route through a selection service + +Selection result examples: + +- brush +- brush face +- entity +- model instance +- gizmo handle +- helper +- empty space + +This makes picking predictable and testable. + +--- + +## Tool architecture + +Tools should be explicit modes with shared lifecycle hooks. + +Example interface: + +```ts +interface EditorTool { + id: string; + label: string; + activate(ctx: ToolContext): void; + deactivate(ctx: ToolContext): void; + onPointerDown(e: ToolPointerEvent): void; + onPointerMove(e: ToolPointerEvent): void; + onPointerUp(e: ToolPointerEvent): void; + onKeyDown?(e: KeyboardEvent): void; + renderOverlay?(): void; +} +``` + +### Initial tool set + +- select +- move +- scale +- create box brush +- material apply +- place entity + +### Later tools + +- face edit +- clip brush +- rotate brush +- vertex/edge editing +- prefab place + +--- + +## Runner interaction architecture + +Keep runtime interaction simple and data-driven first. + +Prefer: +`Trigger -> Action -> Target` + +Example link shape: + +```ts +interface InteractionLink { + id: string; + sourceEntityId: string; + trigger: "enter" | "exit" | "click"; + action: + | { type: "teleportPlayer"; targetEntityId: string } + | { type: "toggleVisibility"; targetId: string; visible?: boolean } + | { type: "playAnimation"; targetModelInstanceId: string; clipName: string } + | { type: "stopAnimation"; targetModelInstanceId: string; clipName?: string } + | { type: "playSound"; targetEntityId: string } + | { type: "stopSound"; targetEntityId: string }; +} +``` + +Rules: + +- trigger kinds are only valid for compatible entity types +- keep link validation explicit +- do not activate sound or animation actions before those systems exist + +--- + +## Audio architecture + +Audio should be a first-class runtime system. + +### Core concepts + +- listener +- positional emitter +- one-shot sound +- looped sound +- trigger-controlled playback + +### Initial requirements + +- spatial audio emitters +- distance falloff settings +- loop support +- runtime start/stop +- browser audio unlock handling + +### Future requirements + +- directional cones +- area ambience blending +- occlusion/obstruction +- subtitles/captions +- mixer buses + +--- + +## Failure philosophy + +The editor must remain trustworthy. + +If something fails: + +- preserve the last valid document +- show the failure clearly +- make it debuggable +- do not silently corrupt state +- do not hide build errors behind generic toasts + +Categories: + +- validation errors +- asset import failures +- geometry build failures +- runtime initialization failures +- browser capability restrictions + +--- + +## Example end-to-end flow + +### Editing a box room + +1. User creates a box brush +2. Tool dispatches a create-box command +3. Document updates +4. Geometry rebuilds the derived preview mesh +5. Viewport updates the visible scene +6. User applies a material to a wall face +7. Command updates face material/UV state +8. Material preview refreshes +9. User hits Run +10. Runtime build validates the document and constructs runtime scene data +11. Runner starts in the selected navigation mode +12. User walks the scene with runtime interactions active + +This is the core product loop. + +--- + +## Minimal viable architecture boundary summary + +Must remain separate: + +- canonical document vs three.js objects +- editor viewport vs runtime scene +- command layer vs ad hoc mutation +- authoring JSON vs export/package output +- brush data vs generated mesh +- asset records vs model instances +- entities vs model instances +- UI state vs document state + +If these boundaries hold, the product can grow safely. +If they collapse, the codebase will become brittle quickly. diff --git a/prompts.txt b/prompts.txt new file mode 100644 index 00000000..45d84108 --- /dev/null +++ b/prompts.txt @@ -0,0 +1,1113 @@ +These prompts assume the repo docs are already updated. +Use one fresh Codex chat per prompt. +Each prompt is written to be copy-paste ready. + +--- + +## Prompt 0 — Repo foundation / bootstrap + +```text +You are working in a new repo for a browser-based brush editor + built-in runner for lightweight interactive 3D scenes. + +Read and follow these files first: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend what is there. +- Do not re-architect unless the current code clearly violates the docs. +- Keep the repo as a single Vite app with domain folders under src/. +- Do not use the React tree as the canonical state container. + +Your task is to implement the foundation slice only. + +Goals: +- Bootstrap the project with React + Vite + TypeScript. +- Set up a minimal app shell with a visible three.js viewport region and placeholder side panels. +- Add strict TypeScript config, lint/format scaffolding if missing, and a small folder structure under src/ that matches the architecture docs. +- Add a minimal versioned canonical SceneDocument model. +- Add a migration entry point, even if it only handles the current version. +- Add a minimal Command interface and CommandHistory with undo/redo support. +- Add a thin external editor store/service that owns the document, selection, tool mode, and command history. +- Add local draft save/load scaffolding for the empty document. +- Add explicit JSON import/export scaffolding for the document. +- Add test setup for Vitest and Playwright. +- Add one smoke test that proves the app boots and the viewport shell is visible. +- Do not implement real geometry tools yet. +- Do not overbuild infrastructure. +- Do not add React Three Fiber. +- Do not split into a monorepo. + +Expected output: +- A working app that starts locally. +- A visible layout with a center viewport and side panels. +- A minimal empty document factory. +- A command stack that can handle at least a dummy command. +- Basic scripts in package.json for dev, build, test, test:e2e, and typecheck. +- Initial test files. +- Small, coherent file structure. + +Constraints: +- Keep the canonical document independent from three.js objects. +- Keep the viewport imperative and plain three.js. +- Keep the implementation as small as possible while preserving architecture seams. +- Avoid speculative plugin systems or ECS. +- If you introduce persisted schema, version it from day one. + +Please: +1. Inspect the repo. +2. Implement the slice fully. +3. Update any missing config/scripts. +4. Run the relevant build/tests locally if possible. +5. At the end, report: + - what changed + - why it changed + - which files were added/updated + - how to run it + - what was verified + - known limitations +``` + +--- + +## Prompt 1 — Box brush authoring + +```text +You are implementing the first real vertical slice of a browser-based brush editor. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Do not re-architect unless the current code clearly violates the docs. +- If you change the persisted SceneDocument schema, update versioning, migrations, and at least one migration/compatibility test. + +Current goal: +Implement Slice 1.1 — Box brush authoring. + +Requirements: +- Add canonical BoxBrush support to the SceneDocument. +- Keep early box brushes axis-aligned only. +- Do not implement arbitrary brush rotation in this slice. +- Unless the repo already has a compatible equivalent, represent a box brush canonically as: + - `kind: "box"` + - `center` + - positive `size` + - stable face records keyed by `posX | negX | posY | negY | posZ | negZ` +- Implement create/select/move/resize for box brushes. +- Add grid snapping. +- Render box brushes in the three.js editor viewport. +- Add outliner presence for brushes. +- Ensure save/load JSON works for box brushes. +- Add undo/redo support through commands for all authoring actions in this slice. +- Keep the box brush stored canonically as structured brush data, not raw triangle soup. +- Keep editor mesh generation derived from canonical brush data. +- Keep the UI simple and real. Button-driven creation is acceptable if it is usable. +- Do not implement face UV editing yet. +- Do not implement fancy primitives yet. + +Testing expectations: +- Unit/domain tests for create box brush command and undo/redo +- Serialization round-trip test for a document with at least one box brush +- Browser/e2e smoke proving a user can create a box brush and it persists after reload through the current persistence path +- Geometry sanity tests if you introduce a mesh builder + +Important architecture rules: +- Document is source of truth +- Commands own mutations +- three.js scene is derived +- No raw three.js objects in the document +- No R3F + +Deliverables: +- End-to-end usable box brush slice +- Any small UI needed to exercise it +- Tests +- Brief manual QA notes in your response + +Please implement this slice completely, run the relevant checks if possible, and then report: +- changed files +- commands added +- how box brush canonical data is represented +- how to test/use it +- what remains intentionally out of scope +``` + +--- + +## Prompt 2 — Face materials and UV basics + +```text +You are implementing Slice 1.2 — Face materials and UV basics. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Do not re-architect unless the current code clearly violates the docs. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Make it possible to assign materials to individual box brush faces and edit basic UV parameters. + +Requirements: +- Introduce a canonical material registry in the document. +- Add a tiny starter material library stored locally in the repo. +- Add face selection for box brushes using the stable box face IDs. +- Allow applying a material to a single face. +- Persist explicit UV state canonically per face using concrete values. +- Unless the repo already has a compatible equivalent, store these per-face UV fields: + - `offset` + - `scale` + - `rotationQuarterTurns` + - `flipU` + - `flipV` +- Support these operations: + - offset + - scale + - rotate 90 + - flip U + - flip V + - fit to face +- Treat “fit to face” as a command that rewrites explicit UV values. +- Do not persist a separate procedural fit flag yet. +- Persist all face material and UV data through save/load. +- Reflect material and UV changes in viewport rendering. +- Add a minimal material browser panel and/or inspector controls. +- Keep UV state canonical in the document, not only in generated mesh UV buffers. +- Do not overcomplicate the material system yet. +- Do not build a huge texture pipeline yet. + +Important: +- A major goal is to preserve Hammer/TrenchBroom-style speed. +- The UX can be simple at first, but it must be real and usable. +- Commands must cover material application and UV edits so undo/redo works. + +Testing expectations: +- Round-trip save/load test with per-face material + UV state +- Domain tests for apply-material and UV edit commands +- Geometry/render tests if useful for derived UV output +- Browser/e2e test for assigning a face material through the UI if feasible + +Implementation guidance: +- Keep the starter material library small and local to the project +- Prefer simple thumbnails / labels over overdesigned UI +- Keep face identification stable in the canonical box brush representation + +Please implement the slice fully and report: +- how face IDs are represented +- how UV state is stored +- what UI affordances were added +- what tests were added +- how to verify manually +``` + +--- + +## Prompt 3 — Runner v1 + +```text +You are implementing Slice 1.3 — Runner v1. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Do not re-architect unless the current code clearly violates the docs. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Make the authored scene playable inside the browser. + +Requirements: +- Add a runtime build step from SceneDocument to a runtime scene representation. +- Add a built-in runner/play mode reachable from the editor. +- Support: + - first-person navigation + - orbit visitor mode +- First-person can be simple, but should feel real: + - `WASD` movement + - mouse-look when active + - graceful pointer-lock failure handling +- Orbit visitor should provide a clear fallback for non-FPS navigation. +- Add minimal typed PlayerStart support in a way that is compatible with the later full entity system. +- Add basic collision against axis-aligned box-brush-generated geometry, enough for a small room test. +- Allow entering and leaving run mode safely. +- Preserve editor state when leaving run mode. +- Keep the runner as a sibling system, not a hack inside editor-only viewport code. +- Do not add triggers or audio yet. +- Do not add future nav modes yet. + +Implementation guidance: +- Reuse three.js where appropriate, but keep runtime-specific logic separate from editor helpers. +- Keep collision deterministic and explicit about limitations. +- PlayerStart should become part of the canonical document, not an editor-only setting. + +Testing expectations: +- Domain/build tests for runtime scene construction from a simple document +- E2E/smoke test that enters run mode successfully +- If possible, a minimal interaction test that the player spawns at PlayerStart + +Please implement the slice fully and report: +- what runtime modules/classes were added +- how edit mode and run mode are separated +- how PlayerStart is represented +- known limitations of collision/movement +- how to run and verify manually +``` + +--- + +## Prompt 4 — End-to-end first-room polish + +```text +You are implementing Slice 1.4 — polish for the first complete room workflow. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Do not redesign the product or rewrite earlier slices. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Strengthen the first real user loop: +create box brush -> texture faces -> save/load -> run scene. + +Requirements: +- Add basic document validation and visible validation/build errors. +- Improve snapping feedback and active-tool feedback. +- Add a minimal toolbar or command surface for key authoring actions. +- Improve save/load UX enough that the first-room workflow feels coherent. +- Add or refine scene/world settings only if needed for the first-room slice. +- Tighten rough edges in the editor/runner transition. +- Add smoke/regression coverage for the first-room loop. + +Minimum validation scope: +- duplicate IDs +- invalid box sizes +- missing material refs +- invalid entity refs introduced so far +- missing PlayerStart when entering first-person mode, if that matters in the current implementation + +Important: +- This is not a redesign pass. +- This is not a “make it pretty” pass. +- It is a coherence and trust pass. +- Prioritize usability, error visibility, and slice completeness. + +Testing expectations: +- E2E flow for create -> texture -> save/load -> run +- Validation tests for obvious bad states +- Missing regression tests for the first-room loop + +Please implement only what materially improves the first-room workflow and report: +- UX improvements made +- validation/build diagnostics added +- tests added +- manual QA flow you used +``` + +--- + +## Prompt 5 — Entity system foundation + +```text +You are implementing Slice 2.1 — Entity system foundation. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Reuse and extend the existing PlayerStart path rather than rebuilding it in parallel. +- Do not merge model instances into entities. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Add a typed entity system to the editor and runtime foundation. + +Initial entity types to support: +- PlayerStart +- SoundEmitter +- TriggerVolume +- TeleportTarget +- Interactable + +Requirements: +- Add explicit typed entity schemas to the canonical document model. +- Add an entity registry/defaults layer. +- Add an entity placement workflow. +- Add viewport helpers/icons/gizmos for entities. +- Add entity selection and inspector editing. +- Persist entities through save/load. +- Make runtime build consume entities, even if only some are active yet. +- Keep entities typed; do not implement a generic script blob system. +- Keep editor visuals for entities separate from runtime behavior. +- Keep model instances, if any exist already, in their own collection. + +Implementation guidance: +- Keep the first version small and explicit. +- Use clear defaults and property validation. +- Ensure entity IDs and references are stable. + +Testing expectations: +- Domain tests for entity creation/editing +- Serialization round-trip tests +- Browser/e2e test for placing and selecting an entity if feasible + +Please implement fully and report: +- entity types added +- how the registry/defaults work +- how placement works +- how entities appear in viewport/outliner/inspector +- what runtime integration exists so far +``` + +--- + +## Prompt 6 — Trigger -> Action -> Target foundation + +```text +You are implementing Slice 2.2 — Trigger -> Action -> Target foundation. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Do not build a generic scripting system or node graph. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Enable the first simple data-driven interactions without scripting. + +Requirements: +- Add canonical schemas for trigger/action/target links. +- Unless the repo already has a compatible equivalent, represent links as explicit records with: + - stable link ID + - source entity ID + - trigger kind + - typed action payload +- Support authoring and persistence of these links. +- Add runtime evaluation of trigger -> action -> target. +- Add minimal UI for configuring links in the inspector. +- Keep the system typed and explicit. + +Initial supported trigger sources: +- TriggerVolume enter +- TriggerVolume exit + +Initial supported actions: +- teleport player +- toggle visibility + +Important: +- Keep it data-driven, not script-driven. +- Do not activate sound or animation actions yet. +- Do not build a generic node graph. +- Do not overdesign event buses. +- Focus on the smallest real interaction system that works end-to-end. + +Testing expectations: +- Domain tests for link validation +- Runtime tests for dispatch behavior with fixtures or mocks +- E2E/manual verification for at least one actual trigger flow + +Please implement the slice fully and report: +- how links are stored canonically +- which trigger types and actions are active now +- how runtime dispatch works +- how to test an example interaction +- known limitations +``` + +--- + +## Prompt 7 — Click interactions and runner prompts + +```text +You are implementing Slice 2.3 — Click interactions and runner prompts. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Preserve compatibility with the current Trigger -> Action -> Target system. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Allow the user to click interactive entities in run mode and receive clear prompts/feedback. + +Requirements: +- Add click-target support in the runner. +- Add a minimal prompt / interaction UI. +- Support action-on-click behavior for Interactable entities. +- Add interaction distance and basic targeting rules. +- Keep behavior deterministic and understandable. +- Preserve compatibility with the existing Trigger -> Action -> Target system. +- Separate runtime input handling from editor picking. + +Implementation guidance: +- Keep the UI minimal and legible. +- Prefer explicit interaction affordances over hidden magic. +- Interaction range should be a clear authored/configured value or a simple documented default. + +Testing expectations: +- Runtime/browser tests for click targeting +- E2E or manual verification for click-to-trigger flow +- Regression coverage for prompt visibility logic if practical + +Please implement fully and report: +- how click targeting works +- what prompt UX was added +- how interaction range is defined +- how to verify manually +``` + +--- + +## Prompt 8 — GLB/GLTF import + +```text +You are implementing Slice 3.1 — GLB/GLTF import. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Keep placed imported models separate from entities. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Import GLB/GLTF assets, register them, and place them in the scene. + +Requirements: +- Add an asset registry to the canonical document or asset domain. +- Implement a GLB/GLTF import workflow. +- Add the smallest reliable project-storage addition needed so imported assets survive reload. +- Prefer IndexedDB-backed project asset storage for binary payloads if browser storage is needed. +- Keep stable asset records in the canonical document. +- Never rely on ephemeral Blob URLs as the only persisted reference. +- Extract and store useful metadata: + - asset id + - name + - stable persistence reference + - contained materials/textures if useful + - animations list if present + - bounding box / dimensions if feasible +- Add preview/thumbnail support if practical, but do not let thumbnail generation block import. +- Allow placing an imported model instance in the scene. +- Allow selecting and transforming a model instance. +- Persist asset references and placed model instances through save/load. +- Render imported assets in editor and runner. + +Important: +- Imported assets should be first-class but must not replace brushes. +- Distinguish clearly between asset records and scene model instances. +- Keep the implementation small and reliable. +- Do not build a giant asset-management subsystem yet. + +Testing expectations: +- Round-trip tests for asset refs / placed model instances +- At least one fixture GLB/GLTF test asset +- E2E or browser verification for import and placement if possible + +Please implement fully and report: +- asset registry design +- model instance representation +- what metadata is extracted +- what limitations exist on import +- how to test with the included fixture(s) +``` + +--- + +## Prompt 9 — Animation playback + +```text +You are implementing Slice 3.2 — Animation playback. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Reuse the existing Trigger -> Action -> Target system rather than inventing a second dispatch path. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Enable playback of animations from imported GLB/GLTF assets. + +Requirements: +- Detect and surface imported animations in asset metadata and/or model instance config. +- Add a way to configure an animation target or animated model instance. +- Integrate animation playback into the runner. +- Add `play animation` and `stop animation` action wiring through the existing interaction system. +- Add minimal inspector UI needed to choose or inspect animation clips. +- Persist animation-related settings through save/load. +- Keep it small and explicit. +- Do not build a full timeline editor. + +Testing expectations: +- Tests for imported animation metadata availability +- Runtime tests for play/stop dispatch if feasible +- Manual or e2e verification using a small animated fixture + +Please implement fully and report: +- how animations are exposed to the author +- how runtime playback is managed +- what actions are supported +- how to test it +``` + +--- + +## Prompt 10 — Spatial audio + +```text +You are implementing Slice 3.3 — Spatial audio. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Reuse the existing Trigger -> Action -> Target system rather than inventing a second dispatch path. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Make positional/spatial audio a first-class runner feature. + +Requirements: +- Support audio asset references for SoundEmitter entities. +- Add the smallest reliable project-storage addition needed so imported audio survives reload if that does not already exist. +- Prefer reusing any existing project asset storage introduced for GLB/GLTF import. +- Implement positional audio in the runner. +- Support at least: + - loop + - one-shot or triggered playback + - volume + - ref distance + - max distance if applicable +- Handle browser audio unlock / user gesture requirements gracefully. +- Integrate with existing trigger/action flows. +- Add `play sound` and `stop sound` actions to the existing interaction system. +- Add minimal inspector controls for sound settings. +- Persist all relevant settings through save/load. + +Important: +- Spatial audio is a core product feature. +- Keep the authoring flow understandable. +- Don’t attempt advanced occlusion or buses yet. + +Testing expectations: +- Domain tests for sound entity config +- Runtime tests for action dispatch into the audio system where practical +- Manual QA notes for real spatial verification +- Browser behavior notes for audio unlock + +Please implement fully and report: +- audio system structure +- entity fields added/used +- how browser unlock is handled +- what was tested automatically vs manually +``` + +--- + +## Prompt 11 — Wedge/ramp and cylinder prism + +```text +You are implementing the first additional brush-primitive slice. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Keep generated mesh derived from canonical primitive data. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Add two more canonical brush primitives: +- wedge / ramp +- cylinder prism + +Requirements: +- Add canonical representation for each primitive. +- Add creation workflows. +- Add viewport rendering. +- Ensure save/load support. +- Ensure runner/runtime build support. +- Reuse existing material/face systems where possible. +- Keep primitive authoring simple and explicit. +- Do not introduce arbitrary mesh editing. + +Important: +- Geometry robustness matters more than flashy UI. +- It is acceptable to ship these two primitives now and leave stairs/arch for later prompts. + +Testing expectations: +- Strong geometry tests for each primitive +- Serialization round-trip tests +- Manual verification in viewport and runner + +Please implement fully and report: +- canonical schema for each primitive +- creation UX +- any limitations in face/material support +- what tests protect geometry correctness +``` + +--- + +## Prompt 12 — Stairs primitive + +```text +You are implementing the stairs brush primitive as its own vertical slice. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Keep generated mesh derived from canonical primitive data. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Add a canonical stairs primitive. + +Requirements: +- Add canonical representation for stairs. +- Add creation workflow. +- Add viewport rendering. +- Ensure save/load support. +- Ensure runner/runtime build support. +- Reuse existing material/face systems where possible. +- Keep authoring explicit and understandable. +- Define step-count and size constraints clearly. + +Important: +- Geometry robustness matters more than flashy UI. +- Do not introduce arbitrary mesh editing. + +Testing expectations: +- Dense geometry tests for stairs +- Serialization round-trip tests +- Manual verification in viewport and runner + +Please implement fully and report: +- canonical schema +- creation UX +- any limitations in face/material support +- what tests protect geometry correctness +``` + +--- + +## Prompt 13 — Arch primitive + +```text +You are implementing the arch brush primitive as its own vertical slice. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Keep generated mesh derived from canonical primitive data. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Add a canonical arch primitive. + +Requirements: +- Add canonical representation for an arch primitive. +- Add creation workflow. +- Add viewport rendering. +- Ensure save/load support. +- Ensure runner/runtime build support. +- Reuse existing material/face systems where possible. +- Keep authoring explicit and deterministic. +- Define any segment-count or thickness constraints clearly. + +Important: +- Geometry robustness matters more than flashy UI. +- Do not introduce arbitrary mesh editing. + +Testing expectations: +- Dense geometry tests for the arch +- Serialization round-trip tests +- Manual verification in viewport and runner + +Please implement fully and report: +- canonical schema +- creation UX +- any limitations in face/material support +- what tests protect geometry correctness +``` + +--- + +## Prompt 14 — Constrained brush clipping + +```text +You are implementing a constrained v1 brush clipping slice. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Do not introduce a full convex-brush system in this slice. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Add a clip tool with predictable, undoable results under explicit constraints. + +Requirements: +- Add a clip tool workflow. +- Support at least: + - preview of the clip plane/line + - split brush or keep one side +- Store results as valid canonical brushes using currently supported brush kinds only. +- Preserve material/face information as sensibly as possible for v1. +- Ensure undo/redo is robust. +- Ensure clipped brushes save/load and run correctly. + +Scope constraint: +- Prefer a first version that clips only axis-aligned box brushes with principal-axis clip planes if that keeps the implementation reliable. +- Unsupported cases must fail clearly in the UI. + +Important: +- This is a high-risk geometry feature. +- Prefer a smaller but reliable implementation over an ambitious one. +- Be explicit about unsupported cases. + +Testing expectations: +- Geometry tests for clip results +- Command tests for undo/redo +- Manual QA for common clip flows + +Please implement fully and report: +- how clipping works internally +- what user workflow exists +- what constraints/unsupported cases remain +- what tests were added +``` + +--- + +## Prompt 15 — Better viewport layouts + +```text +You are implementing the viewport-layout ergonomics slice. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Avoid rewriting the whole viewport architecture unnecessarily. + +Current goal: +Improve level-authoring ergonomics with classic editor-style view support. + +Requirements: +- Add orthographic top/front/side views. +- If feasible, add a split multi-view layout. +- Improve camera/control ergonomics. +- Improve snapping feedback if needed to support these views. +- Preserve existing selection and tool behavior across views as much as possible. + +Important: +- This slice is about workflow speed. +- Keep the implementation understandable. +- Avoid rewriting the whole viewport architecture unnecessarily. + +Testing expectations: +- Browser/manual verification for view switching and basic authoring +- Any integration tests that are stable and worth adding + +Please implement fully and report: +- which view modes/layouts were added +- how camera handling is structured +- what manual QA scenarios were used +- any remaining rough edges +``` + +--- + +## Prompt 16 — Better material library + +```text +You are implementing Slice 5.1 — Better material library. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Preserve compatibility with the existing face-assignment workflow. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Make the material workflow fast and pleasant enough for repeated real use. + +Requirements: +- Expand the material browser with: + - categories + - tags + - search + - favorites + - recent materials +- Preserve compatibility with existing face assignment workflow. +- Keep the implementation performant for a modestly larger material set. +- Add small UI refinements necessary to make assignment fast. + +Important: +- This is a workflow slice, not a rendering-tech slice. +- Prefer fast browsing and assignment over over-designed visuals. +- Do not introduce a complicated backend or remote library system yet. + +Testing expectations: +- Domain tests for favorites/recent logic if introduced +- Browser tests for search/filter behavior if practical +- Manual QA for speed of assignment flow + +Please implement fully and report: +- material browser improvements +- data model changes +- performance considerations +- how to verify the workflow manually +``` + +--- + +## Prompt 17 — Prefab foundation + +```text +You are implementing a constrained prefab foundation slice. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Do not build a dependency-graph editor. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Make repeated reusable scene elements possible with explicit, simple semantics. + +Requirements: +- Add a prefab definition concept. +- Allow creating or registering reusable placeable prefab content. +- Allow placing prefab instances in the scene. +- Persist prefab definitions and instances through save/load. +- Add a prefab browser or equivalent UI affordance. + +Use these v1 semantics unless the repo already has a clearly compatible equivalent: +- prefab instances reference a prefab definition by ID +- instance transform is allowed +- no per-instance internal structural overrides yet +- definition changes do not silently live-update all instances; provide an explicit refresh/apply path if updates are supported + +Important: +- Keep prefab semantics simple and explicit. +- Do not build a full dependency graph editor. +- Be clear about what is supported vs deferred. + +Testing expectations: +- Serialization tests +- Domain tests for prefab instance behavior +- Manual/e2e verification for placing multiple instances + +Please implement fully and report: +- prefab data model +- instance/update behavior +- UI workflow +- limitations and deferred features +``` + +--- + +## Prompt 18 — GLB export improvements + +```text +You are implementing the first dedicated export slice. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Keep canonical JSON as the authoring format. +- If you change persisted schema, update versioning, migrations, and at least one compatibility test. + +Current goal: +Improve GLB/GLTF export from the authored scene without distorting the editor data model. + +Requirements: +- Improve or add GLB/GLTF export from the authored scene. +- Build export data downstream from the canonical document and/or runtime build. +- Preserve material, asset, animation, and scene structure as sensibly as possible. +- Add minimal export-oriented validation or diagnostics if needed. +- Do not conflate export with the canonical save format. +- Do not build a standalone packaged runner in this slice. + +Important: +- Export is downstream from the authoring document/runtime build. +- Do not distort the editor data model to match export constraints. + +Testing expectations: +- Export tests with small fixtures +- Manual verification that exported output loads in the runner or a standard viewer if applicable + +Please implement fully and report: +- export flow +- what is included vs omitted in export +- what limitations remain +- how to verify the exported result +``` + +--- + +## Prompt 19 — Scene packaging and embeddable runner + +```text +You are implementing the packaging/deployment slice. + +Read and follow: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Before coding: +- Inspect the current repo and extend the existing implementation. +- Keep this separate from canonical save/load and separate from plain GLB export. + +Current goal: +Make scenes more shareable and deployable through packaged runner output. + +Requirements: +- Clarify and implement a scene packaging path. +- Add or improve a standalone/embeddable runner route if appropriate for the current architecture. +- Package the runtime scene and required assets/materials so the result can be opened without the editor. +- Keep the implementation small and explicit. +- Add any minimal production-oriented optimization hooks that are easy and justified. +- Do not redesign the editor just to support packaging. + +Important: +- Canonical JSON remains the authoring format. +- Packaging is downstream from authoring and runtime build. +- This slice is about deployment/shareability, not about changing authoring semantics. + +Testing expectations: +- Packaging tests with small fixtures if practical +- Manual verification that a packaged scene loads in the standalone/embedded runner + +Please implement fully and report: +- packaging flow +- output options +- what is included vs omitted +- how to verify the packaged result +``` + +--- + +## Meta prompt — Audit the slice before merging + +```text +Please audit the current branch/work for architecture compliance and slice completeness. + +Read and use: +- AGENTS.md +- architecture.md +- roadmap.md +- testing.md + +Then inspect the implementation and answer these questions by making concrete improvements where needed: + +1. Does the slice work end-to-end? +2. Is the canonical document still clearly separated from three.js runtime/editor objects? +3. Are editor mutations routed through commands? +4. Are save/load and undo/redo covered where they should be? +5. If persisted schema changed, were versioning, migrations, and compatibility tests updated? +6. Are there obvious missing tests for the slice? +7. Are there speculative abstractions or dead scaffolds that should be removed? +8. Are failure modes surfaced clearly enough? +9. Does the implementation still match the intended vertical slice, without scope creep? + +Please: +- inspect the current repo first +- make targeted improvements +- remove unnecessary scaffolding if present +- add missing tests if obvious +- run the narrowest relevant checks if possible +- report remaining risks honestly +``` diff --git a/roadmap.md b/roadmap.md new file mode 100644 index 00000000..393e8d71 --- /dev/null +++ b/roadmap.md @@ -0,0 +1,606 @@ +# roadmap.md + +## Overview + +This roadmap is organized as vertical slices. +Each slice must deliver an end-to-end usable capability across: + +- document model +- commands +- viewport/editor behavior +- UI +- persistence +- runner behavior where relevant +- tests +- manual QA notes + +We optimize for: + +- proving the product loop early +- preserving architecture +- shipping coherent slices +- avoiding speculative complexity + +If a roadmap item is too large for one implementation pass, split it into smaller end-to-end sub-slices rather than landing half-systems. + +--- + +## Product north star + +A browser-based brush editor with a built-in runner, enabling users to quickly create and share lightweight interactive 3D spaces with: + +- brush-authored layout +- material/texture workflows +- imported GLB/GLTF assets +- spatial audio +- typed entities and simple interactions +- optional navigation modes + +--- + +## Early project decisions + +These are locked for the early milestones: + +- world space is **Y-up** +- early repo shape is a single Vite app with domain folders under `src/` +- canonical document state lives outside the React tree +- the document is versioned from day one +- early box brushes are axis-aligned only with fixed face IDs +- placed imported models are `modelInstances`, not `entities` +- local draft persistence plus explicit JSON import/export is acceptable early +- broad roadmap items may be split into smaller implementation chats as long as each chat still lands a coherent vertical slice + +--- + +## Milestone structure + +### Milestone 0 +Foundation and repo discipline + +### Milestone 1 +First real room: brush layout + materials + play mode + +### Milestone 2 +Entities and runtime interaction + +### Milestone 3 +Imported models, animation, and audio + +### Milestone 4 +Better brush editing and authoring ergonomics + +### Milestone 5 +Scene packaging, sharing, and quality improvements + +### Milestone 6 +Power-user systems and ecosystem growth + +--- + +## Milestone 0 — Foundation + +### Goals + +Create the minimum project skeleton that supports fast vertical slicing without overbuilding. + +### Deliverables + +- repo structure established under a single app +- TypeScript + Vite + React app booting +- three.js viewport shell visible +- thin external editor store/document skeleton +- versioned scene document and migration entry point +- command history scaffold +- local draft save/load scaffold plus JSON import/export scaffold +- test runner setup +- Playwright basic smoke setup +- docs established and aligned + +### Acceptance criteria + +- app boots locally +- empty viewport renders +- empty document loads +- command stack can push a dummy command and undo/redo +- one smoke test passes +- docs exist and are consistent + +### Out of scope + +- real geometry tools +- real runtime +- real asset import +- full inspector + +--- + +## Milestone 1 — First playable slice + +### Vision + +The user can create a box brush, assign materials to faces, save the scene, reload it, and run around it. + +This is the first proof that the product is real. + +### Slice 1.1 — Box brush authoring + +#### Deliverables + +- axis-aligned box brush schema +- stable box face IDs +- create box brush command +- select box brush +- move/resize box brush +- grid snapping +- viewport render of box brushes +- basic outliner presence +- save/load support + +#### Acceptance criteria + +- user can create at least one box brush +- box persists through save/load +- selection works reliably +- transform edits are undoable +- no arbitrary brush rotation is introduced yet + +--- + +### Slice 1.2 — Face materials and UV basics + +#### Deliverables + +- material registry +- small local starter material library +- face selection +- apply material to a single face +- basic UV controls: + - offset + - scale + - rotate 90-degree steps + - flip U/V + - fit to face by rewriting explicit UV values +- inspector integration +- material browser panel + +#### Acceptance criteria + +- user can texture a simple room quickly +- per-face assignments persist through save/load +- UV edits persist +- editor rendering reflects those changes immediately + +--- + +### Slice 1.3 — Runner v1 + +#### Deliverables + +- runtime build from document +- first-person navigation +- orbit visitor mode +- mode switch +- minimal typed `PlayerStart` support +- basic collision against axis-aligned box brush geometry +- play-from-editor action + +#### Acceptance criteria + +- user can press Run and navigate the scene +- first-person works with keyboard/mouse +- orbit visitor works +- leaving run mode returns to editor state safely +- `PlayerStart` does not need to be rebuilt later as a separate foundation + +--- + +### Slice 1.4 — End-to-end polish for “first room” + +#### Deliverables + +- status/errors panel +- document validation basics +- improved snapping feedback +- basic toolbar +- coherent save/load UX for the current persistence path +- basic scene settings if needed + +#### Acceptance criteria + +- creating a tiny room feels coherent +- failures are visible +- no obvious corruption issues +- smoke tests cover the loop + +--- + +## Milestone 2 — Entity-driven interactions + +### Vision + +The user can place non-brush entities and author simple interactive scenes without scripting. + +### Slice 2.1 — Entity system foundation + +#### Deliverables + +- typed entity base +- entity registry +- entity icons/helpers in viewport +- entity placement workflow +- entity inspector +- save/load support +- extension of the existing `PlayerStart` path rather than a parallel rewrite + +#### Initial entity types + +- PlayerStart +- SoundEmitter +- TriggerVolume +- TeleportTarget +- Interactable + +#### Acceptance criteria + +- entities can be placed, selected, edited, saved, and loaded +- runtime build can consume them +- model instances remain separate from entities + +--- + +### Slice 2.2 — Trigger -> Action -> Target foundation + +#### Deliverables + +- typed trigger/action/target schema +- action dispatch pipeline +- editor UI for linking +- runtime evaluation + +#### Initial trigger sources + +- TriggerVolume enter +- TriggerVolume exit + +#### Initial actions + +- teleport player +- toggle visibility + +Sound and animation actions are intentionally deferred until their runtime systems exist. + +#### Acceptance criteria + +- user can build a basic non-scripted interaction without code +- links survive save/load +- runtime behavior is deterministic + +--- + +### Slice 2.3 — Click interactions and runner prompts + +#### Deliverables + +- click target support +- prompt UI +- action-on-click behavior +- interaction distance settings +- compatibility with the existing trigger/action/target system + +#### Acceptance criteria + +- user can click an entity to trigger something +- prompts are understandable +- keyboard/controller fallback rules are documented + +--- + +## Milestone 3 — Assets, animation, audio + +### Vision + +The tool becomes more than brush-only by supporting imported GLB/GLTF assets and native spatial audio. + +### Slice 3.1 — GLB/GLTF import + +#### Deliverables + +- import workflow +- asset registry +- persistent project storage for imported binary data +- place imported model instance +- transform model instance +- save/load support for asset refs and model instances + +#### Acceptance criteria + +- user can import a GLB/GLTF and place it in scene +- asset metadata is preserved +- imported assets survive reload +- runtime renders imported model instances correctly + +--- + +### Slice 3.2 — Animation playback + +#### Deliverables + +- detect imported animations +- animation config on model instances or equivalent explicit target config +- play/stop animation actions +- animation trigger binding + +#### Acceptance criteria + +- imported animated asset can be triggered in runner +- editor exposes basic animation controls/settings + +--- + +### Slice 3.3 — Spatial audio + +#### Deliverables + +- audio asset import/reference +- positional emitter runtime support +- distance settings +- loop/one-shot settings +- triggerable playback +- browser audio unlock UX +- play/stop sound actions integrated into the trigger system + +#### Acceptance criteria + +- sound emits from authored world positions +- playback is spatial in runner +- author can test it locally with clear UX + +--- + +## Milestone 4 — Better brush ergonomics + +### Vision + +The editor starts feeling closer to the old-school map-editor joy. + +These roadmap items may be delivered as multiple smaller implementation chats if that produces cleaner vertical slices. + +### Slice 4.1 — More brush primitives + +#### Deliverables + +- wedge/ramp +- cylinder prism +- stairs +- arch + +#### Acceptance criteria + +- each new primitive is: + - creatable + - editable + - save/load safe + - renderable in runner + - covered by geometry tests + +--- + +### Slice 4.2 — Brush clipping + +#### Deliverables + +- clip tool +- split/keep side options +- preview visualization +- undo/redo support + +#### Acceptance criteria + +- clip operations are predictable and reversible +- resulting brushes remain valid +- unsupported clip cases fail clearly instead of silently producing ad hoc geometry + +--- + +### Slice 4.3 — Better viewport layouts + +#### Deliverables + +- top/front/side orthographic views +- optional split layout +- improved transform workflows +- configurable snapping + +#### Acceptance criteria + +- level-authoring speed materially improves +- camera controls are documented and stable + +--- + +## Milestone 5 — Material and ecosystem maturity + +### Vision + +The editor becomes attractive for repeated use, not just demos. + +These items are also likely candidates for sub-slices if needed. + +### Slice 5.1 — Better material library + +#### Deliverables + +- categories +- tags +- search +- favorites +- recent materials +- starter library expansion + +#### Acceptance criteria + +- material assignment feels fast +- modestly larger libraries remain usable + +--- + +### Slice 5.2 — Prefabs and reusable assets + +#### Deliverables + +- prefab definition support +- prefab placement +- prefab instance updating rules +- prefab browser + +#### Acceptance criteria + +- user can create or import reusable building blocks +- instances remain manageable +- update behavior is explicit and documented + +--- + +### Slice 5.3 — Export and packaging improvements + +#### Deliverables + +- GLB export improvements +- scene packaging options +- embeddable runner route or bundle +- production asset optimization hooks where easy and justified + +#### Acceptance criteria + +- user can reasonably share or deploy scenes +- runner package loads reliably in target browsers + +--- + +## Milestone 6 — Power-user growth + +### Vision + +Expand capability without compromising the core. + +### Candidate slices + +- advanced UV tools +- nav waypoints authoring +- camera zones / guided tours +- ambient zones and audio buses +- lightweight scripting +- plugin/tool API +- collaborative editing groundwork +- remote asset libraries +- scene templates/starter kits + +These are only pursued after the earlier core loop feels solid. + +--- + +## Priority order inside the roadmap + +When schedule pressure forces tradeoffs, prefer work that strengthens: + +1. edit -> save/load -> run loop +2. brush ergonomics +3. material/texture speed +4. typed entities and interactions +5. imported asset support +6. runner stability and input/audio quality +7. ecosystem niceties + +--- + +## Definition of “vertical slice complete” + +A slice is complete only when: + +- the feature is usable by a human end-to-end +- it is represented in the canonical document +- it supports save/load +- it is visible and usable in the UI +- it is test-covered appropriately +- obvious failure modes are handled +- it does not violate architecture boundaries + +--- + +## Known risk areas + +### High-risk technical areas + +- brush geometry robustness +- per-face UV persistence +- picking accuracy +- collision generation from brush data +- imported asset/material compatibility +- browser audio unlock behavior +- input edge cases across browsers +- export correctness + +### Process risks + +- overbuilding infrastructure before a slice needs it +- letting the three.js scene graph become canonical state +- adding too many entity types too early +- under-testing geometry/serialization boundaries +- chasing polish before proving workflow + +--- + +## Quality gates by milestone + +### M0 quality gate +- app boots +- empty document loads +- docs stable +- tests run + +### M1 quality gate +- user can make a textured room, save/reload it, and walk it + +### M2 quality gate +- user can place interactive entities without code + +### M3 quality gate +- user can import a GLB and combine it with brush scenes, animation, and audio + +### M4 quality gate +- editor starts feeling genuinely ergonomic + +### M5 quality gate +- project becomes reusable for real experiments / small productions + +--- + +## Deferred items list + +These are explicitly deferred unless reprioritized: + +- full multiplayer collaboration +- advanced physics gameplay +- procedural generation systems +- full scripting VM +- lightmapping pipeline +- node-based materials +- native desktop packaging as a priority +- R3F integration as a core dependency +- custom rendering backend beyond three.js + +--- + +## Expected first public “wow” moment + +The first moment that will make the product feel truly exciting is likely this: + +1. create a brutalist room with box brushes +2. texture faces quickly from the library +3. import an animated GLB sculpture or door +4. place a positional sound source +5. hit Run +6. walk through it in-browser with sound and interaction + +The roadmap should always move toward making that loop feel better. diff --git a/testing.md b/testing.md new file mode 100644 index 00000000..e3afe900 --- /dev/null +++ b/testing.md @@ -0,0 +1,649 @@ +# testing.md + +## Philosophy + +This project is a tool and a runtime. + +That means we must test both: + +- **correctness of authored data and transformations** +- **actual browser behavior experienced by the user** + +We do not rely on a single testing style. +We use a layered strategy: + +1. unit tests +2. domain/model tests +3. geometry and serialization tests +4. browser-level integration tests +5. end-to-end tests +6. manual QA for spatial/editor ergonomics + +The goal is not maximal test count. +The goal is confidence in the edit -> save/load -> run loop. + +--- + +## Testing priorities + +Highest-priority confidence areas: + +1. document validity and migrations +2. undo/redo correctness +3. brush generation correctness +4. per-face material/UV persistence +5. runtime build correctness +6. asset import survival +7. runner navigation/input reliability +8. spatial audio and interaction basics +9. critical regressions caught in CI + +--- + +## Test stack + +Recommended baseline: + +- **Vitest** for unit and integration tests +- **Vitest Browser Mode** where real browser behavior is needed at component/integration level +- **Playwright** for end-to-end testing +- optional lightweight golden fixtures for serialized documents and runtime builds + +No snapshot-heavy strategy by default. +Prefer explicit assertions over giant snapshots. + +--- + +## Global testing rules + +### Schema changes + +Whenever the persisted `SceneDocument` schema changes: + +- make the compatibility decision explicit +- bump the version when needed +- add at least one migration or compatibility test + +### Persistence coverage + +For every author-authored feature that persists: + +- add a round-trip save/load test +- cover the current persistence path used by the product at that milestone +- avoid assuming that runtime-only state is persisted + +### Small fixtures + +Prefer tiny, explicit fixtures over large assets or giant snapshots. + +--- + +## Test categories + +## 1. Pure unit tests + +Purpose: + +- fast confidence on isolated logic + +Scope: + +- math helpers +- grid snapping +- ID utilities +- small schema defaults +- validation helpers +- transform calculations +- UV helper logic +- entity defaulting logic + +Characteristics: + +- no DOM +- no WebGL +- no three.js renderer boot if avoidable +- deterministic +- extremely fast + +Examples: + +- `snapValue(1.23, 0.5) -> 1.0` +- UV rotate/flip calculations +- entity schema default application +- command label generation if logic matters + +--- + +## 2. Domain/model tests + +Purpose: + +- validate the canonical document model and command behavior + +Scope: + +- document factories +- migrations +- command execution +- command undo/redo +- selection semantics where model-driven +- validation rules + +Examples: + +- create brush command adds valid brush +- undo removes it cleanly +- redo restores the same result +- invalid entity reference is detected +- old scene version migrates correctly + +These tests should not need a browser renderer. + +--- + +## 3. Geometry tests + +Purpose: + +- verify brush/kernel correctness + +Scope: + +- primitive generation +- face generation +- topology expectations +- collision mesh generation +- UV projection generation +- clipping results +- derived mesh determinism + +Examples: + +- box brush creates expected face count +- stairs generator creates expected step count +- fit-to-face UV produces finite values +- clipping yields valid child brushes +- generated geometry contains no NaNs +- rebuild is deterministic for the same input + +### Geometry test principles + +- assert invariants, not fragile exact arrays unless necessary +- prefer bounded numeric comparisons +- verify no degenerate triangles where required +- test edge cases: tiny sizes, rejected zero-like values, unsupported cases failing clearly + +Geometry is a high-risk area and deserves dense testing. + +--- + +## 4. Serialization tests + +Purpose: + +- ensure document persistence is trustworthy + +Scope: + +- save/load round trips +- migration paths +- invalid file handling +- missing refs behavior +- canonical normalization if any + +Examples: + +- scene round-trips without losing face materials +- UV state survives save/load +- imported asset refs survive save/load +- unsupported version throws an understandable error +- migration from v1 to v2 preserves semantics + +### Required pattern + +For every substantial document feature, add at least: + +- one round-trip save/load test +- one migration or backward-compatibility consideration if schema changed + +--- + +## 5. Browser integration tests + +Purpose: + +- verify real browser behavior that pure tests cannot cover + +Use for: + +- pointer interactions +- keyboard shortcut handling +- focus issues +- canvas/UI interaction boundaries +- panel interactions +- browser API edge behavior +- audio unlock flows where practical +- pointer lock flows where practical + +Examples: + +- clicking viewport selects a brush +- dragging a gizmo updates inspector values +- applying material through UI changes a selected face +- entering play mode mounts the runtime canvas +- pointer lock request path is handled correctly + +--- + +## 6. End-to-end tests + +Purpose: + +- verify the actual user flows across the product + +Playwright covers: + +- page loading +- cross-browser execution +- real input simulation +- visible UI assertions +- route/deployment behavior +- screenshot and trace capture on failures + +### Required e2e flows for early milestones + +#### E2E-01 Empty app boots +- app loads +- viewport visible +- no fatal console errors + +#### E2E-02 Create box brush +- create box brush +- select it +- persist through the current save path +- reload +- brush still exists + +#### E2E-03 Apply material +- create room or brush +- assign material to a face +- persist through the current save path +- reload +- material persists + +#### E2E-04 Run scene +- place `PlayerStart` +- enter run mode +- runtime loads +- first-person or orbit mode active + +#### E2E-05 Import asset +- import test GLB +- place a model instance +- reload +- instance remains visible + +#### E2E-06 Trigger action +- create trigger and target +- run scene +- activate trigger +- target effect occurs + +These flows should expand with milestones. + +--- + +## 7. Manual QA + +Some qualities are hard to fully automate, especially in spatial tools. + +Manual QA is required for: + +- authoring feel +- camera comfort +- snapping quality +- transform ergonomics +- texture workflow speed +- runtime movement feel +- browser UX polish +- spatial audio perception + +### Manual QA checklist style + +Every slice should include: + +- setup +- expected steps +- expected result +- known limitations +- browser(s) tested +- screenshots or short recordings if helpful + +--- + +## Test directory guidance + +Suggested structure: + +```txt +src/ + ... +tests/ + unit/ + domain/ + geometry/ + serialization/ + browser/ + e2e/ +fixtures/ + documents/ + assets/ + exports/ +``` + +Alternative layouts are fine if the categories remain conceptually clear. + +--- + +## Naming conventions + +Use descriptive names. + +Good: + +- `create-box-brush.command.test.ts` +- `scene-roundtrip.materials.test.ts` +- `runtime-trigger-teleport.e2e.ts` + +Bad: + +- `misc.test.ts` +- `editor2.test.ts` +- `utils.spec.ts` + +Test names should tell a future reader: + +- what behavior is being protected +- what broke if it fails + +--- + +## Core invariants to protect + +The following invariants are important enough to deserve repeated coverage: + +### Document invariants + +- IDs are unique +- references resolve or fail clearly +- version is known/migratable +- entity payload matches type schema +- model instances are not mixed into entity collections + +### Command invariants + +- execute changes state correctly +- undo restores previous state +- redo reproduces execute result +- command history remains coherent + +### Geometry invariants + +- generated meshes contain finite numeric values +- expected face counts/topology rules hold +- collision/output is deterministic +- invalid inputs fail safely + +### Serialization invariants + +- save/load preserves semantics +- unsupported versions do not silently corrupt +- migrations are explicit and tested +- binary asset persistence survives the current project-storage strategy + +### Runtime invariants + +- runner loads valid scenes +- missing optional systems fail gracefully +- navigation controller activation is exclusive and consistent +- interactions target the correct entities or model instances + +--- + +## What to unit test vs what to e2e test + +### Unit test + +When logic is: + +- deterministic +- isolated +- data-heavy +- performance-sensitive +- easier to debug outside the browser + +Examples: + +- brush face generation +- UV transforms +- validation +- migrations +- command sequencing + +### E2E test + +When behavior depends on: + +- actual browser input behavior +- canvas and DOM interaction +- route/app boot +- browser APIs +- focus/pointer lock/input timing +- asset load flows + +Examples: + +- selecting and moving things via UI +- entering play mode +- first-person input behavior +- import workflow if browser-exposed +- prompt/click interactions + +--- + +## Fixture strategy + +Use small, explicit fixtures. + +### Document fixtures + +- minimal empty doc +- one-box-room +- textured-room +- trigger-scene +- imported-asset-scene +- migration-old-version scene + +### Asset fixtures + +- tiny GLB static mesh +- tiny GLB animated mesh +- simple audio file +- placeholder textures + +Keep fixtures: + +- tiny +- deterministic +- checked into the repo when legally safe +- documented + +Do not use giant random assets in core CI. + +--- + +## Browser support testing + +At minimum, regularly test in: + +- Chromium +- Firefox +- WebKit where relevant + +Not every test must run in every browser in every iteration, but critical e2e coverage should include cross-browser confidence at appropriate cadence. + +Early CI suggestion: + +- smoke in Chromium on every push +- broader cross-browser on main branch / PR gate / nightly depending on cost + +--- + +## CI expectations + +Baseline CI pipeline should include: + +1. install +2. typecheck +3. lint +4. unit/domain/geometry/serialization tests +5. browser integration tests where stable +6. Playwright smoke/e2e subset +7. test artifact upload on failure + +### Required artifacts on e2e failure + +Capture where possible: + +- screenshots +- traces +- video if worth the storage cost +- console logs +- failed document/export fixture if relevant + +These artifacts materially reduce debugging time. + +--- + +## Performance testing + +Do not overcomplicate early performance testing, but do track basic regressions. + +Recommended early checks: + +- app boot time smoke metric +- scene build time for a representative small scene +- brush rebuild time for representative test cases +- asset import of a small reference GLB +- runtime frame stability in a standard test scene + +This can begin as manual/dev benchmarking and later become more formal if needed. + +--- + +## Audio testing notes + +Spatial audio is important, but automated audio verification is limited. + +### Automate what we can + +- sound entities load +- trigger paths call correct audio system methods +- invalid audio refs surface errors +- autoplay rules behave as expected in app state + +### Manually verify + +- perceived spatial positioning +- distance attenuation feel +- loop transition quality +- browser-specific unlock friction + +Include manual audio QA notes in slices touching audio. + +--- + +## Input testing notes + +Input in browser apps is full of edge cases. + +Explicitly test: + +- keyboard focus transitions +- pointer lock enter/exit +- escape handling +- canvas vs panel focus +- gamepad absent/present behavior +- drag cancellation when pointer leaves element/window + +Where automating is hard, document the manual verification steps. + +--- + +## Regression policy + +Every bug fix should add one of: + +- a unit/domain/geometry test +- a browser integration test +- an e2e test +- a documented manual regression step if automation is genuinely not feasible yet + +Do not accept “fixed” without protecting against recurrence. + +--- + +## Done criteria from a testing perspective + +A slice is not done until: + +- happy path is covered +- one obvious failure path is covered +- save/load or persistence path is covered if the feature is author-authored +- manual QA notes are written +- test commands are documented if new setup is needed + +--- + +## Minimum test commands to maintain + +Keep the project easy to verify. + +Recommended scripts: + +```json +{ + "test": "vitest run", + "test:watch": "vitest", + "test:browser": "vitest --browser --run", + "test:e2e": "playwright test", + "test:e2e:ui": "playwright test --ui", + "test:typecheck": "tsc --noEmit" +} +``` + +Exact commands may evolve, but the repo should always expose a simple path for: + +- fast local checks +- browser checks +- e2e checks +- CI checks + +--- + +## What we do not test aggressively yet + +Initially, avoid over-investing in: + +- screenshot snapshot forests +- fragile pixel-perfect rendering tests +- massive browser matrix on every commit +- giant scene stress tests before the core workflow is stable +- plugin systems we do not yet have + +Test the heart of the product first: + +- data integrity +- brush correctness +- interaction correctness +- runtime usability