280 lines
9.2 KiB
Markdown
280 lines
9.2 KiB
Markdown
# AGENTS.md
|
||
|
||
## Purpose
|
||
|
||
This is the mandatory high-signal brief for agents working in this repo.
|
||
|
||
Read this file first.
|
||
Then read `CHAT_CONTEXT.md`.
|
||
After that, inspect the code and open only the relevant sections of `architecture.md`, `roadmap.md`, and `testing.md`.
|
||
|
||
Do not read the large docs end-to-end by default.
|
||
|
||
When docs and code disagree:
|
||
|
||
1. trust the code for current behavior
|
||
2. trust `AGENTS.md` + `CHAT_CONTEXT.md` for current intent
|
||
3. use the larger docs as selective reference
|
||
4. update stale docs if your slice materially changes behavior
|
||
|
||
---
|
||
|
||
## Product
|
||
|
||
This repo is a browser-based engine/editor for interactive 3D environments with a built-in runner.
|
||
|
||
Core loop:
|
||
|
||
1. author
|
||
2. save/load
|
||
3. run immediately in-browser
|
||
|
||
Primary product priorities:
|
||
|
||
- intuitive whiteboxing / level blocking
|
||
- imported assets as first-class content
|
||
- typed entities and simple interactions
|
||
- very fast edit -> run iteration
|
||
- web-native delivery and sharing
|
||
|
||
This is not:
|
||
|
||
- a Blender replacement
|
||
- a general CAD tool
|
||
- an unlimited engine platform
|
||
- a full physics sandbox unless the roadmap explicitly says so
|
||
|
||
---
|
||
|
||
## Hard Rules
|
||
|
||
### Canonical state
|
||
|
||
- The canonical `SceneDocument` / project state is the source of truth.
|
||
- Do not store three.js objects in canonical document state.
|
||
- Do not make the three.js scene graph the source of truth.
|
||
- Editor-authored mutations should go through commands.
|
||
|
||
### Layering
|
||
|
||
- `document` owns canonical state
|
||
- `commands` own undoable mutations
|
||
- `geometry` owns derived solid/mesh/collider generation
|
||
- `viewport-three` owns editor rendering and interaction helpers
|
||
- `runtime-three` owns play-mode runtime behavior
|
||
- `entities` own typed non-model scene objects
|
||
- `assets` own imported external resources and adapters
|
||
- `serialization` owns save/load/versioning/migrations
|
||
|
||
### Persistence
|
||
|
||
- The document is versioned from day one.
|
||
- If persisted schema changes, update version/migration/validation and add at least one compatibility test.
|
||
- Canonical save format is project JSON.
|
||
- Once binary assets matter, user-facing save/load must be a portable project package containing canonical JSON plus referenced assets.
|
||
- Runner/deployment output is separate from editable save/load.
|
||
- Never rely on Blob URLs as the only persisted asset reference.
|
||
|
||
### Models, entities, world
|
||
|
||
- Imported assets live in the asset registry.
|
||
- Placed imported models live in `modelInstances`.
|
||
- `modelInstances` are not `entities`.
|
||
- Typed runtime/editor objects such as `PlayerStart`, `TriggerVolume`, and lights live in `entities`.
|
||
- Global ambient/sun/background/fog belong in `world` settings.
|
||
- Local authored lights belong in typed entity schemas.
|
||
|
||
### Project time and living-world direction
|
||
|
||
- Project time is a global project-level system, not a separate main clock per scene.
|
||
- Scene world settings may opt in/out of time-driven lighting, but scenes should not own independent core time progression.
|
||
- Near-term time slices should prioritize authored day/night control:
|
||
- sunrise/sunset
|
||
- day phases
|
||
- night/dawn/dusk appearance
|
||
- scene-level lighting opt-in/out
|
||
- Do not build a large generic schedule editor before the runtime hooks it would drive are real.
|
||
- The shared control surface and scheduler/notebook foundations now exist; extend them instead of adding new parallel time-orchestration paths.
|
||
- Long-term world logic should resolve deterministically from:
|
||
- global time
|
||
- persistent/cycle flags
|
||
- scene/location context
|
||
- Prefer deterministic resolution over fully simulating unloaded scenes.
|
||
- The scheduler/notebook should be the default authoring surface for time-based orchestration.
|
||
- Do not keep adding one-off per-entity or per-system time fields once a scheduler/control-surface path exists.
|
||
- When a new typed runtime/editor capability is added and it is meaningfully time-steerable, extend the control surface and make it schedulable in the same direction of work or document clearly why it is intentionally deferred.
|
||
- Treat this as a product rule, not a nice-to-have:
|
||
- new schedulable capability -> control-surface support
|
||
- control-surface support -> scheduler/notebook availability
|
||
- NPC presence, routines, dialogue variants, interaction availability, and path progress should eventually be reconstructible from authored rules plus global state.
|
||
- If loop/reset mechanics are added later, they should reset/re-resolve cycle-scoped state rather than trying to rewind arbitrary runtime simulation.
|
||
|
||
### Dialogue direction
|
||
|
||
- Dialogue content should remain authored data, not ad hoc runtime-only strings.
|
||
- New dialogue work should prefer reusable authored resources and references over NPC-only bespoke fields.
|
||
- NPCs, interactions, triggers, scheduler/sequencer layers, and later event-driven systems should be able to consume the same dialogue foundations where appropriate.
|
||
|
||
### Imported model collision
|
||
|
||
- Collision authoring for imported models belongs on `modelInstances`, not assets.
|
||
- Supported imported-model collision modes must stay explicit and typed.
|
||
- Generated collision data is derived data, not canonical source data.
|
||
- If broad-phase/narrow-phase pruning or non-box collider support is needed, prefer Rapier over custom collision math.
|
||
- Collision mode meanings are fixed unless deliberately changed:
|
||
- `none` = no collider
|
||
- `terrain` = heightfield collider, static only
|
||
- `static` = triangle mesh collider, fixed only
|
||
- `static-simple` = voxel-boxified fixed compound collider for static environment use
|
||
- `dynamic` = convex decomposition into compound collider, dynamic/kinematic capable
|
||
- `simple` = one cheap primitive or one convex hull
|
||
|
||
### Whiteboxing direction
|
||
|
||
- The product is moving away from grid-bound brush thinking toward whitebox solids.
|
||
- Floating point position/rotation/scale are allowed.
|
||
- The grid is a snap/reference helper, not a hard law.
|
||
- Whiteboxing should converge on one coherent transform-driven interaction model.
|
||
- Object / face / edge / vertex editing are valid goals.
|
||
- Non-planar quads are acceptable if derived triangulation is deterministic.
|
||
- Whitebox solids do not have to remain convex.
|
||
- Collision should come from the solid collider path, not old axis-aligned assumptions.
|
||
|
||
---
|
||
|
||
## Implementation Strategy
|
||
|
||
### Default workflow
|
||
|
||
1. Inspect the current repo first.
|
||
2. Extend the existing implementation.
|
||
3. Keep the slice as small and vertical as possible.
|
||
4. Reuse existing paths instead of adding parallel architecture.
|
||
5. Verify with the narrowest relevant checks.
|
||
|
||
### Vertical slices
|
||
|
||
Good slice:
|
||
|
||
- document changes
|
||
- commands
|
||
- viewport/editor behavior
|
||
- UI
|
||
- persistence
|
||
- runner behavior if relevant
|
||
- tests
|
||
- brief manual QA notes
|
||
|
||
Bad slice:
|
||
|
||
- scaffolding with no user-facing payoff
|
||
- duplicate systems
|
||
- speculative abstractions
|
||
|
||
### Read selectively
|
||
|
||
Only open full reference sections when needed:
|
||
|
||
- `architecture.md` for non-trivial runtime/editor/data-model boundaries
|
||
- `roadmap.md` for future direction and accepted scope
|
||
- `testing.md` for which test layers to add
|
||
|
||
If the slice is local and obvious, do not reload half the repo’s docs.
|
||
|
||
---
|
||
|
||
## Code Rules
|
||
|
||
### Do
|
||
|
||
- use TypeScript only
|
||
- keep types explicit
|
||
- prefer pure functions for transforms/build steps
|
||
- isolate browser/three.js side effects
|
||
- fail loudly in development
|
||
- surface useful diagnostics instead of silently ignoring errors
|
||
- keep geometry/collision generation testable outside the browser where practical
|
||
|
||
### Don’t
|
||
|
||
- add R3F casually
|
||
- add ECS casually
|
||
- over-generalize the entity system
|
||
- replace canonical whitebox data with hidden renderer-only mutations
|
||
- invent hidden magic behavior without schema support
|
||
- remove tests to get green CI
|
||
- silently corrupt state on failure
|
||
|
||
---
|
||
|
||
## UX Rules
|
||
|
||
Prioritize:
|
||
|
||
- fast selection
|
||
- direct transforms
|
||
- understandable tool state
|
||
- visible feedback
|
||
- quick play testing
|
||
- clear failure modes
|
||
|
||
Every meaningful feature should answer:
|
||
|
||
- what the user sees
|
||
- what the user clicks/drags/types
|
||
- how it is undone
|
||
- how failure is shown
|
||
- how it is tested
|
||
|
||
---
|
||
|
||
## Testing Rules
|
||
|
||
At minimum, match the slice:
|
||
|
||
- pure/domain tests for deterministic logic
|
||
- serialization tests for persisted features
|
||
- runtime/build tests where runtime behavior changes
|
||
- browser/e2e only when real browser behavior matters
|
||
|
||
If schema changes:
|
||
|
||
- add round-trip coverage
|
||
- add migration/compatibility coverage
|
||
|
||
Prefer small explicit fixtures over giant snapshots.
|
||
|
||
---
|
||
|
||
## Vocabulary
|
||
|
||
Use precise terms:
|
||
|
||
- `Document`: canonical editor state
|
||
- `Whitebox Solid`: author-authored blockout / gameplay-space solid
|
||
- `Box Solid`: the first whitebox solid shape; old code may still say “box brush”
|
||
- `Face` / `Edge` / `Vertex`: editable parts of a whitebox solid
|
||
- `Asset`: imported external resource
|
||
- `Model Instance`: placed instance of an imported asset
|
||
- `Entity`: typed scene object with editor/runtime semantics
|
||
- `Collider`: derived runtime collision representation
|
||
- `Project Package`: portable editable bundle
|
||
- `Runner Package`: deployable playable output
|
||
- `Build`: deterministic document -> runtime transformation
|
||
|
||
Avoid vague terms like “thing” or “object” when a domain term exists.
|
||
|
||
---
|
||
|
||
## Required Closeout
|
||
|
||
For meaningful changes, report briefly:
|
||
|
||
1. what changed
|
||
2. why
|
||
3. files touched
|
||
4. how you verified it
|
||
5. known limitations
|
||
|
||
If you could not verify something, say so plainly.
|