engine-package
暂无简介
- License 许可
- GPL-3.0
- 所属仓库
- xirtus/3JSE
- 最近更新
- 2026-10-20
- Stars
- ★ 2
- Forks
- 0
03 SKILL.md 正文
Engine Package
Use when the task is to build or change a @3jse/* engine package (or the editor app) in this monorepo — as opposed to building a game with Three.js, which is what 3jse-director and the provider skills cover. Load on demand; do not keep in always-on context.
docs/ROADMAP.md is the sequencing contract; docs/ARCHITECTURE.md + docs/GAMEPLAY_IR.md + docs/ENTITY_COMPONENT_MODEL.md are read before writing engine code. This skill is the repo conventions those docs assume but don't spell out.
Reuse ladder, engine edition
-
An existing
@3jse/*package already covers the capability. Searchpackages/*/srcfirst. Current map (keep updated as packages land):Capability Package World / Level / Entity / Component / Scheduler / Prefab / Input @3jse/runtimeGameplay IR (frontend + interpreter + JS emitter + source map) @3jse/irNode canvas over the IR @3jse/graphglTF/GLB import, thumbnails, metadata, character detection @3jse/assetsProject save/load in the PROJECT_FORMAT.mdtree@3jse/projectCharacter controller + camera rig @3jse/characterAnimation state machine + blend tree + TwoBoneIK @3jse/animationRapier physics integration @3jse/physics-rapierSave games (tagged-component snapshots) @3jse/saveSpawn points + object pooling @3jse/spawningStarter templates (Third Person, …) @3jse/templatesNetcode: replication, authority, prediction, RPC, priority/bandwidth, lag comp, WebSocket transport @3jse/networkingTimeline / sequencer runtime @3jse/cinematicsShareable-URL snippet sandbox @3jse/playgroundInput recording + deterministic replay @3jse/replayMCP-shaped agent tool server @3jse/agentSemantic system model / FeelSpec / Atlas graph compiler / agent-scoping @3jse/atlasPlugin manifest / host / extension-point versioning / package catalog @3jse/pluginsPublish pipeline: tree-shake, asset finalize, manifest, notices, static-host files @3jse/packagingAudio: bus mixer, AudioSource/Listener/ReverbZone, event router, musical grid + MIDI/OSC @3jse/audioUI/HUD: retained widget tree, flexbox-subset layout, data binding, hit-test, renderer seam @3jse/uiMaterial Graph -> TSL codegen + CPU reference evaluator + validation @3jse/materialsTerrain: heightfield sampling, chunk mesher, LOD, bounded-residency streamer @3jse/terrainFoliage: deterministic field scatter -> InstancedMesh instance data @3jse/foliageNavigation: grid bake / A* + string-pull / flow field / NavAgent / PolyNavMesh seam @3jse/navPolygon navmesh bake from THREE geometry via recast-navigation-js -> PolyNavMesh @3jse/nav-recastProvider-agnostic LLM chat client (OpenAI / Anthropic / DeepSeek / Gemini / OpenRouter / Groq / Ollama / any OpenAI-compatible) @3jse/llmParticles/VFX: CPU SoA sim, curves/gradients over life, ParticleEmitter component/system @3jse/vfxTHREE-side render bridges: terrain chunks / foliage InstancedMesh / particle Points from the headless cores @3jse/render3jseCLI: publish (runs @3jse/packaging + esbuild) / info@3jse/cliVendored MIT ecosystem libs (mesh-bvh, troika text, postprocessing, …) @3jse/extrasVendor registry + fetcher; Tier A wraps (poseidon/gaia/dryad/demiurge) @3jse/vendor,@3jse/water-poseidonetc. -
A sibling package's pattern (copy the shape, not a dependency edge you don't need).
-
A reference game in
docs/REFERENCE_GAMES.md(dambeavers ECS core, 3jsurf headless tools, …). -
Custom — last resort, with a one-line justification in the package's index/header comment.
Non-negotiable conventions (proven by the packages that already pass)
- Headless-first. Gameplay/logic code runs with no renderer, no canvas, no DOM.
World.step(dt)is caller-driven, neverrequestAnimationFrame-owned. A package that can't be exercised in a plain vitestnodetest is wrong. Physics is the only async seam (Rapier WASM init) — isolate it. - Components are plain JSON data. Primitives, arrays, plain objects, entity-id strings. No functions, Maps, or class instances in component data. Behaviour lives in Systems, not component methods.
- Register components as an import side effect. Every package with components does
import "./components.js"(or./systems.js) from itsindex.ts, and that module callsregisterComponent(...)at module scope. Matches@3jse/runtime's own builtins. Consumers get a working component set just by importing the package. Object3Dis the Transform. Spatial entities store position/rotation/scale onentity.object3Ddirectly — never a parallel copy. Non-spatial entities ({ spatial: false }) haveobject3D === nulland are not in the render scene.- Import from
three/webgpu, never barethree, in any package that touches the scene graph — they are non-identical builds and mixing specifiers creates twoObject3Dclasses. .jsextensions in relative TS imports (./foo.jseven though the file isfoo.ts) — the repo'smoduleResolution: "Bundler"+isolatedModulessetup requires it. Copy an existing package'simportlines.- Scheduler stage + registration order is load-bearing. Stages run
fixed → variable → late; within a stage, systems run in registration order. Kinematic movement (@3jse/character) registers before@3jse/physics-rapier's system so the move is queued beforephysics.step()commits it. Document any ordering dependency in the system factory's doc comment. - Determinism. Seed RNG; route time-scaling through one
worldDt = dt * scaleclock; make structural results reproducible. Replay/ghost/netcode all assume it. - Stable ids on load.
createEntity/createLevelaccept an optionalidso a loader (@3jse/project) rehydrates persisted ids instead of session-local counters. Don't reintroduce a hidden global counter as the only id source. - Testability via a virtual filesystem. Anything that reads/writes project files works over a
Record<path, string>map (see@3jse/project), so it's testable with no disk and is "recoverable without the editor" (PROJECT_FORMAT.md).
Package scaffold
packages/<name>/:
package.json—"name": "@3jse/<name>","type": "module","main"/"types": "./src/index.ts",exports: { ".": "./src/index.ts" }, scriptstypecheck(tsc --noEmit -p tsconfig.json) +test(vitest run), deps onworkspace:*siblings, dev-depstypescript+vitest(+@types/threeif it imports three).tsconfig.json—{ "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "dist", "rootDir": "src" }, "include": ["src"] }.src/index.ts— the public barrel; explicit re-exports; the component-registration side-effect import last.src/*.test.ts— at least a smoke/round-trip test per module sopnpm -r teststays a real gate.- After scaffolding:
pnpm install(links the workspace), thenpnpm --filter @3jse/<name> typecheck && pnpm --filter @3jse/<name> test.
Evidence for engine work (not the game evidence report)
A game task uses templates/EVIDENCE_REPORT.example.md (core loop, screenshots, draw calls). Engine-package / roadmap-spike work uses instead:
- The phase/deliverable's exit criterion, quoted, then met / partially met / not met with specifics.
- A round-trip or invariant proof where the claim is structural (serialize→load→serialize byte-identical; parse→emit→re-parse behaviourally identical; N-frame headless sim settles / stays within bounds).
- A benchmark table where the claim is performance (min/avg/p95/max, % of frame budget, hardware named).
- A routing ledger (rung-0 search result · chosen approach · why · fallback).
- Written to
evidence/phase<N>-<slug>.mdand one line inBUILD_TASKS.md(phase · task · status · evidence file · commit).
Verify before claiming done
pnpm -r typecheckclean (includesapps/editor).pnpm -r testgreen — if it's red for an infrastructural reason (a package's vitest globbing vendored files), fix that first; a red workspace gate hides real regressions.pnpm --filter @3jse/editor buildstill succeeds if runtime/any editor dep changed.node 3JSE_Harness_v0.2/scripts/verify-harness.mjsPASS.- New package added to this skill's rung-0 table and to
docs/FILE_INDEX.txtif it's a harness file (engine packages underpackages/are not).