Where a constraint solver beats hand-scheduling

A walkthrough of the public Stripboard benchmark on the indie-feature fixture — a 24-scene, 4-location, 92-page synthetic production with a 5-person cast and an 18-shoot-day target. The fixture ships in the Stripboard repo; you can clone it and re-run everything below with pnpm bench indie-feature. Numbers on the live benchmark page are regenerated from the JSON output of that command — never hand-edited.

This post walks through one fixture so the rest of the benchmark page makes sense. If you only have ten minutes, skip straight to /benchmark and run the harness yourself; this exists to add the narrative.

The fixture, in one paragraph

24 scenes across four locations: cabin (8 scenes), forest (8), town (4), highway (4). Five named cast — hero (in every scene), rival, mentor, sidekick, love, plus a single-day cameo. Hard constraint: the mentor character has a hard cast-out on day 10 (a real-world stand-in for an actor with a back-to-back booking). Soft constraints: cluster scenes by location to minimise company moves, batch day-vs-night, keep cast hold days under three for everyone except hero.

The hand-scheduled ground truth

This is the schedule a working 1st AD might build by hand in Movie Magic after about half a day of strip-shuffling. It clusters cabin scenes in the first window (the cabin is the most location-constrained), then forest, then mixes town and highway on the back half once the bigger cast is gone. Mentor exits after day 10 as required; cabin is empty from day 5 onward; the day/night ratio is the natural mix of the script.

Hand-scheduled ground truth — first 6 of 18 shoot days
indie-feature · constructed from corpus/indie-feature/ground-truth.json
Day 12026-06-01
sc-1EXT/Dcabinhero3/8
sc-2INT/Dcabinhero, rival4/8
Day 22026-06-02
sc-3INT/Dcabinhero, rival, mentor5/8
sc-4INT/Ncabin+love6/8

Day/night break inside one location is a typical company-day pattern.

Day 32026-06-03
sc-17EXT/Dcabinhero7/8
sc-18INT/Dcabinhero, rival8/8
Day 42026-06-04
sc-19INT/Dcabin+mentor3/8
sc-20INT/Ncabin+love4/8

Cabin wraps. From day 5 the company moves to forest.

Day 52026-06-05
sc-7INT/Dforesthero, sidekick, mentor3/8
sc-8EXT/Nforest+love4/8
Day 62026-06-06
sc-23INT/Dforesthero, sidekick, mentor7/8

Note the single-strip day — mentor and sidekick are both inbound for sc-23, so it gets its own slot rather than pairing with a non-mentor scene.

You can see the AD’s reasoning in the layout: cluster the location-constrained scenes first, get them done before the cast list expands, save the more flexible town and highway scenes for the back half when only hero is on call. This is the work hand-scheduling does well — it bakes in judgement about which constraints matter most on your particular shoot.

What the solver does differently

The interesting part of the benchmark isn’t whether the solver beats the AD on raw days saved (often it doesn’t, on a well-built ground truth). It’s what happens when the constraints change. A re-schedule after a cast-availability bump or weather day takes a 1st AD anywhere from 2–8 hours in Movie Magic, because every move ripples and there’s no solve again button. The solver re-runs in milliseconds.

So the case-study question for the indie-feature fixture isn’t "who built the better baseline?" — it’s "what does it cost to move?" Drop a hard cast-out for love on day 8 and re-solve:

The honest caveat: the solver’s cost function on the published fixture is currently optimising aggressively for the simulated-annealing objective and not yet penalising single-day collapse hard enough on this fixture class — see the /benchmark page for the current per-fixture numbers and where the solver wins and loses today. That’s the whole point of shipping the harness publicly: the methodology and the numbers move together, in the open.

Where Movie Magic still wins

Three places, on this fixture and in general:

  1. Strip-by-strip judgement on a known shoot. A 1st AD who has run this exact crew before has gut-feel constraints that are hard to write down. ("Don’t put the rival and the love interest on the same call sheet on a night exterior in cabin country, the transport bill goes through the roof.") Stripboard’s constraint DSL covers cast holds, location windows, day/night ratios, and company moves; it does not yet cover transport-cost bumps or social-dynamic ones.
  2. Call sheets and DOOD. Movie Magic’s full call-sheet templates are battle-tested on 25 years of productions. We export a stub for the next shoot day and a clean DOOD; for paymaster work you keep the MM seat for export.
  3. .sex round-trip with the union ecosystem. EP Payroll, IATSE paymasters, and completion bond auditors all read .sex. We read .sex (so you can ingest an existing schedule into the solver), but we don’t write it. That’s an intentional scoping choice — see the Stripboard FAQ.

Gotchas in constraint translation

If you re-run this benchmark on your own fixture, two things will bite you:

Both are documented in the methodology section on the benchmark page. If something looks wrong on your fixture, file an issue with the JSON output and the host string — three of the four scheduler bugs we’ve found in the beta came in that way.

Run it yourself

The benchmark, the fixtures, the solver, and this site are all Apache-2.0. The single CTA on this post is the same one on the landing page — there’s no signup gate, no email capture, no "book a demo" button.

git clone https://github.com/jmnprlabs/jmnpr.git
cd jmnpr && pnpm install
pnpm --filter @jmnpr/production build
pnpm bench indie-feature

That writes packages/production/bench/results/indie-feature.json. Diff it against the same file on this commit; numbers should match within wall-time noise. Then go to stripboard.jmnpr.co/benchmark and verify the published numbers came from the same JSON.