matlab/roadrunner-build-scenario-from-osc
> Build a RoadRunner Scenario programmatically from an OpenSCENARIO 1.x (.xosc) file using the `roadrunner-scenario-authoring` skill. Use when the user wants to recreate a scenario from a .xosc file, interpret an OpenSCENARIO file and build it programmatically, reconstruct a .xosc as a RoadRunner scenario, generate a MATLAB script from a .xosc file, or convert an OpenSCENARIO file to MATLAB code. Do NOT use when the user says "import" a .xosc file — that means they want RoadRunner's built-in importScenario API, not programmatic reconstruction. Handles position translation (LanePosition and RoadPosition to world coordinates), construct mapping, relative references, trajectory/route handling, parameter expressions, catalog references, and phase logic topology.
npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill roadrunner-build-scenario-from-osc
Interpret an OpenSCENARIO 1.x (.xosc) file and recreate the scenario in
RoadRunner using the roadrunner-scenario-authoring skill. Translates positions,
maps constructs, preserves relative references, and builds correct phase logic.
importScenario(rrApp, xoscPath), not this skill. Simply call the API directly.importScenario (let them — it works for simple cases)roadrunner-scenario-authoring)roadrunner-export-scenario)If a construct cannot be mapped, skip it and warn the user.
DurationCondition, do not substitute SimulationTimeCondition for unsupported
triggers, do not add any construct not in the source.
polyline vertices present in the source XOSC — no fewer, no more. Do not
reduce 90 vertices to 5. Do not duplicate start/end points during extraction.
<LogicFile>.Import it — do not search for a scene with a similar name.
RelativeTargetSpeed delta=-8, preserve it as SpeedReference="actor" with
Direction="slower", Speed=8. Do not compute and hardcode 7 m/s.
the Scenario Description under "Unsupported Constructs."
(MW_WaitAction) into end conditions. Do not create phases for scaffolding
elements that have no meaningful actor actions.
This skill operates in two steps. Complete Step 1 first, present the description
to the user for review, then proceed to Step 2 only after approval.
Parse the .xosc and its referenced .xodr following this strict logical order.
Read the .xosc XML. If the file is invalid XML, missing required elements, or
fails basic structural checks, stop and report the error. Do not guess or
assume missing data. If data is ambiguous, state the assumption explicitly.
Before interpreting any values, resolve all references:
${...} expressionsto concrete numeric values. Process in declaration order (later params may
reference earlier ones).
<CatalogLocations>), find the entry by catalogName + entryName, extract
the vehicle/pedestrian definition (model3d path, category, bounding box).
% Parameter expression resolution example
params.HostSpeed_kph = 80;
params.LeadTime_s = 6;
params.hostSpeed_ms = params.HostSpeed_kph / 3.6; % 22.2222
params.leadSpeed_ms = params.hostSpeed_ms * 0.5; % 11.1111
params.initSeparation = (params.hostSpeed_ms + params.leadSpeed_ms) * params.LeadTime_s; % 200
For each actor's Private actions in <Init>:
scripts/xoscPositionToWorld.p)scripts/xoscPositionToWorld.p)xoscPositionToWorld MUST be numeric.XML attributes are always strings — convert with str2double() before calling:
pos = xoscPositionToWorld(xodrPath, 'LanePosition', ...
'roadId', str2double(roadId), 'laneId', str2double(laneId), ...
's', str2double(s), 'offset', str2double(offset));
Passing strings silently produces wrong coordinates (up to 12m error).
(skip center lane when dLane crosses from negative to positive IDs)
Actors always align with road direction at their anchor point. Do NOT include
heading in the scenario description — it cannot be applied.
Note: The h attribute from XOSC is still needed for RelativeObjectPosition
translation (to rotate dx/dy in the entity's local frame), but it is not set
on the placed actor.
For relative: describe as <abs(delta)> m/s <direction> relative to <ref actor>
where direction is "slower" (delta < 0), "faster" (delta > 0), or "same" (0).
This means either: (a) in Init, or (b) in Story where the trigger chain
resolves to t=0. Resolve by tracing: if Event StartTrigger is
StoryboardElementStateCondition(Act, runningState) → check Act's
StartTrigger; if that references Story's runningState → check Story's
StartTrigger. If the chain terminates at SimulationTimeCondition >= 0,
treat as t=0. If any link in the chain uses a non-zero time, duration,
distance, or other condition → not supported. Skip and warn.
When supported, extract exactly the polyline vertices as route waypoints
(never reduce, never duplicate start/end points). Determine speed reference:
<Timing> in TimeReference → Speed Reference: "route-time-data".Include the time attribute from each vertex in the description.
Ignore SpeedAction — timing overrides speed.
<None/> in TimeReference → Speed Reference: absolute (use SpeedAction value)Translate any non-WorldPosition vertices using scripts/xoscPositionToWorld.p.
trigger chain). When supported, extract all waypoints (LanePosition or
WorldPosition). Always use absolute speed from SpeedAction. If trigger
chain does not resolve to t=0 → not supported. Skip and warn.
initial speed, same as TeleportAction + SpeedAction). May also combine
with FollowTrajectoryAction or AssignRouteAction — in those cases the
existing rules (items 4 and 5) apply. Extract position from the nested
<Position> element and convert to world [x, y, z]. Describe the actor
in the Actors section so the authoring skill places it via addActor.
Do not include Initial Speed in the Actors section — the actor has no
initialization. Speed is defined in the Phase Logic after the WaitAction.
Since addActor places all actors at scenario start (no mid-scenario
spawn), replicate the delayed appearance using phase logic:
FIRST phase — inserted before the actor's auto-created init phase
is where speed/behavior is configured (e.g., ChangeSpeedAction)
IS the first phase. Only two phases per actor: WaitAction → behavior
NO speed — it only waits for the spawn condition. Speed (e.g.,
ChangeSpeedAction at 17.88 m/s) must be placed on the auto-created init
phase that comes AFTER the WaitAction. Never assign speed on or before
the WaitAction.
ChangeLaneAction orChangeLateralOffsetAction in Story, it must be in lane-following mode
(no route). Do NOT include route waypoints for such actors.
Ignore global init actions (e.g., EnvironmentAction) that do not affect actors.
The goal is to describe intent — what each actor does, what triggers it,
and what ends it. Do NOT preserve the XOSC structural hierarchy (Acts, Events,
ManeuverGroups). Collapse scaffolding into simple action descriptions.
Handling MW_WaitAction (placeholder Acts):
the Act's StopTrigger as its end condition. Ignore the MW_WaitAction.
the end condition for whatever phase PRECEDES it in the serial chain. Set the
condition directly on that preceding phase — do NOT create a separate
WaitAction phase. Exception: If there is no preceding phase, or the
preceding phase already has an end condition, create a WaitAction phase with
the Act's StopTrigger as the end condition.
Determining execution order:
Look at StartTriggers to determine serial/parallel relationships:
StoryboardElementStateCondition(X, completeState) → runs after X endsStoryboardElementStateCondition(X, runningState) → runs parallel with XSimulationTimeCondition >= 0 → starts immediatelyParallel groups and serial successors:
When an Act contains multiple Events that run in parallel, they form a
ParallelPhase. If a subsequent action triggers on that Act's completeState,
it is serial after the ParallelPhase (the container), not after any
individual child phase. An Act completes when ALL its events finish — so the
successor must wait for the entire parallel group.
What to capture for each action:
name attribute from the XOSC <Action> tagWrite a structured description using roadrunner-scenario-authoring terminology
so the authoring skill can execute it directly:
## Scene
- OpenDRIVE file: <filename from LogicFile>
- Import required: yes (use `roadrunner-import-scene` with format "OpenDRIVE")
## Parameters (if any)
- <name> = <resolved value> (original expression: <expr>)
## Actors
For each actor:
- Name: <XOSC entity name>
- Type: Vehicle / Pedestrian
- Asset: <model3d path> (AssetType: "VehicleAsset" or "CharacterAsset")
- Initial Position: [x, y, z] (translated from <original position type>)
- Anchoring:
- Lane-following (no route): autoAnchor (actor must be anchored to road for lane following)
- **Exception:** If the actor's translated position is on a junction connector road,
do NOT autoAnchor — anchoring on junctions shifts the position to an
unpredictable anchor point. Place the actor at the exact world coordinates instead.
- Path-following (has route): do NOT autoAnchor (positions are precise world coordinates)
- Movement Mode: path-following (has route) or lane-following (no route)
- **Anchoring and Movement Mode are REQUIRED fields.** Every actor description
must explicitly state the anchoring decision (autoAnchor or NOT autoAnchor)
and movement mode. Do not omit these even when the choice seems obvious from
context — the downstream authoring skill needs them stated explicitly.
- Initial Speed: <value> m/s (absolute)
OR: <delta> m/s <direction> relative to <reference actor>
- Route (if path-following):
- Waypoints: [x, y, z] per row (ALL vertices — never simplify)
- Timestamps: [t0, t1, t2, ...] (if timed trajectory — sets Point.Time)
- Speed Reference: "route-time-data" (timed) or absolute value (untimed)
- Freeform: true (route follows exact waypoint positions, not road geometry)
- Do NOT autoAnchor route waypoints
## Phase Logic
Use RoadRunner action/condition type names (see references/openscenario-mapping.md):
For each meaningful action (skip MW_WaitAction placeholders):
- Actor: <who>
- Phase Name: <from XOSC Action name attribute>
- Action: <RoadRunner action type> (e.g., ChangeSpeedAction, ChangeLaneAction)
- Properties: Speed=X, DynamicsShape="step", Direction="left", etc.
- Trigger: <RoadRunner condition type> (e.g., SimulationTimeCondition, DurationCondition)
- Properties: Time=X, Duration=X, Distance=X, Rule="ge", etc.
- End Condition: <RoadRunner condition type> with properties
- Topology: serial after <previous> / parallel with <sibling>
## Scenario End Conditions
- End: <condition type> on RootPhase (e.g., SimulationTimeCondition, Time=60)
- Fail: <condition type> on RootPhase (e.g., CollisionCondition)
## Unsupported Constructs
- <construct>: <why it cannot be mapped>
Show the Scenario Description to the user. Ask:
*"Here is the scenario description I extracted. Review the actors, positions,
phase logic, and relative references. Should I adjust anything before generating
the MATLAB script?"*
Wait for user approval before proceeding to Step 2.
After the user approves the scenario description, delegate execution to the
dependent skills. This skill does NOT generate MATLAB code. It only
interprets the .xosc and produces the description.
Import into a new scene and create a new scenario:
newScene(rrApp) to get a clean scene (no leftover roads)ProjectionMode = "noprojection" to preserve the .xodr's nativecoordinate system:
importOpts = openDriveImportOptions;
importOpts.ProjectionMode = "noprojection";
importScene(rrApp, xodrPath, "OpenDRIVE", importOpts);
newScenario(rrApp) to create a fresh scenario on the imported scene**CRITICAL: You MUST invoke /roadrunner-scenario-authoring to build the
scenario. Do NOT write MATLAB code directly. Do NOT call MCP MATLAB tools
(mcp__matlab__evaluate_matlab_code, mcp__matlab__run_matlab_file) yourself.
The authoring skill handles all code generation and execution.**
Invoke /roadrunner-scenario-authoring with the full approved scenario
description as the argument. Prefix it with:
> Build the following scenario in RoadRunner. The scene is already
> imported and a new scenario has been created.
Then paste the complete scenario description (Actors, Phase Logic, End
Conditions, etc.) so the authoring skill can execute it directly.
Include the following mapping details in the instruction so the authoring
skill applies them correctly:
Anchoring rules:
needs to be anchored to the road to follow lanes correctly.
waypoints — positions are precise world coordinates and autoAnchor would shift
them from their intended positions, misaligning trajectories.
CollisionCondition patterns (include in end conditions):
| XOSC Pattern | What to Specify |
|---|---|
| <EntityRef entityRef="ActorB"/> (specific pair) | "Collision between [Actor] and [ActorB]" |
| <ByType type="vehicle"/> (any vehicle) | "Collision between [Actor] and any vehicle" |
Multiple <ConditionGroup> elements (OR logic in StopTrigger): describe
each as a separate end/fail condition on RootPhase.
Consult these during Step 1 to map XOSC constructs to RoadRunner terminology:
references/openscenario-mapping.md — XOSC action/condition types → RoadRunner API type names, state mapping, rule mapping, property mappingscripts/xoscPositionToWorld.p — MATLAB function: call to translate any XOSC position type to world [x, y, z] using the .xodr file| Mistake | Why It's Wrong | Correct Approach |
|---------|---------------|-----------------|
| Skipping autoAnchor on lane-following actors without routes | Actor won't follow lane properly without being anchored to road | Lane-following actors (no route/trajectory) MUST be autoAnchored — EXCEPT on junction connector roads where anchoring shifts position |
| Using autoAnchor on junction connector roads | Anchoring on junctions shifts the actor to an unpredictable anchor point, misaligning the position | If the translated position is on a junction, place at exact world coordinates without autoAnchor |
| Using autoAnchor on path-following actors with routes | Shifts positions, misaligns trajectories | Path-following actors and their route waypoints should NOT be autoAnchored — positions are already precise world coordinates |
| Passing string parameters to xoscPositionToWorld | Function silently gives wrong coordinates (up to 12m error) | Always use str2double() on XML attribute values before calling: 'roadId', str2double(id), 'laneId', str2double(lane), 's', str2double(s), 'offset', str2double(off) |
| Adding a pass-through init phase before WaitAction for AddEntityAction actors | Adds an unnecessary phase; actor should do nothing until spawn time | WaitAction IS the first phase — only two phases: WaitAction → behavior |
| Including Initial Speed in Actors section for AddEntityAction actors | Actor has no initialization before the wait | Speed is set in Phase Logic after WaitAction, not in Actors section |
| Using ActorActionPhase for WaitAction | WaitAction is not an actor action | WaitAction must be in a SystemActionPhase |
roadrunner-import-scene for scene import, roadrunner-scenario-authoring for building.fbx for vehicles, .rrchar for characters----
Copyright 2026 The MathWorks, Inc.
----
Take matlab/roadrunner-build-scenario-from-osc from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.