WAREHOUSEMODEL
FREECAD Β· ANALYTICAL MODEL Β· LIVE 3D β€” ONE SOURCE OF TRUTH
About ← Projects
Drag to orbit Β· right-drag to pan Β· scroll to zoom Β· click a rack to see that slot's route and cycle time

Floor Plan (Blueprint)

A dimensioned plan drawn from the same calculations.js results as everything else on this page β€” the same row and aisle positions the 3D view and the FreeCAD model use β€” and redrawn on every change. Dashed lines inside a row are the lanes of deep rack types; dotted lines are aisle centre lines.

Simulated Day

The key results above are averages and a steady-state queueing formula. This runs the day event by event β€” trucks arriving at random through the day (busiest hour = the peak-hour factor), queueing for doors, lift trucks fetching and storing every pallet β€” 30 times with different random arrivals, and shows the average and the range across those days. Press β–Ά Play a day above the 3D view to watch one.

Decisions

Save the current design as a scenario, change things, save again β€” every scenario is recalculated here side by side (best value in each row highlighted). Scenarios stay in this browser; a share link carries one design to anyone.

No saved scenarios yet β€” the table shows the current design only.

Data & Files

Import your data

A movements CSV (one row per pallet movement or order line: date and time, SKU, pallets, and in/out if you have it) and, optionally, an inventory CSV (SKU, pallets on hand). Column names are matched loosely. The files are read in your browser β€” nothing is uploaded.

none
none (optional)

Export the design

The current design, in formats CAD and BIM tools open. All geometry comes from the same layout as the 3D view and the plan.

Building, walls, slabs, one element per rack row, dock doors and spaces, with every input and key result as property sets. Checked against the IFC4 schema with IfcOpenShell. The floor plan in metres on named layers (walls, racks with bay lines, aisles, docks, zones, notes) β€” AutoCAD R12, opens almost anywhere. The live 3D model as a .glb file β€” racks, pallets, building and trailers. The dimensioned floor plan above.

Regenerate this exact design as a real, parametric FreeCAD model (run from the warehouse-model folder):

Visual Analytics

Traceability β€” where every number comes from

Every KPI above is derived through these exact steps. Nothing is a black box.

Why does this matter? β€” reading the model

Storage capacity is pure geometry: how many rack rows fit across the building's width, how many bays fit along its length, times levels and positions per bay. Change aisle_width and watch fewer or more rack rows fit β€” a physical consequence, not a tuning knob on the capacity number itself.

Utilization is deliberately independent of capacity: current_inventory_pallets is a real-world operating fact (how much is actually in the building right now), so shrinking capacity without changing demand is exactly how utilization climbs past 100% β€” a genuine overflow condition, not a clipped display.

Rack type sets how deep each lane is. Deeper lanes (double-deep, push-back, drive-in) need fewer aisles, so the same floor holds more pallets β€” but fewer of them can be reached directly (selectivity), and because a lane only holds one product, part-empty lanes waste space, so the realistic ceiling (practical capacity) is lower. VNA keeps every pallet reachable and saves space with very narrow aisles instead, at the price of a guided turret truck.

Vertical fit is checked the way a rack designer would: each level must hold a load plus the beam and a lift-off gap, and the top load must stay the sprinkler clearance below the lowest obstruction (0.46 m for standard sprinklers, 0.91 m for ESFR under NFPA 13).

Cycle time is an exact average over this layout, not a textbook approximation: every receiving or shipping door to every aisle, bay and level, along a rectilinear route (door β†’ across the staging zone β†’ down the aisle). Lift trucks raise the load only after stopping, so lift time adds to driving time β€” which is why taller racks cost time even when the floor gets smaller. Trips are single-command (one pallet per trip, random storage); smarter slotting and combined trips come in a later version.

Docks are sized by trucks, not pallets: each door turns a truck every truck_turn_time minutes, receiving and shipping doors are separate (one can be the bottleneck while the other is idle), and they are sized for the peak hour, not the daily average. Trucks arrive at random, so they queue well before the doors are 100% busy: the wait comes from the Erlang C queueing formula (M/M/c), corrected for turn times that vary less than purely random ones (Allen–Cunneen). The lift-truck fleet is sized for the peak hour too, allowing for the share of each hour a truck really works.

Slotting and flow. With class-based (ABC) storage the fastest-moving pallets live in the quickest positions. How much that saves depends on the demand skew β€” and on where the doors are. With I-flow (receive at one end, ship from the other) a bay close to the receiving doors is far from the shipping doors, so ABC only gains across the width and in height; with U-flow (both on one wall) it gains along the aisles too. Dual-command trips store one pallet and fetch another on the same trip; mid cross-aisles shorten the drive between the two, at the cost of some bays.

Cost uses flat illustrative rates (see the Cost sliders) β€” it shows how racking, building shell and dock costs shift relative to each other as the design changes, not a quotation.

Guided experiments β€” try these
  1. Geometry. Double warehouse_length. Does storage capacity double too? (Watch bays_per_row in the Traceability panel β€” the two cross-aisles are a fixed cost, so a longer building is slightly more efficient per metre, not exactly double.)
  2. Capacity without footprint. Leaving warehouse_length and warehouse_width untouched, can you raise storage capacity by changing only rack_height and levels_per_rack? What has to be true of clear_height for that to work?
  3. Utilization under fixed capacity. Freeze the building and racking parameters. Raise current_inventory_pallets past the storage capacity shown in Key Results. What warning appears, and what does that mean operationally?
  4. A trade-off. Narrow aisle_width to fit more rack rows. Capacity rises β€” but does Avg. Round Trip rise, fall, or stay flat? Why might a real facility still avoid the narrowest legal aisle?
  5. The bottleneck shifts. Push daily_throughput_pallets up while holding dock count fixed. At what point does Dock Utilization β€” not storage β€” become the binding constraint? Now raise peak_hour_factor: the average day hasn't changed, so why do you need more doors?
  6. Rack types. Switch to Double-deep, then Drive-in. Capacity rises β€” what happens to selectivity and to the practical capacity? Then try VNA and narrow the aisle to 1.8 m: how does it compare with double-deep on capacity, and why would you still pick one over the other?
  7. Slotting. Switch storage_policy to ABC and open the ABC class view. How much does the time per move drop? Now switch flow_layout to U-flow β€” why does ABC suddenly save much more?
  8. Dual command. With I-flow, raise dual_command_share: the time per move gets worse. Read the design note, switch to U-flow and try again. Then add two mid_cross_aisles in a 200 m building: what do you gain and what do you give up?
  9. Queues before capacity. Double daily_throughput_pallets. Door utilization is still under 100%, so why does Truck Wait jump? Add one door and watch the wait fall far more than the utilization.
  10. What should we build? Open Decisions β†’ Optimiser and press Find designs. Why does the cheapest design use tall racks and a small footprint? Allow selectivity down to "any": what wins, and what would you have to know about the products before choosing it?
  11. What matters most? In Sensitivity, look at annual cost: drivers' wages usually top the tornado β€” which is why fewer, faster truck trips (slotting, U-flow) are worth more than cheaper racking.
  12. Averages hide queues. Raise peak_hour_factor to 2.5. The daily totals don't change, but look at the Simulated Day: the busiest hour's wait and the yard queue grow. Then set sim_lift_trucks to one fewer than recommended β€” work spills past closing, and outbound trucks wait at their doors for pallets.
  13. Going up. Add a level (5 levels) without changing the rack height. What warning appears? Raise rack_height until it clears β€” and watch the cycle time and the clear-height check.
How this is built β€” architecture

freecad/create_model.py is the authoritative engineering model: it reads data/parameters.json, builds the warehouse in FreeCAD (floor/walls/roof via Part::Box, a live Spreadsheet::Sheet holding every parameter as a named, unit-tagged, expression-bindable cell), and exports a tessellated GLB snapshot. Toggle Reference Model above to load that real export.

web/src/calculations.js is the analytical model β€” the same layout arithmetic FreeCAD's script runs, reimplemented in JS so it can recompute instantly as you drag a slider, with every function returning a trace array (see the Traceability panel). Unit tests check it by hand calculation, over thousands of random designs, and against a brute-force walk over every slot; a parity test runs the FreeCAD script's layout code on the same random designs and requires identical results.

web/src/visualization.js is the live 3D view: procedural Three.js geometry built from the same parameters and the same layout numbers, rebuilt on every change. It is not the GLB β€” a baked mesh can't resize itself β€” and the app never implies otherwise.

web/src/simulation.js is a discrete-event simulation of the day that takes every lift-truck task time from the same per-slot formulas; its tests check that lift-truck work per pallet matches the analytic model and that door waits match the queueing formula. web/src/optimizer.js searches designs through the same model; its tests re-check every design it returns. web/src/exporters.js writes the IFC and DXF files (tested by opening them in IfcOpenShell and FreeCAD), and web/src/dataimport.js turns movement and inventory data into model inputs.