optional-skills/creative/unreal-mcp/references/recipes.md
Complete build sequences from a plain-English brief to a delivered capture.
Written against the discovery contract, because the live tool surface is
project-dependent: each step names the capability to locate (via
list_toolsets / describe_toolset) and the exact values to feed it —
not hardcoded tool names, which drift while the plugin is experimental.
Every step = four parts:
INTENT what this step achieves
DISCOVER which toolset/tool capability to use (locate via describe_toolset)
VALUES the exact arguments/numbers (from scene-craft.md)
VERIFY the query or screenshot that proves it worked
Dispatch shape: call_tool with toolset_name, tool_name, and an
arguments object matching the described schema — result returns on the
same turn.
LIGHTING RULE for every recipe: set Mobility = Movable on every light you spawn (Lumen GI ignores Static/Stationary lights — the #1 "why is GI dead" cause).
Session preamble for every recipe (do once):
list_toolsets → note the qualified names (e.g.
editor_toolset.toolsets.scene.SceneTools,
EditorToolset.EditorAppToolset).describe_toolset on each group you'll touch → cache schemas.SceneTools.get_current_level) and inventory the
environment: find_actors for DirectionalLight, SkyAtmosphere,
SkyLight, ExponentialHeightFog, PostProcessVolume, VolumetricCloud.
Configure existing environment actors; spawn only what's missing —
template levels ship with most of them, and duplicates compound into
whiteouts.intensity — it tells you the scene's exposure
calibration (template worlds are often calibrated around intensity: 10,
not physical lux; see pitfalls 12b before applying scene-craft absolute
values).EditorAppToolset.CaptureViewport with a
captureTransform is the virtual camera — no viewport piloting needed.Save the level + dirty packages after every phase marked 💾. One tool call at a time throughout — no batching, ever.
Brief: "a sunny clearing with some rocks and a path"
Phase 1 — environment shell
SkyAtmosphere, SkyLight (real-time capture),
DirectionalLight at rotation (0, −55, 40) [roll, pitch, yaw],
intensity 90,000 lux, temperature 5,800 K, "atmosphere sun light" on;
ExponentialHeightFog density 0.008.
VERIFY actor list shows all four; screenshot reads as daytime sky, not
black (if black: exposure — see Phase 3).Phase 2 — ground & blocking
/Engine/BasicShapes/Plane.Plane at (0,0,0), scale (100,100,1)
→ 100×100 m ground. Label Ground./Engine/BasicShapes/Cube.Cube at scattered locations within
±2,000 cm of origin, non-uniform scales between (1.5,1.5,1) and (4,3,2),
yaws randomized 0–360°, sunk 10–30 cm into the ground so nothing floats.
A path: 6–10 flattened cubes scale ≈(1.2,0.8,0.05) snaking through.
VERIFY screenshot at eye height (camera z≈165) along the path axis: rocks
read as varied, nothing floats, scale sane against the 180 cm yardstick
(place one 180 cm-tall cylinder temporarily as a human stand-in, delete
after checking). 💾Phase 3 — exposure & mood
Phase 4 — deliver
HighResShot 3840x2160 from a framed viewpoint (see Recipe C
Phase 2 for framing rules).
VERIFY file exists in Saved/Screenshots; vision_analyze against brief;
iterate lighting yaw/fog once if flat. 💾 Report actor labels + paths.Brief: "a dim cozy room at night, warm lamp, blue moonlight through window"
Phase 1 — room shell from primitives
Phase 2 — lighting (the point of this recipe)
Phase 3 — dress & deliver
/Game/StarterContent/ Props/SM_TableRound, SM_Chair, SM_Lamp_Ceiling, materials
M_Wood_Pine on floor, M_Basic_Wall on walls. Otherwise assign
MaterialInstances with warm-neutral base colors to primitives.
VERIFY final HighResShot 3840x2160, vision-check, 💾, report.Brief: "make it golden hour and give me a cinematic shot of <subject>"
Phase 1 — relight for golden hour
Phase 2 — the camera
EditorAppToolset.CaptureViewport with captureTransform — a
virtual camera; no CineCamera or viewport piloting needed for stills.
VALUES position: subject-distance by lens-equivalent framing — for a
prop/monument subject ~500–800 cm back, height 120–160 cm; rotation
aimed so the subject sits on a thirds intersection, horizon in upper or
lower third. Slight upward pitch (+2° to +5°) from below eye height
reads heroic and guarantees sky/horizon in frame.
For an actual CineCameraActor (user wants a camera in the level, DoF,
or a Sequencer shot): spawn /Script/CinematicCamera.CineCameraActor,
set focal/aperture/focus via ObjectTools on its CineCameraComponent,
then capture with captureTransform matching its transform.
VERIFY capture at viewport res first; iterate framing cheaply, then take
the final.Phase 3 — deliver
HighResShot 3840x2160 (or user's target res) through the
piloted camera. For a sequence/turntable instead of a still: this needs a
Level Sequence with a Camera Cut track + Movie Render Queue — treat as
its own task; warn about first-render shader-compile stall.
VERIFY read file, vision_analyze: rim light present? focus falloff on
the right plane? horizon off-center? Iterate at most twice, then deliver
MEDIA: path + what was changed. 💾Brief: "here's model.fbx / a Fab asset — put a ring of them around the fountain"
Phase 1 — import
/Game/Imported with no dialog stall.
DISCOVER import capability (if none advertised: custom toolset wrapping
unreal.AssetImportTask with automated=True — see tool-surface.md;
the automated flag is what prevents a modal import dialog from
freezing the whole MCP loop).
VALUES destination /Game/Imported, save=true.
VERIFY asset-exists query on the resulting long package name; spawn one
instance at origin, screenshot, check scale against 180 cm yardstick —
DCC exports are routinely 100× off (meters vs centimeters). Fix by
actor scale or reimport with unit conversion.Phase 2 — populate
Phase 3 — deliver
If discovery shows no shipped tool for a step (no import tool, no console-exec for HighResShot, etc.):
RefreshTools + session
restart to appear.Never claim a phase done without its VERIFY evidence. The user can't check the editor for you — the screenshots are the ground truth they see.