Files
webeditor3d/AGENTS.md

15 KiB
Raw Blame History

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
    • CHAT_CONTEXT.md
    • then inspect the relevant sections of architecture.md, roadmap.md, and testing.md for the active slice
    • if a slice touches persistence, runtime, or testing boundaries in a non-obvious way, read the relevant full doc sections before changing code
  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 editors 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