Skip to main content

Dynamics

The way dynamics work here is quite different from Wolfram Mathematica. Key changes were made for the sake of performance, flexibility—and perhaps a bit of @JerryI’s imagination (one of the maintainers).

Architecture

All dynamics—similar to what you’d expect in Mathematica—are handled entirely on the frontend, i.e., in your browser.

The core engine is powered by the WLX Library (via the WLJSTransport package).

Some expressions are designed to run directly on the frontend, without needing Kernel-side definitions. In other cases, you can use the Offload expression to explicitly tell the Kernel to pass unevaluated expressions to the frontend. This allows flexible structuring of your code to balance performance and control.

tip

Learn more here

tip

Always keep track of which parts of your code execute on the Wolfram Kernel (server) vs. the frontend (browser). This is crucial for writing predictable and performant code.

If You're Looking for Just Manipulate

If you want to see how curves change with parameters, check out ManipulatePlot or ManipulateParametricPlot.

ManipulatePlot[Sin[w z + p], {z,0,10}, {w, 0, 15.1, 1}, {p, 0, Pi, 0.1}]

A general-purpose Manipulate is available, but not recommended for plotting.

For small expressions that need to update on a timer or trigger, use Refresh:

Refresh[Now // TextString, 1]

This will update the time in the output cell every second.

... or Animate

If you’re looking to create standalone animations that can be embedded or exported, use AnimatePlot:

AnimatePlot[{Sin[x c], Sinc[x c]}, {x, -10, 10}, {c, 1, 10, 0.1}]

Using Wolfram Language and WLJS you can animate anything - see Animation

Animate[Row[{Sin[x], "==", Series[Sin[x], {x,0,n}], Invisible[1/2]}], {n, 1, 10, 1}, AnimationRate->3]

Automatic Tracking of Held Symbols

This doesn’t mean Set will automatically reevaluate on nested symbol changes, but many graphics primitives work out of the box. Use Offload to send symbols to the frontend:

length = 1;

Graphics[{Cyan,
Rectangle[{-1, -1}, {length // Offload, 1}]
}]
info

Offload wraps the value in a symbol unknown to the frontend, forcing it to fetch and create a dynamic link.

Note: The binding here is between Rectangle and length, not the whole Graphics expression. Learn more in the advanced section of the documentation.

danger

Not all functions support dynamic updates. Check the Reference to confirm whether a function supports updates.

Event-Based Approach

You can use GUI elements as event generators:

slider = InputRange[-1, 1, 0.1, "Label" -> "Length"]
EventHandler[slider, Function[l, length = l]];

Once an event is fired, the handler function is executed.

The slider symbol is a special object with both a representation and an event ID.

🍪 Example 0 – Simple Rotation

EventHandler[InputRange[0, 2.0 Pi, 0.1], Function[a,
angle = a
]]
% // EventFire;

Graphics[Rotate[Rectangle[{-1, -1}, {1, 1}], angle // Offload]]

🍪 Example 1 – Wave Packet

cell 1
packet[x_, t_] := Sum[Sin[-w t + w x], {w, 0, 3, 0.05}] / 10;
line = Table[{x, packet[x, 0]}, {x, 0, 10, 0.1}];

Graphics[Line[line // Offload], Frame -> True, FrameLabel -> {{"amplitude"}, {"distance"}}]
cell 2
EventHandler[InputRange[0, 5, 0.5, 0], Function[t,
line = Table[{x, packet[x, t]}, {x, 0, 10, 0.1}];
]]

🍪 Example 2 – Hello World Spray

Module[{
text = "Hello World"
},
Column[{
EventHandler[InputText[text], (text = #)&],
Graphics[Table[{
RandomColor[],
Rotate[
Text[text // Offload, RandomReal[{-1, 1}, 2]],
RandomReal[{0, 3.14}]
]
}, {40}]]
}]
]

Event Handlers for Graphics Primitives

p = {0, 0};
Graphics[{
White,
EventHandler[
Rectangle[{-2, -2}, {2, 2}],
{"mousemove" -> Function[xy, p = xy]}
],
PointSize[0.05], Cyan,
Point[p // Offload]
}]

Available events:

  • drag
  • zoom
  • click
  • mousemove
  • mouseover

For 3D:

  • transform
note

Graphics primitive handlers are part of the wljs-graphics-d3 library.

More info in Mouse and Keyboard.

Combination of manual and automated dynamics

Our built-in ManipulatePlot function allows to make basic interactive plots in a single line of code, however, you can add your own dynamic features manually if needed.

For example

Module[{label, pos},
ManipulatePlot[x w, {x,0,1}, {w,0,2},
Epilog->Text[Style[label // Offload, FontSize->14], pos // Offload],
"UpdateFunction" -> Function[input,
label = StringTemplate["w = ``"][SetPrecision[input,2]];
pos = {0.5, input 0.5 + 0.2};
True
]
]
]

Auto-Generating Dynamic Symbols

Use OffloadFromEventObject to turn event objects into dynamic symbols:

🍪 Example 3 – FABRIK Solver

cell 1
chain = {Cos[#[[1]]], Sin[#[[2]]]} & /@ RandomReal[{-1, 1}, {65, 2}] // Sort;
lengths = Norm /@ (Reverse[chain] // Differences) // Reverse;
cell 2
fabrik[lengths_, target_, origin_] := Module[{buffer, prev},
buffer = Table[With[{p = chain[[-i]]},
If[i === 1,
prev = target;
target
,

prev = prev - Normalize[(prev - p)] lengths[[1-i]];
prev
]
], {i, chain // Length}] // Reverse;

Table[With[{p = buffer[[i]]},
If[i === 1,
prev = origin;
origin
,

prev = prev - Normalize[(prev - p)] lengths[[i-1]];
prev
]
], {i, chain // Length}]
]
cell 3
Graphics[{
Line[chain // Offload],
Red, PointSize[0.06],
EventHandler[Point[{-1, -1}], {"drag" -> Function[xy, chain = fabrik[lengths, xy, First[chain]]]}],
Blue, Point[origin // Offload]
}, PlotRange -> {{-2, 2}, {-2, 2}}, ImageSize -> 500, "TransitionType" -> "Linear", "TransitionDuration" -> 30]

🍪 Example 4 – Opacity Animation

opacity = 0.5;
Graphics[{
Opacity[Offload[opacity]], Red, Disk[{0, 0}, Offload[1 - opacity]],
Blue, Opacity[Offload[1.0 - opacity]], Disk[{0, 0}, Offload[opacity]]
}, ImagePadding -> None]

EventHandler[InputRange[0, 1, 0.1], Function[value,
opacity = value;
]]

info

All examples are shipped with the app. Locate them here:

Or access them from the top-bar menu.

🍪 Example 5 – 3D Morph Mesh

sample[t_] := With[{
complex = ParametricPlot3D[
(1 - t) * {
(2 + Cos[v]) * Cos[u],
(2 + Cos[v]) * Sin[u],
Sin[v]
} + t * {
1.16^v * Cos[v] * (1 + Cos[u]),
-1.16^v * Sin[v] * (1 + Cos[u]),
-2 * 1.16^v * (1 + Sin[u]) + 1.0
},
{u, 0, 2\[Pi]},
{v, -\[Pi], \[Pi]},
MaxRecursion -> 2,
Mesh -> None
][[1, 1]]
},
{
complex[[1]],
Cases[complex[[2]], _Polygon, 6] // First // First,
complex[[3, 2]]
}
]
Module[{
vertices, normals, indices
},
{
EventHandler[InputRange[0,1,0.1,0], Function[value,
With[{res = sample[value]},
normals = res[[3]];
indices = res[[2]];
vertices = res[[1]];
];
]],

{vertices, indices, normals} = sample[0];

Graphics3D[{
SpotLight[Red, 5 {1,1,1}], SpotLight[Blue, 5 {-1,-1,1}],
SpotLight[Green, 5 {1,-1,1}], PointLight[Magenta, {10,10,10}],
GraphicsComplex[vertices // Offload, {
Polygon[indices // Offload]
}, VertexNormals->Offload[normals, "Static"->True]]
}, Lighting->None]
} // Column // Panel
]

How to Embed on a Web Page?

No Kernel connection needed. Use AnimatePlot or Dynamic HTML.

tip

Explore our Blog 📻 for more examples and dev notes.

How to Turn It Into an App?

See Standalone Widgets.