acdream/docs
Erik 51178f7c77 fix(render): VM3 review fixes - pin the filmic decodes, re-derive vignette for linear, name the authored sun colour
Fix round from Opus review of 87677f9c (APPROVE WITH FIXES):

1. (A1/A3) Hardened the atmospheric_filmic.frag / atmospheric_bloom_
   downsample.frag shader-source pinning test: asserts the exact decode
   call count (6 - three in lowFusedScene, three in main's non-fused
   branch), that the 2.2 display-gamma exponent and 1/2.2 inverse in
   atmospheric_common.glsl are formatted FROM AtmosphericColorPipeline
   .DisplayGamma (so shader literal and CPU-tested value cannot drift),
   that the 0.18 contrast pivot in atmospheric_filmic.frag is formatted
   from AtmosphericColorPipeline.LinearMidGrey, and pins
   AtmosphericPostProcessGraph.BloomKneeLinear/BloomThresholdLinear as
   exact literals (0.73f / 1f). Also removed a stray trailing "()" from
   an existing comment in atmospheric_filmic.frag that was inflating the
   decode-call count to 7.

2. (B1) Re-derived the "vignette-strength" default for the linear-light
   post stack. The vignette multiply now happens on linear colour before
   the final encode, so a corner factor of (1 - strength) displays as
   (1 - strength)^(1/2.2), not (1 - strength) directly. The accepted
   look was strength 0.12 under the OLD gamma-space pipeline: a 12%
   on-screen corner darkening. Under strength 0.12 in the new linear
   pipeline that same 0.88 corner multiplier would only display as
   0.88^(1/2.2) ~= 0.9435 (5.6% darkening - visibly weaker). Solving
   (1 - strength)^(1/2.2) = 0.88 gives strength = 1 - 0.88^2.2 ~= 0.245,
   which reproduces the accepted 12% corner darkening. Since
   RenderPackSettingValueCodec requires every declared default to be
   step-aligned from the minimum and 0.245 is not a multiple of the old
   0.01 step, the step also moves to 0.005 (a finer slider, not
   coarser) so the exact derived default is a valid grid point -
   verified by running the ExternalTierTwoPackCanRenameEveryOwnedId
   AndShaderAsset validation test, which failed with "invalid default
   value" before this correction. Also updated the matching fallback in
   AtmosphericPostProcessGraph.FromDescriptor (0.12f -> 0.245f) for
   consistency, and added
   AtmosphericColorPipelineTests.VignetteDefaultReproducesTheAccepted
   TwelvePercentCornerDarkening pinning encode(1-0.245) ~= 0.88.

3. (A4) Renamed VolumetricShaftFrameParameters.LinearSunColor ->
   AuthoredSunColor in VolumetricShaftQuality.cs (internal, 2 references,
   both in that file - safe). Left LightSource.ColorLinear unrenamed:
   grep shows 13 files depend on it (GlobalLightPacker, SceneLightingUbo,
   LightBake, LightManager, EnvCellRenderer, RenderingDiagnostics, and
   several Core tests) across the shared retail default-path lighting
   UBO pipeline - renaming it is out of VM3's pack-only scope and would
   touch the mandatory-unchanged default path. Added a pointer comment
   on the field in LightSource.cs (and a one-line note at its
   WorldRenderFrameBuilder.cs call site) documenting the same
   display-space-not-linear fact and explaining why the rename is
   deferred to its own default-path colour-space pass.

4. (B4) Added a citation beside acesFitted in both atmospheric_filmic
   .frag and its C# mirror (AtmosphericColorPipeline.AcesFitted):
   Krzysztof Narkowicz, "ACES Filmic Tone Mapping Curve" (2016). The fit
   takes linear scene light in and returns linear display light in
   [0,1] - it does not itself gamma-encode. Evidence: acesFitted(0.80 *
   decode(0.46)) = 0.2064 un-encoded versus the accepted 0.51 on screen.

5. (B2) Rewrote the VM3 section of docs/plans/2026-08-22-visualmaster-
   campaign.md with the shipped truth in place of the pre-implementation
   guess: exposure stays 0.80 (at exposure 1.0 the linear pipeline maps
   gamma-0.5 to 0.6017, essentially the same 0.6163 the owner called too
   bright), bloom threshold stays 1.0 (a fixed point of both exponents),
   knee moves 0.45 -> 0.73, vignette-strength moves 0.12 -> 0.245. Added
   the old-vs-new curve table at exposure 0.80 across ten gamma inputs.
   Replaced the acceptance criteria's "new automated test on the
   recording RHI" with the CPU mirror + shader-source pins actually
   used, and recorded that the real-frame masked capture WAS run
   (retail vs High-with-every-effect-neutral, artifacts/vm3):
   independently re-verified by re-running the pixel diff against the
   checked-in screenshots - 110,561 px at |delta|=1 and exactly 95
   pixels at |delta|>=5, confined to foliage-canopy silhouette edges
   against sky with nothing on any ground/building/water surface. Noted
   the Stage-1 luminance table re-capture is still owed at the owner
   gate.

