Annotate Modelica 3D Animation
Adds __Wolfram(Animation(...)) annotations to a MultiBody model so Simulation
Center opens a configured 3D animation: named cameras, follow cameras, trace
paths, playback behavior and vector scaling — all stored in the model file.
Only models using Modelica.Mechanics.MultiBody components with a visual
representation get an Animation view. Simulate first (simulate-modelica):
you need the trajectory extents to place cameras and size the scene, and a
model that fails to simulate has no animation to configure.
Unlike the control-panel, graphics and plots annotators, this skill has no
generator engine — you author the annotation text and splice it in by hand,
then validate. That puts the merge-into-annotation(...) step (below) on you;
get it right and confirm with validate-modelica.
This is a vendor-specific annotation (Modelica spec §18.1): other tools
ignore it and preserve it on save, and it does not affect flattening — it only
tells System Modeler how to build the 3D animation. It sits directly inside the
class annotation(...), as a sibling of experiment and Documentation
(never nested inside Documentation).
The annotation
annotation(__Wolfram(Animation(
cameras = {
Camera(name = "Follow", distance = 8, rotation = {0.5, 0.5, 0.5, 0.5},
follow = bodyShape.shape1, followMode = "NODE_CENTER_AND_AZIM"),
Camera(name = "Top", center = {32, -19, 0}, distance = 90, rotation = {0, 0, 0, 1})},
windows = {
Window(name = "Default", camera = "Follow", preferred = true,
autoPlay = true, repeat = true, timeScale = 0.5,
trace = {bodyShape.shape1},
vectorSettings = {VectorSettings(quantity = "Force", scale = 0.1)})})));
Splicing it into the model
The Animation(...) goes inside the single class-level annotation(...), as
a sibling of experiment/Documentation — not in its own second annotation.
No class annotation yet — add one before the terminating end <Class>;:
annotation(__Wolfram(Animation(...)));
end MyModel;
An annotation(...) already exists (e.g. experiment) — add __Wolfram
as another argument inside it, don't create a second block:
annotation(
experiment(StopTime = 10),
__Wolfram(Animation(...)));
A __Wolfram(...) already exists (e.g. from FMI or a control panel) — add
Animation(...) as another argument inside that same __Wolfram(...), rather
than a second __Wolfram:
annotation(__Wolfram(
FMI(version = "2.0", kind = "ME"),
Animation(...)));
Two annotation(...) blocks on one class, or two __Wolfram(...) inside one
annotation, is invalid — merge instead. If the class already carries an
Animation(...), edit that one rather than adding a second.
Camera fields
name, center = {x,y,z}, distance, rotation = {q1,q2,q3,q4} (quaternion).
center is ignored when follow is set (a follow camera derives its center
from the tracked object), so omit it on follow cameras.
follow = <cref> attaches the camera to a shape. The cref must be the
low-level visualizer instance inside the component (its
Visualizers.Advanced.Shape/Arrow/Surface), not the component itself —
follow = bodyShape is ignored and the camera stays unattached. That leaf
name depends on the component: vis for Visualizers.FixedShape, shape for
FixedShape2/Parts.Fixed, shape1 (and shape2 for the CM sphere) for
Parts.BodyShape, cylinder/sphere for Parts.Body, sphere for
PointMass, arrow for WorldForce/SignalArrow, and a nested path like
frameTranslation.shape for BodyBox/BodyCylinder. The reliable way to get
the exact cref is to pick the shape in Simulation Center (right-click →
Camera Follow Mode, or Trace) and keep the cref it stores.
followMode: "NODE_CENTER" (Object Center), "NODE_CENTER_AND_AZIM"
(Object Center and Azimuth), "NODE_CENTER_ROTATION" (Object Center and
Rotation). For fast-spinning bodies avoid NODE_CENTER_ROTATION — the camera
spins with the body; NODE_CENTER_AND_AZIM gives a natural chase view.
Window fields
camera = "<name>", preferred = true (open automatically after the first
simulation), autoPlay = true, repeat = true, timeScale = <r>.
trace = {<cref>, ...} draws trace paths, using the same low-level visualizer
crefs as follow above (e.g. bodyShape.shape1, not bodyShape).
groundGrid = false hides the ground grid. Omit the field to keep the grid:
a stored false re-applies every time the window opens, so remove it from
the annotation rather than toggling in the viewer.
vectorSettings = {VectorSettings(quantity = "Force", scale = <m/N>, diameter = <r>)} and defaultVectorDiameter = <r> scale MSL 4.x vector
visualizers (e.g. WorldForce arrows).
Quaternion starting points (z-up world)
| View |
rotation |
| Top (looking down −z) |
{0, 0, 0, 1} |
| Horizontal, looking along −x |
{0.5, 0.5, 0.5, 0.5} |
| Horizontal, looking along +y |
{0.7071, 0, 0, 0.7071} |
If the ground renders vertical, the camera's up-axis is wrong — start from one
of these and adjust, or set the camera in Simulation Center once ("Add Camera
to Model") and keep the numbers it writes.
Workflow
Simulate; read the motion extents from the results.
Add a ground plane so motion reads against a fixed reference — size it from
the simulated extents plus margin, top surface just below the motion floor:
Modelica.Mechanics.MultiBody.Visualizers.FixedShape ground(
shapeType = "box", lengthDirection = {1, 0, 0}, widthDirection = {0, 1, 0},
length = 90, width = 60, height = 0.02, r_shape = {-10, -19, -0.03},
color = {60, 150, 60});
connect(world.frame_b, ground.frame_a);
Add cameras (a follow camera for playback plus fixed top/side views for
shareable stills — the window's trace applies to every camera).
Add one Window with playback flags and traces; validate the model
(validate-modelica) and let the user confirm the view in Simulation Center.
After a user stores anything from Simulation Center's animation dialogs, diff
the annotation: a GUI store rewrites the whole Window(...) from the current
viewer state, overwriting autoPlay, repeat, timeScale, groundGrid and
trace with whatever the viewer happens to show at that moment (e.g. autoPlay
becomes whether playback is running, trace becomes the currently traced
shapes). So re-apply hand-authored values after a store — do GUI stores first,
hand-edits last.
CAD shapes
Attach CAD geometry to FixedShape / BodyShape with
shapeType = "modelica://<Library>/Resources/<file>.stl" (ship the file in the
library's Resources/ folder). For file shapes, length/width/height act
as scale factors (set all three to one scale value), and lengthDirection /
widthDirection remap the CAD file's axes into the MultiBody frame.
In Wolfram Language, CreateSystemModel[Import["part.stl"]] (pass the imported
mesh, not the path) generates a ready part: a Body with the full inertia
tensor computed from the geometry plus a matching FixedShape, with consistent
axes and the frame at the center of mass.
1---2name: annotate-modelica-animation3description: Add Wolfram System Modeler 3D-animation annotations (__Wolfram(Animation(cameras, windows))) to a MultiBody .mo model — stored cameras (fixed or following an object), trace paths, auto-play/repeat, time scale, ground grid and force-vector scaling — so the model opens with a ready-made animation in Simulation Center. Use this skill whenever the user wants to add or store an animation, camera, camera follow mode, trace path, or animation window settings in a model, attach a CAD shape, or make a MultiBody animation presentation-ready. Triggers on phrases like 'add a camera to the model', 'store the animation', 'follow the body with the camera', 'add a trace path', 'top/side/front view', 'animate this multibody model', 'attach a CAD file', 'the animation opens empty'.4---56# Annotate Modelica 3D Animation78Adds `__Wolfram(Animation(...))` annotations to a MultiBody model so Simulation9Center opens a configured 3D animation: named cameras, follow cameras, trace10paths, playback behavior and vector scaling — all stored in the model file.1112Only models using `Modelica.Mechanics.MultiBody` components with a visual13representation get an Animation view. Simulate first (`simulate-modelica`):14you need the trajectory extents to place cameras and size the scene, and a15model that fails to simulate has no animation to configure.1617Unlike the control-panel, graphics and plots annotators, this skill has no18generator engine — you author the annotation text and splice it in by hand,19then validate. That puts the merge-into-`annotation(...)` step (below) on you;20get it right and confirm with `validate-modelica`.2122This is a **vendor-specific annotation** (Modelica spec §18.1): other tools23ignore it and preserve it on save, and it does not affect flattening — it only24tells System Modeler how to build the 3D animation. It sits directly inside the25class `annotation(...)`, as a sibling of `experiment` and `Documentation`26(never nested inside `Documentation`).2728## The annotation2930```modelica31annotation(__Wolfram(Animation(32 cameras = {33 Camera(name = "Follow", distance = 8, rotation = {0.5, 0.5, 0.5, 0.5},34 follow = bodyShape.shape1, followMode = "NODE_CENTER_AND_AZIM"),35 Camera(name = "Top", center = {32, -19, 0}, distance = 90, rotation = {0, 0, 0, 1})},36 windows = {37 Window(name = "Default", camera = "Follow", preferred = true,38 autoPlay = true, repeat = true, timeScale = 0.5,39 trace = {bodyShape.shape1},40 vectorSettings = {VectorSettings(quantity = "Force", scale = 0.1)})})));41```4243### Splicing it into the model4445The `Animation(...)` goes inside the **single** class-level `annotation(...)`, as46a sibling of `experiment`/`Documentation` — not in its own second `annotation`.4748- **No class annotation yet** — add one before the terminating `end <Class>;`:4950 ```modelica51 annotation(__Wolfram(Animation(...)));52 end MyModel;53 ```5455- **An `annotation(...)` already exists** (e.g. `experiment`) — add `__Wolfram`56 as another argument inside it, don't create a second block:5758 ```modelica59 annotation(60 experiment(StopTime = 10),61 __Wolfram(Animation(...)));62 ```6364- **A `__Wolfram(...)` already exists** (e.g. from FMI or a control panel) — add65 `Animation(...)` as another argument inside that same `__Wolfram(...)`, rather66 than a second `__Wolfram`:6768 ```modelica69 annotation(__Wolfram(70 FMI(version = "2.0", kind = "ME"),71 Animation(...)));72 ```7374Two `annotation(...)` blocks on one class, or two `__Wolfram(...)` inside one75annotation, is invalid — merge instead. If the class already carries an76`Animation(...)`, edit that one rather than adding a second.7778### Camera fields7980- `name`, `center = {x,y,z}`, `distance`, `rotation = {q1,q2,q3,q4}` (quaternion).81 `center` is ignored when `follow` is set (a follow camera derives its center82 from the tracked object), so omit it on follow cameras.83- `follow = <cref>` attaches the camera to a shape. **The cref must be the84 low-level visualizer instance inside the component (its85 `Visualizers.Advanced.Shape`/`Arrow`/`Surface`), not the component itself** —86 `follow = bodyShape` is ignored and the camera stays unattached. That leaf87 name depends on the component: `vis` for `Visualizers.FixedShape`, `shape` for88 `FixedShape2`/`Parts.Fixed`, `shape1` (and `shape2` for the CM sphere) for89 `Parts.BodyShape`, `cylinder`/`sphere` for `Parts.Body`, `sphere` for90 `PointMass`, `arrow` for `WorldForce`/`SignalArrow`, and a nested path like91 `frameTranslation.shape` for `BodyBox`/`BodyCylinder`. The reliable way to get92 the exact cref is to pick the shape in Simulation Center (right-click →93 Camera Follow Mode, or Trace) and keep the cref it stores.94- `followMode`: `"NODE_CENTER"` (Object Center), `"NODE_CENTER_AND_AZIM"`95 (Object Center and Azimuth), `"NODE_CENTER_ROTATION"` (Object Center and96 Rotation). For fast-spinning bodies avoid `NODE_CENTER_ROTATION` — the camera97 spins with the body; `NODE_CENTER_AND_AZIM` gives a natural chase view.9899### Window fields100101- `camera = "<name>"`, `preferred = true` (open automatically after the first102 simulation), `autoPlay = true`, `repeat = true`, `timeScale = <r>`.103- `trace = {<cref>, ...}` draws trace paths, using the same low-level visualizer104 crefs as `follow` above (e.g. `bodyShape.shape1`, not `bodyShape`).105- `groundGrid = false` hides the ground grid. Omit the field to keep the grid:106 a stored `false` re-applies every time the window opens, so remove it from107 the annotation rather than toggling in the viewer.108- `vectorSettings = {VectorSettings(quantity = "Force", scale = <m/N>,109 diameter = <r>)}` and `defaultVectorDiameter = <r>` scale MSL 4.x vector110 visualizers (e.g. `WorldForce` arrows).111112### Quaternion starting points (z-up world)113114| View | `rotation` |115|------|-----------|116| Top (looking down −z) | `{0, 0, 0, 1}` |117| Horizontal, looking along −x | `{0.5, 0.5, 0.5, 0.5}` |118| Horizontal, looking along +y | `{0.7071, 0, 0, 0.7071}` |119120If the ground renders vertical, the camera's up-axis is wrong — start from one121of these and adjust, or set the camera in Simulation Center once ("Add Camera122to Model") and keep the numbers it writes.123124## Workflow1251261. Simulate; read the motion extents from the results.1272. Add a ground plane so motion reads against a fixed reference — size it from128 the simulated extents plus margin, top surface just below the motion floor:129130 ```modelica131 Modelica.Mechanics.MultiBody.Visualizers.FixedShape ground(132 shapeType = "box", lengthDirection = {1, 0, 0}, widthDirection = {0, 1, 0},133 length = 90, width = 60, height = 0.02, r_shape = {-10, -19, -0.03},134 color = {60, 150, 60});135 connect(world.frame_b, ground.frame_a);136 ```1371383. Add cameras (a follow camera for playback plus fixed top/side views for139 shareable stills — the window's `trace` applies to every camera).1404. Add one `Window` with playback flags and traces; validate the model141 (`validate-modelica`) and let the user confirm the view in Simulation Center.142143After a user stores anything from Simulation Center's animation dialogs, diff144the annotation: a GUI store rewrites the whole `Window(...)` from the current145viewer state, overwriting `autoPlay`, `repeat`, `timeScale`, `groundGrid` and146`trace` with whatever the viewer happens to show at that moment (e.g. `autoPlay`147becomes whether playback is running, `trace` becomes the currently traced148shapes). So re-apply hand-authored values after a store — do GUI stores first,149hand-edits last.150151## CAD shapes152153Attach CAD geometry to `FixedShape` / `BodyShape` with154`shapeType = "modelica://<Library>/Resources/<file>.stl"` (ship the file in the155library's `Resources/` folder). For file shapes, `length`/`width`/`height` act156as scale factors (set all three to one scale value), and `lengthDirection` /157`widthDirection` remap the CAD file's axes into the MultiBody frame.158159In Wolfram Language, `CreateSystemModel[Import["part.stl"]]` (pass the imported160mesh, not the path) generates a ready part: a `Body` with the full inertia161tensor computed from the geometry plus a matching `FixedShape`, with consistent162axes and the frame at the center of mass.