# Macrostep 04 — Raylib visualization workbench ## Objective Deliver the first useful interactive product: a portable, resize-safe raylib laboratory that runs the CPU backend and makes the rule, kernels, neighborhoods, and update logic visible. ## Dependencies Macrosteps 00–03 complete. ## Phase 4.1 — Application lifecycle and scheduler ### Substep 4.1.1 — Raylib ownership Initialize and own raylib on the main thread. Keep handles out of the mathematical core. Establish explicit startup, running, backend-rebuild, and shutdown states so partial resource failures do not corrupt the model. ### Substep 4.1.2 — Decoupled timing Implement: - render FPS independent of a fixed updates-per-second simulation clock; - pause, single-step, reset, and an explicit finite `advance N steps` command that is not tied to rendering; - bounded catch-up to avoid a spiral of death; - headless benchmarking outside the render loop rather than an uncapped frame-driven mode; - model `dt` independent of wall-clock tick duration. Animations and camera movement are time-based, not frame-count-based. ### Substep 4.1.3 — Unified action map Map keyboard, mouse, and UI widgets to one `Action` enum. Retain practical legacy aliases (`p`, `c`, `x/y`, parameter pairs, preset cycling), but do not encode behavior directly in key handlers. Add a searchable/help overlay. ## Phase 4.2 — Shared presentation primitives ### Substep 4.2.1 — Scalar texture uploader Convert CPU scalar fields to reusable raylib textures without allocating every frame. Start with a portable normalized or packed upload path; retain original `f32` values in the model. Make filtering (`nearest` default, optional linear) explicit. ### Substep 4.2.2 — Palettes Implement named versions of all seven legacy palettes in one shared Rust/GLSL definition: 1. phase hue on black; 2. white on black; 3. black on white; 4. value rainbow; 5. brown/green; 6. gold/brown; 7. phase-shifted value rainbow. Sanitize palette inputs and show a legend/range. Palette phase changes in units per second. ### Substep 4.2.3 — Cameras - 2-D uses a coherent `Camera2D`, cursor-centered wheel zoom, drag pan, reset, and fit-to-view. - 1-D and 3-D placeholders use their own presentation state; do not overload simulation coordinates. - Window resize changes presentation only, never simulation shape or state. ## Phase 4.3 — Model and logic views ### Substep 4.3.1 — Live state Render the selected field at correct aspect ratio with periodic coordinate indicators. Display generation, update rate, render FPS, shape, seed, preset, dynamics, integrator, and backend. ### Substep 4.3.2 — Read-only inspection Provide a tab/grid selector for: - `A`, `M`, `N`, `S`, derivative/increment, and proposed next state; - raw/normalized disk and ring kernels; - rule surface `S(N,M)` with labeled axes and current `(N,M)` probe; - radial kernel profile and numeric value-under-cursor. Inspection never modifies state. Keep `c` as an optional “next primary view” shortcut. ### Substep 4.3.3 — Compare layout Support at least a two-pane mode, for example `A | S`, `M | N`, or `kernel | radial profile`. All panes refer to the same committed generation and show stale-generation warnings if an async backend is introduced later. ## Phase 4.4 — Configuration UI Build a collapsible raylib-native panel (or a deliberately selected raygui binding after a compatibility spike) with sections: - run/preset/variant; - domain and initializer; - rule intervals and curves; - dynamics/integrator/timestep and RK4 relaxation reference when applicable; - kernel geometry; - backend, FFT algorithm, and performance; - view/palette/camera; - capture and diagnostics. Classify edits visibly: - **Hot:** presentation and pointwise rule edits; apply immediately. - **Warm:** kernel geometry/timestep/integrator; rebuild caches and invalidate integration history as specified. - **Cold:** shape, topology, variant, or backend; require transactional recreate/apply. Provide sliders plus precise numeric entry. Show validation inline; never silently clamp model parameters to UI ranges. ## Phase 4.5 — Presets, sessions, and capture ### Substep 4.5.1 — Preset browser Filter by variant/dimension/tags, show provenance and notes, and indicate modified (“dirty”) parameters. Applying a preset is transactional and logs the resulting run descriptor. ### Substep 4.5.2 — Persistence Persist user preferences separately from model presets. Add “save as user preset,” not append-to-bundled-file behavior. Save enough precision for exact round trips. ### Substep 4.5.3 — Exports Provide: - viewport PNG, optionally with HUD; - native field image with active palette; - restart-state export (field plus metadata, numerical history resets on load); - exact continuation checkpoint with integrator/variant history; - metadata sidecar containing run descriptor and generation. Use collision-safe timestamp/sequence names in the platform pictures/data directory. ## Phase 4.6 — Robustness and UX tests - Resize/minimize/fullscreen/high-DPI smoke tests. - Launch from arbitrary working directories. - Repeated valid/invalid warm and cold edits. - Pause and single-step accuracy. - Screenshot/state export while paused and running. - Keyboard focus does not alter parameters while numeric input is active. - Visible fallback if texture/shader creation fails. ## Deliverables - Portable raylib application using the CPU planar backend. - Discoverable controls, inspectors, preset browser, and exports. - Stable action, camera, palette, and presentation abstractions for later variants. ## Exit gate - A user can launch, choose a preset, reset with a seed, run/pause/step, edit parameters, and inspect every base pipeline channel. - Headless and interactive CPU runs produce identical model states for equal commands. - Resize and fullscreen never reset simulation. - No inspection mode destroys or advances state. - The application works outside the repository and reports failures visibly.