Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Programmatically author RoadRunner scenarios from MATLAB using roadrunnerAPI. Use when adding actors, creating routes, building scenario logic (phases, conditions, actions), placing vehicles/pedestrians, defining cut-in/crossing/ follow scenarios, or any programmatic scenario creation in RoadRunner. Triggers on: roadrunnerAPI, scenario authoring, add actor, create route, phase logic, cut-in scenario, pedestrian crossing, scenario from MATLAB.
.claude/skills/matlab-roadrunner-scenario-authoring/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 219% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 211% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 302% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 162% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 298% | 0% |
Programmatically create RoadRunner scenarios from MATLAB: actors, routes, phase logic, and validation — all via roadrunnerAPI.
roadrunner-corematlab-scenario-builderroadrunner-rrhd-authoringroadrunner-import-sceneroadrunner-scenario-simulatingVerify rrApp exists. If not, ensure RoadRunner is connected first (e.g., via roadrunner-core or manually).
matlabif ~exist('rrApp', 'var') || ~isvalid(rrApp) error("No active RoadRunner session. Use the roadrunner-core skill."); end
Path setup: Before calling helper functions, ensure the scripts directory is on the MATLAB path:
matlabaddpath('<path-to-skill>/scripts');
matlabopenScene(rrApp, sceneName); newScenario(rrApp); rrApi = roadrunnerAPI(rrApp); rrs = rrApi.Scenario; phaseLogic = rrs.PhaseLogic; rrprj = rrApi.Project;
Before placing actors, survey the scene to find valid lane positions. Use the helperSceneAwareness script for automated analysis, or query manually via HD Map export:
matlabsceneInfo = helperSceneAwareness(rrApp, NumActors=2, ScenarioType="cut-in");
See references/scene-awareness.md for manual HD Map query patterns when the helper is unavailable.
Option A — Batch placement (recommended for 2+ actors):
matlabactorSpecs(1) = struct(Name="Ego", AssetPath="Vehicles/Sedan.fbx", ... AssetType="VehicleAsset", LaneIndex=1, Fraction=0.1, Speed=15); [actors, report] = helperPlaceActors(rrs, rrprj, phaseLogic, sceneInfo.HDMap, actorSpecs); ego = actors{1}; % cell array — use curly braces
Option B — Manual placement:
matlabvehicleAsset = getAsset(rrprj, "Vehicles/Sedan.fbx", "VehicleAsset"); actor = addActor(rrs, vehicleAsset, position); actor.Name = "Ego"; autoAnchor(actor.InitialPoint); % Snaps to nearest road
Post-placement check: Verify actor.InitialPoint.WorldPosition is NOT [0 0 0].
See references/asset-catalog.md for available vehicle/character paths.
Option A — Scene anchors available:
matlabanchors = getAnchors(rrApp); % Use remapAnchor for cross-scene portability (not findSceneAnchor) anchorPt = findSceneAnchor(rrs, anchors(1).Name); anchorToPoint(actor.InitialPoint, anchorPt); actor.InitialPoint.ForwardOffset = 20; actor.InitialPoint.LaneOffset = 1;
Option B — No scene anchors (use autoAnchor):
matlabactor = addActor(rrs, asset, approximatePosition); autoAnchor(actor.InitialPoint); % Must be within 5m of road
Option C — Relative to another actor:
matlabanchorToPoint(target.InitialPoint, ego.InitialPoint); target.InitialPoint.ForwardOffset = 30; target.InitialPoint.LaneOffset = 1;
Routes put actors in path-following mode. Actors without routes drive in lane-following mode along their anchored lane.
matlabroute = actor.InitialPoint.Route; fwdPt = addPoint(route, actor.InitialPoint.WorldPosition + [20 0 0]); autoAnchor(fwdPt); % For vehicles: disable freeform so route follows road surface % (Do NOT do this for pedestrians — they need freeform to cross roads) for i = 1:numel(route.Segments) route.Segments(i).Freeform = false; end
When to add routes:
ChangeLaneActionWhen NOT to add routes:
ChangeLaneAction — they MUST be in lane-following mode (no routes)ChangeLateralOffsetAction — same requirementRoute point rules:
autoAnchor for route points — position must be within 5m of roadanchorToPoint + ForwardOffset on route points — causes validation failureseg.Freeform = false on each segment to follow road geometry (freeform routes ignore road surface and may float above/below the road)See references/actions-and-conditions.md for the complete catalog.
matlab% Get actor's initial phase (auto-created with addActor) initPhase = initialPhaseForActor(phaseLogic, actor); % Modify default speed (initial phase already has ChangeSpeedAction) initPhase.Actions(1).Speed = 20; % Add sequential phase nextPhase = addPhaseInSerial(phaseLogic, initPhase, "ActorActionPhase"); nextPhase.Actor = actor; % REQUIRED — never omit % Set trigger condition on initial phase cond = setEndCondition(initPhase, "LongitudinalDistanceToActorCondition"); cond.Actor = actor; % REQUIRED cond.ReferenceActor = otherActor; cond.Distance = 10; % Add action to next phase action = addAction(nextPhase, "ChangeLaneAction"); action.Direction = "left";
Multi-actor phase logic: Each actor's phase chain is independent. Any phase that has a subsequent phase MUST have an end condition — without one, the phase runs indefinitely and subsequent phases never execute. For multi-actor scenarios, ensure EVERY phase with a successor has an appropriate end condition set via setEndCondition.
matlabvalidate(rrs);
After validation passes, present a summary of what was created — never simulate unless explicitly asked.
MANDATORY: Before writing ANY code, complete Steps 0–1 below and present your plan to the user for confirmation. Do not skip this — scenarios built without pre-analysis frequently fail due to wrong timing, missed collisions, or impossible trigger conditions.
Step 0 — Clarify intent: If the user's prompt is ambiguous about ANY of the following, ASK before proceeding:
Step 1 — Physics-first design (REQUIRED for timed interactions): For collisions, near-misses, cut-ins, pedestrian crossings, and any scenario where actors must arrive at the same point at a specific time — you MUST derive kinematic parameters before writing code. Follow the full 5-step process in references/physics-first-design.md:
Present your decomposition to the user — show actors, placement, speeds, trigger timing, and expected outcome. Get confirmation before executing code.
helperSceneAwareness type to use:ScenarioType="following") — leader/follower, overtake start, emergency brakeScenarioType="cut-in") — lane changes, merges, parallel drivingLongitudinalDistanceToActorCondition) — requires speed differential between actorsDurationCondition) — works regardless of speeds, simplerSimulationTimeCondition) — absolute time, good for choreographed sequencesrequired_gap = lane_change_distance + closing_rate × (lane_change_distance / actor_speed) + 5mWhen newScenario() is called, RoadRunner automatically creates:
Do NOT duplicate these. To modify the default collision condition:
matlabrootPhase = phaseLogic.RootPhase; % The fail condition already exists — access it directly % To change the end time: rootEndCond = setEndCondition(rootPhase, "SimulationTimeCondition"); rootEndCond.Time = 30; % Override default 60s
.Actor on ActorActionPhase and condition objects — never omitphase.Actions(1) insteadautoAnchor requires proximity — point must be within 5m of road surface"le" and "ge" are valid (not "lt", "gt")"eq", "gt", "lt", "ge", "le", "ne"setEndCondition not addEndCondition — only one end condition per phaseChangeLaneAction requires lane-following mode — do NOT add routes to actors that need lane changesanchorToPoint + ForwardOffset on route points — causes validation failure; use autoAnchor onlyLaneOffset can land on junction connectors — for lane-change scenarios, place actors on verified parallel lanes using HD Map positions + autoAnchor instead of LaneOffsetLaneChangeReference="actor" + Direction="same-lane" when targeting another actor's lane, or compute direction via cross product (see references/scenario-templates.md).ParentPhase, not on child phases[0 0 0] means anchoring failed silentlyremoveActor does not exist; WorldPosition is read-only after anchoring. Placement mistakes require newScenario() and rebuilding. Plan placement carefully before executing.autoAnchor unreliable at lane boundaries — Use fraction ≥ 0.2 and ≤ 0.8 when querying HD Map positions. At lane start/end points, multiple lanes converge and autoAnchor may snap to the wrong lane.lane_change_distance + (closing_rate × maneuver_time) + vehicle_length. A 20m lane change at 5 m/s closing rate needs ≥ 30m initial gap.seg.Freeform = false on each segment so the route follows road geometry. Do NOT disable freeform on pedestrian routes — pedestrians cross roads and need freeform paths.bumper_gap = center_distance - (vehicle1_length/2 + vehicle2_length/2). Timing: t_collision = bumper_gap / closing_rate. Account for ~1s acceleration ramp from rest (vehicles don't reach target speed instantly).LaneOffset must be positive; you cannot place two vehicles facing each other on the same road segment via the programmatic API. Use rear-end or crossing-path collision designs instead.setEndCondition — setEndCondition(phase,"Type").Property = N fails on ActorActionPhase (works only on InitialPhase). Always store the result first: c = setEndCondition(phase, "Type"); c.Property = N;. This two-line pattern works on ALL phase types.ActorActionPhase — call addAction only once per phase. The auto-created initial phase (from initialPhaseForActor) is the only exception. For concurrent actions, use a ParallelPhase with one ActorActionPhase child per action.egoPos + [X, Y, 0] only works on world-axis-aligned roads. For pedestrians and crossing actors, always use helperGetPositionFromHDMap to get position and heading, then compute the perpendicular crossing direction: hdg2D = hdg(1:2)/norm(hdg(1:2)); perpDir = [-hdg2D(2), hdg2D(1), 0];FourWaySignal, FourWayStop, and T_Intersection, approach lanes do not connect to opposing exit lanes via the routing API. Use single-arm routes (approach → connected exit lane in the same corridor) or lane-following mode only. Cross-arm routes fail validate.helperSceneAwareness the parameter is MinLaneLength (default 30); for helperSurveyLanes/helperGetPositionFromHDMap use MinLength. On intersection scenes use 30 since approach lanes are short. Compute needed length: max_speed × scenario_duration + 20m. Using 80+ on small scenes leaves fewer lanes than expected.| Wrong (hallucinated) | Correct | |---------------------|---------| | RelativeLaneOffset | NumLanesOffset | | SimulationTime | SimulationTimeCondition | | addEndCondition | setEndCondition | | listAssets / getAssets | getAsset(proj, path, type) | | getActors / listActors | rrs.Actors | | actor.Speed | initPhase.Actions(1).Speed | | route.addWaypoint | addPoint(route, position) | | removeActor / deleteActor | Does not exist — use newScenario() | | actor.WorldPosition = ... | Read-only — reposition via newScenario() + re-place | | cond.Comparison | Does not exist on SimulationTimeCondition (just set .Time) | | rrApp.ProjectFolder | Not a public property — use status(rrApp) | | DistanceType = "gap" | Use "space" (spatial) or "time" (time-gap) | | ConstraintType = "acceleration" | Use "asset", "custom", or "none" | | PhaseState = "completed" | Use "end" (valid: "idle", "start", "run", "end") | | MeasureDistance = "euclidean" | Use "lane" or "actor" | | "MovableObjects/..." | Use "Props/TrafficControl/..." with "MovableObjectAsset" type | | syncAction.TargetPoint = actor.InitialPoint | Shared reference trap — use route waypoints as independent Points | | LateralOffsetAction | ChangeLateralOffsetAction (full name required) | | .Offset (on ChangeLateralOffsetAction) | .LateralOffset | | laneTable.LaneIndex | laneTable.Index (column name from helperSurveyLanes) | | action.Rate | Use .DynamicsDimension = "rate"; .DynamicsValue = N; | | setEndCondition(...).Property = N | c = setEndCondition(...); c.Property = N; (two-line pattern) | | MinLength (on helperSceneAwareness) | MinLaneLength — only lower-level helpers use MinLength | | "text" + status(rrApp) | status(rrApp) returns a struct — use s = status(rrApp); s.Scene.Filename | | actors(i) from helperPlaceActors | actors{i} — returns a cell array, use curly-brace indexing |
| Function | Purpose | Since | |----------|---------|-------| | roadrunnerAPI(rrApp) | Create authoring API handle | R2025a | | addActor(rrs, asset, pos) | Add actor to scenario | R2025a | | getAsset(proj, path, type) | Load asset by path | R2025a | | autoAnchor(point) | Snap point to nearest road | R2025a | | anchorToPoint(pt, anchor) | Anchor point to reference | R2025a | | addPoint(route, pos) | Add waypoint to route | R2025a | | initialPhaseForActor(logic, actor) | Get actor's init phase | R2025a | | addPhaseInSerial(logic, phase, type) | Add sequential phase | R2025a | | addPhaseInParallel(logic, phase, type) | Add concurrent phase | R2025a | | setEndCondition(phase, type) | Set phase trigger | R2025a | | addAction(phase, type) | Add behavior action | R2025a | | validate(rrs) | Check scenario validity | R2025a | | validate(rrs, ObjectRoot=obj) | Validate specific object (phase, actor, route) | R2025a | | findActions(phase, type) | Find actions of a type in a phase | R2025a | | createAsset(proj, path, type) | Create new asset (vehicle, character, behavior) | R2025a | | getAnchors(rrApp) | List scene anchors | R2024a | | getAsset with "CharacterAsset" | Load pedestrian asset | R2025a |
| Mode | Trigger | Behavior | Compatible Actions | |------|---------|----------|-------------------| | Lane-following | No route waypoints | Follows anchored lane at set speed | ChangeLaneAction, ChangeLateralOffsetAction | | Path-following | Has route waypoints | Follows waypoint path | ChangeSpeedAction, ChangeLongitudinalDistanceAction |
ChangeLaneAction ONLY works in lane-following mode (no routes)[X Y Z]"Vehicles/Sedan.fbx").fbx_rrx, API uses .fbx; disk shows .rrchar_rrx, API uses .rrchar"Ego", "TargetVehicle", "Pedestrian1")ScenarioBasic.rrscene (310 forward lanes, ScenarioStart anchor)FourWaySignal, FourWayStop, T_IntersectionDeploy these helpers into the user's MATLAB path for automated scene analysis and batch placement. They depend on each other: helperSceneAwareness calls helperSurveyLanes and helperGetPositionFromHDMap.
| Script | Purpose | When to use | |--------|---------|-------------| | scripts/helperSceneAwareness.m | Export HD Map, survey lanes, classify road features, recommend placements | First step before placing actors — provides positions, lane context, and feature classification | | scripts/helperSurveyLanes.m | Filter/sort lanes by type, direction, length | When you need lane geometry data without full scene analysis | | scripts/helperGetPositionFromHDMap.m | Arc-length interpolation along lanes, nearest-point queries | When you need precise positions at specific fractions along a lane | | scripts/helperPlaceActors.m | Batch place, anchor, set speed, verify multiple actors | When placing 2+ actors — automates the manual add/anchor/verify loop | | scripts/helperClassifyRoadFeatures.m | Elevation-based road feature classification (bridge, ground, ramp) | Used internally by helperSceneAwareness; call directly for custom feature queries |
Usage pattern:
matlab% 1. Run scene awareness to get lane data and recommended positions sceneInfo = helperSceneAwareness(rrApp, NumActors=2, ScenarioType="cut-in"); % 2. Define actor specs (do NOT pre-initialize with actorSpecs=[]) actorSpecs(1) = struct(Name="Ego", AssetPath="Vehicles/Sedan.fbx", ... AssetType="VehicleAsset", LaneIndex=1, Fraction=0.1, Speed=15); actorSpecs(2) = struct(Name="Target", AssetPath="Vehicles/Sedan.fbx", ... AssetType="VehicleAsset", LaneIndex=2, Fraction=0.2, Speed=20); % 3. Batch place and verify (actors is a cell array) [actors, report] = helperPlaceActors(rrs, rrprj, phaseLogic, sceneInfo.HDMap, actorSpecs); assert(report.AllValid, "Placement failed: " + report.Summary); ego = actors{1}; target = actors{2}; % curly braces required
For scenes with multiple elevation levels (bridges, overpasses, underpasses), use the RoadFeature parameter to target a specific road structure:
matlab% Place actors specifically on the bridge deck sceneInfo = helperSceneAwareness(rrApp, NumActors=2, ScenarioType="following", ... RoadFeature="bridge"); % LaneIndex=1 now refers to the longest BRIDGE lane, not the longest overall lane actorSpecs(1) = struct(Name="Leader", AssetPath="Vehicles/Sedan.fbx", ... AssetType="VehicleAsset", LaneIndex=1, Fraction=0.3, Speed=15, ... FilterLaneIDs=sceneInfo.FilteredLaneIDs);
Available feature labels: "bridge", "ground", "ramp", "overpass"
When to use RoadFeature:
When RoadFeature="" (default): The summary shows all detected features so you can ask the user which one they mean:
Road features detected:
bridge: 10 lanes, total 700m, connected path 192m, elevation 7.9-8.6m
ground: 3 lanes, total 490m, connected path 165m, elevation 2.4-2.8mOutput fields for feature-aware placement:
sceneInfo.RoadFeatures — full feature classification structsceneInfo.FilteredLaneIDs — lane IDs matching the requested feature (pass to actorSpecs.FilterLaneIDs)sceneInfo.LaneNetwork — full lane connectivity from helperAnalyzeHDMapLanesRoadRunner ships example helpers at <RoadRunner-Install>/Tools/MATLAB/api/scenario/common (e.g., helperAddCutInAndSlowCar, helperAddPedestrian). These use anchorToPoint + LaneOffset for actor placement.
When built-in helpers are suitable: Simple scenes with clearly separated lanes (straight roads, known layouts).
When to prefer this skill's approach instead: Scenes with junctions, complex layouts, or unknown geometry — LaneOffset can land actors on junction connectors that don't support lane changes. HD Map positions + autoAnchor works reliably on any scene.
Key pattern from built-in helpers: ChangeLaneAction supports LaneChangeReference="actor" with Direction="same-lane" — the actor moves to the reference actor's lane automatically, eliminating cross-product direction computation. See references/scenario-templates.md Cut-In section for usage.
references/actions-and-conditions.md — Complete catalog of all action types, condition types, their properties and valid values. Consult when building phase logic.references/routes-and-points.md — Full Point properties, RouteSegment configuration, time-based trajectories, and route read-only properties. Consult for precise positioning, trajectory timing, or curve configuration.references/collision-utility.md — CollisionUtility configuration for collision analysis between specific actor pairs. Consult when setting up collision monitoring.references/asset-catalog.md — Available vehicle and character asset paths with naming conventions. Consult when adding actors.references/scene-awareness.md — HD Map export pattern for querying lane geometry when helperSceneAwareness is unavailable. Consult when placing actors on unknown scenes.references/lane-connectivity.md — Lane network topology, road feature classification, and connected path queries. Consult when placing actors on specific road features (bridge, ramp) or when you need lane connectivity information.references/scenario-templates.md — Tested code patterns for cut-in, pedestrian crossing, lead-follow, emergency brake. Consult when building specific scenario types.references/physics-first-design.md — Pre-authoring kinematic analysis: derive speeds, gaps, and timing before writing code. Consult for collision/near-miss/timed-interaction scenarios.Copyright 2026 The MathWorks, Inc.
Other measured skills in the registry, with their headline benchmark lift.