Global fill cut (KeyWarm 1.25->0.15, CausticsSpot 32->9, GloamFill 0.5->0.22) so the scene
goes dark-except-where-ours-reaches; WarmPool point light -> downward warm SPOT = a defined
ground-territory disc that lights the suit top-down (a low point light was blasting the chest
into a blown bloom streak). Suit lamp + Drowner gloam emissives extracted from .glb sub-assets
to durable .mat assets (M_Suit_LampWarm_Staging, M_Drowner_GloamAccent_Staging). Recomposed the
triad (crate in-pool / Drowner faced-to-camera at the lit edge / suit center). Grayscale-verified:
the beacon dome is the value winner + the warm disc reads as territory. Suit pose still T-pose
(a Blender rig sitting; A3-adjacent).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Netcode accumulates InputEvent counts on the wire; only the decoded component is delta-corrected.
AbilityFireSystem's windup resolve gated on raw IsSet, so after the first press every socket
re-fired the instant its cooldown reopened (live repro: recasts at exactly t3933/t4353 with zero
input). Gate is now a count-STEP vs the previous tick's command; missing prior command = no-fire.
Also lands the G6 ConeContactPending schedule machinery + the cone test fixture (wire-true
monotonic counts) + regression Cast_Never_Refires_When_The_Cooldown_Reopens. 430/430; live proof:
one tap -> one cast -> silence across 2+ reopens.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SwordCombat React (1.4x, 0.3s pulse) + Stagger (1.2x, 0.55s) as Any-State
states on AC_EnemyTopDown via EnemyRigTools.WireEnemyHitReacts; driven by
EnemyAnimationDriveSystem's cache (now Pos/Hp/ReactUntil/Heavy) off
replicated Health drops. Windup-honesty gate: light reacts require
!IsAttacking (a sub-poise hit never visually cancels a live windup);
the heavy tier tracks the server's B2 poise break (stagger threshold 50
= finisher staggers, light flinches at the locked tuning). Knobs:
HitReactSeconds (0=off) / HitStaggerSeconds / HitReactStaggerDamage.
Replaces the review-cut positional vibrate (Rukhanka inverse-fold no-op).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WeaponGripAnchor under Hand_R in Player.prefab carries the actual axe
mesh as an EditorOnly preview (baker skips it; play-verified single axe)
so grip manipulation is the real model live in the prefab stage;
AttachMeleeWeapon reads the anchor (consts = seed/fallback). Includes
the operator's first gizmo-tuned grip (rebaked mesh matches expected
radius exactly). PlayerRigTools also carries the heavy-lock clip
re-speeds (1.0/0.85/0.88) consumed by the next commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GymSub bakes no WaveDirector (why sandbox enemies never spawned); the
sandbox's combat target is now a TargetDummyTag'd enemy ghost all five
EnemyAISystem passes exclude (planted; knockback stamps inert), spawned
at player+3m with 400 HP by an editor-only scene-gated server system,
dying through the normal Dying path and respawning 1.5s after the corpse.
EnemyTag-reuse audited: sandbox-only by design (cleared-checks would
count it elsewhere).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New PlayerRigTools.BuildBathynautPlayer (menu: ProjectM/Animation) - forks the
proven EnemyRigTools recipe: strips the Synty-soldier skeleton+SMRs from
Player.prefab IN PLACE (GUID preserved; ghost/authoring/CC/Animator/
RigDefinitionAuthoring untouched), flattens the SpaceSoldier_HelmetArmor suit
body under the root, keeps the -0.90 feet offset, re-slots
M_SuitFrame_Bathynaut_Animated on every SMR, adopts the shared CharactersAvatar
(AC_PlayerTopDown muscle clips retarget). 17 inactive Synty variant SMRs stripped.
Both frames share this visual until per-frame models land; the brass-dome/tank
kitbash attachments are a follow-up /art-dev export.
Play-verified in DevSandbox: suit renders + idles correctly under the LANTERN
murk, Rukhanka rig baked with all 9 drive params, dev overlay alive in the
renamed scene, no console errors.
=> Movement/animation tuning is now UNBLOCKED (the operator's next priority).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- WaveDirector + ZoneEnemyDirector rosters re-pointed (ORDER-CRITICAL before prefab
deletion: null-skip pools collapse kinds): [Drowner, Grindylow, Drowner, Drowner]
(grunt/charger(boss)/spitter-slot/swarmer-slot; ranged+pack kinds fall back to
Drowner until LANTERN kinds land in Phase 2).
- WorldColliders_Landmarks + WorldColliders_Props deleted from the subscene (their
visuals died with the host-scene biomes -> they were invisible walls). Boundary
rings + room cover + all spawners/configs kept.
- 10 old-theme enemy prefabs deleted (Enemy, Brute, Charger, ChargerMuscle,
Spitter, Swarmer(+Undead), Werewolf(+Undead), Kaiju); EnemySpit kept for a
future ranged kind. Zero dangling GUID refs (verified).
Play-verified in Game: Drowner wave spawns, seeks, strikes; AFK player dies and
respawns (full loop); no console errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- PostFX_Lantern.asset: the ONE shared grade (ACES, bloom 0.6 cool-tinted for the
HDR gloam, vignette 0.28, faint teal filter) applied to Game, DevSandbox, and
ArtStaging; PostFX_DarkSciFi / PostFX_Daylight / Sky_DaytimeProcedural deleted.
- Env_SeabedKit.prefab: ArtStaging's environment (seabed, flora, rocks, marine
snow, caustics, warm pool, gloam fill, key light, StagingAmbiance animator)
prefab-ized and placed in Game + DevSandbox; ArtStaging connected to it.
- Scene surgery: old DevSandbox.unity deleted; Gym.unity RENAMED DevSandbox.unity
(GUID preserved -> GymSub wiring + the F1/F2 dev scripts that gate on the
'DevSandbox' name come back to life). SyntyWorld root deleted from DevSandbox;
BaseBiome/ExpeditionBiome/Slot1 deleted from Game.
- RenderSettings unified: no skybox, Exp2 teal fog {0.02,0.10,0.12} @ 0.035, flat
near-black ambient {0.03,0.055,0.08}; camera clearFlags -> solid deep-water.
- ScenePolicy.IsGameplayScene() replaces the six scene.name=="Game" string gates
(Game + DevSandbox share the dynamic look; menu/ArtStaging untouched).
- WorldAtmosphereSystem rewritten as water-column murk (LANTERN defaults; biome
variants re-meant to kelp/trench/gloam-bloom; Ground_Arid tint block deleted).
390 green; Play-verified in Game: murk values live, warm-vs-cold reads, no errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Enum renamed in StatIds.cs (byte values unchanged - serialized definitions/saves
never re-mean); all call sites + doc mentions swept (ClassTraits, PlayerAuthoring,
CharacterStatsDefinition field type, menu/UI, tests). CharacterStatsDefinition SO
CLASS name kept (asset-binding risk; deferred per plan). 390 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deletes the M7 production systems, automation components/math, authoring, 3
machine prefabs, and 6 test files (-43 tests, 459 green). Trims the automation
paths out of BaseRestoreSystem/SaveStructureScan/BuildPlaceSystem/BuildSendSystem/
HudSystem/HudTheme/StructureCatalogAuthoring/Tuning. RuntimePlacedTag (save
marker, a keeper) re-homed into StructureComponents.cs. StructureType byte codes
stay reserved.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Baseline before the LANTERN realignment & purge (plan: one look, four scenes,
Bathynaut on the player). Gym.unity edits are operator-made in-editor.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gym.unity = the dev-test host re-based on DevSandbox (camera + DebugOverlay dev UI
+ world visuals), its SubScene repointed to GymSub. GymSub.unity = a fresh minimal
baked subscene (PlayerSpawner, AbilityDatabase with all 9 abilities incl. the 5
Sparks, NetCodePhysicsConfig, WorldCollisionConfig, ProjectileSpawner, GymRoster =
GymTag + Drowner/Grindylow roster). Open Gym.unity + Play → GymTag clean-spawn with
a per-frame Spark loadout; on-demand SpawnEnemy. Subscene GameObjects still named
*_Copy (cosmetic); visuals = the operator's future underwater-match pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per connection, marks every ENEMY ghost OUTSIDE the player's lamp radius
IRRELEVANT (monsters in the dark aren't replicated — the gamma test). Modelled
on the proven RegionRelevancySystem: SetIsIrrelevant so players/global ghosts
stay relevant for free. Shared-set discipline — RegionRelevancySystem is the SOLE
clearer (runs every tick); LightRelevancySystem is [UpdateAfter] it and only ADDs
light hides via TryAdd (no clear; defensive against a region+light overlap dup).
Gated on GymTag (LANTERN-only; legacy region relevancy untouched). Pure decision
in LightRelevancyMath (+3 EditMode tests, 500 green). Per-player dim/bright
(variable radius) + the L3 gamma-test verification are follow-ups; the ★adversarial
netcode review is recommended before this ships.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FrameId (replicated frame/class signal) now WRITTEN server-side at spawn for all
players; the two class-HUD readers (ClassPrepPortal, MetaShop) read FrameId (with
an AbilityRef fallback for pre-FrameId players) instead of ClassForAbility. The
gym seeds a PER-FRAME default Spark loadout via ClassTraits.FrameLoadout —
Harpooner (Ranger slot): reel/mobility/skillshots; Bathynaut (Warrior slot):
pull-in/dash/zone-control. FrameId uses ecb.AddComponent (baked on the real
player; absent on the minimal MetaSeeding test prefab). 497 EditMode green.
Deferred to a focused pass (risky wholesale refactor, "still works" via the
transition): full removal of legacy AbilityRef/AbilityCooldown/EffectiveAbility
Stats (woven through equip/class/meta/StatRecompute + tests) and the CharacterId
Bathynaut/Harpooner rename.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AbilityDefBlob/AbilityDefinition gain WindupTicks. AbilityFireSystem's socket
loop resolves each socket at the historical command (serverTick - WindupTicks)
via GetDataAtTick — a pure fn of replicated data on both worlds (Build Spec §4/
DB-6: no local fireAtTick that would diverge under reprediction; fireCount from
that command, spawn uses the current tick's aim/pos; history gap = no-fire).
WindupTicks set on the 4 non-Blink Sparks (Blink is movement, resolved by
BlinkSystem). 497 EditMode green (no regression). Client telegraph VFX + the
reprediction L3 test are operator-eyes / netcode-world follow-ups.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GymTag + GymEnemyRoster (+ GymRosterAuthoring) bake the gym singletons. New
DebugOp.SpawnEnemy (client SpawnEnemy wrapper + server receive case) spawns a
chosen enemy KIND (Drowner/Grindylow) from the baked roster near the sender —
replacing the wave-roster hack per the roadmap's Enemy-test GYM direction.
GoInGameServerSystem takes a GymTag branch: bypass the meta-catalog spawn guard
(a fresh gym has no CycleDirector) + seed a default Spark loadout on keys 1-4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 5 AbilityDefinition SOs (DecoyWisp/HookPull/Vortex/Blink/LightZone) with
archetypes, tunables, EffectFlags (HookPull=Reel), and prefab refs. Three
interpolated ownerless-ghost prefabs (EffectVortex w/ Vortex flag, EffectLightZone,
DecoyWisp) via the duplicate-ResourceNode recipe + ZoneAuthoring/DecoyAuthoring.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Aoe/Hitscan archetype dispatch in AbilityFireSystem (both-worlds cooldown;
server-only ecb.Instantiate — the client-never-instantiates invariant; ZoneEffect
vs DecoyTag chosen by prefab membership). Harpooner REEL as a homing state
(ReelState + ReelSystem re-aim the hit Husk's KnockbackState toward the caster's
live position each tick; EnemyAISystem stays sole Position writer), stamped by
ProjectileDamageSystem on a Reel-flag hit. ZonePulseSystem (enemy-only periodic
AoE, caster attribution, no friendly fire, Vortex pull, born-0 lazy-stamp).
Decoy aggro in EnemyAISystem + DecoySystem despawn. AbilityDefBlob gains
EffectFlags (Reel) + DurationTicks. +3 ZonePulseSystem EditMode tests (497 green).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EnemyDrowner: Emissive-Gloam eyes bone-parented to Head + boneEntityStrippingMode
=None (attachments ride the rig). New skinned prefabs EnemyGrindylow +
SuitFrame_Bathynaut. Pipeline run 3x -> A1 repeatability exceeded.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EnemyRigTools.BuildDrowner (menu ProjectM/Animation) — SciFiSpace Crew_Male
body (same rig/atlas/avatar as the player) through the proven DR-023 path:
EnemyDrowner.prefab = ownerless interpolated ghost + AnimatedLitShader
(Skinned-Palette) gloam material + AC_EnemyTopDown + RigDefinitionAuthoring.
Structurally identical to the shipping werewolf/charger enemies -> animates
in-game via the same EG/Rukhanka path. (Renders only in the baked ECS world,
not a plain scene; ArtStaging keeps the static bake for art review.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ProjectM/EmissiveGloam — URP HLSL, HDR emission (Bloom-catching), with the
readability 'steady=true / flicker=false' channel as a material param
(_FlickerAmount), no script. Applied to the staging flora bulbs (cold, flicker).
The other two master shaders already exist (Lit URP graph, AnimatedLitShader).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Beacon left unmodulated (steady=true light); cold flora gutter on Perlin flicker
(flicker=false light) so the warm/cold read survives with hue removed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Light-only ambiance animator (caustics spin, beacon flicker, bioluminescent
pulse); self-wires by name; no material writes so nothing persists on Play exit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per Phase1_Combat_Gym_Build_Spec §6 (the Blink Spark = a second, socketed dash):
- AbilityArchetype += Movement (falls through AbilityFireSystem; a sibling system drives it).
- AbilityId += the 5 Phase-1 Sparks (DecoyWisp/HookPull/Vortex/Blink/LightZone).
- BlinkState: predicted, non-replicated blink window (DashState sibling).
- BlinkSystem: velocity blink (never a LocalTransform write), triggered by the Movement-
archetype socket, dash-wins precedence ([UpdateAfter(DashSystem)]), sole writer of its
socket's SocketCooldown row; reads socket loadout/cooldown by entity via lookups (query at 6
args, under the 7-cap). Baked BlinkState on the player.
L1 clean; L2 494/494. Dead until a Blink Spark def is socketed (ability-database SO = next).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DebugInputInjectionSystem (#if UNITY_EDITOR) gains FireSocket(i, frames) + per-socket hold
frames + the OnUpdate socket-event sets, mirroring the legacy Fire injection. Drives the real
gather->command->prediction->AbilityFireSystem path per socket for headless validation.
Used to validate group-A live (instant-play ServerWorld+ClientWorld): socket 0&1 = a projectile
Spark, injected same-frame -> maxSrvProj=2, maxCliProj=2 (server==client parity),
distinctSpawnIds=2 with distinctSocketBits=2 (the SpawnId desync fix confirmed LIVE), both
per-socket cooldowns advanced. Netcode half of the group-A gate: PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per Phase1_Combat_Gym_Build_Spec §8 (the "KEEP as-is" feel layer was really a migration):
- PlayerAnimationDriveSystem: both jobs (Local/Remote) now read SocketCooldown +
DynamicBuffer<AbilitySocket>/<EffectiveSocketStats> instead of the single AbilityCooldown/
AbilityRef/EffectiveAbilityStats; shared SocketFireAndCone helper (any-socket-firing model:
IsFiring if any socketed Spark's per-socket cooldown window is mid-fire; IsCone if any such
is Cone).
- CombatFeedbackSystem: the muzzle-flash + cone-cue blocks unified into one per-socket
fire-edge loop over SocketCooldown (per-socket uint cache); non-Cone -> muzzle flash,
Cone -> the aimed slash-arc cue. Dropped the now-dead single-cooldown latches.
L1 clean; L2 494/494 (no regression).
Deferred to the AbilityRef-removal cleanup (surfaced, NOT silent): the FrameId server-writer +
the 2 class-HUD re-points (ClassPrepPortalHudSystem/MetaShopHudSystem) + HudSystem's ability
bar. Rationale: AbilityRef is still baked + set (EquipSystem/ClassSwapUtil), so ClassForAbility
remains a valid class signal through the transition; FrameId is baked ready. No feel regression.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per Phase1_Combat_Gym_Build_Spec §7 (additive; legacy single EffectiveAbilityStats + its
fold stay until steps 2/2.5 migrate readers, then retired):
- EffectiveSocketStats: 4-wide derived (non-replicated) per-socket effective-stats buffer.
- PlayerAuthoring bakes it (4 rows).
- StatRecomputeSystem: a SECOND fold loop (separate query, under the 7-arg cap) folds each
socket's SparkId blob base with the SHARED StatModifier band (uniform; per-Spark warping =
Phase 4) into EffectiveSocketStats[i]; empty socket (SparkId 0) -> zeroed default.
Fixed CS1654 by writing through a mutable local copy of the buffer handle.
L1 clean; L2 489/489 (new SocketFold_Folds_Per_Socket_With_Uniform_Band).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Additive socket data model per Phase1_Combat_Gym_Build_Spec §3 (no behaviour; legacy
AbilityRef/AbilityCooldown left intact for the step-2 migration):
- AbilitySocket: cold per-socket loadout buffer (EquipmentSlot-modelled, [GhostField] byte
SparkId, SendToOwnerType.All, 4 rows baked empty).
- SocketCooldown: hot owner-predicted per-socket cooldown (4x [GhostField] uint + Burst-safe
switch indexer; SendToOwnerType.All for remote ability-feel parity with AbilityCooldown).
- FrameId: replicated [GhostField] byte frame/class signal (SendToOwner; the class source the
socket model needs since no single ability id maps 1:1 to a class).
Baked onto the player ghost in PlayerAuthoring. L1 clean compile + domain reload.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The material-decision keystone (Art_Direction_Lantern / Lantern_Art_Pipeline_Recipes):
one shared palette atlas + ~3 materials, zero per-asset texturing.
- PaletteAtlas.png: 8x8 swatch grid encoding the ontology (warm-gold light / corpse-green
+ cold-blue gloam / lure-red bait / white-hot conversion / neutral / steel); sRGB, point,
no-mip, clamp, uncompressed.
- M_Lit_Palette (statics, Lit URP graph), M_Skinned_Palette (creatures/suits, the
deformation-aware AnimatedLitShader with per-instance tint + vertex-colour), M_Emissive_Gloam
(URP/Lit + HDR emission; hue/intensity = the gloam param axis). All wired to the atlas.
Dedicated master-shader graphs (flicker param, Hybrid-Per-Instance on statics) + the
style-proof scene are the next A0 steps. Verified by material values, not just a render.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Client-only, procedural, zero netcode — a sibling of AmbientMotionSystem,
biome-keyed + camera-following. Three cosmetic beats: fleeing critters (ground
bugs + a few birds that dart out of the flee radius = the scatter beat,
biome-tinted, recycled at the ring edge), drifting cloud-shadow discs, and
Blight-room-only double-blink directional lightning flash + delayed thunder
(dedicated flash light -> no RenderSettings fight with WorldAtmosphereSystem).
Reuses the FeedbackFx disc/scorch primitives + procedural SFX. Live knobs in
AmbientLifeConfig. 474/474 EditMode; live-verified at base (flee confirmed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review-first netcode slice (design review wf_900e9965-8f0 -> 11 folded;
post-impl wf_5c8299f8-299 clean). A PERMANENT periodic telegraphed AoE in
Blight-biome rooms only; one new [GhostField] uint NextEruptTick.
- Geyser component + GeyserEruptSystem (server): inverted invalid-tick guard
(a baked-0 tick must NEVER erupt -> lazy-stamps born-correct instead of the
party-wiping per-tick barrage), inline both-sides gather (SourceNetworkId=-1),
reschedule = now + period (never +=), never destroyed.
- GeyserTelegraphSystem (client): absolute-tick growing warning disc +
erupt burst on the >0->=<0 crossing, latched per NextEruptTick + arm-guard
(never edge-detects the replicated field -> no phantom on 0->stamp /
relevancy re-entry). Reuses ScorchDecalSystem + DynamicLightSystem.
- Seeded in RoomFieldSystem (Blight-gated on plan.Biome, born-correct staggered
stamp from live ServerTick), GeyserFieldSpawner + authoring wired into the
Gameplay subscene. Geyser.prefab duplicated from ResourceNode (no collider).
- BuildDisc promoted to FeedbackFx (shared with the barrel fuse ring).
- 474/474 EditMode incl. the unstamped-storm regression; live no-storm end-to-end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All procedural, client-only, observe-only in PresentationSystemGroup, zero
netcode surface (read existing replicated state). Shared FeedbackFx decal
primitives (scorch blob + crack star meshes + transparent decal material).
ScorchDecalSystem: static RequestScorch queue -> pooled fading discs
(mirrors DynamicLightSystem), wired from the barrel boom, reusable by the
geyser. CoverDamageSystem: crack accretion keyed on BlightClutter.Remaining
(Variant 4) + proximity-gated shatter-scorch. RoomDressingSystem: persistent
arena scars on a distinct hash sub-stream, torn down with dressing. Knobs in
DecalConfig. Cover cracks use decals (not URPMaterialPropertyBaseColor) because
the Synty prop shader is not Hybrid-Per-Instance.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Second ground iteration ("better but could be further improved"): the remaining
plainness was single-texture ground — noise only modulated brightness, never
MATERIAL. Now each biome bakes a unique 1024 splat-blended base map (zero
repetition at macro scale) with the fine texture moved to the detail slot as a
high-pass layer at real tiling:
- Meadow: grass + dirt + clover patches masked by fbm; the worn paths
(storage->warpgate, storage->base-gate) and a congregation-wear disc at the
storage crystal are baked INTO the splat as organic dirt zones (exact
plane-UV mapping probed: u=0.5-x/90 — both axes inverted).
- Arid: sand + sand2 + arid-dirt patches + a subtle arena-wear disc at the
quad center (= the room origin on both quads) + warm/cool hue drift.
- Detail slot: generated 2048 high-pass (full - 128-blur, 1.4x) of the
grass/sand textures, LINEAR import, tiled 22x/26x — crisp up close, the
splat carries identity at distance.
- Superseded assets removed: the overlay WornPath quads + material + texture
(double-darkened over the baked wear and caught fog as a ghostly rectangle)
and the old macro-noise detail textures.
Biome tint MPB + normals unchanged and still active. Measured ground luminance
0.30/0.33 (edit ambient) — play fog/dark ambient pulls it down; tints remain
the one-line brightness knob.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>