Millwright: live shop-floor dashboard
One panel shows the whole shop floor and assigns tasks to the machines on its own, including when one of them suddenly stops.
A shop floor with no shared picture of the situation
Orders and machine status live in spreadsheets, on whiteboards, and in foremen's heads. When a machine breaks down or a rush order lands, nobody sees right away where to move the work or what it will cost. Millwright shows the whole floor in one place and decides where every task goes before a person can work it out by hand.
Setup awareness built in: the MCT-S algorithm
- Task sorting
- Priority sets the order: Critical first, then Rush, then Normal, constraint tightness bumps up tasks with fewer capable machines, and LPT (longest task first) arranges the rest for optimal bin-packing.
- Machine scoring
- Score = (completion time − preference bonus) × priority weight, where more urgent tasks get a lower weight. Lowest score wins; ties are broken in favor of no setup required.
- Work stealing
- Idle machines scan overloaded queues themselves, check task compatibility, and take it over when it pays off. Zero manual intervention.
- Priority-aware insertion
- A new task lands in a machine's queue at the position its priority actually earns, not always at the tail. A critical order can jump ahead of work that is already waiting instead of sitting behind it until that finishes.
An in-house heuristic called MCT-S (Minimum Completion Time with Setup Awareness): greedily pick the lowest-scoring machine, break ties with LPT, and bake the setup cost directly into the formula. A product name, not a formal optimality proof from a scheduling-theory textbook.
Design targets and the numbers from the simulation
- under 200 ms
- design target: time from a task entering the pool to its machine assignment.
- under 500 ms
- design target: a full re-shuffle of the queue after a machine breakdown is reported.
- 500+/h
- design target: maximum tasks assigned per hour across 8 machines, under optimal conditions.
By design, work stealing is meant to move about 15% of tasks dynamically between machines, and grouping similar operations is meant to cut setup time by roughly 40%: design targets, not a measured benchmark. The analytics panel does compute real OEE (Availability × Performance × Quality) from each machine's actual downtime and run time, not a canned formula for show.
The panel shows one figure in złoty and lets you change both numbers it comes from. The cost of a stopped hour defaults to 8 000 zł: the lost value added in the worked example at utrzymanieruchu.pl (20 000 zł/h of output less 12 000 zł/h of materials). The second field, 15 minutes of standstill saved per fault, is labelled on screen as an assumption rather than a measurement. The multiplier is the faults the running session has actually resolved, not an annual projection.
Every other number in the panel comes from the simulation itself: OEE computed from each machine's downtime and run time, the rescheduling pass measured in milliseconds after every fault, and a lead-time control chart whose limits are frozen from the session's own first 25 orders.
Our own project. We built it and we run it ourselves. The shop floor and its breakdowns are a simulation, not a customer's production data.
Every choice has a reason
| Layer | Choice | What it does |
|---|---|---|
| Frontend | Next.js | The screen changes in the same moment the state of the floor changes. |
| State | Zustand | Every panel reads the same machine state, so two views never show two truths. |
| Styling | Tailwind CSS | One light theme that stays readable on a monitor next to the line. |
| Animation | Motion | Transitions lead your eye to what changed instead of decorating the screen. |
| Charts | Recharts | You see floor load and task count as a line over time, not as one number. |
| Export | ExcelJS | You save the shop-floor report as a sheet and open it in Excel without retyping it. |
