From f6904445d8628477af5a1b4b70c5cea475a751ae Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Fri, 18 Sep 2026 18:11:44 +0200 Subject: [PATCH] Physics stage 1a: new page Physics, Rigidbody and collider material in Colliders, Concepts, Home, Sidebar and Architecture, check total 1052 (#146) --- Architecture.md | 10 ++++-- Colliders.md | 15 +++++---- Concepts.md | 1 + Development.md | 2 +- Home.md | 1 + Physics.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ _Sidebar.md | 1 + 7 files changed, 109 insertions(+), 10 deletions(-) create mode 100644 Physics.md diff --git a/Architecture.md b/Architecture.md index ec3d70d..fcd7db6 100644 --- a/Architecture.md +++ b/Architecture.md @@ -67,7 +67,7 @@ ``` web/index.html Vite source page (dev) index.html built page (generated, served) src/core/model/ Project (object holders), Asset + AssetTypes, SceneObject, Properties (value types), hierarchy, walk (generic parent/child walks), instance (container content resolved from its template), usages (where an asset is used), container (the cycle guard), placement (what may be dropped where), texture (frames and the slice grid), tile (the three kinds and their block shapes, reading a tile's pictures, the animation step), autotile (which quarter tile a neighbourhood asks for, the 47/16 tiles a block produces, 1 for a plain tile), tilemap (the cells of a layer, which neighbours a cell is joined to, the cells a stroke or a rectangle covers), tilemapCollision (the solid cells of a map, drawn in or out by their tile's collision scale and merged into rectangles, and where one sits in the world), animation (which frame at time t, a row's value there, what a row may aim at, the players on an object; KeyRef and its lookups) + animationPreview (the root at a frame, written into copies), graphLookup (what a graph sees of the project: behaviors to run, state machines to read), Scope (where a state machine's current state lives: per instance or one for the run — variables are shared by living on a Variables asset instead) -src/core/properties/ PropertySchema, kinds (one row per value kind), listItems (an item's kind, read off its value), resolve (the only override merge), deviation (what is gold), collider/camera/bounds geometry, aspect, enabled, editorRun, assetRef/textureRef (how a reference reads), declaredRows (the row a Property node declares in a shader or particle graph, and the params that node has in both) +src/core/properties/ PropertySchema, kinds (one row per value kind), listItems (an item's kind, read off its value), resolve (the only override merge), deviation (what is gold), collider/camera/bounds geometry, rigidbody (what the engine reads off a rigidbody, a collider's material and the scene), aspect, enabled, editorRun, assetRef/textureRef (how a reference reads), declaredRows (the row a Property node declares in a shader or particle graph, and the params that node has in both) src/core/commands/ undoable commands, CommandStack, SetBagValueCommand base, RenameCommand base (undone by renaming back: variable, struct field, port), one import command shape for texture/font/sound, require.ts (validated lookups, and what an instance may not change), naming.ts src/core/graph/ graph model, NodeRegistry/NodeContext/values, interpreter, dropTarget, nested (behaviors as nodes), emitGraph (the walk both graph compilers share: each node once, in dependency order; cycles and property names reported), @@ -80,9 +80,13 @@ src/core/store/ serialize (untrusted JSON → Project), tilemapCells (the FileStore (what the server holds of one kind) + HttpFileStore (one generic client over the three file collections) — TextureStore, FontStore and SoundStore are its type parameters, nothing else src/core/time.ts the global clock: one scaled step a frame, shared by the world, the particles, the shaders and the animation preview -src/runtime/ World, Entity, System interface, Input tracker, CollisionSystem, AnimationSystem, BehaviorSystem, +src/runtime/ World, Entity, System interface, Input tracker, CollisionSystem (the editor run's detection), + solids (what `Move` collides with and how it slides, which body a collider belongs to, the + CollisionSource both collision systems give the behaviors), AnimationSystem, BehaviorSystem, Audio (the AudioSink a run plays into — the counterpart of Input on the way out) -src/runtime/physics/ engine (loads Rapier once, reports its state, converts between pixels and metres) +src/runtime/physics/ engine (loads Rapier once, reports its state, converts between pixels and metres), + PhysicsSystem (Play's collisions: one engine body per rigidbody, free collider and tilemap, + the fixed step, the poses handed back, the contact pairs sorted into events) src/ui/ widget toolkit (generic, knows nothing about assets) src/viewport/ view (transforms), items (what to draw), symbols (how to draw it), FileLibrary (load once, never retry a failure, tell the listeners) ← TextureLibrary, FontLibrary; diff --git a/Colliders.md b/Colliders.md index 9021d47..4a5f942 100644 --- a/Colliders.md +++ b/Colliders.md @@ -4,19 +4,22 @@ from that *body* and it moves with it. Right-click an object in **Scene objects* collider* to get one with one click: a box collider sized like the sprite, parented at its centre. Colliders can be reused across objects, overridden per instance and stacked (hitbox + hurtbox on one sprite; colliders of the same body never collide with each -other). They are editor symbols: green outlines in edit mode, invisible in play mode. +other). They are editor symbols: green outlines in edit mode, invisible in play mode. Three more rows – +friction, bounciness, density – are the material a rigidbody feels (see [Physics](Physics)). A collider takes the transform of its body: a box turns and grows with the sprite it sits on, a circle grows (see *Transform* in [Scene editing](Scene-editing)). A turned box is tested as the box it is — separating axes, not its upright frame — so a wall turned by 45 degrees blocks along its slant. -Play runs a `CollisionSystem` (`src/runtime/systems/CollisionSystem.ts`) before the behaviors: -every frame it tests all collider pairs (world transforms applied; touching edges do not count) -and sorts them into *enter*, *stay* and *exit*. Detection never pushes anything apart. A -behavior receives `On collision enter/stay/exit` for the colliders of its **owner** (its +Before the behaviors, every frame sorts the colliders that overlap (world transforms applied; +touching edges do not count) into *enter*, *stay* and *exit*. While playing that is the physics +engine's work (`PhysicsSystem`, see [Physics](Physics)), which also simulates rigidbodies; the +editor run tests all pairs itself (`CollisionSystem`) and pushes nothing. Without a rigidbody +both come to the same answer. A behavior receives `On collision enter/stay/exit` for the colliders of its **owner** (its parent; itself when top-level): the outputs are `other` (the other body), `other collider` -and `collider` (the own one). `Is touching(a, b)` answers the same question on demand — an +and `collider` (the own one); while playing, `On collision enter` also tells the direction and +the strength of the contact (see [Physics](Physics)). `Is touching(a, b)` answers the same question on demand — an object stands for its collider children, a collider for itself. The geometry lives in `src/core/properties/collider.ts` so editor and runtime agree on it. diff --git a/Concepts.md b/Concepts.md index 42d8fb4..a10bf4c 100644 --- a/Concepts.md +++ b/Concepts.md @@ -16,6 +16,7 @@ | **Variables asset** | Declarations and nothing else — no graph, no position, never placed. A `Variables` node naming it reads and writes **one value per key for the whole run**, however many graphs point at it. The values start at the declared ones on every Play and are never written back, so playing cannot change the project; while a run is on the asset's inspector shows them live and an edit there reaches the run at once. Two such assets may declare the same name without meeting. See [Behaviors](Behaviors). | | **Run in editor** | A switch only behaviors have (default off). With it on the behavior keeps running while the project is **not** playing — and unlike Play it then edits the *saved* model: what it moves or writes is a real change, autosaved and not on the undo stack. See *Running without Play*. | | **Collider** | A shape (box or circle) for collision detection, placed as a **child** of the object it belongs to (its *body*). Drawn as a green outline in edit mode only. | +| **Rigidbody** | Placed as a **child** of an object, it hands that object to the physics engine while playing: it falls with the scene's gravity, bounces and rests on colliders, pushed by what it meets. At most one per object. See [Physics](Physics). | | **Override** | A per-object value that replaces the asset's value for one property. Only changed keys are stored; the inspector paints their label gold and offers a reset (↺) and an **apply** (↑) that writes the value into the asset instead. Both appear only where the value really differs from its base — an override carrying the asset's own value is none. | | **Default** | Every property has a schema default. Asset values that differ from it are marked gold in the inspector and can be reset (↺) the same way an override can. The asset's name in the **Assets** panel carries the same gold while any of them does (`assetDeviates`, `src/core/properties/deviation.ts` — the inspector marks the rows of that same schema, so the list cannot claim a deviation the inspector then fails to show). A behavior's variables are not in it: their default is declared on the variable itself, so the asset value cannot differ from it. | | **Instance** | An object resolved from a placed container's template. Its **values** can be edited — position, name, property overrides — and only what actually deviates is stored, as a sparse `instanceEdits` entry on the container object keyed by the template path. Everything else keeps following the template. Its **structure** cannot: it can not be removed, re-parented or given a collider, and nothing of the scene can be parented into it. ↺ ▾ resets to the nearest base, which inside a container is the **template as the containers in between leave it**; ↑ ▾ offers **Apply to container** (write the value into the template, where every other instance still at the old value picks it up) and/or **Apply to asset** (which drops the template's override as well). With one base left the menu collapses to a plain ↺ / ↑, with none the buttons disappear. Gold marks the same thing the buttons offer. | diff --git a/Development.md b/Development.md index da10eee..7d9a43c 100644 --- a/Development.md +++ b/Development.md @@ -12,7 +12,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs # code is lost (tail's is reported), so a red run reads as green npm run build # writes dist/ and regenerates index.html ./build.sh # the same under `set -o pipefail`, for callers that pipe the output -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1045 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1052 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result diff --git a/Home.md b/Home.md index f977892..83c5b00 100644 --- a/Home.md +++ b/Home.md @@ -14,6 +14,7 @@ Live: · Widget playground: