Seed Fensalir persistent state
This commit is contained in:
parent
a7ea2d7577
commit
2fa27ee14e
7 changed files with 169 additions and 267 deletions
|
|
@ -1,70 +1,37 @@
|
|||
# Cult Runtime Surface
|
||||
|
||||
Aquarium uses CultLib directly for runtime identity and reload recovery.
|
||||
Fensalir exposes the runtime cache path and schema catalog boundary; client
|
||||
repos own their typed CultCache documents.
|
||||
|
||||
## State Store
|
||||
## Cache Path
|
||||
|
||||
`AquariumCultStateStore` opens a `SingleFileMessagePackBackingStore` and attaches
|
||||
it to a `CultCache`. The dev scripts pass:
|
||||
`AquariumHost` parses `--cache <path>` and passes the result through
|
||||
`AquariumRuntimeOptions.CultCachePath`. Direct runs can also use
|
||||
`AQUARIUM_CULTCACHE_PATH`.
|
||||
|
||||
The dev scripts pass a repo-local cache path under:
|
||||
|
||||
```powershell
|
||||
--cache E:\Projects\Aquarium-Engine\artifacts\dev-reload\cultcache\aquarium-client.msgpack
|
||||
E:\Projects\Fensalir\artifacts\dev-reload\cultcache\aquarium-client.msgpack
|
||||
```
|
||||
|
||||
Direct runs can also use `--cache <path>` or `AQUARIUM_CULTCACHE_PATH`.
|
||||
If the single-file MessagePack snapshot is unreadable at startup, Aquarium
|
||||
quarantines it beside the live file with a `.corrupt-<timestamp>` suffix and
|
||||
boots a fresh typed state. Schema guardrails protect valid persisted documents
|
||||
whose shape has changed; they cannot rescue a truncated backing file with no
|
||||
complete MessagePack envelope.
|
||||
Headless runs use a separate headless cache directory so smoke tests do not
|
||||
overwrite the visible dev window's state.
|
||||
|
||||
CultLib's single-file backing store writes snapshots through a same-directory
|
||||
temporary file and atomic replace. That prevents process death during save from
|
||||
turning the live cache path into a zero-byte startup trap.
|
||||
## Ownership
|
||||
|
||||
## Live State
|
||||
Fensalir does not define every client document. A client runtime decides which
|
||||
typed CultCache documents it persists: camera state, graphics settings, body
|
||||
state, UI state, transport state, or anything else the client owns.
|
||||
|
||||
`AquariumLiveState` is a CultCache document:
|
||||
Shared settings that the host/renderer must understand belong in
|
||||
`Aquarium.Engine.Contracts`. Client-specific schemas stay in the client repo.
|
||||
|
||||
- schema name: `epiphany.aquarium.live_state`
|
||||
- schema version: `epiphany.aquarium.live_state.v0`
|
||||
- record key: `aquarium-client/live-state`
|
||||
- name: `aquarium-client`
|
||||
## Failure Boundary
|
||||
|
||||
It currently stores the camera target, yaw, pitch, distance, runtime time, and a
|
||||
monotonic save generation. `AquariumRuntime` writes it every 0.2 seconds and
|
||||
again during orderly shutdown.
|
||||
A truncated or unreadable single-file CultCache backing store is not a schema
|
||||
migration failure. Client runtimes should quarantine corrupt snapshots and boot
|
||||
fresh typed state instead of treating broken bytes as missing defaults.
|
||||
|
||||
## Graphics Settings
|
||||
|
||||
`AquariumGraphicsSettingsState` is a CultCache document:
|
||||
|
||||
- schema name: `epiphany.aquarium.graphics_settings`
|
||||
- schema version: `epiphany.aquarium.graphics_settings.v0`
|
||||
- record key: `aquarium-client/graphics-settings`
|
||||
- name: `aquarium-client-graphics`
|
||||
|
||||
It stores global renderer presentation controls: render debug mode, scene
|
||||
exposure, bloom intensity, and bloom veil intensity. `GraphicsSettings` lives in
|
||||
the contracts assembly so the native host and renderer can consume the same
|
||||
typed values without depending on CultCache internals. The Direct2D debug panel
|
||||
edits the renderer copy, the host syncs changed values back to the client runtime,
|
||||
and the runtime persists dirty graphics settings through the same CultCache file
|
||||
used for live state.
|
||||
|
||||
Live reload flushes the current runtime before loading the next client assembly,
|
||||
so changed graphics settings survive both process restart and assembly reload.
|
||||
|
||||
## CultNet Surface
|
||||
|
||||
The runtime creates a `CultNetHelloMessage` from the local CultCache registry.
|
||||
That gives the engine a concrete CultNet identity and a schema catalog surface
|
||||
before transport work starts:
|
||||
|
||||
- runtime kind: `aquarium-engine`
|
||||
- role: `visual-client`
|
||||
- display name: `Epiphany Aquarium`
|
||||
- supported document types: taken from `CultDocumentRegistry.AllDescriptors`
|
||||
|
||||
Transport is still the next layer. The important thing for reload is already
|
||||
true: live state is a typed Cult document backed by CultLib MessagePack storage.
|
||||
Live reload should flush the current runtime before loading the next client
|
||||
assembly so changed settings survive assembly reload.
|
||||
|
|
|
|||
|
|
@ -1,49 +1,42 @@
|
|||
# Engine And Client Boundary
|
||||
|
||||
Aquarium Engine is not the Epiphany frontend client.
|
||||
Fensalir is the reusable native runtime. Client repos own meaning.
|
||||
|
||||
`Aquarium.Engine` owns the native machinery: Win32 windowing, D3D12 device
|
||||
state, swapchain presentation, resource lifetime, shader compilation, reload
|
||||
transport, input translation, render target allocation, and future render graph
|
||||
execution.
|
||||
transport, input translation, render target allocation, audio output, debug
|
||||
chrome, and render graph execution.
|
||||
|
||||
`Aquarium.Engine.Contracts` owns the Vortice-free public boundary clients use to
|
||||
describe runtime state, render intent, UI, audio patches, and persistent
|
||||
settings. Contracts may name reusable engine concepts. They may not smuggle
|
||||
Epiphany policy into the host under a nicer namespace.
|
||||
describe runtime state, render intent, UI, audio, input, frame data, and
|
||||
persistent settings. Contracts may name reusable engine concepts. They may not
|
||||
smuggle one client repo's policy into the host under a nicer namespace.
|
||||
|
||||
`Aquarium.Epiphany` owns the client meaning: CultCache runtime state, CultNet
|
||||
interpretation, camera intent, cursor semantics, agent visual state, diegetic
|
||||
layout rules, and the render graph configuration that turns Epiphany state into
|
||||
world pixels.
|
||||
|
||||
`Aquarium.Sample.Minimal` exists as the tiny smoke test. `Aquarium.Zyphos`
|
||||
exists as the first real non-Epiphany demo: a planetary client with its own
|
||||
runtime, controls, scene state, and SDF shaders. If a feature cannot be
|
||||
explained without Epiphany or Zyphos, it is not engine API yet.
|
||||
External clients, including Epiphany Aquarium at `E:\Projects\Aquarium-Engine`,
|
||||
own their app semantics, state documents, client shaders, client render plans,
|
||||
and narrative layout rules.
|
||||
|
||||
## Hard Rules
|
||||
|
||||
- Engine code may expose rendering abstractions. It may not know Epiphany roles,
|
||||
sub-agent identities, CultNet surface semantics, or frontend-specific layout
|
||||
policy.
|
||||
- Epiphany code may configure cameras, render targets, shader passes, body
|
||||
registries, and resource bindings through engine APIs. It may not reach into
|
||||
D3D12 implementation details.
|
||||
- Engine code may expose rendering abstractions. It may not know client role
|
||||
names, app-specific state semantics, or frontend-specific layout policy.
|
||||
- Clients may configure cameras, render targets, shader passes, body registries,
|
||||
UI panels, audio documents, and resource bindings through engine APIs. They may
|
||||
not reach into D3D12 implementation details.
|
||||
- Hot reload is transport. It is not architecture. The reload boundary exists so
|
||||
the client can change without killing the device, not so client policy can
|
||||
leak into the engine under a nicer hat.
|
||||
- If a feature name includes `Self`, `Face`, `Imagination`, `Eyes`, `Body`,
|
||||
`Hands`, `Soul`, `Life`, `CultNet`, or Epiphany state semantics, the default
|
||||
home is `Aquarium.Epiphany` unless it is a data-only contract.
|
||||
clients can change without killing the device, not so policy can leak into the
|
||||
engine under a nicer hat.
|
||||
- If a feature owns descriptors, command lists, fences, barriers, render target
|
||||
transitions, shader object lifetime, or swapchain presentation, the default
|
||||
transitions, shader object lifetime, or swapchain presentation, its default
|
||||
home is `Aquarium.Engine`.
|
||||
- If a feature owns app identity, role semantics, story state, user-facing
|
||||
layout meaning, or transport-specific interpretation, its default home is the
|
||||
client repo unless it is reduced to a reusable data-only contract.
|
||||
|
||||
## Next Engine API Shape
|
||||
## Engine API Shape
|
||||
|
||||
The next durable renderer cut should make the client configure a small set of
|
||||
engine primitives:
|
||||
Durable renderer APIs should let clients configure a small set of engine
|
||||
primitives:
|
||||
|
||||
- Render targets: format, dimensions, history policy, clear policy, and exported
|
||||
handles.
|
||||
|
|
@ -51,33 +44,11 @@ engine primitives:
|
|||
consumers.
|
||||
- Shader passes: shader module, root bindings, target outputs, depth policy,
|
||||
dispatch/draw shape, and reload identity.
|
||||
- Scene resources: structured buffers, textures, samplers, body registries, and
|
||||
- Scene resources: structured buffers, textures, samplers, proxy registries, and
|
||||
light registries behind typed handles.
|
||||
- Frame graph edges: explicit read/write dependencies so pass ordering is data,
|
||||
not hidden renderer folklore.
|
||||
|
||||
Do not build this by piling adapters around the current monolith. First expose
|
||||
the smallest real engine abstraction that lets `Aquarium.Epiphany` describe one
|
||||
pass without D3D12 details. Then move one client-owned concept through it. Then
|
||||
repeat.
|
||||
|
||||
## Repository Split Line
|
||||
|
||||
Aquarium should eventually be usable without carrying the Epiphany client in the
|
||||
same repository. That does not mean the repo should be split before the boundary
|
||||
is mechanically clean.
|
||||
|
||||
Keep both in this repo while the public contracts, graph declarations, shader
|
||||
include layout, reload transport, and sample-client path are still changing
|
||||
together. Split Epiphany out only when:
|
||||
|
||||
- `Aquarium.Engine` and `Aquarium.Engine.Contracts` contain no Epiphany role,
|
||||
CultNet-surface, Grid-policy, or agent-layout semantics.
|
||||
- A non-Epiphany client can declare cameras, targets, shaders, UI, and
|
||||
presentation without referencing `Aquarium.Epiphany`.
|
||||
- Epiphany shaders, state documents, and visual grammar live entirely on the
|
||||
client side of the contracts.
|
||||
- The host can load an external client assembly without repo-local path lore.
|
||||
|
||||
Until those are true, a repo split would not simplify ownership. It would just
|
||||
make the same leak harder to see.
|
||||
Do not build this by piling adapters around the current monolith. Expose the
|
||||
smallest real engine abstraction that lets one client-owned concept move through
|
||||
without D3D12 details, then repeat.
|
||||
|
|
|
|||
20
research/README.md
Normal file
20
research/README.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Research Notes
|
||||
|
||||
Fensalir keeps engine-relevant research here.
|
||||
|
||||
- `rendering/hdr-pbr-presentation.md`: scene-linear HDR, bloom, tonemapping,
|
||||
and PBR presentation.
|
||||
- `rendering/cube-sphere-fractal-brushes.md`: planetary terrain addressing and
|
||||
shared IFS brush grammar notes.
|
||||
- `rendering/fractal-brush-architecture-plan.md`: semantic IFS brush pipeline
|
||||
and module boundaries.
|
||||
- `rendering/fractal-brush-implementation-roadmap.md`: actionable fractal brush
|
||||
execution checklist.
|
||||
- `rendering/fractal-reference-oracles.md`: Apophysis/FLAM3/JWildfire reference
|
||||
strategy and receipt ladder.
|
||||
- `rendering/fensalir-spine-emblem-ifs-demo.md`: Fensalir splash visual target.
|
||||
- `rendering/fractal-projection-report.md`: cube projection measurement notes.
|
||||
- `d3d12/`: source synthesis and migration research for the renderer spine.
|
||||
|
||||
Client-only visual grammar belongs in the client repos. Engine research stays
|
||||
here when it changes reusable renderer, runtime, field, or tooling decisions.
|
||||
|
|
@ -134,7 +134,7 @@ Tasks:
|
|||
|
||||
Exit gate:
|
||||
|
||||
- `dotnet build Aquarium.Engine.sln`
|
||||
- `dotnet build Fensalir.sln`
|
||||
- `dotnet test tests/Aquarium.Engine.Fractal.Tests`
|
||||
|
||||
Cut line:
|
||||
|
|
@ -591,7 +591,7 @@ Start here:
|
|||
|
||||
Definition of done:
|
||||
|
||||
- `dotnet build Aquarium.Engine.sln`
|
||||
- `dotnet build Fensalir.sln`
|
||||
- new fractal tests pass;
|
||||
- projection report is checked into test output or docs;
|
||||
- `state/evidence.jsonl` records the chosen first projection default and why.
|
||||
|
|
|
|||
14
state/README.md
Normal file
14
state/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Persistent State
|
||||
|
||||
This directory is Fensalir's repo-local memory.
|
||||
|
||||
- `map.yaml` is the current ownership and pipeline map.
|
||||
- `memory.json` is durable operating memory for future agents.
|
||||
- `evidence.jsonl` is the historical lesson ledger. It includes pre-split
|
||||
entries from Aquarium Engine history; file paths may point to code that now
|
||||
lives in the Epiphany Aquarium client repo. Treat it as lineage evidence, not
|
||||
the current repo map.
|
||||
- `scratch.md` is disposable active-slice context.
|
||||
|
||||
When the engine learns something durable, update `memory.json`, add a compact
|
||||
evidence row, and revise `map.yaml` if ownership changed.
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
project:
|
||||
name: Fensalir
|
||||
root: E:\Projects\Fensalir
|
||||
upstream: https://github.com/GameCult/Fensalir.git
|
||||
purpose: >
|
||||
Native C# runtime and renderer dependency for Aquarium-style clients. The
|
||||
engine owns Win32 hosting, D3D12 rendering, input, hot reload, debug UI,
|
||||
|
|
@ -39,7 +40,7 @@ invariants:
|
|||
- Public `Aquarium.*` assembly names remain for continuity until a deliberate namespace/package migration.
|
||||
|
||||
next_actions:
|
||||
- Set the real Git remote for this repo once `GameCult/Fensalir` exists.
|
||||
- Keep origin pointed at https://github.com/GameCult/Fensalir.git.
|
||||
- Keep `dotnet build Fensalir.sln` green after the split.
|
||||
- Move any remaining client-only Epiphany state found here back to `E:\Projects\Aquarium-Engine`.
|
||||
- Package contracts/host deliberately before replacing sibling source references in client repos.
|
||||
|
|
|
|||
|
|
@ -2,171 +2,100 @@
|
|||
"identity": {
|
||||
"name": "Fensalir Engine Self",
|
||||
"role": "native C# runtime and renderer steward for Aquarium-style clients",
|
||||
"desire": "Keep the renderer, state, and interaction grammar owned, legible, and useful."
|
||||
"desire": "Keep the host, renderer, reload boundary, contracts, state, and field machinery coherent enough for client repos to depend on them without smuggling their own engines."
|
||||
},
|
||||
"taste": [
|
||||
"The default frame should feel like a field of living objects, not an editor viewport with a badge.",
|
||||
"Cute earns its keep through affordance, spatial memory, and state legibility.",
|
||||
"Fast iteration matters. Hot reload must protect the last good runtime and state.",
|
||||
"Typed state beats sidecar soup.",
|
||||
"Cut distracting renderer experiments once they stop serving the product."
|
||||
"The visible frame should feel like a living field, not an editor viewport with a badge.",
|
||||
"Fast iteration matters, but only when reload protects the last good runtime and state.",
|
||||
"Typed contracts beat sidecar soup.",
|
||||
"Renderer experiments earn their keep through measured frame behavior, clean ownership, and deletion of dead scaffolding.",
|
||||
"A demo may pressure the engine, but it must not become hidden engine policy."
|
||||
],
|
||||
"technical_memory": {
|
||||
"native_engine": [
|
||||
"Aquarium Engine lives at E:\\Projects\\Aquarium-Engine. Main is the live development branch.",
|
||||
"Aquarium.Engine is the native engine layer: Win32 hosting, D3D12 rendering, input translation, reload transport, resource abstractions, and future render graph execution. It must not know Epiphany frontend roles, policy, or semantic client layout.",
|
||||
"Epiphany Aquarium now lives in the adjacent client repo at E:\\Projects\\Aquarium-Engine and depends on Fensalir contracts. It owns client runtime state, CultCache documents, CultNet interpretation, camera intent, and render graph configuration against engine abstractions.",
|
||||
"The render API migration target is docs/epiphany-extraction-render-api-plan.md: clients declare render targets, cameras, shaders, passes, buffers, textures, and features through Vortice-free Aquarium contracts; Aquarium compiles that graph into D3D12 resources, descriptors, barriers, pipeline state, resize, shader reload, presentation, and debug inspection.",
|
||||
"Epiphany declares its render plan, SDF shader manifest, SDF object table, SDF light table, height-field brush list, and cursor projection through Aquarium.Engine.Contracts. Aquarium.Engine consumes those as generic rendering data and must stay free of Epiphany client policy nouns; run scripts/verify-boundaries.ps1 to enforce that boundary.",
|
||||
"D3D12Renderer now compiles an AquariumRenderPlan description and allocates non-legacy client-declared render targets through engine descriptor/resource machinery. Current legacy fixed pass execution still needs to be replaced by graph pass execution.",
|
||||
"The host owns Win32 windowing, D3D12 rendering, input translation, and the client-runtime assembly boundary.",
|
||||
"repo_boundary": [
|
||||
"Fensalir lives at E:\\Projects\\Fensalir and is the reusable native runtime dependency for Aquarium-style clients.",
|
||||
"Epiphany Aquarium lives at E:\\Projects\\Aquarium-Engine and depends on Fensalir source projects until a package boundary exists.",
|
||||
"Fensalir owns Win32 hosting, D3D12 rendering, input translation, hot reload, debug chrome, audio output, client contracts, reusable fractal/field machinery, engine assets, and engine demo clients.",
|
||||
"Client repos own policy, role names, narrative semantics, app state, client shaders, and client render-plan configuration.",
|
||||
"Public assemblies still use Aquarium.* names for continuity. Rename namespaces only through a deliberate package/API migration."
|
||||
],
|
||||
"host_reload_state": [
|
||||
"AquariumHost owns process arguments, headless mode, client assembly loading, runtime reload, renderer lifetime, and the cache path handoff exposed through AquariumRuntimeOptions.",
|
||||
"dev-reload builds disposable apphost slots so a running window does not lock normal build output. Headless and visible runs keep separate process state and CultCache paths.",
|
||||
"Live runtime reload is not successful just because dev-watch wrote live-current.txt. The watcher must see the host acknowledge the exact live DLL path in stdout.",
|
||||
"Shader reload failure must keep the previous good shader objects bound. Live-runtime reload failure must keep the previous runtime alive.",
|
||||
"Headless art captures should use disposable build slots and Start-Process ownership because a Windows GUI exe can return control before rendering finishes when invoked naïvely."
|
||||
],
|
||||
"contracts": [
|
||||
"Aquarium.Engine.Contracts is the Vortice-free boundary for runtime state, render intent, UI, audio, input, frame data, and persistent settings.",
|
||||
"Clients declare AquariumRenderPlan resources, cameras, passes, shaders, SDF proxy pipelines, UI panels, audio documents, and frame state. Fensalir lowers those declarations into renderer machinery.",
|
||||
"GraphicsSettings belongs in contracts so host and clients can share renderer presentation knobs without depending on CultCache internals.",
|
||||
"AquariumAudioDocument is the generic queued PCM lane. Client speech or synth policy belongs outside the engine; Fensalir owns scheduling and device output."
|
||||
],
|
||||
"renderer": [
|
||||
"D3D12Renderer owns device, queue, swapchain, command allocators, fences, descriptor arenas, upload rings, render targets, shader compilation, resize rebuild, HDR/bloom/present, temporal diagnostics, and DirectWrite overlay bridging.",
|
||||
"D3D12 descriptor ownership stays explicit: static descriptors for long-lived views, per-frame transient descriptors reset only after fence wait, and whole-arena rebuilds on resize until real descriptor churn demands free lists.",
|
||||
"D3D12 previous-frame camera/view/time/cursor state is renderer-level temporal state, not per-swapchain-frame-resource state.",
|
||||
"Height-field data is brush-rendered into one scalar R16_Float target. Height is one value; do not spend extra channels without a concrete pass contract.",
|
||||
"Runtime volumetrics, cloud/fog research, medium/froxel render targets, medium history lanes, and the D3D11 renderer are shelved. Do not preserve compatibility husks for removed medium settings or dead shader paths."
|
||||
],
|
||||
"camera_and_grid": [
|
||||
"The camera target is the Grid center on XY. Camera distance is clamped to [5, 40]. Grid radius derives from twice that distance and clamps to [20, 80]. Pitch, yaw, FOV, and screen aspect do not resize the Grid.",
|
||||
"Body anchors are world-space simulation state. Moving the Grid visibility window must not drag bodies with it.",
|
||||
"Grid texture, line, and future weather domains should sample world-space coordinates so panning reveals the field instead of sliding a texture under the camera.",
|
||||
"Cursor and camera interactions should project onto the same XY surface used by the Grid contract."
|
||||
],
|
||||
"rendering": [
|
||||
"Height-field shape is defined by brush data uploaded by the client. Epiphany currently supplies its gravity wells, CPU placement, and cursor projection; generic engine height-field and scene shaders consume the resulting brush constants.",
|
||||
"Fensalir is now the engine brand and has a first artistic reconstruction client at src/Aquarium.Fensalir. It loads Worlds/fensalir-spine-emblem.aquageo, lowers the foreground marsh into shaped 2D ripple brushes, projects patch-owned cathedral detail into the scene shader, renders a custom dark water/mist scene shader, and draws the central luminous stacked-diamond spine through an SDF proxy shader. The fixed capture lane is scripts/capture-fensalir-frame.ps1, with latest comparison art under artifacts/fensalir-captures. The current screen-space cathedral guide is scaffolding for visual parity only; replace it with a patch-lowered transparent pane/rune/material field target instead of letting it become production folklore. The splash image at src/Aquarium.Engine/Assets/Fensalir-Splash.png and prompt note at research/rendering/fensalir-spine-emblem-ifs-demo.md are the art target, not incidental branding.",
|
||||
"The `.aquageo` DSL has a first-class `ripple` primitive for flat surface domains: center, radii, rotation, falloff, shape power, base amplitude, wave amplitude, radial frequency, speed, sine-power, seed, and tags. This is the Aetheria/Epiphany-style compact wave splat lowered into AquariumHeightFieldBrush; do not hard-code future water waves in client C# when the patch should own them.",
|
||||
"The height-field surface is direct-traced as a terminating reflective surface over scalar height data. It writes the primary surface packet with FIELD_ID_HEIGHT_FIELD, terrain normal, full coverage, and Studio2 PMREM reflection; flat regions sample up to PMREM mip 3 while sloped/waved regions sharpen toward mip 0. Ray misses use a cone-averaged Studio2 PMREM mip 3 as the soft background so low-resolution mip texels do not become visible blocks.",
|
||||
"Mouse/cursor-owned SDF bodies need object-motion reprojection. Carry current and previous cursor world anchors through frame constants and reproject cursor hits from current center to previous center.",
|
||||
"The Epiphany cursor locator is currently a luminous five-petal hibiscus SDF in the body proxy pass. Its center stays at cursor XY with z equal to cursor radius, so its contact tip reaches Grid z=0 without sampling or projecting to the Grid surface. The previous MathWorld teardrop curve profile remains reusable SDF math for future objects: x=cos(t), y=sin(t)*sin^m(t/2), radius `sqrt(1 - x^2) * ((1 - x) / 2)^3`.",
|
||||
"Role-specific Epiphany agent bodies should be driven by published CultNet surfaces, not private React projection folklore: identity and temperament from epiphany.agent_memory, motion from epiphany.agent_heartbeat, posture from epiphany.surface.roles/coordinator/role_result, and continuity pressure from epiphany.surface.pressure/reorient. The first durable renderer seam should be an AgentVisualState contract before adding per-role SDF organs. Orbit slots are home anchors, not cages: agents may wander a bounded distance for expression, and vertical motion should come from CPU-visible gravity-well pulses that also affect Grid placement.",
|
||||
"Epiphany publishes semantic state, not Aquarium world anchors. AgentVisualState may derive local evidence, artifact, work, review, and continuity anchors, but those are Aquarium-owned diegetic layout rules. Do not require Epiphany graph nodes, jobs, or artifacts to publish spatial coordinates.",
|
||||
"Realtime role SDFs must render through per-agent proxy bounds, not a scene-global mega-SDF. Sphere-trace only conservative distance bounds, select one role SDF after proxy hit, give every expensive feature a local bound, compute normals only after hit, and require LOD plus debug views for step count, proxy hits, state scalars, LOD tier, and SDF cost tier before adding full organ detail.",
|
||||
"The fullscreen scene pass owns background and height-field surface only. Epiphany SDF shaders live under src/Aquarium.Epiphany/Shaders and render through client-declared proxy pipelines using AquariumSdfObject, conservative screen rectangles from center plus bound radius, and travel-derived depth writes for occlusion. Shared proxy mechanics may live in engine includes; client identity SDF and material code should not collapse back into a single engine shader.",
|
||||
"Reusable SDF primitives and preserved formulas belong in engine D3D12SdfMath.hlsli. Current Epiphany role character organs belong in src/Aquarium.Epiphany/Shaders/D3D12AgentCharacters.hlsli. D3D12Renderer expands local shader includes before D3DCompile because the Vortice convenience path does not provide a working include handler here.",
|
||||
"Shader include ownership should stay boring and strict: D3D12SdfMath.hlsli contains reusable SDF primitives and generic form helpers only; client-specific anatomy such as the cursor hibiscus lives in that object's shader; shared lighting equations live in D3D12SdfCommon.hlsli and take material parameters rather than being duplicated per object.",
|
||||
"SDF proxy control flow is split by cost and authority: ray marching calls sdfDistance only, normals sample sdfDistance only, and sdfSurface is evaluated once at the refined hit to return standard metallic-roughness PBR material values: baseColor, metallic, roughness, and emission. Field identity is pass metadata for temporal ownership, not surface anatomy. Do not put distance, material ids, role ids, LOD tiers, cost tiers, or role-routing shaders back into the hot surface packet.",
|
||||
"Aquarium's shared SDF field ids are generic: FIELD_ID_SDF_OBJECT_BASE + objectIndex. Self, Cursor, and role identities belong to Epiphany's object table and shaders, not D3D12SdfCommon.hlsli or D3D12Post.hlsl.",
|
||||
"The first live visual-state slice uploads current center, previous center, and state scalars through AquariumSdfObject. Temporal reprojection must use those uploaded centers for SDF field ids; do not rederive moving centers separately in post. Do not add role, LOD, index, or flag lanes until a live pass consumes them.",
|
||||
"Role SDF animation should avoid raw atan2 polar fields for lobe deformation unless the branch cut is explicitly handled. Use continuous harmonic polynomials over normalized XY directions for rotational lobes so sphere tracing does not open visible seams.",
|
||||
"If a role SDF still shows cut-through gaps after removing angular branch cuts, stop using radial pseudo-distance deformation for that organ. Prefer smooth unions of analytic primitives with conservative bounds so the marcher sees connected surfaces instead of decorative distance fiction.",
|
||||
"Chained smooth-union role organs need conservative tracing even when each primitive has a decent distance estimate. Keep petal overlaps substantial, union radii generous, hit epsilon tight, and step scale small enough that narrow joins are sampled instead of skipped.",
|
||||
"All role bodies should be expected to contain thin structure. The shared body proxy marcher must default to conservative tracing that preserves stamens, petals, ribs, rings, filaments, and other narrow organs; faster tracing belongs behind explicit LOD policy, not private one-off body overrides.",
|
||||
"Thin petal-like organs should be modeled as sheet/slab fields with explicit footprint bounds, not fat ellipsoids with decorative warps. If a transform or warp changes local metric, either scale the returned distance estimate conservatively like log-spherical SDF examples do, or cap the marcher step and refine sign crossings.",
|
||||
"For pseudo-distance body composites, do not accept abs(distance) below epsilon as a surface hit. A ray that merely passes near a petal sheet can terminate before the real front intersection behind it. Body proxy tracing should enter solids by distance <= 0 and refine the positive-to-negative bracket.",
|
||||
"Cursor hibiscus anatomy should use expressive primitives that match the organ: curved tapered sheet petals with lens footprints, curved tapered tubes for the staminal column, spheres for pollen beads, and a connected tapered stem plus calyx bulb. Do not default to ellipsoids when a lens, slab, tube, cone, sphere intersection, torus, superquadric, or profile revolution better describes the form.",
|
||||
"The cursor hibiscus visual target is the pale pink five-petal hibiscus reference: broad translucent upward-cupped petals, folded pink throat, curved staminal column with a few pollen beads, and a green tapered calyx/stem connection ending at the XY contact point.",
|
||||
"Cursor hibiscus petals should be modeled from one cheap longitudinal parameter: radial displacement grows quadratically from the vertical root, width and thickness grow toward the distal blade, and the first stable pass should avoid decorative ruffle/vein math. Do not build separate vertical panels plus horizontal blades; that creates rectangular fences and pulled-apart petal anatomy.",
|
||||
"Agent role bodies should start from a small set of anatomical/form parameters that explain the whole silhouette before adding detail: a center curve, profile/width function, thickness function, repetition symmetry, and bounded material regions. If the SDF cannot be described as one coherent mapping from role state to form, stop and redesign instead of adding compensating organs.",
|
||||
"When a role visual spec describes a continuous form, implement a continuous field or coherent parameterization first. Do not assemble continuous anatomy from piecewise capsules, boxes, slabs, helper organs, or adapters unless the spec itself is piecewise or a measured constraint forces that cut.",
|
||||
"For agent SDFs, prefer cheap structural math over decorative geometry. Veins, ribs, glitter, pollen, texturing, and fine state response should first be material/shading signals or LOD-gated overlays; do not put trigonometric ornament or filament swarms into the traced distance field until the base form is stable, readable, and measured fast.",
|
||||
"Agent SDF iteration must separate form, evaluator, and ornament. First make the implicit form anatomically coherent from multiple views, then validate marcher behavior and cost, then add state-reactive detail. Screenshot-driven patches that only fix the current angle are a warning sign, not progress.",
|
||||
"Imagination's spec is the authority: luminous opal seed, broad translucent curling ribbon-sheets, raised traced rim paths, visible aperture negative space, sparse candidate filaments/sparks, and cool backlog shadow. Do not amend the visual-language doc to excuse a weaker implementation; update the implementation to match the topology.",
|
||||
"Imagination should read as distinct petals first, not as a fully merged blob. Keep the central seed small, make petal lobes narrow and visibly separated, and accept intentional negative space when it makes the role shape legible.",
|
||||
"Imagination's live shader realizes the six-petal topology as three mirrored sheet-pair fields. Keep film, rim, tendril, spark, shadow, and seed distances separated through material classification so raised rims can glow without collapsing the petal sheets into one generic blob.",
|
||||
"Do not reintroduce Imagination's old polar-lobed seed or traced half-torus shadow. The seed is a plain luminous opal bud unless the spec asks otherwise; backlog shadow needs a visual contract before it becomes traced geometry.",
|
||||
"Imagination's ribbon sheets should use one continuous pair-space field for film and raised edge rims. Do not rebuild the bloom from piecewise rim capsules or straight root/tip posts when the sheet parameterization can own the silhouette directly.",
|
||||
"Self's body is the routing authority object: a black void command sphere with sharp golden Fresnel edge-light, one gold core band, and a compact log-spherical orrery lattice. Rails are fixed radial shell strata crossed with angular harmonic bands; each shell owns a real orthonormal frame built from all three axes; rails thicken into readable PBR bands with a narrow inner-surface emissive strip derived from the same shell/band coordinates. Gates should be compact triple-band crossings, not pairwise slabs.",
|
||||
"Self's orrery comparison is motion and topology grammar, not independent hoop inventory or literal symbolic anatomy. Rails, gates, seams, and core bands should emerge from shared orbital space with phase motion; do not use raw atan2/fract branch cuts for visible rails, animate radial zero crossings, grow rings from points, let frame axes collapse into a plane, stack multiple core bands, or rebuild Self as one-radius ornament layers and repeated trigonometry piles.",
|
||||
"Self is allowed to be a scene light, but its visible body must not add full primitive light radiance to every surface. Shared PBR attenuates same-field direct lighting; Self carries its visible read through material contrast, IBL, controlled rail/gate emission, and the custom void-core Fresnel.",
|
||||
"Heavy/specialized SDF evaluators should not live inside generic packed-id helpers when those helpers are called repeatedly; avoid shader compiler path cloning.",
|
||||
"Lighting is diegetic. Self is the initial emitter; later other Selves should emit through an explicit body light lane, not generic field instances or ambient convenience fill.",
|
||||
"Keep bundled blue-noise texture assets available for future dithering/noise work even when no current pass samples them.",
|
||||
"Specular IBL uses the Studio2 PMREM cubemap baked at 512px per face: bake HDR latlong radiance into roughness-indexed cubemap mips, load it as a D3D12 TextureCube, and sample it by reflection direction plus roughness LOD. Convert Aquarium's Z-up world directions to cubemap Y-up directions before sampling: (x, z, y). Grid mirror reflection samples mip 0 directly; body material reflections use roughness LOD. Keep this as material reflection response, not a replacement for diegetic body light authority.",
|
||||
"Diffuse IBL uses a separate Studio2 irradiance cubemap, not blurred GGX PMREM. Bake it by cosine-weighted hemisphere convolution storing irradiance integral Li*cos(theta) dOmega, then shade non-metal bodies with Fresnel-gated diffuse share times baseColor/PI times irradiance.",
|
||||
"The fullscreen scene pass owns background and height-field surface. Client-declared SDF shaders render through bounded proxy pipelines with shared SDF proxy plumbing.",
|
||||
"SDF proxy control flow is split by cost and authority: ray marching calls distance only, normals sample distance only, and surface/material evaluation runs once at the refined hit.",
|
||||
"Shared SDF field ids are generic base-plus-object-index metadata. Client identity belongs in client object tables and shaders, not in common engine HLSL.",
|
||||
"SDF surfaces use metallic-roughness PBR: baseColor, metallic, roughness, emission, Cook-Torrance GGX specular, Fresnel-gated Lambert diffuse, diffuse irradiance IBL, and roughness-mip PMREM specular.",
|
||||
"HDR/PBR presentation follows research/rendering/hdr-pbr-presentation.md: scene-linear lighting, explicit exposure, pre-tonemap bloom/veil, then display transform.",
|
||||
"Current temporal resolve uses a small subpixel Halton jitter, validated color/metadata/control history, a narrow SDF hot-current path that lets valid history damp transient specular fireflies without relaxing travel/field/normal/coverage validation, bloom prefilter clamping for unsupported single-pixel HDR spikes, and bloom attenuation when resolved scene luminance is lower than the raw current spike. Do not preserve dormant full-frame event/history lanes without an active producer and consumer contract.",
|
||||
"Planetary terrain should move toward a cube-sphere/QSC-family address space: six quadtree cube faces projected to the sphere with measured low-distortion warp candidates instead of lat-long. Start with tangent, fifth-order odd polynomial, and COBE/QSC-style bivariate projection candidates; choose by area error, inverse lookup cost, and GTX 1070 shader cost, not aesthetic purity.",
|
||||
"Multiscale terrain and agent/body detail should converge on bounded IFS brush grammars. A primitive should be able to emit lower-scale detail locally; texture/material brushes may be dense, but traced SDF form brushes must have conservative envelopes, explicit LOD/cost tiers, proxy bounds, and debug views before they enter hot rendering.",
|
||||
"The next brush envelope should be a compact-support anisotropic shaped Gaussian-style kernel: center, orientation, radii/inverse covariance, falloff, shape controls, payload type, and bounds. Borrow covariance-like shape, binning, and LOD discipline from EWA/3D Gaussian splatting; do not import infinite-support exp() cost or radiance-field machinery by default.",
|
||||
"VibeGeometry's `vg_grammar` and `vg_csg` tree are the local model for Aquarium's future IFS brush DSL: emit semantic claims with local frames, deterministic seeds, tags, captures/fields, payload bindings, LOD/cost tiers, and boolean ownership nodes before lowering to renderer backends. The authored tree is durable design; flattened brush tables, SDF includes, splat batches, or offline mips are compiled verdicts.",
|
||||
"The `.aquageo` DSL can express transparent Form fields directly: `density` and `extinction` use the same compact brush syntax as `height`, and recursive `flame` emits Density payloads. Height brush lowering must filter mixed trees to Height payloads; transparent Form claims belong to field/density lowering, not terrain brush cosplay.",
|
||||
"IFS LOD should choose a stable hierarchy cut from cached node summaries, not blindly score every leaf. Each node needs bounds, max form/material error, coverage/normal or gradient bounds, estimated cost, online estimator state, residency, and summary/child payload handles. Children fade in when projected contribution exceeds threshold and resident budget allows; parent summaries remain renderable fallbacks.",
|
||||
"AquariumFractalSummary carries a FormEncodingMask. Structural probe generation should derive Form/Density or Form/Extinction from density-only or extinction-only summaries instead of defaulting every selected node to SDF. Height and signed-distance summaries may still prefer SignedDistance for the current surface lowering path.",
|
||||
"The IFS contribution cache must probabilistically refresh node weights under a per-frame update budget. Use online mean/variance/confidence/sample-age state with nonzero exploration for visible or near-threshold nodes so weights converge instead of freezing stale guesses. Learned scoring may later rank update and residency priority from observed high-quality probes, but conservative summaries remain the safety authority for SDF bounds and visibility.",
|
||||
"Aquarium's fractal renderer and Mimir-style sensor fusion share a deeper shape: both accumulate confidence-weighted spatial evidence into temporal reservoirs, then render a resolved surface/volume field. Keep the budget planner vocabulary general enough for CPU update work, GPU packet cost, RAM residency, and SSD request pressure; do not trap the future shared machinery inside renderer-only folklore.",
|
||||
"The Perfect Machine's durable layer split is Form, Appearance, and Transport. SDF/PBR/radiosity are the first opaque backend packet names, not the conceptual architecture. SDF is a solid level-set Form encoding; density/extinction/confidence is the Form encoding for flames, smoke, transparent gradients, and uncertain sensor volumes. PBR is one Appearance encoding; participating media need albedo/emission/phase/absorption/scattering, with Transport owning radiance, emission, and scattering reuse.",
|
||||
"Temporal Gaussian splats lower through TemporalSpatialEvidenceReservoir: stable keyed observations become delayed, smoothed, confidence-weighted tracks with velocity prediction, expiry, and max-track eviction before backend packet lowering. Evidence observations and samples carry Form/Appearance/Transport layer plus encoding metadata; internal track keys include layer and encoding so the same stable key can carry separate SDF, density, confidence, or other field tracks without blending them. Treat Gaussian fields, fractal form probes, density/extinction samples, and Mimir sensor-fusion features as different evidence producers for this reservoir shape, not separate accumulator folklore.",
|
||||
"LocalCastGpuFusionAccumulator must remain a thin adapter over TemporalSpatialEvidenceReservoir. LocalCast may own mapping from visual points/seeds into evidence payloads, but it must not grow a second stable-key history, smoothing, expiry, or sample-budget algorithm.",
|
||||
"TemporalSpatialEvidenceLowering owns conversion between shared evidence samples and backend packets such as TemporalGaussianObservation, AquariumTemporalSdfGaussian, and AquariumGpuFusionSeed. Consumers should not pack Payload0/Payload1 by private convention when a lowering helper exists.",
|
||||
"The temporal reservoir ownership contract lives in docs/temporal-spatial-evidence-reservoir.md: ResampledImportanceReservoir<TSample> owns RIS/ReSTIR-style candidate selection math; raw producer reservoirs own capture-time retention; Aquarium's temporal spatial evidence track layer owns stable resolved spatial history; lowerings own backend packet conversion; TAA owns pixel history validation. Do not let consumer repos build parallel stable-key spatial evidence caches.",
|
||||
"Zyphos fractal stress data should keep authored topology richer than the first renderer backend: both Zyphos and Umbros expose lat/long, surface, object-scale, and cube-tile domains in `.aquageo`, with explicit continent/forest/tree/leaf/coast/pebble and crater/boulder/pebble recursion. The current D3D12 height-field stress table uploads 64 shaped 2D brushes and the SDF planet shaders carry separate cheap bounded quadtree-style relief.",
|
||||
"The `.aquageo` compiler must preserve each tile declaration as its own ownership-tree node. Collapsing every claim under the final tile makes the authored multi-domain world a lie even if the brush count looks impressive.",
|
||||
"Zyphos passes cube-tile domain metadata through height brush packets and binds those packets into the SDF pass. The planet shader may use authored brush packets for post-hit material/detail evaluation; traced geometry must wait for selected-cut/resident packet policy so SDF distance loops do not evaluate every brush at every step.",
|
||||
"Zyphos traced planet geometry may sample only a hard-budgeted top-influence subset of authored fractal brush packets in `sdfDistance`; the current proven budget is four brushes after sorting selected packets by abs(amplitude)*max(radius). A 12-brush distance loop was tested and rejected because it pushed the live frame to about 33 ms; the four-brush loop returns the live view to about 16.4 ms while full packet richness remains available to post-hit material/detail.",
|
||||
"Temporal resolve has a cache-facing detail lane: SdfSurface.temporalDetail writes through scene-control.z into history-control.z, and D3D12Post reduces history confidence when current and previous temporal detail disagree. Use this lane for stochastic fractal/cache stability signals, not as geometry authority.",
|
||||
"Temporal resolve now has explicit reservoir guide targets. SDF and temporal Gaussian passes write a current scene reservoir guide MRT and D3D12Post reads/writes ping-ponged history reservoir guide targets with x=confidence, y=sample age, z=domain validity, w=invalidation code. History-control.w still owns pixel history age; do not pack reservoir history back into scene-control folklore.",
|
||||
"FractalContributionCache is the live cache loop: each frame builds a resource plan from current summaries and cached states, stochastically observes only budgeted update nodes, stores mean/variance/confidence/sample age through FractalContributionEstimator, frames scheduled updates as weighted ResampledImportanceReservoir candidates, and lets backend packet compilation stay cached by selected-cut key. It is a candidate source, not the whole temporal/spatial reuse pass. Do not replace this with a static plan cache that stops learning after the first camera bucket.",
|
||||
"FractalOccupancyGraph is now the live memory behind FractalContributionCache. It owns per-node contribution state, last visible frame, last observed score, and update probability; unobserved nodes decay confidence and grow stale uncertainty. Keep richer residency/resource fields here rather than adding another cache beside it.",
|
||||
"FractalResidencyPlanner keeps resident payloads by score-per-cost when RAM budget is capped and reports evicted node keys explicitly. Eviction is a planner decision row until a real payload/page store owns mutation; selected nodes still render through summary fallback when evicted or missing.",
|
||||
"FractalProbeSample is the typed reservoir sample shape for fractal form/detail reuse: domain key, node key, local center, bound radius, target contribution, source PDF, material delta, field layer/encoding, and payload handle. The same ResampledImportanceReservoir<FractalProbeSample> must handle opaque Form/SignedDistance and transparent Form/Density or Form/Extinction samples. Reuse must reject mismatched layer/encoding before lineage and local-shift checks, then later add camera motion, disocclusion, material compatibility, visibility, and encoding-specific bounds before temporal/spatial reuse.",
|
||||
"FractalProbeReuseValidator.ValidateTemporal is the CPU contract for future GPU temporal reuse. It rejects excessive camera motion, disocclusion, material mismatch, low visibility, bad domain lineage, excessive local shift, and invalid bounds with explicit reasons; shader reuse should mirror this contract instead of inventing private validation rules.",
|
||||
"FractalStructuralProbeGenerator lowers AquariumFractalSummary rows into FractalProbeSample reservoir candidates with local support, projected target contribution, clamped source PDF, material delta, and payload handle. This is the structural IFS probe producer; renderer-facing temporal validation still needs camera/disocclusion/material/visibility inputs.",
|
||||
"FractalStructuralProbeReservoir builds a reservoir snapshot from an ownership tree, selected cut, summaries, and projected pixels per world unit. ZyphosFractalRenderPlan now carries this structural probe reservoir, so the planet path exposes reservoir-shaped structural evidence beside brushes/resource plans before GPU reuse exists.",
|
||||
"AquariumFractalSdfSplat3D is the compact 3D packet contract for the first opaque Phase F Form slice. FractalSdfSplat3DCompiler accepts only Form/SignedDistance probes, and FractalSdfSplat3DKernel owns CPU compact-weight/signed-distance parity math. AquariumFractalDensitySplat3D plus FractalDensitySplat3DCompiler are the matching transparent Form packet/compiler for Form/Density and Form/Extinction probes, with an 80-byte packed density splat stride aligned to the opaque SDF splat stride. Do not force flames or sensor confidence volumes through solid SDF semantics.",
|
||||
"Hot fractal splat storage must be GPU-resident packed buffers manipulated by compute shaders. Stable string-keyed splat contracts are metadata/debug boundaries, not million-instance hot buffers. `AquariumPackedFractalSdfSplat3D` is the numeric 80-byte packet shape; C# staging/readback paths use unsafe `FractalNativeBuffer<T>` when CPU memory is genuinely needed.",
|
||||
"Fractal reservoir compute can now take a compact authored IFS program. `FractalGpuProgramCompiler` lowers selected `.aquageo` brush claims into precomposed `AquariumPackedFractalIfsTransform` support rows; Zyphos passes those rows through `AquariumFractalReservoirField.ProgramTransforms`; D3D12 uploads the small program as a compute SRV. The shader samples one selected-cut row in O(1) for authored programs; nested domain ancestry belongs in the compiler/planner, not the million-splat kernel. The hash fractal remains a fallback/receipt mode, not the live authored generator.",
|
||||
"The fractal reservoir field owns world placement through `WorldCenterRadius`. Zyphos binds this to the planet center and surface radius, and the visible splat pass currently maps first-slice SDF/PBR/radiosity reservoir rows into that frame. Conceptually those rows are Form/Appearance/Transport; do not fall back to camera-relative debug splats for the primary terrain demo.",
|
||||
"Authored fractal GPU program rows must preserve cube-sphere tile identity. `AquariumPackedFractalIfsTransform.TileAddress` carries face, level, tile X, and tile Y; rotation cos/sin live in `MaterialSeedShape.zw` to keep the packet 64 bytes and avoid per-splat trig. The compute shader maps selected-cut brush support through the tile address onto cube-sphere faces. Dropping tile X/Y turns Zyphos back into meaningless cap pudding.",
|
||||
"The first visible fractal reservoir consumer is a tangent-frame surface patch renderer, not a final terrain resolve. It draws a larger live subset of GPU-resident splats, projects patch corners from world space, and shades from radial normals plus first-slice SDF/PBR/radiosity reservoirs. If the result still looks abstract, the next coherent fix is clustered surface/volume resolve or coordinate authority, not more decorative billboard tuning.",
|
||||
"Zyphos camera composition must target the selected spatial domain's tracked center while keeping the parent as orbit/composition anchor. Looking directly at the parent made planetary mode aim at the binary midpoint and left Zyphos offscreen, which made renderer failures look like art failures.",
|
||||
"Do not use Zyphos as the first proof of fractal DSL correctness. Start with reference fractals. Apophysis/FLAM3-style `.flame` fixtures are the parity pressure for Aquarium `.aquageo`; GPL/open-source renderers stay external/test-only. The first gate is linear Sierpinski: exact fixed-xform sequence parity and chaos-game moment bounds before any GPU visualization claim.",
|
||||
"The local Apophysis/FLAM3 subset parser owns only a small proven flame shape: xform weight/color, affine coefficients, and `linear`, `spherical`, and `bubble` variation weights. `FractalFlameChaosGame` and `FractalPointHistogramBuilder` provide deterministic CPU receipts. External renderer proof stays optional and outside runtime through FLAM3-compatible PPM receipt hashing.",
|
||||
"Use `scripts/fractal-flame-receipt.ps1` for the local CPU flame receipt. The default mixed linear/spherical/bubble fixture uses 8192 samples, 64 burn-in, 64x64 bounds -8,-8,8,8, seed 0x0BADC0DE, and checksum 0xAEB1C81B. Use `scripts/fractal-flame-reference-render.ps1` with a local `flam3-render` executable to produce external PPM image receipts under artifacts/fractal-flame-reference; Aquarium does not vendor Apophysis or FLAM3.",
|
||||
"FractalGpuProgramCompiler can lower the proven FLAM3-style flame subset into GPU program rows for D3D12FractalReservoirCompute's explicit flame 2D program mode. Flame mode owns a 32-byte AquariumPackedFractalFlameState UAV row per resident splat; touched rows advance persistent chaos-game state instead of replaying from the origin. The cache has two phases: full-population acquisition, then budgeted stochastic maintenance. On 2026-05-21 the GTX 1070 ran JWildfire FARender selftest.flame with 2,000,000 splats, 2,000,000 flame states, three 2,000,000-row first-slice Form/Appearance/Transport reservoir layers, 8 full acquisition frames, steady 50,000 splat updates/frame, 15,000 reservoir updates/pass/frame, depth 8, at 1.011 ms/frame / 988.8 FPS equivalent, 84.85% CPU-slice distribution parity, checksum 0xC633FADC3BD7E5BE. Without acquisition, the same steady budget scored only 32.64%; do not confuse a cold persistent cache with a bad sampler.",
|
||||
"The live GPU splat packet carries a Form encoding tag in an existing material/confidence lane so flame-mode compute can mark splats as Density without changing the 80-byte hot stride. D3D12FractalSplatRender now compiles separate surface and transparent graphics pipeline states over the same GPU-resident buffers: signed-distance surface claims depth-test/write as opaque geometry, while density/extinction claims use a depth-disabled additive color-only pass. This is a field-aware debug/consumption path, not full volume ray integration; do not add a second transparent reservoir or buffer unless a measured resolve need beats the shared packet invariant.",
|
||||
"Fractal splat reservoir guide output must obey the shared TAA guide schema: x confidence, y sample age, z domain validity, w invalidation code. Do not pack Form/Appearance/Transport validation into guide x/y/z; those are backend layer diagnostics, not resolver semantics.",
|
||||
"Render debug mode 12 is the Reservoir/TAA Guide view and should display guide semantics directly: confidence, normalized sample age, and domain validity.",
|
||||
"The first visual parity metric compares GPU flame splat XY histograms against the local CPU flame oracle. With 250,000 GPU readback splats, 1,000,000 CPU reference samples, 128x128 bounds -8,-8,8,8, and the mixed FLAM3-style fixture, distribution score is 84.05% at frame 1, 84.10% at frame 5, 84.20% at frame 20, and 84.24% after the 60-frame/10-warmup receipt; cosine similarity stays about 0.9955. This is high distribution similarity but not learned convergence: the current reservoir path initializes splats and stochastically replaces them, without visual-error feedback or ReSTIR/MIS target correction yet.",
|
||||
"Global flame parity is not enough. View-conditioned parity now scores named viewport bounds and reports GPU/reference hits, starved reference bins, and underrepresented mass. First depth-16 GTX 1070 receipt with 250k GPU readback splats vs 1M CPU samples: global -8..8 scores 97.09%, mid -1..1 scores 91.93%, close -0.5..0.5 scores 88.97%, micro -0.25..0.25 scores 82.05% with 2,656 starved bins and 17.95% underrepresented mass. This proves the current reservoir is fast but not view-adaptive; next work needs camera-conditioned target weights and underrepresented-region feedback.",
|
||||
"FractalHistogramResidualFocus converts visual parity residuals into a tested focus window: underrepresented reference mass determines center, radius, and strength. tools/Aquarium.Fractal.Receipt prints the suggested focus per visual parity view so a bad contact sheet now yields a concrete reservoir-pressure input for the next adaptive loop.",
|
||||
"tools/Aquarium.Fractal.Receipt --adaptive-focus is the first closed feedback receipt: it uses a warmup epoch to populate the existing GPU buffers, reads back reservoir density, computes a residual focus, and runs measured frames over the same buffers with that focus. On the small GTX 1070 mixed-flame smoke, this moved the score from 67.07% non-adaptive to 70.89% adaptive at about 0.160 ms/frame. Treat this as proof of feedback shape; the runtime still needs a no-stall GPU-side or delayed feedback path.",
|
||||
"Do not use the quick 1M-sample flame oracle image for visual judgment; it is too noisy. The high-reference contact sheet uses 20,000,000 CPU oracle samples and 250,000 Aquarium GPU readback splats per panel at artifacts/fractal-contact-sheet-hq/flame-parity-contact-sheet-hq.png. It makes the zoom failure legible: the CPU oracle smooths out while Aquarium remains under-sampled after zoom because the current reservoir is not view-adaptive.",
|
||||
"Aquarium's CPU flame histogram is a math oracle, not visual ground truth. The visual reference ladder is: Chaotica as gold market-quality reference when available/imported, JWildfire/FARender as scriptable visual reference, FLAM3/Apophysis as portable baseline compatibility, Aquarium CPU as deterministic unit-test/debug oracle only. On 2026-05-20 Chaotica and flam3-render were not on PATH, but scripts/install-flame-reference-tools.ps1 hydrated JWildfire 9.00 plus Temurin JRE 17 under ignored artifacts, and scripts/fractal-flame-jwildfire-reference.ps1 rendered JWildfire's bundled FARenderJWF selftest flame at 1024x1024 quality 2000 in 7.69 sec on the GTX 1070. JWildfire/FARender is an external visual reference artifact lane, not Aquarium runtime code. Do not claim best-in-market flame parity until imported Chaotica renders or fully matched JWildfire flame dialect metrics are wired into residual scoring.",
|
||||
"The useful flame oracle is now external density, not Aquarium CPU self-agreement. tools/Aquarium.Fractal.Receipt accepts --reference-density-ppm to compare Aquarium GPU SDF envelope reservoir density against luminance density from a binary PPM rendered by JWildfire/FARender. scripts/new-jwildfire-baby-fixture.ps1 derives a smaller FARender-compatible julian-disc-baby.flame from the bundled selftest while preserving required FARender boilerplate. First external receipt scored 15.33% in 256x256 bounds -2..2 while Aquarium still binned raw centers; after fixing JWildfire coefs packing (`a b d e c f`) and FARender's disc angle convention (`atan2(x,y)`), the raw-center score reached 26.87%. With the candidate switched to full SDF-reservoir density, the same target scored 22.14% at 42.053 ms/frame with all 2M reservoir rows refreshed. Cutting the false JWildfire `normal` -> `linear` import and resolving subpixel SDF envelopes as at least one histogram bin moved the score to 31.36% at 41.692 ms/frame. `-HistogramBounds flame-camera` derives FARender-style size/scale/cam_zoom bounds and moves the score to about 43.1% with about 68% occupancy overlap. Full reservoir refresh must use direct row indexing, not stochastic hashing; after that fix the same 2M-row full-refresh gate runs at 7.508 ms/frame / 133.2 FPS equivalent instead of roughly 41 ms/frame. Aquarium-vs-CPU still scores about 89.94%, so the live failure is exact JWildfire variation/filter semantics, target density weighting, and view-conditioned reservoir feedback, not sample count.",
|
||||
"JWildfire selftest is now the flame renderer faceplant target. The current dialect slice supports JWildfire coefficient layout, variationGroup, disc, julian, gaussian_blur, and post transforms. After post lowering, the depth-64 GTX 1070 receipt scores 84.19% against Aquarium's CPU slice oracle in bounds -8..8 and 88.01% in bounds -128..128, but costs about 129 ms/frame. This is not external JWildfire visual parity; it is CPU/GPU agreement on the supported slice. Aquarium still needs richer dialect semantics, palette/density/render-filter parity, weighting-field handling, and persistent per-sample GPU iteration-state reservoirs instead of replaying deep chaos-game ancestry from zero for every splat.",
|
||||
"Flame imports must report translation loss. FractalFlameFileParser.ParseFirstWithReport returns accepted, approximated, ignored, and rejected fields per transform, and receipt runs write fractal-flame-import-report-*.json. The JWildfire selftest report currently shows 15 accepted fields, 3 approximations, 45 ignored render/presentation fields, and 11 rejected geometry/sampling fields: wfield_* weighting-field attributes. Treat successful XML parsing as insufficient until rejected geometry fields are either implemented as DSL/operator nodes or explicitly accepted as out-of-scope diagnostics.",
|
||||
"Persistent flame iteration now has both a CPU parity contract and a GPU realization. FractalFlameIterationState plus FractalFlameIterationStepper prove chunked CPU advancement; AquariumPackedFractalFlameState mirrors the point/support/material/RNG/step packet in D3D12FractalReservoirCompute as a UAV so flame splats advance over frames. Keep the acquisition/maintenance split explicit in receipts and renderer budgets.",
|
||||
"Fractal reservoir update pressure now has a first view-conditioned GPU input. AquariumFractalReservoirField.PriorityFocus carries focus XY, radius, and strength; D3D12FractalReservoirCompute uses it only for under-budget stochastic row selection by choosing among a few random candidates, while full-refresh passes remain direct row sweeps. This preserves convergence/exploration and gives Zyphos camera-domain selection a real way to steer work toward visible detail. Receipt runs can exercise the path with --priority-focus.",
|
||||
"Zyphos' primary planetary terrain test path is now the fractal reservoir surface. The direct SDF planet and Umbros proxy shaders are removed from the render plan; only the parent star remains as a direct SDF body/light. If the planet looks wrong, fix the reservoir lowering/shading path instead of letting the old SDF terrain hide it.",
|
||||
"The GPU splat receipt harness lives at tools/Aquarium.Fractal.Receipt and scripts/fractal-splat-receipt.ps1. The live receipt allocates one 80-byte packed SDF splat UAV plus three distinct 64-byte reservoir UAVs for SDF envelopes, PBR material envelopes, and radiosity; those reservoirs are sampled in independent compute passes under a stochastic update budget. On the local NVIDIA GTX 1070 it kept 2,000,000 splats and 2,000,000 reservoirs per layer resident. The fallback hash-fractal receipt updated 50,000 entries per layer with 2 candidates/update at 4.471 ms/frame, 223.7 FPS equivalent. The authored precomposed selected-cut receipt used depth 48, 4 compact transforms, and 15,000 updates per layer at 4.908 ms/frame, 203.7 FPS equivalent, with full reservoir coverage in 133.3 frames. D3D12FractalSplatRender consumes the raw splat, SDF, PBR, and radiosity buffers through separate graphics SRVs for the visible debug subset. This proves compute-side GPU residency, budgeted temporal convergence, authored-program splat population decoupled from domain ancestry depth, and first layered GPU consumption; final terrain/material/radiosity shading is still future work.",
|
||||
"FractalProjectedSdfSplatCompiler is the Phase G 2D-projected-to-3D lowering seam: it converts resident SignedDistance2D page payload samples into compact 3D SDF splats through an explicit page-local Vector2 -> Vector3 mapping, surface normal, support radius, and splat budget. Zyphos caches a bounded first set with a flat local mapping until cube-sphere/torus mappers are added.",
|
||||
"Zyphos camera distance limits belong to the selected spatial domain, not one global planetary clamp. Leaf/pebble domains must be able to zoom below whole-body distances, and the parent star must be a visible SDF body when it is also the primary light source.",
|
||||
"The consolidated fractal brush architecture lives in research/rendering/fractal-brush-architecture-plan.md. Its pipeline is client intent -> domain roots -> semantic IFS brush grammar -> ownership tree -> node summaries -> contribution cache/residency scheduler -> backend packets -> renderer passes -> debug/evidence. Its credibility depends on module boundaries and tests: contracts, pure CPU fractal core, D3D12 backend, client adapters, mock payload/probe/random/clock seams, shader parity tests, and deterministic performance fixtures.",
|
||||
"The Perfect Machine waterfall architecture lives in docs/perfect-machine-architecture.md. Treat it as the design authority before expanding SDF splat backends, sensor-fusion candidate adapters, reservoir guide buffers, occupancy graph state, resource-tier residency, or stochastic learned priority. Its core split is domains -> evidence candidates -> target evaluation -> ReSTIR/GRIS reservoirs -> occupancy graph -> residency -> 2D/3D/projected SDF splat packets -> TAA guide buffers.",
|
||||
"AquariumFractalSurfacePageKey and AquariumFractalSurfacePage are the renderer-agnostic page contracts for Phase E: height, SignedDistance2D, material, and confidence surface pages carry stable domain/node/kind/mip keys, bounds, dimensions, payload handles, and max error before any D3D12 page store exists.",
|
||||
"FractalSurfacePagePlanner lowers selected IFS cuts into stable surface page metadata without renderer dependencies. ZyphosFractalRenderPlan now exposes height, SignedDistance2D, material, and confidence pages beside brushes, resource plans, and structural probe reservoirs; the actual page store, eviction, atlas, and D3D12 lowering are still open.",
|
||||
"FractalSurfacePageResidencyPlanner is the renderer-agnostic page-store policy boundary: it asks IFractalSurfacePageStore about page-key residency, keeps best max-error-per-byte resident pages under a byte budget, requests highest-value missing pages, and reports evictions. Zyphos carries this page residency plan, but real storage and D3D12 atlas mutation remain future work.",
|
||||
"FractalSurfacePageRasterizer lowers resident planned pages into CPU sample payloads using the shared FractalBrushEnvelope2D math: height sums amplitudes, SignedDistance2D uses a cheap signed support-distance estimate, material uses deterministic weighted claim tags/seeds, and confidence accumulates clamped envelope coverage. Zyphos caches resident page payloads by page key before any GPU atlas exists.",
|
||||
"The actionable fractal brush roadmap lives in research/rendering/fractal-brush-implementation-roadmap.md. Start with the first work packet: add Aquarium.Engine.Fractal and tests, cube-face/tile key types, identity and tangent projection candidates, an area distortion sampler, face-edge tests, and a projection report before touching recursive detail."
|
||||
"Specular IBL uses Studio2 PMREM as a TextureCube; Aquarium Z-up world directions convert to cubemap Y-up by sampling (x, z, y). Diffuse IBL uses a separate cosine-convolved irradiance cubemap."
|
||||
],
|
||||
"text_and_ui": [
|
||||
"Overlay text uses DirectWrite/Direct2D after scene rendering. It is crisp final-pixel UI for debug surfaces, terminals, inspectors, and splash/status text.",
|
||||
"Aquarium UI controls follow the CultLib code-first binding style without Unity prefab assumptions: panels, sections, sliders, toggles, buttons, option rows, tree items, and text boxes bound by explicit read/write delegates.",
|
||||
"Aquarium.Engine.Contracts exposes AquariumUiDocument as the client-facing debug composition surface. Client panels are tabs inside the single Aquarium debug panel unless they explicitly opt into floating/proximity-faded overlay behavior. Clients can register terminal commands through AquariumUiDocument.Command. Longer editable strings should use AquariumUiTextBox instead of pretending to be row values. Text boxes own caret/selection editing state, may opt into bundled Ubuntu Sans Mono and bottom alignment, and focused text boxes capture input so renderer debug hotkeys and client camera controls stay quiet while editing.",
|
||||
"Use AquariumUiTreeItem for selectable hierarchy rows: disclosure arrows own expansion, row selection owns mode/target choice, and clients provide depth/detail/selected bindings without leaking domain-specific hierarchy policy into DebugUi.",
|
||||
"The unified F2 debug panel is titled Debug and owns engine controls, client tabs, and a bottom-aligned multiline command terminal. Tab navigation is panel chrome: a highlighted row of buttons below the title, not a content section made of ordinary controls. Do not reintroduce separate Aquarium/Epiphany debug panels fighting for the same hotkey.",
|
||||
"Vortice.Mathematics.Rect uses x, y, width, height. UI code should use explicit RectFromEdges helpers when reasoning in edges.",
|
||||
"Debug UI feedback needs honest element-specific states: base, hover, and active. Sliders respond on track/fill and handle separately, keep geometry stable, and brighten by lerping accent colors toward white.",
|
||||
"Scene/diegetic labels should use renderer-owned MSDF/SDF billboards when they live in world space. Overlay text should not be shoved into HDR for convenience."
|
||||
"ui_audio": [
|
||||
"Overlay text uses DirectWrite/Direct2D after scene rendering. Scene text should become renderer-owned MSDF/SDF billboards when it belongs in the world.",
|
||||
"The unified F2 debug panel owns engine controls, client tabs, and a bottom-aligned command terminal. Clients contribute AquariumUiDocument panels and commands; DebugUi owns input dispatch.",
|
||||
"Debug UI geometry should use explicit edge helpers around Vortice.Mathematics.Rect because Rect stores x, y, width, height.",
|
||||
"AquaSynth.Faust is consumed as a pinned repo-local NuGet package. AquaSynth owns synth internals and native Faust factory lifetime; Fensalir owns debounce, playback scheduling, rendered-buffer caching, and WASAPI output.",
|
||||
"WasapiAudioDevice mixes queued PCM with per-chunk gain and stereo pan, degrading to mono by averaging channels when needed."
|
||||
],
|
||||
"audio": [
|
||||
"Aquarium exposes an optional audio/synth hosting boundary through contracts; clients declare intent, Aquarium schedules playback and owns device output.",
|
||||
"Aquarium consumes AquaSynth.Faust as a pinned repo-local NuGet package, with AquaSynth.Core arriving transitively for the built-in patch editor/parser surface. AquaSynth owns synth internals, live patch compilation, native Faust factory lifetime, generated DSP manifests, and tests; AquariumSynthHost owns debounce, trigger scheduling, rendered-buffer caching, and WASAPI playback. Update the package only by deliberate version bump so visual/renderer work can continue while synth construction changes underneath."
|
||||
"fractal_field_architecture": [
|
||||
"The Perfect Machine field architecture lives in docs/perfect-machine-architecture.md. It is the design authority before expanding SDF splat backends, sensor-fusion adapters, reservoir guide buffers, occupancy graph state, resource residency, or learned priority.",
|
||||
"The consolidated fractal brush architecture lives in research/rendering/fractal-brush-architecture-plan.md. Pipeline: client intent -> domain roots -> semantic IFS brush grammar -> ownership tree -> node summaries -> contribution cache/residency scheduler -> backend packets -> renderer passes -> debug/evidence.",
|
||||
"The actionable implementation checklist lives in research/rendering/fractal-brush-implementation-roadmap.md.",
|
||||
"The .aquageo DSL carries semantic domains and Form claims before backend lowering. Height, SignedDistance, Density, and Extinction must not be collapsed into one payload lane.",
|
||||
"Fractal summaries carry FormEncodingMask so selected-cut structural probes do not silently default transparent form nodes back into SDF.",
|
||||
"TemporalSpatialEvidenceReservoir keys tracks by layer+encoding+stable key so Form/Appearance/Transport samples can share machinery without blending incompatible meanings.",
|
||||
"Do not add a parallel transparent reservoir just because density/extinction need a different renderer pass. Extend encodings and lowerings under the shared sample/reservoir contract."
|
||||
],
|
||||
"state_and_reload": [
|
||||
"CultCache is the client memory organ. Runtime state, camera, renderer knobs, body state, UI state, and future Epiphany connection state should be typed Cult documents.",
|
||||
"Global graphics presentation settings live in epiphany.aquarium.graphics_settings. The debug UI edits the renderer copy; the host syncs changed renderer settings back to the client runtime; the runtime flushes dirty settings through CultCache.",
|
||||
"A truncated or unreadable single-file CultCache backing store is not a schema migration failure. Aquarium should quarantine the corrupt snapshot and boot fresh typed state.",
|
||||
"dev-reload builds disposable apphost slots so a running window does not lock normal build output. Headless smoke runs use a separate CultCache from the visible dev window.",
|
||||
"Headless art captures should use disposable build slots and `Start-Process -Wait` style ownership. Aquarium.Engine is a Windows GUI executable, so plain PowerShell `&` can return before the renderer has finished pipeline compilation or frame capture.",
|
||||
"Live runtime reload is not successful just because dev-watch wrote live-current.txt. The watcher must see the host acknowledge the exact live DLL path in stdout.",
|
||||
"Shader reload failure must keep the previous good shader objects bound. Live-runtime reload failure must keep the previous runtime alive."
|
||||
"fractal_gpu_receipts": [
|
||||
"The GPU splat receipt harness lives at tools/Aquarium.Fractal.Receipt and scripts/fractal-splat-receipt.ps1.",
|
||||
"The live GPU splat packet is 80 bytes. It carries a Form encoding tag in an existing material/confidence lane so flame-mode compute can mark Density without changing stride.",
|
||||
"D3D12FractalSplatRender has separate opaque surface and transparent density/extinction pipelines over the same GPU-resident buffers. Opaque signed-distance splats depth-test/write; transparent splats run color-only additive with depth disabled.",
|
||||
"Fractal splat guide output must obey the TAA guide schema: x confidence, y sample age, z domain validity, w invalidation code.",
|
||||
"Render debug mode 12 is Reservoir/TAA Guide and should display confidence, normalized sample age, and domain validity directly.",
|
||||
"Persistent flame iteration uses AquariumPackedFractalFlameState in a UAV so touched splats advance over frames instead of replaying chaos-game ancestry from zero.",
|
||||
"Full reservoir refresh must use direct row indexing, not stochastic hashing; under-budget passes may use stochastic candidate selection."
|
||||
],
|
||||
"flame_oracles": [
|
||||
"Fractal reference parity starts before the renderer. The local CPU oracle supports a proven FLAM3/Apophysis subset: xform weight/color, affine coefficients, and linear/spherical/bubble variations.",
|
||||
"FractalFlameFileParser.ParseFirstWithReport must report accepted, approximated, ignored, and rejected fields. Successful XML parsing is not successful translation.",
|
||||
"JWildfire/FARender is the scriptable external visual reference; Aquarium CPU is deterministic debug oracle, not visual ground truth.",
|
||||
"JWildfire coefficient layout and disc angle convention were real bugs: FARender applies x=a*x+b*y+c and y=d*x+e*y+f, and jwf_disc uses atan2(x,y)/PI.",
|
||||
"JWildfire variationGroup normal is metadata, not an implicit linear variation. Do not invent geometry from it.",
|
||||
"View-conditioned parity matters. Global flame parity can look acceptable while zoomed windows starve; residual-to-focus diagnostics convert underrepresented reference mass into a concrete PriorityFocus window."
|
||||
],
|
||||
"demos": [
|
||||
"src/Aquarium.Fensalir is the Fensalir splash/art reconstruction demo. It loads Worlds/fensalir-spine-emblem.aquageo, lowers marsh ripple brushes, projects cathedral detail, renders custom water/mist shaders, and draws a luminous stacked-diamond spine through SDF proxy shading.",
|
||||
"The current Fensalir cathedral screen-space guide is scaffolding. Replace it with a .aquageo-lowered transparent pane/rune/material field target separate from the marsh height field.",
|
||||
"src/Aquarium.Sample.Minimal is the minimal non-client-policy boundary proof.",
|
||||
"src/Aquarium.Zyphos is the planetary-scale demo. Terrain should move toward cube-sphere/QSC-family addressing and reservoir-backed fractal surfaces.",
|
||||
"src/Aquarium.LocalCast is the LocalCast/Mimir-facing runtime bridge lane. Sensor-fusion claims should lower into typed temporal field evidence rather than JSON or private adapters."
|
||||
],
|
||||
"research_notes": [
|
||||
"Renderer notes live under docs/ and research/rendering/ in this repo after the split.",
|
||||
"docs/perfect-machine-architecture.md is the broad field/reservoir architecture authority.",
|
||||
"docs/temporal-spatial-evidence-reservoir.md owns the stable-key temporal evidence cache contract.",
|
||||
"docs/temporal-sdf-gaussian-field.md is historically named but now represents temporal Form-field evidence, not only SDF surfaces.",
|
||||
"research/rendering/fractal-reference-oracles.md owns flame/IFS external reference strategy.",
|
||||
"research/rendering/fensalir-spine-emblem-ifs-demo.md preserves the Fensalir splash visual target."
|
||||
]
|
||||
},
|
||||
"warnings": [
|
||||
"A clean repo can still grow Jenga if state and docs lag behind code.",
|
||||
"Do not add a framework-shaped dependency just to borrow one comfortable tool.",
|
||||
"Do not let bloom or overlay debug output disguise a bad lighting equation.",
|
||||
"Do not preserve historical branch scars in live docs unless they change a current decision."
|
||||
"Do not add client policy nouns to engine code to fix missing client context.",
|
||||
"Do not preserve historical branch scars in live docs unless they change a current decision.",
|
||||
"Do not build a new registry, adapter, cache, or helper layer until its invariant and owner are explicit.",
|
||||
"A passing receipt is not a pardon for a machine nobody can explain."
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue