01REQUESTitems, containers, rules and objective

OPEN-SOURCE 3D CARTONIZATION & BIN PACKING

Deterministic 3D cartonization
you can verify.

Pack orders into cartons, pallets and containers with an MIT-licensed library for Python, PHP, Rust, Node.js and the browser. Enforce real packing constraints, get exact placements, and see why every refused item did not fit.

PackagesPython · PHP · Rust · JavaScriptPackvium returns placements, a score and a reason for anything it refuses; it does not drive equipment or prescribe control logic.
01 / REQUEST

The whole problem fits in one document.

Items, containers, the rules that make a load legal and the objective you rank by arrive as one JSON request, in exact units. There is no service to stand up, no database to migrate and no hidden state: what you sent is what the answer depends on.

02 / CONTRACT

One contract. Four independent engines.

Python, PHP, a Rust core and a JavaScript fallback implement the same schema separately, rather than one implementation being ported three times. Each either honours a field or rejects it by name. Reading a rule and answering confidently without applying it is the one thing the contract forbids.

03 / RULES

Constraints go into the search, not after it.

Orientation limits, support ratio, cumulative top load, stack density, incompatible tags, axle load and versioned policy rules are compiled into the search itself. An illegal candidate is never generated, instead of being filtered out of an answer that already assumed it away.

04 / SEARCH

Bounded search you can reason about.

Python and PHP run six solvers behind one portfolio under one deadline; Rust runs its own portfolio, and the JavaScript fallback runs a deterministic greedy search over one item ordering under fast and eight under balanced and quality — all under the same effort budget, counted in operations rather than wall clock, with a seed. Each engine is deterministic for a fixed engine version, configuration and seed, so the same request returns the same answer on your laptop, in CI and on the machine that has to justify it later. Across runtimes the guarantee differs: Python and PHP are held to byte-identical canonical results; Rust and the JavaScript fallback are independently validated and held to a per-fixture objective floor.

05 / PROOF

A second implementation checks the first.

An independent validator that shares no code with the solver recomputes the objective and every affected rule from the returned placements. A solver auditing its own bookkeeping proves nothing; recomputation is what makes the result evidence.

06 / ANSWER

Including the reason it said no.

You get placements as exact integers, the score vector they were ranked by, alternatives, and a named reason with a proof level for every item left behind. Then pack those cartons onto a pallet and run the same contract one level up.

02 / REFUSALS AND PROOF

Two guarantees about the answer you get back.

Most packing libraries return an arrangement and leave the rest to you. Two things decide whether you can put that arrangement in front of a customer: what it says about the item that did not fit, and whether the result can be checked by something other than the code that produced it.

01 / REFUSALS

Every item left behind says why

The result carries a reason code per unplaced item, the observations behind it, and how strongly it is backed: proven, observed, inferred, or unknown because a search limit was reached first. That is enough for support to answer a customer without opening the solver.

02 / VALIDATION

Recomputed by a second implementation

A validator that shares no code with the solver derives the objective and every affected rule again, from the placements the engine returned. Four runtimes, one corpus. Of the six open-source engines in our published comparison, none documents an independent recomputation of its own output.

03 / RULES THAT MAKE A LOAD LEGAL

The rules that decide whether a placement is legal.

An arrangement that crushes the bottom carton, tips the load onto one axle or buries the first delivery stop costs more than the space it saved. Each of these rules is enforced while the search runs, and each one has fixtures behind it.

04 / FROM INSTALL TO FIRST ANSWER

One package, one request, one answer to read.

Python and PHP install without runtime dependencies; Node and browser packages ship ready to use; Rust integrates normally through Cargo. No hosted Packvium service is required.

01

Install the engine for your runtime

Python, PHP, Node or the browser. Each package is the same contract, so the choice is your stack's, not the algorithm's.

02

Send the smallest real request

Items, containers and the rules that apply, as JSON on stdin or through the library API. Every engine accepts the same document.

03

Read status, placements, refusals, score

In that order. The status tells you what kind of answer it is; the refusals tell you what to say to whoever asked.

QUICK START / ANY RUNTIME~ 2 MIN
# pip install packvium
from packvium import Container, Dimensions, Item, Packer, PackingConfig

result = Packer(PackingConfig.balanced()).pack(
    items=[Item.create("book", Dimensions.mm("210", "140", "30"), quantity=4)],
    containers=[Container.create("box", Dimensions.mm("400", "300", "250"))],
)

print(result.status)  # feasible
Positions come back as exact integer ticks — precise, not approximate. Python and PHP return byte-identical results; Rust and JavaScript are independently validated. The PHP and Node CLIs take the same JSON on stdin.

05 / EVIDENCE, NOT SCREENSHOTS

Every rule on this site is a committed fixture.

A capability counts only when a named fixture exercises it, every engine implements or rejects it, and the independent validator recomputes it. These are those fixtures: the same files the cross-language gate runs on every change.

06 / SEVEN CAPABILITIES, WORKING

Scroll. Everything on the right is the engine's own answer.

Not a mockup: each drawing is the request beside it, run through @packvium/engine when this page was built - the same request "Open this request" loads - and each rule is backed by the conformance fixture named under it, which the cross-language gate checks on every change.

01 / Exact fit

An exact answer, not an estimate.

Eight identical cubes, one container, no rule in play yet - the baseline every runtime has to agree on before anything harder is meaningful.

THE INPUT BEHIND THIS
"items": [{ "id": "cube", "quantity": 8,
  "dimensions": { "length": "100", "width": "100", "height": "100" } }],
"containers": [{ "id": "box",
  "inner_dimensions": { "length": "200", "width": "200", "height": "200" } }]
200×200×200 · 100.0% used
cube × 8
02 / Obstacles

Obstacles are geometry, not a note in the spec.

A wheel arch, a post or a roof shelf is a reserved volume built from exact boxes, and every placement routes around it - not around a comment beside the result.

THE INPUT BEHIND THIS
"obstacles": [
  { "id": "wheel-arch",
    "origin": { "x": "900", "y": "0", "z": "0" },
    "dimensions": { "length": "300", "width": "150", "height": "200" } }
]
Proven by fixture feature-compound-obstacleInspect evidence →Open this request →
1200×600×600 · 8.3% used
crate × 4wheel-arch
03 / Refusal

A refusal carries a rule and a proof level.

This item is marked keep-upright. It would have fit lying on its side - Packvium refuses it anyway, and names the exact rule that stopped it: rotation_restricted, proven.

THE INPUT BEHIND THIS
"id": "plank",
"keep_upright": true
Proven by fixture regression-rotation-restrictedInspect evidence →Open this request →
Would fit lying down.keep_upright: true ✕ Request requires upright orientation.
REFUSED · 1
plank#1Proven

No permitted rotation fits rotation_restricted

04 / Axle balance

A payload that fits can still overload the axles.

A 650 kg crate and a 5 kg item both fit the trailer's 2000 kg payload with room to spare. Its two axles - 300 kg each, 400/1600 mm apart - share whatever the crate weighs wherever it stands, and 600 kg between them is not enough, so the heavy item is refused, not squeezed in.

THE INPUT BEHIND THIS
"axles": [
  { "position": "400",  "max_load": "300 kg" },
  { "position": "1600", "max_load": "300 kg" }
]
Proven by fixture feature-axle-grossInspect evidence →Open this request →
2000×200×200 · 10.0% used
light × 1
REFUSED · 1
heavy#1Inferred

Would overload an axle wherever it stands axle_overloaded

05 / Unload order

A load is only useful if you can unload it.

Two 300 mm crates in a 600 mm van. Asked whether each can leave without moving another, the engine answers per crate: stop 1's is reachable; stop 2's is blocked - by name and index - until stop 1 is out.

THE INPUT BEHIND THIS
placementReachability(boxes, van, [0, 1])
Proven by fixture feature-stop-indexInspect evidence →Open this request →
12
DOOR ←Stop 2: blocked_by_route [0]Stop 1 out: stop 2 reachable
06 / Nesting

Cartons on pallets on trailers: the same contract, one level up.

The engine packs one container per request. Pack widgets into a carton, then send those cartons as items of the next request, then the pallets of the request after that. Three separate runs, each one feasible, each one checked the same way.

THE INPUT BEHIND THIS
"items": [{ "id": "carton", "quantity": 24,
  "keep_upright": true,
  "dimensions": { "length": "300", "width": "300", "height": "200" } }]
3 CHAINED ENGINE RUNSOpen this request →
  1. 1 · WIDGETS → CARTON12/12 · 300×300×200 · 100.0% used Everything fitted, proven best
  2. 2 · CARTONS → PALLET24/24 · 1200×900×600 · 66.7% used Everything fitted, proven best
  3. 3 · PALLETS → TRAILER8/8 · 2400×1800×1300 · 92.3% used Everything fitted, proven best
Each level is its own request; the container of one becomes the item of the next.

The same discipline applies to the answer itself, not just the placements in it.

INDEPENDENT VALIDATION

Checked again by an implementation that shares no code.

The validator recomputes the objective and every affected rule from the returned placements, with an implementation that shares no code with the solver. Inject a failure to see how a rejected result reports itself.

VALIDATEDfixture / exact-fit
Bounds8 / 8
Collision0
Allowed rotations8 / 8
Support ratioPASS
Cumulative top loadPASS
Stack densityPASS
Centre of massPASS
Axle loadPASS
NO ACCOUNT, NO METER, NO BLACK BOX

07 / RUNTIMES

Install it where your stack already lives.

Four implementations of one request schema, written separately rather than ported from each other. Which one you install is a deployment decision; the answer you get back is the same document either way.

Engines, what they ship and what they are held to
RuntimeShips asSolversExtension pointsHeld to
Pythonpackviumall sixall fivecanonical result equality with PHP
PHPpackvium/packviumall sixall fivecanonical result equality with Python
Rustpackvium, @packvium/browserits own portfoliofour, via SolverRegistryindependent validity, per-fixture objective floor
JavaScript@packvium/enginegreedy, 1 ordering (fast) or 8noneindependent validity, per-fixture objective floor

08 / WHERE TO GO NEXT

Where to go next.

The story explains the model. Everything it does not already link to lives in dedicated pages that grow with the engine instead of stretching the homepage.