|
|
@@ -519,10 +519,10 @@ The Stage 8 specification numbered these decisions D153, D155, D158, D159, D168
|
|
|
|
| D298 | Project refactorings without the editor. `project/refs` finds what references an asset from the pipeline index (`Entry.Deps`) and `mainScene`, locates the places in a file from its text (node path, owner, field, list index), lists missing assets (with the graveyard entry and a same-name suggestion of the same kind) and node references to nodes a scene does not define; it reads through `refs.Source`, which `*pipeline.Pipeline` satisfies. An ID counts as known when it is a builtin, has a file, or is in the index without a grave, so the page artifact of a multi-file script package is not reported as missing. `project/refactor` plans and applies: `PlanReplace` collects the referring files, `Edits` computes their new bytes by replacing the `asset("<id>")` token (overrides, data assets, tables and presets included, which is why it is not a `mutate.Tx`), `Write` backs the originals up under `.aego/recovery/refs-<time>` and writes atomically, `ApplyProject` moves `mainScene`, `Reimport` reimports what changed; `Users` lists referrers outside a deleted set (safe delete), `Delete` deletes through the pipeline, whose scan buries the IDs in the graveyard; `Move` moves an asset with its `.meta` and rewrites the `package` line of a script that changes package; `PlanRename`, `RenameOps` (with the temporary-name pass when names swap) and `ApplyOps` (rolled back on failure) carry batch rename. The rename rules live in `project/rename`. `project.WriteAtomic` is the one atomic writer (`project.Save` and `document.WriteAtomic` use it; files are written 0644). The editor's References, Missing References, Batch Rename and asset move are adapters: open documents are still edited through their history, files on disk go through `project/refactor`. Prefab Apply and Create From Node follow in 9.6c2. Amended in 9.6c2: prefab Apply and Create From Node work without the editor. `refactor.PlanApply` locates the instance (`Locate`), splits its overrides with `prefab.Pick`, bakes the selection into the prefab models (the baker moved from the editor; `Nearest` routes an apply to the nearest nested prefab) and returns the new models, the instance block before and after; `ApplyPlan.Edits` encodes the changed prefab files. `ApplyPrefab` sets the baked models into the document's library and replaces the instance root and every other prefab instance of the document through `mutate`, so the other instances pick up the new values and keep their overrides; `Result.Inverse` carries the blocks taken before the apply and is valid against the old prefab files. `WriteAll` writes the files and rolls back on failure. `mutate.Document.Bytes` saves through `Env.Library`, so overrides on instances are written. `CheckCreate`, `LinkBlock` and `CreatePrefab` turn a node into a prefab file (written, scanned, imported) and link the node to it keeping every node ID; a failure removes the file and its `.meta`. `PrefabLibrary` builds a library from the prefab sources, so tools need no loader. The editor's Apply and Create Prefab call the same functions and keep their history across documents. The data asset and table editors (`editor/core/dataedit`) edit a `mutate.DataDocument`: every change is a `data-set`, `data-reset`, `data-base` (new: the base asset, by ID or path), `row-add`, `row-remove`, `row-restore` or `row-rename` with exact inverses, consecutive edits of one field merge, a value equal to the inherited one (the base for a data asset, the type default for a table row) resets the field, and saving writes the document's own bytes, so untouched fields keep their text. Gizmo property drags go through `commands.SetField` after `props.Normalize` clamps them to the field range; `commands.SetProperty` is gone. |
|
|
|
|
| D298 | Project refactorings without the editor. `project/refs` finds what references an asset from the pipeline index (`Entry.Deps`) and `mainScene`, locates the places in a file from its text (node path, owner, field, list index), lists missing assets (with the graveyard entry and a same-name suggestion of the same kind) and node references to nodes a scene does not define; it reads through `refs.Source`, which `*pipeline.Pipeline` satisfies. An ID counts as known when it is a builtin, has a file, or is in the index without a grave, so the page artifact of a multi-file script package is not reported as missing. `project/refactor` plans and applies: `PlanReplace` collects the referring files, `Edits` computes their new bytes by replacing the `asset("<id>")` token (overrides, data assets, tables and presets included, which is why it is not a `mutate.Tx`), `Write` backs the originals up under `.aego/recovery/refs-<time>` and writes atomically, `ApplyProject` moves `mainScene`, `Reimport` reimports what changed; `Users` lists referrers outside a deleted set (safe delete), `Delete` deletes through the pipeline, whose scan buries the IDs in the graveyard; `Move` moves an asset with its `.meta` and rewrites the `package` line of a script that changes package; `PlanRename`, `RenameOps` (with the temporary-name pass when names swap) and `ApplyOps` (rolled back on failure) carry batch rename. The rename rules live in `project/rename`. `project.WriteAtomic` is the one atomic writer (`project.Save` and `document.WriteAtomic` use it; files are written 0644). The editor's References, Missing References, Batch Rename and asset move are adapters: open documents are still edited through their history, files on disk go through `project/refactor`. Prefab Apply and Create From Node follow in 9.6c2. Amended in 9.6c2: prefab Apply and Create From Node work without the editor. `refactor.PlanApply` locates the instance (`Locate`), splits its overrides with `prefab.Pick`, bakes the selection into the prefab models (the baker moved from the editor; `Nearest` routes an apply to the nearest nested prefab) and returns the new models, the instance block before and after; `ApplyPlan.Edits` encodes the changed prefab files. `ApplyPrefab` sets the baked models into the document's library and replaces the instance root and every other prefab instance of the document through `mutate`, so the other instances pick up the new values and keep their overrides; `Result.Inverse` carries the blocks taken before the apply and is valid against the old prefab files. `WriteAll` writes the files and rolls back on failure. `mutate.Document.Bytes` saves through `Env.Library`, so overrides on instances are written. `CheckCreate`, `LinkBlock` and `CreatePrefab` turn a node into a prefab file (written, scanned, imported) and link the node to it keeping every node ID; a failure removes the file and its `.meta`. `PrefabLibrary` builds a library from the prefab sources, so tools need no loader. The editor's Apply and Create Prefab call the same functions and keep their history across documents. The data asset and table editors (`editor/core/dataedit`) edit a `mutate.DataDocument`: every change is a `data-set`, `data-reset`, `data-base` (new: the base asset, by ID or path), `row-add`, `row-remove`, `row-restore` or `row-rename` with exact inverses, consecutive edits of one field merge, a value equal to the inherited one (the base for a data asset, the type default for a table row) resets the field, and saving writes the document's own bytes, so untouched fields keep their text. Gizmo property drags go through `commands.SetField` after `props.Normalize` clamps them to the field range; `commands.SetProperty` is gone. |
|
|
|
|
| D299 | Agent layer and CLI. `app/agent` is one catalog of commands (`Command`: name `group.verb`, typed arguments with positional order, write flag, `Run(*Session, Args) (*Output, error)`) that the CLI and the MCP server share; a command's MCP tool name and JSON schema come from the same definition. A `Session` loads types, modules, importers and the pipeline like `app.Build` without the engine, renderer or loader, publishes the compiled script types, builds the prefab library from sources (`refactor.PrefabLibrary`) and resolves scenes and prefabs from files; it edits through `scene/mutate` and `project/refactor` and writes atomically, then reimports and reloads the library. Commands: `scene tree|get|set|reset|add-node|remove-node|move|rename|add-comp|remove-comp|apply|validate|new|run`, `prefab create|instantiate|apply|revert|unpack|overrides`, `data get|set|reset|base|rows|add-row|remove-row|rename-row|import|export`, `refs find|missing|fix`, `asset list|move|rename|delete`, `schema list|show`, `project validate`. The CLI form is `aego <group> <verb> <positional> [--flags]`; flags may follow positionals, `--` ends them, a value starting with one dash is positional. `--json` prints `Output` (ok, dryRun, changes, problems, created, files, notes, value) or `{"ok":false,"error":…}`; exit 0, 1 on error, 2 on error-level problems or, with `--strict`, any problem. `--dry-run` applies and rolls back in memory. A project with native code runs the commands in its own binary (`--tool agent`), so its types are known. When another process holds the asset index (`Pipeline.Shared`), commands that create assets refuse, so an asset never gets a derived ID the editor would later replace. `scene run` releases the session's pipeline and runs a scene headless in process through `run.AgentRunner` (no window, no player profile, warnings and errors of the log, the world hash of `run.WorldHash`). Module `OnAdd` hooks run without the editor's visual bounds. `prefab-instantiate` creates an owner instance block (as the editor does), not the runtime spawn copy. Closes D242. |
|
|
|
|
| D299 | Agent layer and CLI. `app/agent` is one catalog of commands (`Command`: name `group.verb`, typed arguments with positional order, write flag, `Run(*Session, Args) (*Output, error)`) that the CLI and the MCP server share; a command's MCP tool name and JSON schema come from the same definition. A `Session` loads types, modules, importers and the pipeline like `app.Build` without the engine, renderer or loader, publishes the compiled script types, builds the prefab library from sources (`refactor.PrefabLibrary`) and resolves scenes and prefabs from files; it edits through `scene/mutate` and `project/refactor` and writes atomically, then reimports and reloads the library. Commands: `scene tree|get|set|reset|add-node|remove-node|move|rename|add-comp|remove-comp|apply|validate|new|run`, `prefab create|instantiate|apply|revert|unpack|overrides`, `data get|set|reset|base|rows|add-row|remove-row|rename-row|import|export`, `refs find|missing|fix`, `asset list|move|rename|delete`, `schema list|show`, `project validate`. The CLI form is `aego <group> <verb> <positional> [--flags]`; flags may follow positionals, `--` ends them, a value starting with one dash is positional. `--json` prints `Output` (ok, dryRun, changes, problems, created, files, notes, value) or `{"ok":false,"error":…}`; exit 0, 1 on error, 2 on error-level problems or, with `--strict`, any problem. `--dry-run` applies and rolls back in memory. A project with native code runs the commands in its own binary (`--tool agent`), so its types are known. When another process holds the asset index (`Pipeline.Shared`), commands that create assets refuse, so an asset never gets a derived ID the editor would later replace. `scene run` releases the session's pipeline and runs a scene headless in process through `run.AgentRunner` (no window, no player profile, warnings and errors of the log, the world hash of `run.WorldHash`). Module `OnAdd` hooks run without the editor's visual bounds. `prefab-instantiate` creates an owner instance block (as the editor does), not the runtime spawn copy. Closes D242. |
|
|
|
|
| D300 | MCP server. `aego mcp` (`app/agent/mcp`) speaks MCP over stdio, one JSON-RPC message per line, without a dependency: `initialize` (protocol 2025-06-18, older 2025-03-26 and 2024-11-05 echoed), `ping`, `tools/list|call`, `resources/list|read|subscribe|unsubscribe`, `resources/templates/list`, `notifications/resources/updated|list_changed`. Tools are the D299 commands one to one (name with underscores, the command's JSON schema, `readOnlyHint` for commands that do not write) plus `docs_search` and `docs_read`; a failing command returns `isError` with the message, a successful one its `Output` as text and `structuredContent`. Resources: `aego://project/manifest`, `aego://project/problems`, `aego://docs/index|<id>`, `aego://schema/index|<type>`, `aego://file/<path>` for scenes, prefabs, data assets and tables. The server keeps an `agent.Kit` (types, modules, importers) and opens a pipeline session per request (a few milliseconds on the platformer), so it never holds the asset index lock between calls and an editor started later owns it. `--watch` polls the project with the pipeline's watcher and notifies subscribed resources; a document that appears or disappears also sends `list_changed`. A native project is served by its own binary (`--tool mcp`, stdin passed through). |
|
|
|
|
| D300 | MCP server. `aego mcp` (`app/agent/mcp`) speaks MCP over stdio, one JSON-RPC message per line, without a dependency: `initialize` (protocol 2025-06-18, older 2025-03-26 and 2024-11-05 echoed), `ping`, `tools/list|call`, `resources/list|read|subscribe|unsubscribe`, `resources/templates/list`, `notifications/resources/updated|list_changed`. Tools are the D299 commands one to one (name with underscores, the command's JSON schema, `readOnlyHint` for commands that do not write) plus `docs_search` and `docs_read`; a failing command returns `isError` with the message, a successful one its `Output` as text and `structuredContent`. Resources: `aego://project/manifest`, `aego://project/problems`, `aego://docs/index|<id>`, `aego://schema/index|<type>`, `aego://file/<path>` for scenes, prefabs, data assets and tables. The server keeps an `agent.Kit` (types, modules, importers) and opens a pipeline session per request (a few milliseconds on the platformer), so it never holds the asset index lock between calls and an editor started later owns it. `--watch` polls the project with the pipeline's watcher and notifies subscribed resources; a document that appears or disappears also sends `list_changed`. A native project is served by its own binary (`--tool mcp`, stdin passed through). |
|
|
|
|
| D301 | Release builds. The `release` job of `ci.yml` runs after `checks` and `build` on every push: master publishes the rolling pre-release `nightly` (the release and its tag are recreated at the new commit), a `v*` tag publishes that release. `tools/release/release.sh [--dry-run] <vX.Y.Z|nightly>` builds `cmd/aego` with cgo, `-trimpath -s -w` for the runner's GOOS/GOARCH (Linux amd64 only for now), packs `aego-<version|nightly>-<os>-<arch>.tar.gz` (`bin/aego`, `VERSION` with tag and commit, `README.txt`) with a `.sha256`, and uploads both through the Gitea API with the job token; a tag that differs from `engine.Version` fails. `tools/release/install.sh`, served at the site root, picks the latest release (`--nightly`, `--version vX.Y.Z`), verifies the checksum, unpacks to `<prefix>/share/aego` and links `<prefix>/bin/aego` (`~/.local` by default), installs missing runtime libraries (Mesa GL and EGL, X11, Wayland, xkbcommon) with the system package manager unless `--no-deps`, and warns about glibc older than 2.39 or OpenGL below 3.3; other systems are told to build from source. On the same Linux runner the job cross-builds Windows with mingw-w64 (`tools/bootstrap-native.sh` sets `CMAKE_SYSTEM_NAME=Windows` when it is not on Windows): `aego.exe`, `aego-editor.exe` (GUI subsystem) and the NSIS installer `aego-<version>-windows-amd64-setup.exe` (`tools/release/windows/aego.nsi`: per user under `%LOCALAPPDATA%\Programs\Aego`, no administrator rights, Start menu and desktop shortcuts, the directory on the user `PATH`, an entry in Settings → Apps; running a newer installer updates in place), plus a `.zip`; `install.ps1` at the site root downloads the latest installer, checks its checksum and runs it silently. A prebuilt `aego` edits, runs and exports script-only projects without Go; native modules and exports to other systems need Go and a checkout (`AEGO_ROOT` or `--engine`). |
|
|
|
|
| D301 | Release builds. The `release` job of `ci.yml` runs after `checks` and `build` on every push: master publishes the rolling pre-release `nightly` (the release and its tag are recreated at the new commit), a `v*` tag publishes that release. `tools/release/release.sh [--dry-run] <vX.Y.Z|nightly>` builds `cmd/aego` with cgo, `-trimpath -s -w` for the runner's GOOS/GOARCH (Linux amd64 only for now), packs `aego-<version|nightly>-<os>-<arch>.tar.gz` (`bin/aego`, `VERSION` with tag and commit, `README.txt`), lists every file in one `SHA256SUMS.txt` (the Gitea instance accepts only some attachment types: `.gz`, `.zip`, `.txt`, not `.exe` or `.sha256`), and uploads them through the Gitea API with the job token; a tag that differs from `engine.Version` fails. `tools/release/install.sh`, served at the site root, picks the latest release (`--nightly`, `--version vX.Y.Z`), verifies the checksum, unpacks to `<prefix>/share/aego` and links `<prefix>/bin/aego` (`~/.local` by default), installs missing runtime libraries (Mesa GL and EGL, X11, Wayland, xkbcommon) with the system package manager unless `--no-deps`, and warns about glibc older than 2.39 or OpenGL below 3.3; other systems are told to build from source. On the same Linux runner the job cross-builds Windows with mingw-w64 (`tools/bootstrap-native.sh` sets `CMAKE_SYSTEM_NAME=Windows` when it is not on Windows): `aego.exe`, `aego-editor.exe` (GUI subsystem) and the NSIS installer, shipped zipped as `aego-<version>-windows-amd64-setup.zip` (`tools/release/windows/aego.nsi`: per user under `%LOCALAPPDATA%\Programs\Aego`, no administrator rights, Start menu and desktop shortcuts, the directory on the user `PATH`, an entry in Settings → Apps; running a newer installer updates in place), plus a `.zip`; `install.ps1` at the site root downloads the latest installer archive, checks it against `SHA256SUMS.txt`, unpacks it and runs the installer silently. A prebuilt `aego` edits, runs and exports script-only projects without Go; native modules and exports to other systems need Go and a checkout (`AEGO_ROOT` or `--engine`). |
|
|
|
|
| D302 | Documentation screenshots. `make shots` opens a copy of `examples/platformer` in the real editor under a clean user profile with `AEGO_SHOTS=<dir>` (`app/edit/shots.go`: a fixed sequence of editor states, each after a fixed number of frames) and writes `docs/shots/*.png`, which are committed; `make shots-check` (part of `make ci`) regenerates them and `tools/shotdiff` fails when more than 3% of the pixels of any image moved by more than 24/255. Frames are read with `Engine.CaptureFrame`, a one-shot hook between `EndFrame` and the swap that reads the default framebuffer through the optional `gpu.BackbufferReader` (implemented by GL 3.3 only). Pages use them as ``; gendocs copies the directory to `assets/shots/`, the editor's docs panel skips images, and `docs/shots/demo.png` is the poster of the landing page demo. |
|
|
|
|
| D302 | Documentation screenshots. `make shots` opens a copy of `examples/platformer` in the real editor under a clean user profile with `AEGO_SHOTS=<dir>` (`app/edit/shots.go`: a fixed sequence of editor states, each after a fixed number of frames) and writes `docs/shots/*.png`, which are committed; `make shots-check` (part of `make ci`) regenerates them and `tools/shotdiff` fails when more than 3% of the pixels of any image moved by more than 24/255. Frames are read with `Engine.CaptureFrame`, a one-shot hook between `EndFrame` and the swap that reads the default framebuffer through the optional `gpu.BackbufferReader` (implemented by GL 3.3 only). Pages use them as ``; gendocs copies the directory to `assets/shots/`, the editor's docs panel skips images, and `docs/shots/demo.png` is the poster of the landing page demo. |
|
|
|
|
| D303 | Docs delivery. The landing page embeds the web demo as a click-to-play iframe over its poster and starts it at once for a visitor who has played it before (a localStorage mark). The Try it loader compiles `aego-docs.wasm` straight from the network response, so the browser keeps both the file and its compiled code in the HTTP cache, and counts a copy of the first download for a progress bar against the uncompressed size written into the page; a localStorage mark of the versioned URL tells later pages the runtime was started before, and they start the first Try it block that scrolls into view without waiting for a click (the Cache API was tried and dropped: responses rebuilt from it lose the compiled-code cache, and probing the HTTP cache with `only-if-cached` holds its lock on the same URL); the block shows the scene as a tree (`sceneio.Outline`, node → components → typed fields linked to their docs, values updated from the runtime and changed ones marked) with Open in editor (downloads the `.aescene`) and Copy as .aescene. The docs runtime shows the `physics.shapes` and `physics.joints` debug draw channels, so colliders and joints are visible without art. nginx serves every `.wasm` with a brotli or gzip copy made at image build, `?v=` URLs as `immutable` for a year, HTML and JSON for 60 seconds (`no-cache` kept the edge proxy in front of the site from storing new pages, so it served stale ones), and `install.sh` as text; the web export preloads its `game.wasm`. Amended 2026-10-20: the site sits behind the edge proxy at 185.170.196.188, whose route to mainserv is slow (~0.2 MB/s) and drops, so the edge serves aego from its own copy (`deploy/edge`): the image carries `__edge/site.tar.gz` and `__edge/version`, the edge timer `aego-wasm-sync` fetches a new site archive with resumable downloads and switches `/var/www/aego-site/current` atomically, and copies each wasm into `/var/www/aego-wasm/<version>/`; anything not there yet goes to mainserv through the proxy, so a new `?v=` never gets old bytes. Pages show the commit in the header, and styles, scripts and the icon sprite are loaded as `?v=<hash of their contents>`, so a new revision reaches every browser within the 60 s HTML lifetime. |
|
|
|
|
| D303 | Docs delivery. The landing page embeds the web demo as a click-to-play iframe over its poster and starts it at once for a visitor who has played it before (a localStorage mark). The Try it loader compiles `aego-docs.wasm` straight from the network response, so the browser keeps both the file and its compiled code in the HTTP cache, and counts a copy of the first download for a progress bar against the uncompressed size written into the page; a localStorage mark of the versioned URL tells later pages the runtime was started before, and they start the first Try it block that scrolls into view without waiting for a click (the Cache API was tried and dropped: responses rebuilt from it lose the compiled-code cache, and probing the HTTP cache with `only-if-cached` holds its lock on the same URL); the block shows the scene as a tree (`sceneio.Outline`, node → components → typed fields linked to their docs, values updated from the runtime and changed ones marked) with Open in editor (downloads the `.aescene`) and Copy as .aescene. The docs runtime shows the `physics.shapes` and `physics.joints` debug draw channels, so colliders and joints are visible without art. nginx serves every `.wasm` with a brotli or gzip copy made at image build, `?v=` URLs as `immutable` for a year, HTML and JSON for 60 seconds (`no-cache` kept the edge proxy in front of the site from storing new pages, so it served stale ones), and `install.sh` as text; the web export preloads its `game.wasm`. Amended 2026-10-20: the site sits behind the edge proxy at 185.170.196.188, whose route to mainserv is slow (~0.2 MB/s) and drops, so the edge serves aego from its own copy (`deploy/edge`): the image carries `__edge/site.tar.gz` and `__edge/version`, the edge timer `aego-wasm-sync` fetches a new site archive with resumable downloads and switches `/var/www/aego-site/current` atomically, and copies each wasm into `/var/www/aego-wasm/<version>/`; anything not there yet goes to mainserv through the proxy, so a new `?v=` never gets old bytes. Pages show the commit in the header, and styles, scripts and the icon sprite are loaded as `?v=<hash of their contents>`, so a new revision reaches every browser within the 60 s HTML lifetime. |
|
|
|
|
| D304 | Camera adjustment is a pull contract. `contracts/camera2d` declares `Adjuster` under `camera2d.adjust`. `render2d.cameras` builds the view of every active Camera 2D from its interpolated pose, then replaces it with `Adjust(node, view)` when the play world has the service; the view goes by value, so the frame does not allocate. Rendering never names the camera module and the camera module never names render systems (D204); the contract may import `render/view` (a depcheck exception). An output is evaluated once per `camera.update` tick; a second Camera 2D on the same output reuses the pose. The edit world has no adjuster, fixed views are never adjusted. The module ID `camera` collides with the scene view state field `"camera"`, which is excepted in depcheck. |
|
|
|
|
| D304 | Camera adjustment is a pull contract. `contracts/camera2d` declares `Adjuster` under `camera2d.adjust`. `render2d.cameras` builds the view of every active Camera 2D from its interpolated pose, then passes it through `view = Adjust(node, view)` when the play world has the service; the value form keeps the per-frame path free of allocations. Rendering never names the camera module and the camera module never names render systems (D204); the contract may import `render/view` (a depcheck exception). An output is evaluated once per `camera.update` tick; a second Camera 2D on the same output reuses the pose. The edit world has no adjuster, fixed views are never adjusted. The module ID `camera` collides with the scene view state field `"camera"`, which is excepted in depcheck. |
|
|
|
|
| D305 | Virtual cameras, priorities, blends and zones. Each output picks the enabled virtual camera with the highest priority; ties go to the lower node handle index, then zones over plain cameras, the later zone over the earlier, and BlendTo/Cut over everything until Release. Zones are derived each tick from the exact world position of the target (not the interpolated one), so entering is deterministic; they never write component fields. A switch blends from the current logical pose, zoom in log space; a replaced blend completes with finished=false. Blends are awaitable handles `aego/camera.Blend`. Outputs are chosen per Camera 2D by `camera.CameraBrain2D`; without it the camera shows the main output. |
|
|
|
|
| D305 | Virtual cameras, priorities, blends and zones. Each output picks the enabled virtual camera with the highest priority; ties go to the lower node handle index, then zones over plain cameras, the later zone over the earlier, and BlendTo/Cut over everything until Release. Zones are derived each tick from the exact world position of the target (not the interpolated one), so entering is deterministic; they never write component fields. A switch blends from the current logical pose, zoom in log space; a replaced blend completes with finished=false. Blends are awaitable handles `aego/camera.Blend`. Outputs are chosen per Camera 2D by `camera.CameraBrain2D`; without it the camera shows the main output. |
|
|
|
|
| D306 | Follow, shake, accessibility and time. Follow reads the interpolated target pose and runs in game time with exponential, rate-independent damping, a deadzone in view fractions, lookahead in seconds of velocity and snapping on teleports. Shake is trauma^exponent times deterministic gradient noise seeded by the output name; it never touches node transforms or the world RNG. Accessibility provides `camera2d.accessibility` with its setting IDs: Screen Shake scales shake, Reduce Motion disables shake and lookahead. Blends and shake follow the VC time domain (unscaled by default). The rewind hash covers active cameras, overrides, zones and game-domain blends and trauma; follow is captured but not hashed, unscaled blends finish on restore. |
|
|
|
|
| D306 | Follow, shake, accessibility and time. Follow reads the interpolated target pose and runs in game time with exponential, rate-independent damping, a deadzone in view fractions, lookahead in seconds of velocity and snapping on teleports. Shake is trauma^exponent times deterministic gradient noise seeded by the output name; it never touches node transforms or the world RNG. Accessibility provides `camera2d.accessibility` with its setting IDs: Screen Shake scales shake, Reduce Motion disables shake and lookahead. Blends and shake follow the VC time domain (unscaled by default). The rewind hash covers active cameras, overrides, zones and game-domain blends and trauma; follow is captured but not hashed, unscaled blends finish on restore. |
|
|
|
|
|
|
|
|
|
|
|
|