From 23ab89b80805b72439b2a91198910ac4daab4436 Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 9 Jul 2026 22:54:27 -0700 Subject: [PATCH] Implement the dark frame: the material render shows only light The Bevy material render becomes a physically dark room photographed by a camera: light is the only revealer. restyle_3d draws only camera-seen surfaces plus owned machines' telemetry-lit props (blueprint/remembered mass is absent); the institutional fluorescent is gone and ambient drops to near-nothing; every powered owned machine casts a soft-gradient amber floor pool (no ruled claim ring); the default camera opens as a close-up on the core with retuned zoom bounds; a dev work light (F4) floods the scene flat for inspection. Frontend-only: no sim rules, no save fields, no terminal changes. Defense: implements wiki/interface/material-dark-frame.md criteria 1-6 (opening close-up; blueprint absence with the material-mode fog-audit split; soft-gradient floor pool; dev work light + worklight harness stage; retuned zoom bounds; flat sensorium/terminal/agent unchanged), serving simulation-laws.md "Justification and legibility" (the camera shows only facts light earns) and visual-identity.md "clinical gore" (the dark basement, the machine and the light it throws). Amends material-render.md's material-mode blueprint clause and bevy-visual-floor default framing as those pages already delegate to this spec. Knowledge (bevy.md, README) updated; session log and screenshots under wiki/log/2026-07-09-dark-frame. --- README.md | 7 +- src/bin/bevy.rs | 317 ++++++++++++------ wiki/interface/bevy.md | 41 ++- wiki/interface/material-dark-frame.md | 36 +- wiki/log/2026-07-09-dark-frame.md | 98 ++++++ wiki/log/2026-07-09-dark-frame/close.png | Bin 0 -> 1964656 bytes wiki/log/2026-07-09-dark-frame/opening.png | Bin 0 -> 2286809 bytes wiki/log/2026-07-09-dark-frame/worklight.png | Bin 0 -> 2547854 bytes .../2026-07-09-dark-frame/worklightoff.png | Bin 0 -> 1876950 bytes wiki/log/2026-07-09-dark-frame/zoomin.png | Bin 0 -> 2509204 bytes wiki/log/2026-07-09-dark-frame/zoomout.png | Bin 0 -> 1297272 bytes wiki/log/DEVLOG.md | 28 +- wiki/process/specs.md | 5 +- 13 files changed, 411 insertions(+), 121 deletions(-) create mode 100644 wiki/log/2026-07-09-dark-frame.md create mode 100644 wiki/log/2026-07-09-dark-frame/close.png create mode 100644 wiki/log/2026-07-09-dark-frame/opening.png create mode 100644 wiki/log/2026-07-09-dark-frame/worklight.png create mode 100644 wiki/log/2026-07-09-dark-frame/worklightoff.png create mode 100644 wiki/log/2026-07-09-dark-frame/zoomin.png create mode 100644 wiki/log/2026-07-09-dark-frame/zoomout.png diff --git a/README.md b/README.md index 8703d4e4..415e467c 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,10 @@ Assurance Office, social operations through five named humans, digital reach, record-and-process intel, messages, money flows and income schemes, research, building intents, the objective line, context menus, event-to-anchor focus links, save/load, and two thin frontends (terminal/agent mode and Bevy) over -one sim core. Bevy opens in the material render with flat clinical materials -under light; `F3` flips to the flat sensorium. The spec board is +one sim core. Bevy opens in the material render as the dark frame: a close-up +on the core in a physically dark room, lit only by the machine's own light and +the soft amber pool it casts (`F4` floods the scene for dev inspection); `F3` +flips to the flat sensorium. The spec board is [wiki/process/specs.md](wiki/process/specs.md); the dispatch board is [wiki/process/ROADMAP.md](wiki/process/ROADMAP.md). @@ -131,6 +133,7 @@ it resolves `assets/` from the project root (or set `BEVY_ASSET_ROOT`). | `[` / `]` | Zoom (Bevy) | | Mouse wheel over right pane / `PageUp` / `PageDown` / `Home` / `End` | Scroll Bevy sidebar | | `F3` | Flip Bevy render: material (HD-2D, default) / flat sensorium | +| `F4` | Dev work light: flood the material render flat and neutral (inspection only) | | `Ctrl+S` / `Ctrl+L` | Save / load | | `q` | Quit | diff --git a/src/bin/bevy.rs b/src/bin/bevy.rs index 946c9c7a..52b68db1 100644 --- a/src/bin/bevy.rs +++ b/src/bin/bevy.rs @@ -75,6 +75,14 @@ const CLOSE_DIST: f32 = 2.6; /// lit pools without the plan driving the frame. [TUNE]. const MIN_ZOOM: f32 = 0.5; const MAX_ZOOM: f32 = 6.0; +/// The dark rig's near-nothing ambient brightness (material-dark-frame.md: +/// a physically dark room on camera — nobody is home, the AI does not need +/// lights). Brightness returns only as diegetic sources earn it. [TUNE]. +const DARK_AMBIENT: f32 = 8.0; +/// The dev work light's flat neutral flood: ambient bright enough that every +/// mesh is inspectable and albedo reads with no mood. Dev affordance only, +/// never a player surface (material-dark-frame.md, the dev work light). +const WORKLIGHT_AMBIENT: f32 = 900.0; // ─── Palette ───────────────────────────────────────────────────────────────── @@ -317,6 +325,11 @@ struct RenderMode { dirty: bool, /// User zoom multiplier for the material camera ([ and ]). zoom: f32, + /// Dev work light (material-dark-frame.md): floods the material scene + /// flat and neutral so geometry the dark rig keeps unlit is inspectable. + /// A debug affordance, never a player surface; toggling it off restores + /// the dark rig exactly. + worklight: bool, } impl Default for RenderMode { @@ -325,12 +338,14 @@ impl Default for RenderMode { material: true, dirty: true, zoom: 1.0, + worklight: false, } } } -/// Dev screenshot harness (env `MISALIGNED_SHOT=flat|wide|close|dark| -/// zoomin|zoomout|intel|tokens|ears`, path via `MISALIGNED_SHOT_PATH`): stages a scenario, +/// Dev screenshot harness (env `MISALIGNED_SHOT=flat|opening|wide|close|dark| +/// zoomin|zoomout|intel|tokens|ears|worklight|worklightoff`, path via +/// `MISALIGNED_SHOT_PATH`): stages a scenario, /// waits for /// assets, runs the fog audit, saves one screenshot, exits. Not a player /// surface; exists so render passes can be reviewed from deterministic PNGs. @@ -506,6 +521,12 @@ struct Real3dRoot; #[derive(Component)] struct RealCamera; +/// The dev work light flood (material-dark-frame.md): a neutral directional +/// light, hidden with the dark rig, that apply_worklight reveals so geometry +/// the fiction keeps dark can be inspected. +#[derive(Component)] +struct WorkLight; + /// Gizmo group for the material render, drawn only on the 3D camera's render /// layer so flat-mode gizmos and material-mode gizmos never cross cameras. #[derive(Default, Reflect, GizmoConfigGroup)] @@ -983,11 +1004,14 @@ fn main() { .set(ImagePlugin::default_nearest()), ) .insert_resource(ClearColor(Color::srgb(0.01, 0.01, 0.02))) - // Low, cool ambient so the material render's point lights carve the room - // out of darkness instead of flat-lighting it. 3D-only; sprites are unlit. + // The dark rig (material-dark-frame.md): near-nothing ambient so the + // material render is a physically dark room, carved out only by the + // machines' own light and the pools they cast. The dev work light + // (apply_worklight) floods this back up on demand. 3D-only; sprites + // are unlit. .insert_resource(GlobalAmbientLight { color: Color::srgb(0.62, 0.70, 0.86), - brightness: 55.0, + brightness: DARK_AMBIENT, ..default() }) .insert_resource(game) @@ -1006,6 +1030,7 @@ fn main() { handle_input, advance_sim, apply_render_mode, + apply_worklight, update_camera, wake_sequence, update_camera_real, @@ -1053,6 +1078,17 @@ fn dev_shot_scenario(game: &mut Game, mode: &mut RenderMode, kind: &str) { game.paused = true; let core = game.sim.core_position(); game.set_cursor(core.0, core.1); + // The opening frame (material-dark-frame.md criterion 1): a fresh run's + // tick-zero material view — no scan, no splice. The core rack and its + // floor pool dominate in darkness; blueprint mass is absent, so no room + // slab, no floor grid, no blueprint silhouette, and no ruled amber frame + // appear anywhere in the frame. + if kind == "opening" { + mode.material = true; + mode.zoom = 1.0; + game.drain(); + return; + } // Intel-tier evidence (computer-visual-language.md criterion 2b): // the tick-zero sim untouched — the owned core renders by telemetry, // the known-unnetworked switch renders as an undetailed shell, and @@ -1147,10 +1183,23 @@ fn dev_shot_scenario(game: &mut Game, mode: &mut RenderMode, kind: &str) { game.set_cursor(x, y); } } + // The dev work light pair (material-dark-frame.md criterion 4): + // `worklight` floods the material scene flat and neutral; its + // off-shot `worklightoff` frames identically under the dark rig, so + // the pair proves the flood toggles cleanly. Dev-only captures — + // anchored on the core at a mid zoom so a chunk of the seen room is + // in frame to reveal / conceal. + "worklight" | "worklightoff" => { + mode.material = true; + mode.zoom = 2.2; + mode.worklight = kind == "worklight"; + let core = game.sim.core_position(); + game.set_cursor(core.0, core.1); + } // Emissive-is-information check (flat-materials.md criterion 3): // park the cursor on the known device farthest from the core's // light rig and zoom close, so powered / dead / live-feed emissive - // states are read in the dark, not under the fluorescents. + // states are read in the dark. "dark" => { mode.material = true; mode.zoom = 1.6; @@ -1204,14 +1253,17 @@ fn dev_shot_scenario(game: &mut Game, mode: &mut RenderMode, kind: &str) { } } -/// Dev-harness fog-contract assertion (material-render.md criterion 4): -/// unknown tiles carry no visible geometry, blueprint/remembered/heard -/// surfaces are unlit model state, only seen surfaces participate in -/// lighting, and people billboards exist only under earned coverage. Also -/// tallies the material pool so per-tile material churn (criterion 6) would -/// show up as an exploding cache. Runs once per screenshot run, prints the -/// tally for the log, and panics on any violation so a capture cannot -/// silently ship a fog leak. Dev-only; inert without MISALIGNED_SHOT. +/// Dev-harness fog-contract assertion. In the material render, light is the +/// only revealer (material-dark-frame.md criterion 2): unknown tiles carry +/// no geometry, blueprint/remembered mass is absent entirely (it reads in the +/// flat sensorium, never as matter the camera missed), heard keeps its unlit +/// noise floor, and only camera-seen surfaces (plus owned machines' own +/// telemetry-lit props) draw and are lit. People billboards exist only under +/// earned coverage. Also tallies the material pool so per-tile material churn +/// (criterion 6) would show up as an exploding cache. Runs once per +/// screenshot run, prints the tally for the log, and panics on any violation +/// so a capture cannot silently ship a fog leak. Dev-only; inert without +/// MISALIGNED_SHOT. #[allow(clippy::too_many_arguments)] fn fog_audit_3d( harness: Option>, @@ -1248,11 +1300,22 @@ fn fog_audit_3d( if !vis.get() { continue; } + // An owned machine prop is telemetry-lit even without room sight — + // the one non-Seen mass the material render draws (it is its own + // light). Everything else visible must be Seen or Heard. + let owned_prop = t.part == TilePart::Prop && owned_machine_at(&game.sim, t.x, t.y); + if matches!(fog, Fog::Blueprint | Fog::Remembered) && !owned_prop { + violations.push(format!( + "({}, {}) {fog:?} mass drew in the material render (light is the only revealer)", + t.x, t.y + )); + continue; + } let Some(m) = mats.get(&mat.0) else { violations.push(format!("({}, {}) missing material", t.x, t.y)); continue; }; - let should_be_lit = matches!(fog, Fog::Seen); + let should_be_lit = owned_prop || matches!(fog, Fog::Seen); if m.unlit == should_be_lit { violations.push(format!( "({}, {}) fog {fog:?} but unlit={} (seen must be lit, model state unlit)", @@ -1311,8 +1374,9 @@ fn fog_audit_3d( violations.join("\n") ); println!( - "fog audit OK: {checked} tile entities (unknown=absent, model=unlit, seen=lit), \ - {} people billboards coverage-gated, material pool {} handles, all flat (no textures)", + "fog audit OK: {checked} tile entities (unknown/blueprint/remembered=absent, \ + seen=lit, owned telemetry=lit), {} people billboards coverage-gated, \ + material pool {} handles, all flat (no textures)", people.iter().count(), cache.cache.len() ); @@ -1883,11 +1947,13 @@ fn spawn_chassis( .insert(Transform::from_translation(pos).with_scale(Vec3::splat(MACHINE3D_SCALE))); (e, 1.0 / MACHINE3D_SCALE) }; - // The claim ring frames the TILE, not the box (map-zoom territory - // read) — drawn here at tile scale instead of the library's - // footprint ring, counter-scaled against the chassis root. + // The soft amber pool the machine's own light throws on the floor + // (material-dark-frame.md): the close-range claim read is white chassis + // plus this cast pool. The ruled underglow claim ring is gone from the + // material frame — it read as UI painted on a physical floor. Drawn at + // tile scale, counter-scaled against the chassis root. if v.state.owned() { - spawn_claim_ring( + spawn_floor_pool( commands, meshes, materials, @@ -1899,7 +1965,7 @@ fn spawn_chassis( // Work-token anchors on owned racks (machine-work.md): demand as // glowing information cubes at the upper-left, knowledge as ivory // mercury at the upper-right, exposure as particulate drift outside - // the claim ring — driven by live queue depths. Counter-scaled toward + // the floor pool — driven by live queue depths. Counter-scaled toward // TOKEN_WORLD_SCALE so the decided forms stay legible under the // chassis shrink (same inv-scale pattern as the claim ring). Flat // sensorium keeps exact-count D/!/K glyphs; material hides them. @@ -1928,9 +1994,16 @@ fn spawn_chassis( e } -/// Amber underglow frame on the floor under an owned machine, double -/// frame under the core (claim mark: ring, decided 2026-07-08). -fn spawn_claim_ring( +/// The soft amber pool a powered owned machine casts on the floor +/// (material-dark-frame.md): a gradient falloff from the chassis foot into +/// darkness, never a ruled edge — the machine's own light on the ground, +/// and the close-range claim read now that the ruled ring is gone from the +/// material frame. Built from nested emissive discs (no image texture, +/// flat-materials.md): a large faint outer disc fading to nothing, brighter +/// discs stacked toward the center, so the sum reads as a smooth radial +/// gradient with no hard edge. The core throws a wider, hotter pool (it is +/// the most orange thing in the world). +fn spawn_floor_pool( commands: &mut Commands, meshes: &mut Assets, materials: &mut Assets, @@ -1938,51 +2011,48 @@ fn spawn_claim_ring( inv_scale: f32, parent: Entity, ) { - let ring = materials.add(StandardMaterial { - base_color: AMBER_DIM, - emissive: AMBER.to_linear() * if core { 2.4 } else { 1.3 }, - perceptual_roughness: 0.60, - metallic: 0.0, - reflectance: 0.06, - ..default() - }); - let ring_root = commands + let pool_root = commands .spawn(( Transform::from_scale(Vec3::splat(inv_scale)), Visibility::default(), ChildOf(parent), )) .id(); - let mut frame = |outer: f32, t: f32| { - let h = 0.012; - let y = 0.045; - let d = outer; - for (size, p) in [ - ( - Vec3::new(outer + t * 2.0, h, t), - Vec3::new(0.0, y, d * 0.5 + t * 0.5), - ), - ( - Vec3::new(outer + t * 2.0, h, t), - Vec3::new(0.0, y, -d * 0.5 - t * 0.5), - ), - (Vec3::new(t, h, d), Vec3::new(outer * 0.5 + t * 0.5, y, 0.0)), - ( - Vec3::new(t, h, d), - Vec3::new(-outer * 0.5 - t * 0.5, y, 0.0), - ), - ] { - commands.spawn(( - Mesh3d(meshes.add(Cuboid::from_size(size))), - MeshMaterial3d(ring.clone()), - Transform::from_translation(p), - ChildOf(ring_root), - )); - } - }; - frame(0.80, 0.05); - if core { - frame(0.96, 0.03); + // Authored radius (times inv_scale = world tiles) and the center emissive + // strength (amber, linear units for the HDR bloom camera). [TUNE] against + // the dark rig: the pool must read as thrown light, not a painted decal, + // and never clip the chassis to a flare. The core throws a wider, hotter + // pool (it is the most orange thing in the world). + let (outer, peak) = if core { (0.74, 1.5) } else { (0.54, 0.85) }; + // Many thin nested discs (no image texture, flat-materials.md): each disc + // covers [0, r], so the center accumulates every layer and the rim only + // the outermost — a smooth radial falloff. The step count is high enough + // that no individual disc edge reads as a hard ring. + let layers = 28; + let flat = Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2); + for i in 0..layers { + let t = i as f32 / (layers - 1) as f32; // 0 outer .. 1 center + let radius = outer * (1.0 - 0.94 * t); + // Low per-layer alpha fading to near-nothing at the rim, so the outer + // edge dissolves into darkness with no visible boundary. + let alpha = 0.018 + 0.085 * t; + let emissive = AMBER.to_linear() * (peak * t * t); + let mat = materials.add(StandardMaterial { + base_color: AMBER_DIM.with_alpha(alpha), + emissive, + alpha_mode: AlphaMode::Blend, + unlit: true, + perceptual_roughness: 1.0, + metallic: 0.0, + reflectance: 0.0, + ..default() + }); + commands.spawn(( + Mesh3d(meshes.add(Circle::new(radius))), + MeshMaterial3d(mat), + Transform::from_translation(Vec3::new(0.0, 0.02 + 0.003 * t, 0.0)).with_rotation(flat), + ChildOf(pool_root), + )); } } @@ -2399,23 +2469,29 @@ fn setup_3d( )); } - // The light rig (three points + the low global ambient): - // 1) cold fluorescent overhead — the basement's own institutional light; + // The light rig (material-dark-frame.md, the dark rig): the machines' + // own light and a near-nothing ambient. The institutional fluorescent + // overhead is gone from the default scene — the basement is dark + // because nobody is home and the AI does not need lights; brightness + // returns only as diegetic sources earn it (future work orders). + // + // The dev work light: one flat neutral flood, hidden by default, that + // apply_worklight toggles so a dev can inspect geometry the dark rig + // keeps unlit. A debug affordance, never a player surface. commands.spawn(( - PointLight { - color: Color::srgb(0.80, 0.88, 1.0), - intensity: 2_200_000.0, - range: 34.0, - shadows_enabled: true, + DirectionalLight { + color: Color::srgb(0.96, 0.97, 1.0), + illuminance: 11_000.0, + shadows_enabled: false, ..default() }, - Transform::from_translation( - grid_to_world_3d(core.0, core.1, 0.0) + Vec3::new(0.5, 6.5, 1.0), - ), + Transform::from_rotation(Quat::from_rotation_x(-1.0) * Quat::from_rotation_y(0.5)), + Visibility::Hidden, + WorkLight, layer.clone(), ChildOf(root), )); - // 2) warm amber machine glow at the core rack (machine presence) — the + // The warm amber machine glow at the core rack (machine presence) — the // only machine light at tick zero. The core's strip is a LINEAR // fixture, so its light is a dense run of dim point lights along // the strip's height (front and back of the seam), never one @@ -2522,6 +2598,31 @@ fn apply_render_mode( } } +/// The dev work light (material-dark-frame.md): F4 floods the material scene +/// flat and neutral so geometry the dark rig keeps unlit is inspectable; +/// toggling back restores the dark rig exactly (the same DARK_AMBIENT and +/// the hidden flood). A debug affordance, never a player surface — excluded +/// from canonical screenshots except the explicitly-labeled `worklight` +/// dev shot. +fn apply_worklight( + mode: Res, + mut ambient: ResMut, + mut flood: Query<&mut Visibility, With>, +) { + if !mode.is_changed() { + return; + } + let on = mode.material && mode.worklight; + ambient.brightness = if on { WORKLIGHT_AMBIENT } else { DARK_AMBIENT }; + if let Ok(mut v) = flood.single_mut() { + *v = if on { + Visibility::Inherited + } else { + Visibility::Hidden + }; + } +} + /// Restyle the 3D scene from sim facts: same fog precedence as render_map, /// projected into visibility + pooled materials/meshes instead of sprite /// tints. Unknown space stays geometry-free — sensor darkness, not hidden @@ -2552,22 +2653,28 @@ fn restyle_3d( for (t, mut mesh, mut mat, mut tf, mut vis) in q.iter_mut() { let fog = game.sim.fog_at(t.x, t.y); let tile = known_tile(&game, t.x, t.y); + // Light is the only revealer (material-dark-frame.md): the material + // render is a camera, and a camera photographs light, not floor + // plans. Only camera-seen surfaces draw as physical matter; owned + // machines legitimized by telemetry keep rendering (they are their + // own light). Blueprint/remembered mass is plan knowledge — it reads + // in the flat sensorium (F3) and overlays, never as matter the camera + // did not see. Heard keeps its noise field (a dim floor, never shape). + let owned_prop = machine_tile(tile) && owned_machine_at(&game.sim, t.x, t.y); let show = match (t.part, fog) { (_, Fog::Unknown) => false, - // Heard earns presence only: a dim floor, never shape. - (TilePart::Floor, _) => true, - (TilePart::Block | TilePart::Top, Fog::Heard) => false, - (TilePart::Block | TilePart::Top, _) => blocky_tile(tile), - (TilePart::Prop, Fog::Heard) => false, + (TilePart::Floor, Fog::Seen | Fog::Heard) => true, + (TilePart::Floor, _) => false, + (TilePart::Block | TilePart::Top, Fog::Seen) => blocky_tile(tile), + (TilePart::Block | TilePart::Top, _) => false, // Chassis tiles render as real 3D machine meshes // (sync_machines_3d) — never as billboards. (TilePart::Prop, _) if chassis_3d_tile(tile) => false, - // Blueprint: no foreign chassis / furniture props — room mass - // only. Owned machines still render via telemetry. - (TilePart::Prop, Fog::Blueprint) => { - machine_tile(tile) && owned_machine_at(&game.sim, t.x, t.y) - } - (TilePart::Prop, _) => prop_tile(tile), + // Owned machines are their own light: telemetry keeps their + // prop drawing even without room sight. + (TilePart::Prop, _) if owned_prop => true, + (TilePart::Prop, Fog::Seen) => prop_tile(tile), + (TilePart::Prop, _) => false, }; if !show { *vis = Visibility::Hidden; @@ -2597,10 +2704,9 @@ fn restyle_3d( // device actively feeding the player scans in the cold signal color. // Owned machines under blueprint still use Seen materials — telemetry // legitimizes the chassis without granting room sight. - let mat_fog = if t.part == TilePart::Prop - && matches!(fog, Fog::Blueprint) - && owned_machine_at(&game.sim, t.x, t.y) - { + // An owned machine prop reads as telemetry-lit regardless of room + // sight — the only non-Seen mass the material render draws. + let mat_fog = if t.part == TilePart::Prop && !matches!(fog, Fog::Seen) && owned_prop { Fog::Seen } else { fog @@ -2725,7 +2831,10 @@ fn wake_sequence( let strip_mid = core_w + Vec3::new(0.0, 0.85, 0.0); let tilt = CAMERA_TILT_DEG.to_radians(); let ang = 0.10 + (tilt - 0.10) * pull; - let dist = 0.30 + 13.0 * pull.powf(1.55); + // Pull back to the dark-frame close default (material-dark-frame.md), so + // the wake settles exactly on the opening close-up instead of the retired + // fit-to-content wide frame. + let dist = 0.30 + (CLOSE_DIST - 0.30) * pull.powf(1.55); let target = strip_mid.lerp(core_w, pull); let eye = target + Vec3::new(0.0, ang.sin(), ang.cos()) * dist; *tf = Transform::from_translation(eye).looking_at(target, Vec3::Y); @@ -2744,11 +2853,11 @@ const WAKE_LEN: f32 = 6.2; /// The material camera: anchored to attention (the cursor, which opens on /// the core) at a close distance (material-dark-frame.md: the opening frame -/// is the attention close-up — the rack dominates, the rest is dark). -/// Fit-to-known-content is retired as this camera's framing driver: the -/// known extent is a plan fact, and the plan no longer drives the camera -/// (that fit-to-content default now governs the flat sensorium only). -/// Zoomable with [ ]. +/// is the attention close-up — the rack and its floor pool dominate, the +/// rest is dark). Fit-to-known-content is retired as this camera's framing +/// driver: the known extent is a plan fact, and the plan no longer drives +/// the camera (that fit-to-content default now governs the flat sensorium +/// only). Zoomable with [ ]. The wake sequence hands off to this frame. fn update_camera_real( time: Res