Turn Shot Designer (Hollywood Camera Work .hcw) scene files into Unreal
Engine 5.8 scenes (compatible with 5.6+) — cameras (with moves), actors,
props, walls, and lights — via a Python script you run inside the editor.
Shot Designer .hcw ──parse──▶ IR (JSON) ──emit──▶ Unreal 5.8 Python script
(plain XML) neutral scene run in the editor
No third-party dependencies for the core pipeline (stdlib only).
pip install -e . # provides the `vsm` command
# or run without installing:
PYTHONPATH=src python -m virtualsetmaker.cli --help# Parse a Shot Designer scene and emit an Unreal script:
vsm build samples/Sceneforclaude.hcw -o scene.py
# Inspect the intermediate representation as JSON:
vsm parse samples/Sceneforclaude.hcw -o scene.json
# Emit straight from a hand-authored IR (no .hcw needed) — good for demos:
vsm emit examples/example_scene.json -o scene.py
# Just confirm a file is a Shot Designer scene:
vsm probe samples/Sceneforclaude.hcw
# List the prop blockout library:
vsm props
# Open the graphical exporter:
vsm gui # (or run `vsm-gui`)vsm gui (or the vsm-gui command / vsm-gui.exe) opens a small exporter:
add one or more .hcw files, choose an export folder, hit Export — each
scene becomes <name>_unreal.py in that folder, with a log of object counts
and any unmatched-prop notes. Last-used folders are remembered in
~/.virtualsetmaker.json.
Standalone exe (no Python needed to run it):
- Get this repo onto the PC (clone or download ZIP).
- Double-click
packaging\build_windows.bat— one-time build; needs Python 3 from python.org with the default tcl/tk option. It installs PyInstaller and producesdist\vsm-gui.exe. - Double-click
dist\vsm-gui.exeto use the exporter from then on.
Or via pip: install Python 3.9+, then pip install . in the repo — this
gives vsm (terminal) and vsm-gui (windowed, no console) commands.
- Enable Edit → Plugins → "Python Editor Script Plugin" (restart once).
- Open the Output Log, switch the dropdown from
CmdtoPython. - Run
py "C:/path/to/scene.py"(or paste the file path).
It spawns the actors/props/walls/lights into the current level and creates a
Level Sequence (/Game/VSM/SEQ_<name>) with the CineCamera(s), any camera
move keyframes, focal-length animation, and a camera-cut track. The sequence
is opened in Sequencer as part of the build (required by the UE 5.6+
LevelSequenceEditorSubsystem spawnable API) and left open for you.
- 1 Shot Designer unit = 1 cm (override with
--units-per-meter). - Shot Designer positions are screen-space (
+ydown) with angles in radians; the one screen→Unreal axis/handedness flip lives incoords.pyso it's calibrated in one place. - Actors render as the UE Mannequin (
SKM_Manny), falling back to a capsule if the mesh isn't in the project.
Props aren't anonymous cubes: each Shot Designer objectKey maps to a
parametric blockout recipe in
emit/blockouts.py — a chair is a seat
- backrest + four legs, a table is a top + legs, an open door is a frame + a
swung panel, all at real-world dimensions. Run
vsm propsto see the recipes.
The library covers the entire Shot Designer object palette (62 recipes, mapped from the app's palette screenshots): all furniture and tables, desk/hand props (laptop, monitor, phone, plate, cup, paper, guns), greenery (bush, tree), every vehicle (car, mini bus, semi truck, trailer, motorcycle, tank, small plane, fighter jet, commercial jet), production gear (camera crane, boom mic, microphone, monitor village, equipment), all door/window types (open, closed, double open, double closed, medium opening, prison bars, window), and floor arrows.
Lights spawn as placeholder rig geometry + a real Unreal light attached at the fixture's emit point, grouped so they move together: fresnels/ellipsoidal/ PAR/scoop/cyc/open-face get a stand + head with a pitched SpotLight at the lens; panels/FLO/softbox/silk/bounce get their slab/frame with a RectLight on the face; china ball/balloon/practical/light-on-a-stick get hanging or lamp geo with a PointLight inside; Sun spawns a DirectionalLight only (position is meaningless for it, so no rig); the Virtual Speed Rail spawns rigging geo with no light.
Matching is exact key first, then ordered substring aliases (COUCHMODERN →
SOFA; BOOMMICROPHONE → boom rig, not phone), so unseen key-name variants land
on the right shape. Unmatched kinds fall back to a labeled 1 m cube and
vsm build prints a note — send a .hcw using that prop and the recipe can be
added in a few lines. Parts spawn grouped (attached to the first part) in the
VSM/Props outliner folder, so each prop moves as one unit.
- Static scenes (placement of camera, actors, props, walls, lights): done,
verified against a real
.hcw. - Camera moves: done. Shot Designer stores a move as numbered camera stop
marks (
<stopMarks>) linked by a<Track>dolly path; the parser merges each chain into one camera keyed at the start and end stops (position and look direction from the stops themselves) plus a key per intermediate track point so curved paths keep their bow (Unreal's AUTO tangents smooth through them). Timing comes from path length at the scene's camera-speed index (speed 3 ≈ 0.75 m/s dolly;_DOLLY_MPS_PER_SPEEDinparse/shotdesigner.py). Verified against straight-line and curved-move samples insamples/.
src/virtualsetmaker/
ir.py neutral scene dataclasses (+ JSON, validation)
coords.py the single Shot Designer→Unreal coordinate transform
parse/shotdesigner.py .hcw XML → IR
parse/probe.py format guard
emit/unreal_python.py IR → Unreal 5.8 Python script
emit/blockouts.py prop + light-fixture blockout recipes
build.py shared build core (used by CLI and GUI)
gui.py tkinter exporter (vsm gui / vsm-gui)
cli.py the `vsm` command
packaging/ PyInstaller spec + Windows one-click build script
examples/example_scene.json hand-authored IR with an animated push-in
samples/Sceneforclaude.hcw real Shot Designer sample
tests/ pytest suite (IR, coords, parser, emitter)
pip install -e ".[dev]"
pytest