6. (B3) Corrected docs/plans/2026-08-21-atmospheric-rendering.md's VM3
   summary sentence: the bloom intermediate is already linear after
   extraction (no separate "bloom read" decode), and the neutral-preset
   claim is now phrased as a measured numerical identity (<=1 LSB on a
   real frame) rather than an unqualified "is" statement.

7. (A5) Corrected toolchain attribution: tools/compile-shaders.ps1 used
   the managed Silk.NET.Shaderc path (shaderc_shared.dll) to compile in
   both this round and the original VM3 commit - a Vulkan SDK glslc was
   detected and its path recorded, but the managed compiler is what
   actually ran. Regenerating this round only changed the atmospheric_
   filmic frag stage's manifest hash (comment-only edits); the compiled
   .spv bytes are unchanged, and every retail-oracle shader
   (mesh_modern, terrain_modern, mesh_detail, etc.) remains untouched.

8. Replaced an invented motive in the atmospheric_filmic.frag contrast-
   pivot comment ("rounded up for a stronger gamma-space contrast
   feel") with the actual reason: the previous 0.5 was simply the [0,1]
   midpoint of the standard contrast formula, not a deliberately chosen
   value; in linear the perceptual mid-grey is 0.18.

Verify: Release build 0 warnings / 0 errors. App hermetic-filter tests:
5970 passed / 0 failed / 0 skipped. VulkanShaderManifestTests: 7/7 pass
(retail-oracle SPIR-V byte-identical; only the atmospheric_filmic frag
manifest hash changed, no .spv bytes changed).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 23:40:48 +02:00
..
architecture docs(vm1): closeout - AP-232 for the translucent detail blend weight; sampler test pins the production constant 2026-08-22 22:50:06 +02:00
audit docs: update audit — Sprint 1 items verified (sequence counters + scenery LCG) 2026-04-13 13:51:39 +02:00
plans fix(render): VM3 review fixes - pin the filmic decodes, re-derive vignette for linear, name the authored sun colour 2026-08-22 23:40:48 +02:00
reference docs(reference): preserve local ACE command catalog 2026-07-27 00:03:58 +02:00
render-packs feat(render): Atmospheric post stack runs in linear light; neutral preset is numerically the pack-off image (Campaign VM VM3) 2026-08-22 23:10:57 +02:00
reports docs: the overnight consolidation report, open questions first 2026-07-29 03:54:43 +02:00
research docs(vm4): every Campaign AR document says what its evidence shows 2026-08-22 22:51:59 +02:00
reviews docs: close r3 test cleanup 2026-08-18 17:02:15 +02:00
superpowers feat(launcher): complete Campaign LA11 pre-gate support 2026-08-15 00:02:04 +02:00
bugs.md docs: reconcile project status and navigation 2026-07-20 13:00:41 +02:00
ci-and-releases.md docs: note that docs-only pushes skip the pipeline 2026-08-19 16:15:04 +02:00
ISSUES.md fix(render): jitter the volumetric march per pixel (IGN); file #421 for the shadow transform buffer (Campaign VM VM5) 2026-08-22 22:56:03 +02:00
README.md docs: point the documentation map at the Timing lane 2026-08-19 15:37:44 +02:00
release-gate.md feat(render): implement Campaign AR and terrain fidelity 2026-08-22 13:13:29 +02:00

acdream documentation map

This page is the entry point for project documentation. It distinguishes current sources of truth from implementation history so an old plan or issue banner cannot silently override the current program state.

Current snapshot — 2026-07-27

  • Milestone state: M3, “Cast a spell,” landed 2026-07-21. M4, “Live in the world,” is active.
  • M4 gameplay program: resume the pre-M4 world-interaction completion program. Favorite-spell overflow, status Use/Assess, and the complete assessment surface are user-accepted. Equipped-child picking and vendor browse/transactions remain Slices 46.
  • Structural/runtime state: all eight GameWindow decomposition slices, Modern Runtime Slices AJ, and the connected visual/lifecycle gates are complete. GameWindow is a 1,622-line composition/callback shell. AcDream.Runtime.GameRuntime owns canonical session, entity/object, gameplay, movement, physics, projectile, environment, and portal state; graphical and no-window hosts borrow the same owner graph.
  • Headless state: Slice K is complete. AcDream.Headless is a presentation-free Windows/Linux host with deterministic commands/events, shared immutable content, multi-session isolation, reconnect, resource telemetry, and 1/5/10/30-session gates. The final two-account native-Linux soak completed ten minutes, logged out through ACE, and converged every ownership ledger.
  • Linux graphical state: Slice L0 and the L1 implementation checkpoint are complete at 66f114b2 and 11501d52. Native Windows passes the active modern-GL/audio/window smoke. WSLg X11/Wayland correctly reject their missing GL_ARB_bindless_texture. Physical-Linux validation and L2L6 are explicitly deferred; resume at the supported AMD/NVIDIA L1 gate.
  • Completed gameplay gates: R6 locomotion/collision/projectile/teleport/ radar, two-client portal-out/materialization, indoor prepared collision, loot ordering, local/remote ground drops, and selection-marker lifetime.
  • Separate visual verification: issue #225, the shared-alpha lifestone/particle result; its connected resource-lifetime and performance routes pass.
  • Carried behaviour debt: issue #153 (far teleport onto an unstreamed edge), #116 (narrowed slide response), #235 (capped/RDP jump cadence), and the active temporary-stopgap rows in the divergence register.
  • Divergence audit: 189 active rows — IA 18, AD 38, AP 91, TS 38, and UN 4 — plus retained struck/retired historical rows such as TS-37.
  • Latest automated baseline: the Release build succeeds with the 17 test-project warnings tracked by issue #228; 8,826 tests pass and five are intentionally skipped. App passes 3,763 / 3 skips. The L1 Windows supported smoke and WSLg X11/Wayland negative-capability reports all end with zero window/GL/input/audio ownership.

Sources of truth

Read these in this order when deciding what to do next:

  1. plans/2026-05-12-milestones.md — the active playable outcome, freeze boundaries, and visual gates.
  2. plans/2026-04-11-roadmap.md — strategic phase ledger: shipped, active, deferred, and future work.
  3. ISSUES.md — tactical defects and small follow-ups. The status inside an issue is authoritative; physical order is not.
  4. architecture/retail-divergence-register.md — every known place runtime behavior can differ from retail.
  5. architecture/acdream-architecture.md and architecture/code-structure.md — ownership, dependency, update-thread, and extraction rules.
  6. architecture/worldbuilder-inventory.md — rendering/DAT code already owned in-tree versus mechanisms still ours to port.

If these disagree, milestones control the current outcome, the roadmap controls work ordering, the issue status controls the individual defect, and the architecture documents control implementation shape. Reconcile the stale document in the same change; do not leave both claims standing.

Research and implementation records

  • research/named-retail/ is the primary retail oracle: named pseudo-C, headers, symbols, and types from the Sept 2013 build.
  • research/decompiled/ is the older Ghidra fallback.
  • research/ contains focused pseudocode, traces, fixtures, and gate reports. A dated research note records evidence; it does not become a new roadmap.
  • superpowers/specs/ and superpowers/plans/ are per-slice design and execution records. Completed plans remain historical.
  • ci-and-releases.md is the SSOT for the Gitea CI pipeline, the self-hosted runners, and how alpha releases are published. Load-sensitive tests live in Lane=Timing; see release-gate.md before adding to it.
  • audit/ contains completion and conformance audits.
  • reference/ace-commands.md preserves the local ACE server's complete in-game command catalog and points to the authoritative per-command help surface.

Durable memory

  • ../claude-memory/MEMORY.md indexes the live subsystem memories and the render/physics digests. Read a domain digest before changing that subsystem, especially its DO-NOT-RETRY table.
  • ../memory/ contains stable engineering references such as the modern rendering pipeline, two-tier streaming, and toolchain notes.

Memory accelerates recall; it does not outrank the canonical documents above. When current truth changes, update the relevant canonical document and distill only the durable lesson into memory.

Historical and deprecated documents

  • bugs.md is the April 2026 bug snapshot. It is preserved for archaeology and is not an active ledger.
  • Dated plans and specs describe the decision at that time. Their completion wording is historical unless the current milestone/roadmap explicitly links the item as active.
  • Old R1→R8 architecture sequencing is superseded. Current execution comes from the milestones and strategic roadmap.

Documentation maintenance rules

  • Update milestone, roadmap, issue, divergence, architecture, and memory claims in the same commit when a shipped change affects them.
  • Keep one issue ID per defect. Narrow an issue in place; do not reuse another issue's number as a shorthand.
  • Mark automated, connected, and visual gates separately. An automated pass is not a visual acceptance, and an RDP throughput sample is not a local-display visual comparison.
  • Preserve research history, but remove stale “current/next” claims from living documents once the state advances.