# Factory Flow Simulator

## Learning goal
Follow individual jobs from arrival to completion. Watch queues reveal the slowest stage and test where another worker helps.

## Model and limits
Deterministic FIFO discrete-event queues with unlimited buffers, fixed service times and one worker each at A and C. Events use time then insertion order for ties. Throughput is completed jobs divided by elapsed time and includes startup. No stochastic breakdowns, walking time, costs or real-business forecast.

## Primary references
- [SimPy: event scheduling](https://simpy.readthedocs.io/en/stable/topical_guides/time_and_scheduling.html)
- [SimPy: shared resources](https://simpy.readthedocs.io/en/stable/topical_guides/resources.html)

## Experiment design
- **Find the queue**: Assembly takes longer than the arrival interval. Parameters: `{"arrival":3,"stageA":2,"stageB":4,"stageC":1}`.
- **Add an assembler**: Two workers share the station B queue. Parameters: `{"arrival":3,"workers":2}`.
- **Move the bottleneck**: A slow inspection stage becomes the limiting capacity. Parameters: `{"stageC":6,"workers":2}`.
- **Overload the line**: Fast arrivals outpace processing capacity. Parameters: `{"arrival":0.5,"jobs":40}`.

These presets are design predictions to investigate, not claims from a usability study. All readouts, animation positions and exported observations come from the same local model. The 2D view uses the same state. Saved setups restart from their parameters, rather than claiming to resume exact progress. Captured baselines are stored separately and survive resets and preset changes.

## Verification
Run `node --test apps/shared/discovery/tests/models.test.cjs` for numerical invariants, limiting cases, determinism and failure-state checks. Run `node apps/shared/tests/catalog.test.cjs` for routes and references. Browser and keyboard validation must be reported separately from numerical tests; automated tests are not user research.

## Discovery studio interaction layer
The studio adds selectable model objects, ray-based 3D picking, keyboard-accessible object selection, an inspector, scene editing where appropriate, model-specific stepping, and 24 measured challenges across the twelve labs. This is an interaction redesign, not a claim of measured learning improvement.

Most parameter changes now preserve current state. Structural changes explicitly start a new run; the exact per-app list is in `apps/shared/discovery/studio-model.js`. Current settings, independently captured baselines and challenge progress retain separate storage. Undo/redo keeps up to 30 edit checkpoints; the timeline keeps the latest 80 model snapshots. Resuming from a historical state creates a new branch. Saved setups still restart from parameters; they do not claim to retain the timeline or local particle pin edits.

Additional instruments derive from the existing model and cited references. Camera and light sweeps hold the remaining inputs fixed; neural curves separate training and validation; compression uses actual coefficients and recomputed quality samples; traffic uses recorded car positions/speeds; factory queues and utilisation use actual events and busy time. Visible instruments can continue collecting data while the hidden 3D view stops drawing.

Run `node --test apps/shared/discovery/tests/studio.test.cjs` for live edits, preserved state, all challenge solutions, direct manipulation, rewind, picking, instrument exports and controller integration. These DOM/renderer-double checks do not replace rendered browser and device review.


## Detailed 3D apparatus
Shared procedural geometry in `apps/shared/discovery/apparatus.js` adds mechanical housings, lens and iris parts, cables, wheels, connectors, moving machine heads and subject-specific markings. The scene uses bevelled housings, smoother curved geometry, instanced material families, a key/fill/rim light arrangement and bounded soft shadows. Cloth has a procedural weave bump map attached to its original model coordinates.

Full detail can be switched to Essential detail without resetting the model. All movements use model state or model time: wheel markers use road position, machine heads use scheduled job progress, conveyors use accumulated worker time, iris blades use the illustrated aperture, and network packets use their scheduled flights. Signal and energy markers illustrate direction, not measured transit speed. The fan is an indicator of the wind setting; it does not add a fluid simulation. Shells, grippers, cables and surface textures do not change the underlying collision model. The 2D fallback retains the same state and geometry.

Additional checks: `node --test apps/shared/discovery/tests/apparatus.test.cjs`. Geometry, state preservation, bounded batching, semantic selection, pause/rewind consistency and fallback behavior are checked with renderer doubles; browser pixels and device frame rates remain unverified.


## Authored model assets
The physical-object labs now load original Blender-authored GLB assets through `model-assets.js` and `model-worlds.js`: articulated industrial arm, mirrorless camera, car (overview and inspection versions), network router, gantry station, optical laser and companion character. The geometry, authored material surfaces and packed texture maps replace corresponding primitive bodies only after loading succeeds. Source `.blend` files, reproducible Python generators, manifests and inspected Blender renders are retained in `assets/models/` and `scripts/`. Mathematical data surfaces stay tied to their original calculations.

The robot uses actual solved joints; camera iris hinges respond to the aperture and a Cutaway toggle exposes the sensor/rays; car wheels and brake lights follow model position/acceleration; factory heads use scheduled job progress. GLB equipment covers remain illustrative, not new collision or optical physics. Camera cutaway distances are display distances; numerical thin-lens readings remain authoritative. The companion uses the motion model's translation and squash/stretch.

Assets load on demand, repeated equipment shares instanced geometry/materials, and only the selected close-up car upgrades from the lighter road mesh. Failure preserves the diagram and exposes Retry model. Inspect model fits the selected geometry rather than applying a fixed camera distance. Full/Essential detail, pause, rewind and existing models/data remain available. A procedural studio reflection environment lights PBR surfaces without external network requests.

Run `node --test apps/shared/discovery/tests/model-assets.test.cjs` for real GLB parsing, file loading, texture/UV presence, hierarchy transforms, exact solver alignment, cutaways, pause/rewind, fitting and car detail selection. Asset product renders were visually inspected in Blender. Browser pixels and device frame rates are still unverified; product renders are not screenshots of the web app.

## Bespoke rebuild (2026-10)
The shared discovery template (and its 3D scene) was replaced by a purpose-built page. `model.js` and `config.js` are unchanged.

- `flow-derive.js` drives the unchanged model in steps of at most 0.25 s of model time and records each sample: queue lengths, busy time, arrivals, completions, per-station completions and the exact area under the jobs-in-line curve (from job arrival/completion times). From these it derives capacity (workers ÷ time per job), the steady-state "fluid" analysis (inflow, queue growth rate, expected throughput, busy fraction), busy share over the last 30 s, throughput over the last 60 s, Little's law terms (L = area ÷ time, λ = finished ÷ time, W = mean time in system of finished jobs) and rush recovery. A "rush" adds jobs with the model's own `rush` action; it is counted as cleared when jobs in the line return to the highest level seen in the 10 s before it. The predicted clear time is extra jobs ÷ (smallest capacity − arrival rate), a fluid approximation that can differ by about one job's worth of time.
- `flow-view.js` is the main 2D view: a flow diagram (arrivals → queue → A → queue → B → queue → C → done) with stacked job tokens coloured by waiting time, worker icons with progress bars, busy bars, capacities, and the bottleneck (lowest capacity, when arrivals reach it) or overloaded stations highlighted. Wide screens use a single horizontal line; the page normally uses a compact row layout (queue beside its station) so the stage fits next to the side control column at 1366×900 and stays sticky above the controls on phones. Token sliding is display-only easing; in the model moves are instant.
- `charts.js` draws five charts from recorded samples: queues over time (with the previous run dashed), job journeys (Gantt rows of waiting vs working), capacity vs arrivals (with measured throughput markers), Little's law over time, and busy-vs-recovery (the fixed-time curve k ÷ (μ(1 − ρ)), measured rush dots at the current capacity, and the textbook M/M/1 wait ρ/(1 − ρ) × service time, clearly labelled as a formula, not simulated).
- `app.js` handles presets (6 questions; "Nearly full" schedules a 5-job rush at 30 s), restarts on every setting change, story text, the model's own prediction question, and three checked challenges (verified solvable: 2 assemblers; all stations at 3 s with arrivals every 3 s; 3 assemblers with A at 1 s and a 5-job rush clearing in about 16 s).

No 3D view: a serial line is a flow, and depth adds nothing a diagram does not show more clearly. Limits: fixed times mean queues form only from overload or rushes, so the "explodes near 100%" lesson is shown through rush recovery plus the labelled textbook curve rather than simulated randomness. Utilisation and throughput use sliding windows and lag after changes.
