Animating with time
An AssemblyNode can use the property self.time to position its children. The time is a number between 0 and 1 that will be resolved in the viewer, and you can use it to position elements relative to time.
Edit root/__init__.py to rotate the pointer of the simple clock:
class SimpleClock(AssemblyNode):
def __init__(self):
self.base = ClockBase()
self.pointer = Pointer()
super().__init__()
def render(self):
angle = -360 * self.time
self.pointer.rotate(angle, [0, 0, 1])
return [self.base, self.pointer]
The angle is negative because a positive rotation around the Z axis is counter-clockwise (the right-hand rule), and clocks run clockwise.
Rendered with solid export — press play to see the pointer rotate:
At this point you should see a rotating pointer in the viewer. If you are using the Openscad viewer, you need to enable animation (View -> Animate) and set fps and number of frames. Reload is not automatic in Openscad while animating.
Positioning operations
Besides rotate(angle, axis), nodes also have translate([x, y, z]). Both apply in the viewer and in tests alike, and return the node itself, so they can be chained:
self.pointer.rotate(angle, [0, 0, 1]).translate([0, 0, offset])
Don’t confuse the node method translate([x, y, z]) with solid2’s translate(x, y, z) primitive used inside a Solid2Node.render(): the primitive shapes the part itself, the node method positions a part within an assembly.
Every render() expresses absolute positions for its instant. Before an assembly re-renders, the operations it applied on its children in previous renders are dropped, so you always compute placement from self.time alone — there is no accumulated state to undo. This also means two different assemblies can drive the same node (say, a wheel spun by its axle and steered by the steering assembly) without disturbing each other’s operations.
Non-linear kinematics
A linear expression of self.time, like -360 * self.time above,
works out of the box. For non-linear movement — anything that needs
trigonometry over time — use solid_node.math, which provides
degree-based sin, cos, tan, asin, acos, atan, atan2 and
sqrt matching OpenScad’s semantics:
from solid_node.math import sin
class Escapement(AssemblyNode):
def render(self):
angle = 15 * sin(360 * 8 * self.time)
self.anchor.rotate(angle, [0, 0, 1])
...
These functions work in both worlds self.time lives in: in the viewer, where time is symbolic and the expression is evaluated client-side as you scrub the timeline, and in tests, where time is a plain number (see testing_steps). Python’s math.sin would crash on symbolic time — and it works in radians, while all angles in Solid Node are degrees.