From d52f1c1ef9a5b2df0726e063274f8bb0be650075 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 14 Sep 2026 08:26:01 +0200 Subject: [PATCH] Particles: a source wears a scene icon, and what isSymbolType really gates (#89) Co-Authored-By: Claude Opus 5 --- Architecture.md | 7 +++++++ Development.md | 4 ++-- Particles.md | 13 ++++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Architecture.md b/Architecture.md index f0d4ba0..c60e43e 100644 --- a/Architecture.md +++ b/Architecture.md @@ -109,6 +109,13 @@ rebased to the second it was stopped at, or it resumes a minute further on. The that changes *when* rather than *what* costs nothing but a term on that one argument — a particle source's `Time scale` is a factor on it and `Prewarm` a summand, so neither needs a frame of simulation nor a line in the drawing code. +**A predicate named after what a thing looks like will be asked what a thing *is*.** `isSymbolType` +reads as "draws an icon", but four callers use it for "is editor decoration": the running world, the +Game tab, the draw order and the upright placement all key off it. Giving a particle source an icon +by adding it there would have taken its particles out of the game. The two questions are now two +functions — `hasSceneIcon` for the drawing, `isSymbolType` for the decoration — and the icon itself +is a decoration of `SceneViewport`, which is editor-only for free because `GameViewport` never syncs +any. Comments state contracts and reasons, not what the code does: a `/** */` on every export whose name does not say it all, `//` only for a decision or gotcha. diff --git a/Development.md b/Development.md index 7b2c84e..63a6917 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 # 821 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 824 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 @@ -156,4 +156,4 @@ widths to find click points. The **render device is not in this repo** — `/dev and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`, -WebGL 2.0, and the same 821 checks as here. +WebGL 2.0, and the same 824 checks as here. diff --git a/Particles.md b/Particles.md index 71c53f6..12ffb40 100644 --- a/Particles.md +++ b/Particles.md @@ -94,6 +94,14 @@ can. Overriding one of them on a placed object is an ordinary override, with res A **behavior** can start a source over with the `Emit` node (its `source` input names which one): in *Burst* mode that is another burst, in *Continuous* mode the stream begins again at particle 0. +**Its icon in the Scene tab.** Like a behavior or a container, a source is marked by an icon of its +own — an orange ring with sparks, upright and unscaled at its position, with the object's name +beside it and a dashed line to its owner when it is parented. The ring is hollow because, unlike +those two, a source *does* draw something: the effect shows through the middle of its own mark. The +icon is editor decoration and never reaches the running game, but the source is **not** an editor +symbol: its particles are scene content, and what is grabbed and framed is the ring-sized square +around its position rather than anything that grows with the source's scale. + ## Recipes **Rain.** `Age in seconds → Multiply(b: 400) → Output.y`, and a `Random(-300, 300)` into @@ -117,6 +125,5 @@ to a cold one over `Age`. - **Particle time is the editor's clock, not the game's.** Pausing the game does not freeze a spray. - **The preview shows the asset, not an instance**: the rows the asset carries, never the ones a particular placed source was given — every one of them may be overridden where it is placed. -- **A source with `Emitting` off draws nothing at all** once the last particle has died, so it - disappears from the scene view; it is still in the hierarchy panel, and selecting it there shows - its handle. +- **A source with `Emitting` off draws nothing at all** once the last particle has died. In the + Scene tab its icon still marks the spot; in the running game there is nothing to see.