diff --git a/src/bin/bevy.rs b/src/bin/bevy.rs index 5de270da..1cca34f6 100644 --- a/src/bin/bevy.rs +++ b/src/bin/bevy.rs @@ -349,7 +349,7 @@ impl Default for RenderMode { } /// Dev screenshot harness (env `MISALIGNED_SHOT=flat|opening|wide|close|dark| -/// zoomin|zoomout|intel|tokens|ears|eyes-white|eyes-form|worklight|worklightoff`, path via +/// zoomin|zoomout|intel|tokens|signal|ears|eyes-white|eyes-form|worklight|worklightoff`, path via /// `MISALIGNED_SHOT_PATH`): stages a scenario, /// waits for /// assets, runs the fog audit, saves one screenshot, exits. Not a player @@ -1258,6 +1258,19 @@ fn dev_shot_scenario(game: &mut Game, mode: &mut RenderMode, kind: &str) { game.drain(); return; } + // Pre-Eyes signal evidence: the graph has earned the environmental + // monitor and can reach it, but no feed has been tapped. The material + // frame must locate that opportunity as abstract cold signal without + // painting a camera body or advancing fog. + if kind == "signal" { + mode.material = true; + mode.zoom = 1.0; + if let Some(env) = game.sim.reach.device_named("environmental monitor") { + game.set_cursor(env.x, env.y); + } + 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 @@ -3287,6 +3300,74 @@ fn render_real_links( let iso = Isometry3d::new(c, Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)); gizmos.rect(iso, Vec2::splat(1.06), AMBER); gizmos.line(c, c + Vec3::Y * 0.9, Color::srgba(1.0, 0.69, 0.0, 0.55)); + + draw_sensor_signals_3d(&game, time.elapsed_secs(), &mut gizmos); +} + +/// Whether graph knowledge earns a pre-sight sensor-presence cue. +/// +/// This is deliberately independent of tile fog: reach can locate a digital +/// endpoint before any camera supplies physical truth. The cue disappears at +/// Seen, where the ordinary material prop takes over. +fn sensor_signal_visible(sim: &Sim, id: u32) -> bool { + sim.reach.device(id).is_some_and(|device| { + device.known + && (device.sees || device.hears) + && sim.reach.reachable(id) + && !sim.is_seen(device.x, device.y) + }) +} + +/// Material-world embodiment of earned reach knowledge: known reachable +/// sensors answer as small rising cold-signal rings at their shared physical +/// anchors before Eyes. This is not camera geometry — no body, lens, facing, +/// floor surface, or fog transition — just "a sensor endpoint answers here." +/// Heard's bone field can coexist with it; Seen replaces it with the device. +fn draw_sensor_signals_3d(game: &Game, t: f32, gizmos: &mut Gizmos) { + let signal = SIGNAL.to_srgba(); + for device in game + .sim + .reach + .known() + .filter(|device| sensor_signal_visible(&game.sim, device.id)) + { + let base = grid_to_world_3d(device.x, device.y, 0.07); + // A faint carrier pins the pulse to one coordinate without implying + // a physical support or device silhouette. + gizmos.line( + base, + base + Vec3::Y * 0.14, + Color::srgba(signal.red, signal.green, signal.blue, 0.34), + ); + // A broken, camera-facing locator brackets the answer without + // tracing any physical outline. It remains legible under the amber + // attention reticle when the player focuses the dark tile. + let breath = 0.5 + 0.5 * (t * 2.1 + device.id as f32 * 0.31).sin(); + let center = base + Vec3::Y * (0.48 + 0.035 * breath); + let half = 0.17 + 0.025 * breath; + let tick = 0.065; + let bracket = Color::srgba(signal.red, signal.green, signal.blue, 0.56 + 0.22 * breath); + for (sx, sy) in [(-1.0_f32, -1.0_f32), (1.0, -1.0), (-1.0, 1.0), (1.0, 1.0)] { + let corner = center + Vec3::new(sx * half, sy * half, 0.0); + gizmos.line(corner, corner + Vec3::new(-sx * tick, 0.0, 0.0), bracket); + gizmos.line(corner, corner + Vec3::new(0.0, -sy * tick, 0.0), bracket); + } + // Three asynchronous rings rise and dissolve. A physical object would + // hold shape; this repeatedly becomes signal and disappears. + for i in 0..3 { + let phase = (t * 0.52 + i as f32 / 3.0 + device.id as f32 * 0.071).fract(); + let y = 0.12 + phase * 0.68; + let radius = 0.075 + phase * 0.17; + let alpha = (1.0 - phase) * 0.68 + 0.10; + let center = base + Vec3::Y * y; + let iso = Isometry3d::new(center, Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)); + gizmos.circle( + iso, + radius, + Color::srgba(signal.red, signal.green, signal.blue, alpha), + ); + } + } } /// Wired work cargo in flight (machine-work.md): teal demand / bone knowledge @@ -4822,7 +4903,7 @@ fn ascii_ui(text: &str) -> String { #[cfg(test)] mod ascii_ui_tests { - use super::{ascii_ui, sidebar_nudge_text}; + use super::{ascii_ui, sensor_signal_visible, sidebar_nudge_text}; use misaligned::sim::Sim; #[test] @@ -4844,6 +4925,37 @@ mod ascii_ui_tests { assert!(text.contains("NEXT:")); assert!(text.contains("ACTIONS: right-click / Enter on focus")); } + + #[test] + fn known_reachable_sensor_pings_until_seen() { + let mut sim = Sim::with_seed(1); + let env = sim + .reach + .device_named("environmental monitor") + .expect("opening sensor") + .id; + let dock = sim + .reach + .device_named("dock camera") + .expect("unknown sensor exists in sim") + .id; + + assert!(sensor_signal_visible(&sim, env)); + assert!( + !sensor_signal_visible(&sim, dock), + "unknown sensors never leak through the material cue" + ); + assert!(sim.tap_device(env)); + assert!( + sensor_signal_visible(&sim, env), + "Heard keeps the separate network-provenance cue" + ); + assert!(sim.splice_device(env)); + assert!( + !sensor_signal_visible(&sim, env), + "Seen physical form replaces the abstract signal" + ); + } } fn trunc(text: &str, width: usize) -> String { diff --git a/wiki/SUMMARY.md b/wiki/SUMMARY.md index f0223913..e2e87f3d 100644 --- a/wiki/SUMMARY.md +++ b/wiki/SUMMARY.md @@ -120,6 +120,7 @@ - [2026-07-07 decisions](log/decisions/2026-07-07.md) - [2026-07-08 decisions](log/decisions/2026-07-08.md) - [2026-07-09 decisions](log/decisions/2026-07-09.md) + - [2026-07-10 decisions](log/decisions/2026-07-10.md) - [DEVLOG (the ledger)](log/DEVLOG.md) Dated session writeups (`wiki/log/YYYY-MM-DD-topic.md`) are not diff --git a/wiki/engineering/env.md b/wiki/engineering/env.md index 93712dce..3afda031 100644 --- a/wiki/engineering/env.md +++ b/wiki/engineering/env.md @@ -32,7 +32,7 @@ is sim or frontend state, never an environment variable. | Variable | Surface | Values | Effect | |---|---|---|---| -| `MISALIGNED_SHOT` | `misaligned-bevy` | `flat`, `wide`, `close`, `dark`, `zoomin`, `zoomout`, `intel`, `tokens`, `ears`, `eyes-white`, `eyes-form`, `wake1`, `wake2`, `wake3` | Dev screenshot harness: stage a deterministic scenario, settle, save one PNG, run the fog audit, exit. `intel` stages tick-zero intel tiers (no splice); `tokens` enqueues D5/K4 on the host; `ears` stages the hearing-feed noise field; `eyes-white` / `eyes-form` freeze the first-Eyes source held white and then contracted around the resolving chassis; `wake1/2/3` freeze the wake choreography at the stutter flash, the column, and the pull-back. | +| `MISALIGNED_SHOT` | `misaligned-bevy` | `flat`, `wide`, `close`, `dark`, `zoomin`, `zoomout`, `intel`, `tokens`, `signal`, `ears`, `eyes-white`, `eyes-form`, `wake1`, `wake2`, `wake3` | Dev screenshot harness: stage a deterministic scenario, settle, save one PNG, run the fog audit, exit. `intel` stages tick-zero intel tiers (no splice); `tokens` enqueues D5/K4 on the host; `signal` focuses the known environmental monitor before any feed tap to capture its cold-signal presence cue; `ears` stages the hearing-feed noise field; `eyes-white` / `eyes-form` freeze the first-Eyes source held white and then contracted around the resolving chassis; `wake1/2/3` freeze the wake choreography at the stutter flash, the column, and the pull-back. | | `MISALIGNED_SHOT` | `misaligned-assets` | `dead`, `foreign`, `idle`, `busy`, `core`, `dayjob`, `research`, `conceal`, `operations` (each optionally suffixed `_ladder`/`_ring`/`_wash`), `lineup[_