On this page:
gen:  pict-renderer
pict-renderer?
pict-renderer-supports?
pict-renderer-render
pict-renderer-list?
default-pict-renderers
21.1 Built-in Rendering
21.2 Defining a Custom Renderer
21.3 Relative Layout
layout-box
layout-horizontal-alignment?
layout-vertical-alignment?
layout-box-width
layout-box-height
layout-box-center
layout-box-anchor?
layout-box-anchor
visual-layout-box
visual-layout-anchor
visuals-layout-box
visual-place-at
visual-align-to
visual-align-horizontal
visual-align-vertical
align-baselines
keep-inside-frame
avoid-overlap
distribute-within
visual-place-above
visual-place-below
visual-place-left-of
visual-place-right-of
visuals-center-at
arrange-visuals-horizontally
arrange-visuals-vertically
21.3.1 Fitting a Background
21.4 Temporary Attention Effects
circumscribe
circumscribe-request?
indicate
indicate-request?
flash
flash-request?
focus-on
focus-on-request?
show-passing-flash
show-passing-flash-request?
wiggle
grow-from-center
grow-from-center-request?
grow-arrow
grow-arrow-request?
draw-border-then-fill
draw-border-then-fill-request?
transform-from-copy
transform-from-copy-request?
21.5 Pict, Bitmap, and Frame Conversion
visual->pict
scene-state->pict
scene->pict
scene-frame-count
frame-index->time
scene-frame->bitmap
21.6 PNG and MP4 Output
render-frames!
render-frames/  report!
render-diagnostics
21.6.1 Authored timelines and selected sections
section
cue
audio-cue
subtitle
authoring-section?
cue?
audio-cue?
subtitle?
make-authored-timeline
timeline-section
timeline-section-names
timeline-section-frame-indices
timeline-section-frame-count
timeline-section-cues
authored-timeline-metadata
authored-timeline?
authored-timeline-scene
21.6.1.1 Rendering selected frames and authored sections
write-subtitles!
render-frame-indices!
render-frame-indices/  report!
render-timeline-section!
render-timeline-section/  report!
section-render-report
automatic-section-cache-key
21.6.2 Mathematical graphs and networks
graph-vertex
graph-vertex?
graph-edge
graph-edge?
graph-layout?
graph
digraph
graph-vertex-partition
graph-edge-weight
graph-edge-curvature
graph-edge-stroke
graph-edge-stroke-width
graph-vertices-path
graph-edges-path
graph-vertex-path
graph-edge-path
graph-bfs
graph-dfs
graph-shortest-path
21.6.3 MP4 encoding and media assembly
encode-mp4!
assemble-authored-mp4!
mux-authored-video!
concatenate-mp4!
render-authored-mp4!
21.6.4 Project execution
execute-prepared-project!
project-execution-report?
21.7 Errors and Validation
21.8 Determinism and Immutability
9.3

21 Pict Renderer Protocol🔗

A Pict renderer converts one kind of semantic Visual into centered local Pict geometry. Renderer selection uses an explicit ordered list. The first renderer that reports support is selected. There is no mutable global registry.

generic interface

gen:pict-renderer : any/c

The generic interface for Pict renderer values. A renderer structure must implement pict-renderer-supports? and pict-renderer-render.

procedure

(pict-renderer? value)  boolean?

  value : any/c
Returns #t when value implements gen:pict-renderer.

procedure

(pict-renderer-supports? renderer visual)  boolean?

  renderer : pict-renderer?
  visual : visual?
Reports whether renderer can render visual. The high-level renderer dispatcher checks that a custom implementation returns a Boolean.

procedure

(pict-renderer-render renderer    
  visual    
  camera)  pict?
  renderer : pict-renderer?
  visual : visual?
  camera : camera?
Renders centered local geometry for a supported Visual. The result must not apply translation in the Visual’s containing coordinate system. A renderer is responsible for interpreting any local geometry, scale, and rotation that its Visual type supports. It should render at full local strength and should not apply semantic global opacity. The high-level adapter applies opacity after renderer dispatch, then a scene or group adapter places the result at the Visual’s reference position.

The high-level renderer dispatcher checks that the result is a Pict. Calling pict-renderer-render directly does not apply semantic opacity.

A renderer that explicitly supports a group or formula assembly replaces the built-in recursive compositor for that Visual. It receives the semantic composite value and camera, but not the surrounding renderer list. It is responsible for interpreting the children or parts, their significant order, their opacity, nested composites, and the complete Visual’s scale and rotation. It must not apply the Visual’s containing-system translation or global opacity. The high-level adapter applies global opacity afterward and the parent adapter places the result.

procedure

(pict-renderer-list? value)  boolean?

  value : any/c
Returns #t when value is a list containing only Pict renderer values. The empty list is valid. It can compose an empty built-in group or an empty formula assembly, but a nonempty leaf needs an explicit supporting renderer.

The ordered built-in renderer list. It contains circle, rectangle, path, arrow, axes, bitmap-image, full-fidelity SVG, and plain-text renderers, followed by the LaTeX formula renderer. Groups are composed by the high-level Pict adapter when no explicit renderer supports them. Formula assemblies use the same recursive compositor through their internal ordered formula parts. Prepend a custom renderer when it should override a built-in leaf or complete composite.

21.1 Built-in Rendering🔗

The built-in circle renderer multiplies the local diameter by the Visual’s x and y scale factors. Non-uniform scale therefore produces an ellipse. Rotation is applied when that ellipse is not rotationally symmetric.

The built-in rectangle renderer multiplies local width and height by the scale factors and then rotates the resulting Pict.

The built-in arrow renderer derives one open shaft and zero, one, or two closed triangular tip subpaths from the semantic arrow. The built-in axes renderer derives the two open shafts, ordered open ticks, and optional closed maximum-end tips. Both then use the ordinary path renderer. Tip dimensions and tick sizes are transformed as local geometry. Stroke width remains cosmetic.

Closed tips use the same odd-even fill, miter join, and butt-cap policy as other closed path geometry. Open shafts and ticks use round endpoint caps and miter joins. The adapter uses the stored stroke style for shaft and tick lines and for tip fill and outline.

The built-in plain-text renderer converts the semantic font size from world units to camera pixels and constructs a platform font from the requested face, family, style, and weight. It renders the one-line string with Pict, applies the stored color, places the chosen anchor at the center of a symmetric local Pict, and then applies semantic scale and rotation around that anchor. Direct font sizes are kept within the drawing backend’s supported range; a final Pict scale preserves the requested world-space size outside that range.

Since version 0.50.1, the completed nonempty local text appearance is rasterized to an alpha bitmap before scene placement. Moving the Visual or panning the camera therefore translates an already-rasterized glyph run instead of asking the platform font backend to rerasterize it at changing device-space origins. This prevents subtle apparent inter-letter spacing changes during smooth motion. The default renderer keeps a bounded renderer-local cache for common immutable text appearances. The cache key excludes position, Visual identity, opacity, and camera center, but includes text/font/color/alignment data, semantic scale and rotation, and camera pixel scale. Camera zoom and appearance transforms therefore rerasterize at their sampled resolution. Unknown adapter-native color objects bypass the cache while retaining stable local-origin rasterization. The same bounded renderer-resource mechanism caches complete formula appearances. Formula position, identity, opacity, and camera center do not invalidate an appearance, while formula source/options, semantic scale/rotation, and camera pixel scale do.

An empty text string produces a transparent one-pixel Pict. Left and right anchors reserve symmetric space on the opposite side of the anchor, and top and bottom anchors do the same vertically. Baseline alignment uses the Pict’s font ascent and descent. These symmetric boxes keep the semantic anchor at the local Pict center, which is the placement convention used by groups and scene states.

The built-in formula renderer chooses one of tex-math, tex-display-math, and tex-real-display-math from the semantic mode. It passes the immutable source, preamble, document-class options, and Preview options to latex-pict with that package’s extra scale set to one. It then maps the selected 10pt, 11pt, or 12pt document base to the formula’s semantic world-unit font size.

Formula anchoring, non-uniform semantic scale, rotation, and opacity follow the same order as plain text. Empty formula source produces a transparent one-pixel Pict without loading latex-pict or running TeX. Nonempty formula rendering can perform external process and native-library work. latex-pict is loaded at that adapter boundary instead of from the pure formula model. That package caches repeated complete TeX documents; source, preamble, or option changes produce a different document.

A formula assembly is composed from its parts in significant back-to-front order. Each part is rendered as an ordinary formula Visual at its stored local position. The same explicit renderer list is passed to every part. An empty assembly produces a transparent one-pixel Pict and does not invoke TeX. The assembly’s uniform scale and rotation are inherited through its part model transforms before rendering, and its global opacity is applied after the parts have been composed.

The built-in path renderer transforms every stored local point by scale and rotation, converts world units to pixels, and draws the result through dc-path%. Sampled function graphs reach this renderer as ordinary path Visuals; no separate graph renderer is used. Line segments become drawing-path line operations. Cubic segments become drawing-path curve operations and remain true cubic curves. Closed subpaths are filled together with the odd-even rule. Open subpaths are stroked without implicit filling. A false fill or stroke selects a transparent brush or pen.

Closed outlines use miter joins and butt caps, which keeps polygon corners sharp. Open paths use round endpoint caps and miter joins between segments.

A partial piece returned by path-geometry-partial is open unless it contains a complete original closed subpath. During create, a closed shape is therefore stroked as it grows and becomes filled when its subpath is complete. In a compound path, one completed closed subpath can be filled while a later subpath is still partial. uncreate performs the same sequence in reverse.

For all built-in Visuals, stroke width is cosmetic: semantic scale does not multiply it. A group is composed recursively from its ordered children. Its uniform scale and rotation are inherited by child model transforms before each child is rendered, so cosmetic stroke widths are not enlarged by scaling a finished composite Pict. The same explicit renderer list is passed to every descendant. Group translation places the complete composite in its containing coordinate system.

The built-in compositor uses a symmetric Pict box around the group anchor. Its half-width and half-height are the largest absolute child extents on each axis. This keeps the anchor at the center even when all children lie on one side. An empty group produces a transparent one-pixel Pict.

Global opacity is applied to the complete local Pict after renderer selection or group composition. It affects fill and stroke together and does not change Pict bounds. World translation is applied later by scene-state->pict. Path reveal is measured in untransformed local arc length. Cubic reveal uses the deterministic approximation described by path-subpath-length. A non-uniform Visual scale can therefore change displayed speed along differently oriented or curved portions.

21.2 Defining a Custom Renderer🔗

Here is a complete custom Visual and renderer:

(require pict
         animate)
 
(struct cross-visual (id position)
  #:transparent
  #:methods gen:visual
  [(define (visual-id value)
     (cross-visual-id value))
   (define (visual-position value)
     (cross-visual-position value))
   (define (visual-with-position value position)
     (struct-copy cross-visual value [position position]))])
 
(struct cross-renderer ()
  #:transparent
  #:methods gen:pict-renderer
  [(define (pict-renderer-supports? renderer visual)
     (cross-visual? visual))
   (define (pict-renderer-render renderer visual camera)
     (define arm
       (camera-length->pixels camera 1))
     (cc-superimpose
      (filled-rectangle arm (/ arm 5))
      (filled-rectangle (/ arm 5) arm)))])
 
(define renderers
  (cons (cross-renderer) default-pict-renderers))

The example’s renderer uses Pict operations, so its module must also require pict.

21.3 Relative Layout🔗

Relative layout measures the Pict that a Visual would produce and converts its pixel dimensions back into world units. Arrow tips, axis ticks, tip outlines, and cosmetic stroke padding are therefore included in the measured box. It then returns new Visual values with updated reference positions. The source Visuals are not mutated.

Layout is renderer-aware. Text, formulas, custom Visuals, and composites can have dimensions that are known only after renderer selection. Every measurement and placement procedure therefore accepts the same #:camera and #:renderers arguments as the Pict adapter. Use the same values for layout and final rendering.

A layout box is the complete symmetric render box of the local Pict. It is not a tight ink box. Transparent padding, text anchor padding, formula anchor padding, group composition extents, and any padding returned by a custom renderer are included. Semantic opacity does not change the box because opacity does not change Pict dimensions.

Measuring a nonempty LaTeX formula with the built-in formula renderer can invoke LaTeX and Poppler. A custom formula renderer can provide deterministic metrics without launching TeX.

struct

(struct layout-box (left bottom right top)
    #:transparent)
  left : finite-real?
  bottom : finite-real?
  right : finite-real?
  top : finite-real?
Represents an axis-aligned rendered box in the containing coordinate system. Coordinates use the library’s mathematical convention: x increases to the right and y increases upward.

The fields have these meanings:

  • left is the smallest horizontal coordinate.

  • bottom is the smallest vertical coordinate.

  • right is the largest horizontal coordinate.

  • top is the largest vertical coordinate.

All four fields must be finite real numbers. left must not exceed right, and bottom must not exceed top. Zero-width and zero-height boxes are valid.

The structure is immutable and transparent. Its public bindings include layout-box, layout-box?, the four field accessors, and struct:layout-box.

procedure

(layout-horizontal-alignment? value)  boolean?

  value : any/c
Returns #t when value is one of:

'left
'center
'right

These symbols select a horizontal coordinate of a layout box.

procedure

(layout-vertical-alignment? value)  boolean?

  value : any/c
Returns #t when value is one of:

'bottom
'center
'top

These symbols select a vertical coordinate of a layout box. Baseline alignment is not part of this layout protocol. A text or formula Visual may still use a baseline as its own semantic anchor before its complete render box is measured.

procedure

(layout-box-width box)  (and/c finite-real? (>=/c 0))

  box : layout-box?
Returns (- (layout-box-right box) (layout-box-left box)).

procedure

(layout-box-height box)  (and/c finite-real? (>=/c 0))

  box : layout-box?
Returns (- (layout-box-top box) (layout-box-bottom box)).

procedure

(layout-box-center box)  vec2?

  box : layout-box?
Returns the midpoint of box.

procedure

(layout-box-anchor? value)  boolean?

  value : any/c
Returns #t when value is one of the nine canonical render-box anchors:

'bottom-left  'bottom  'bottom-right
'left         'center  'right
'top-left     'top     'top-right

These names select both coordinates at once. They are distinct from the one-axis alignment predicates and intentionally do not infer a baseline from a renderer.

procedure

(layout-box-anchor box anchor)  vec2?

  box : layout-box?
  anchor : layout-box-anchor?
Returns the point selected by anchor in box’s containing coordinate system. For example, 'top-right gives (vec2 (layout-box-right box) (layout-box-top box)).

procedure

(visual-layout-box visual    
  [#:camera camera    
  #:renderers renderers])  layout-box?
  visual : visual?
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Renders visual as local Pict geometry with camera and renderers, then returns its complete symmetric box in the Visual’s containing coordinate system.

If the local Pict has pixel width w, pixel height h, camera scale s, and Visual position (x,y), the result is:

layout-box(x - w/(2s), y - h/(2s), x + w/(2s), y + h/(2s))

The selected renderer must follow the Pict-renderer protocol and return centered local geometry. The procedure checks that the Visual position is a vec2, that its identity is a symbol, and that the Pict dimensions are finite and nonnegative.

This procedure can perform adapter effects. In particular, measuring a nonempty formula through the built-in formula renderer can run TeX.

procedure

(visual-layout-anchor visual    
  anchor    
  [#:camera camera    
  #:renderers renderers])  vec2?
  visual : visual?
  anchor : layout-box-anchor?
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Measures visual as visual-layout-box would and returns the selected canonical anchor. The result is in the Visual’s containing world or frame coordinate system.

procedure

(visuals-layout-box visuals 
  [#:camera camera 
  #:renderers renderers]) 
  (or/c layout-box? false/c)
  visuals : (listof visual?)
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns the smallest axis-aligned box containing the measured boxes of all visuals. List order does not change the union. Returns #f for an empty list.

The camera and renderer list are validated even for an empty list. Every nonempty Visual is measured with visual-layout-box using the supplied context.

procedure

(visual-place-at visual    
  position    
  [#:anchor anchor    
  #:camera camera    
  #:renderers renderers])  visual?
  visual : visual?
  position : vec2?
  anchor : layout-box-anchor? = 'center
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns an immutable copy of visual whose measured anchor is exactly position. The default moves its render-box center. Identity, appearance, and all transform components other than translation are preserved.

procedure

(visual-align-to visual    
  reference    
  [#:anchor anchor    
  #:reference-anchor reference-anchor    
  #:camera camera    
  #:renderers renderers])  visual?
  visual : visual?
  reference : visual?
  anchor : layout-box-anchor? = 'center
  reference-anchor : layout-box-anchor? = anchor
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns an immutable copy of visual whose selected anchor equals reference’s selected reference-anchor. The default aligns centers. Both Visuals must be measured in compatible world or frame coordinate systems. This is a compile-time layout calculation, not a live constraint: later animation of either Visual does not update the returned one.

procedure

(visual-align-horizontal visual    
  reference    
  alignment    
  [#:camera camera    
  #:renderers renderers])  visual?
  visual : visual?
  reference : visual?
  alignment : layout-horizontal-alignment?
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns a copy of visual whose selected horizontal box coordinate is equal to the same coordinate of reference. The symbols 'left, 'center, and 'right select the coordinate.

Only the x component of the Visual position changes. Its y component, identity, geometry, style, transform components other than translation, opacity, and children remain as supplied by its visual-with-position implementation. reference is unchanged.

procedure

(visual-align-vertical visual    
  reference    
  alignment    
  [#:camera camera    
  #:renderers renderers])  visual?
  visual : visual?
  reference : visual?
  alignment : layout-vertical-alignment?
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns a copy of visual whose selected vertical box coordinate is equal to the same coordinate of reference. The symbols 'bottom, 'center, and 'top select the coordinate.

Only the y component of the Visual position changes. The x component and the reference Visual remain unchanged.

procedure

(align-baselines visuals    
  [#:baseline baseline    
  #:camera camera    
  #:renderers renderers])  (listof visual?)
  visuals : (listof visual?)
  baseline : (or/c finite-real? false/c) = #f
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns one immutable positioned copy per input Visual, in input order. Their reference y coordinates are all set to baseline, or to the first Visual’s reference y coordinate when it is #f. In particular, this aligns the true baselines of text made with #:vertical-alignment 'baseline. Other Visual kinds use their ordinary reference position; no hidden font baseline is inferred for them.

procedure

(keep-inside-frame visual    
  [#:margin margin    
  #:camera camera    
  #:renderers renderers])  visual?
  visual : visual?
  margin : (and/c finite-real? (>=/c 0)) = 0
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns an immutable copy translated minimally so its complete measured render box is inside camera’s viewport after the requested margin. A Visual larger than the available viewport is centred on that axis. The operation is a construction-time correction, not a live camera or viewport constraint.

procedure

(avoid-overlap visuals    
  [#:direction direction    
  #:gap gap    
  #:camera camera    
  #:renderers renderers])  (listof visual?)
  visuals : (listof visual?)
  direction : (or/c 'right 'up) = 'right
  gap : (and/c finite-real? (>=/c 0)) = 0
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns ordered immutable copies separated by a deterministic greedy pass. 'right moves later Visuals rightward until their measured boxes leave at least gap horizontal space; 'up does the analogous vertical pass. It is intentionally not a general two-dimensional packing or constraint solver.

procedure

(distribute-within visuals    
  start    
  end    
  [#:axis axis])  (listof visual?)
  visuals : (listof visual?)
  start : finite-real?
  end : finite-real?
  axis : (or/c 'horizontal 'vertical) = 'horizontal
Returns ordered immutable copies whose reference x or y coordinates are evenly spaced, including start and end. An empty list returns empty; a singleton is placed at their midpoint. The unselected coordinate and all other Visual properties are preserved.

procedure

(visual-place-above 
  visual 
  reference 
  [#:gap gap 
  #:horizontal-alignment horizontal-alignment 
  #:camera camera 
  #:renderers renderers]) 
  visual?
  visual : visual?
  reference : visual?
  gap : (and/c finite-real? (>=/c 0)) = 1/4
  horizontal-alignment : layout-horizontal-alignment? = 'center
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns a copy of visual placed above reference. The bottom edge of the returned Visual’s box is exactly gap world units above the top edge of the reference box.

The selected horizontal coordinates are aligned. The default aligns box centers; 'left and 'right align the corresponding edges.

procedure

(visual-place-below 
  visual 
  reference 
  [#:gap gap 
  #:horizontal-alignment horizontal-alignment 
  #:camera camera 
  #:renderers renderers]) 
  visual?
  visual : visual?
  reference : visual?
  gap : (and/c finite-real? (>=/c 0)) = 1/4
  horizontal-alignment : layout-horizontal-alignment? = 'center
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns a copy of visual placed below reference. The top edge of the returned Visual’s box is exactly gap world units below the bottom edge of the reference box. The requested horizontal box coordinates are aligned.

procedure

(visual-place-left-of visual 
  reference 
  [#:gap gap 
  #:vertical-alignment vertical-alignment 
  #:camera camera 
  #:renderers renderers]) 
  visual?
  visual : visual?
  reference : visual?
  gap : (and/c finite-real? (>=/c 0)) = 1/4
  vertical-alignment : layout-vertical-alignment? = 'center
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns a copy of visual placed to the left of reference. The right edge of the returned Visual’s box is exactly gap world units to the left of the reference box. The requested vertical box coordinates are aligned.

procedure

(visual-place-right-of 
  visual 
  reference 
  [#:gap gap 
  #:vertical-alignment vertical-alignment 
  #:camera camera 
  #:renderers renderers]) 
  visual?
  visual : visual?
  reference : visual?
  gap : (and/c finite-real? (>=/c 0)) = 1/4
  vertical-alignment : layout-vertical-alignment? = 'center
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Returns a copy of visual placed to the right of reference. The left edge of the returned Visual’s box is exactly gap world units to the right of the reference box. The requested vertical box coordinates are aligned.

procedure

(visuals-center-at visuals    
  center    
  [#:camera camera    
  #:renderers renderers])  (listof visual?)
  visuals : (listof visual?)
  center : vec2?
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Translates every Visual by the same displacement so that the center of their union layout box is center. Input order and Visual identities are preserved. The input values are unchanged.

Returns an empty list when visuals is empty. The camera, renderer list, and center are still validated.

procedure

(arrange-visuals-horizontally 
  visuals 
  [#:gap gap 
  #:vertical-alignment vertical-alignment 
  #:center center 
  #:camera camera 
  #:renderers renderers]) 
  (listof visual?)
  visuals : (listof visual?)
  gap : (and/c finite-real? (>=/c 0)) = 1/4
  vertical-alignment : layout-vertical-alignment? = 'center
  center : (or/c vec2? false/c) = #f
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Arranges visuals from left to right in their existing list order. Without #:center, the first Visual keeps its original position. Each later Visual is placed to the right of the previously arranged Visual with the requested gap and vertical alignment.

When center is a vec2, the complete arranged list is translated as one unit so that its union layout box has that center. #f leaves the first Visual fixed. An empty input list returns an empty list.

The procedure returns a new list and does not reorder identities. Arrangement uses adjacent measured boxes; it is not a constraint solver and does not recompute automatically after later content, renderer, camera, or transform changes.

procedure

(arrange-visuals-vertically 
  visuals 
  [#:gap gap 
  #:horizontal-alignment horizontal-alignment 
  #:center center 
  #:camera camera 
  #:renderers renderers]) 
  (listof visual?)
  visuals : (listof visual?)
  gap : (and/c finite-real? (>=/c 0)) = 1/4
  horizontal-alignment : layout-horizontal-alignment? = 'center
  center : (or/c vec2? false/c) = #f
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Arranges visuals from top to bottom in their existing list order. Without #:center, the first Visual keeps its original position. Each later Visual is placed below the previously arranged Visual with the requested gap and horizontal alignment.

When center is a vec2, the complete arranged list is translated as one unit so that its union layout box has that center. #f leaves the first Visual fixed. An empty input list returns an empty list.

The returned list preserves order and identities. Layout is a one-time immutable calculation. It does not maintain a live relationship between the arranged Visuals.

21.3.1 Fitting a Background🔗

A background can be fitted around measured content by adding padding to the union box:

(define arranged
  (arrange-visuals-vertically
   (list title formula explanation)
   #:gap 1/3
   #:center origin
   #:camera default-camera
   #:renderers default-pict-renderers))
 
(define content-box
  (visuals-layout-box arranged
                      #:camera default-camera
                      #:renderers default-pict-renderers))
 
(define background
  (rectangle #:id 'background
             #:center (layout-box-center content-box)
             #:width (+ (layout-box-width content-box) 3/2)
             #:height (+ (layout-box-height content-box) 3/2)))
 
(define card
  (group (cons background arranged)
         #:id 'card))

The example adds three quarters of a world unit on every side. The background is first in the group child list, so it is painted behind the content.

21.4 Temporary Attention Effects🔗

procedure

(circumscribe target 
  [#:padding padding 
  #:color color 
  #:stroke-width stroke-width]) 
  circumscribe-request?
  target : (or/c visual? symbol? visual-path?)
  padding : (and/c finite-real? (>=/c 0)) = 1/5
  color : any/c = "gold"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Creates a temporary rounded outline that draws, holds, and erases over one play clip. target may be a top-level Visual/id or an explicit nested built-in group/formula path. At every interior sample, its resolved world-space Visual is measured through the ordinary renderer; the outline consequently follows simultaneous target translation, rotation, scale, and formula-layout changes regardless of request order in the play clip.

The outline does not mutate the target and is absent at both structural clip endpoints. It measures a renderer box rather than visible glyph contours, and does not respond to camera or renderer changes within the same clip.

procedure

(circumscribe-request? value)  boolean?

  value : any/c
Returns #t when value is a request created by circumscribe.

procedure

(indicate target    
  [#:padding padding    
  #:color color    
  #:stroke-width stroke-width])  indicate-request?
  target : (or/c visual? symbol? visual-path?)
  padding : (and/c finite-real? (>=/c 0)) = 1/5
  color : any/c = "gold"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Creates a temporary rounded outline that pulses once over one play clip. Target resolution, renderer-aware nested live measurement, and endpoint behavior are the same as circumscribe.

procedure

(indicate-request? value)  boolean?

  value : any/c
Returns #t when value is a request created by indicate.

procedure

(flash target    
  [#:radius radius    
  #:color color    
  #:stroke-width stroke-width])  flash-request?
  target : (or/c visual? symbol? visual-path?)
  radius : (and/c finite-real? (>=/c 0)) = 1/2
  color : any/c = "gold"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Draws a short eight-ray burst around the target’s live rendered-box centre. The transient overlay is absent at both clip endpoints.

procedure

(flash-request? value)  boolean?

  value : any/c
Recognizes a flash request.

procedure

(focus-on target    
  [#:radius radius    
  #:color color    
  #:stroke-width stroke-width])  focus-on-request?
  target : (or/c visual? symbol? visual-path?)
  radius : (and/c finite-real? (>=/c 0)) = 1/2
  color : any/c = "gold"
  stroke-width : (and/c finite-real? (>=/c 0)) = 3
Expands and fades a circular live-target focus ring over one play clip.

procedure

(focus-on-request? value)  boolean?

  value : any/c
Recognizes a focus-on request.

procedure

(show-passing-flash target 
  [#:time-width time-width 
  #:color color 
  #:stroke-width stroke-width]) 
  show-passing-flash-request?
  target : (or/c path-visual? symbol? visual-path?)
  time-width : (real-in 0 1) = 1/5
  color : any/c = "gold"
  stroke-width : (and/c finite-real? (>=/c 0)) = 4
Renders only a moving arc-length sliver of a path Visual. A symbol/path target is checked when the play clip is compiled.

procedure

(show-passing-flash-request? value)  boolean?

  value : any/c
Recognizes a show-passing-flash request.

procedure

(wiggle target    
  [#:angle angle    
  #:cycles cycles])  succession-animation-request?
  target : (or/c visual? symbol? visual-path?)
  angle : finite-real? = 1/12
  cycles : exact-positive-integer? = 2
Returns an ordinary reversible rotation succession. It ends at exactly the initial rotation and follows normal composition timing.

Introduces an absent Visual from an invisible, centre-scaled source and restores the exact supplied endpoint at completion.

procedure

(grow-from-center-request? value)  boolean?

  value : any/c
Recognizes a grow-from-center request.

procedure

(grow-arrow visual)  grow-arrow-request?

  visual : arrow-visual?
Introduces an absent arrow from its start endpoint, including its arrowhead.

procedure

(grow-arrow-request? value)  boolean?

  value : any/c
Recognizes a grow-arrow request.

Introduces an absent path Visual by tracing its outline with arc-length timing, then fading in its original fill and final stroke style.

procedure

(draw-border-then-fill-request? value)  boolean?

  value : any/c
Recognizes a draw-border-then-fill request.

procedure

(transform-from-copy source 
  destination 
  [#:path-arc path-arc 
  #:route route]) 
  transform-from-copy-request?
  source : (or/c visual? symbol? visual-path?)
  destination : (and/c visual? affine-visual? opacity-visual?)
  path-arc : finite-real? = 0
  route : (or/c #f formula-route?) = #f
Keeps the source in place while a transient copy moves to the initially absent destination. A supplied route overrides the default circular path-arc.

procedure

(transform-from-copy-request? value)  boolean?

  value : any/c
Recognizes a transform-from-copy animation request.

21.5 Pict, Bitmap, and Frame Conversion🔗

procedure

(visual->pict visual    
  camera    
  [#:renderers renderers])  pict?
  visual : visual?
  camera : camera?
  renderers : pict-renderer-list? = default-pict-renderers
Selects the first explicit supporting renderer and validates its local Pict. When no explicit renderer supports a built-in group or formula assembly, the adapter recursively composes its ordered children or parts and passes the same renderers list to every descendant. An explicit renderer that reports support for the complete composite therefore overrides the built-in compositor.

The dispatcher does not apply translation in the Visual’s containing coordinate system. It also does not interpret an affine transform on behalf of a custom renderer. The built-in circle, rectangle, path, plain-text, and formula renderers apply their Visuals’ scale and rotation themselves. The built-in group compositor inherits the group’s uniform scale and rotation through its children before rendering. A formula assembly delegates the same composition rule to its ordered formula parts.

When visual implements gen:opacity-visual, its visual-opacity result must satisfy opacity?. Opacity one returns the rendered or composed Pict unchanged. Lower values use Pict alpha without changing the Pict’s width, height, or reference placement. A custom renderer therefore receives opacity behavior without handling it itself. Group opacity is applied after its children have been composed.

A derived-visual? cannot be rendered by visual->pict directly because no scene-state scalar context is available. Resolve it first with scene-state-resolved-ref, or render through scene-state->pict or scene->pict.

If no renderer supports the concrete Visual, an exception is raised. Invalid custom support, render, or opacity-protocol results also raise exceptions.

procedure

(scene-state->pict state    
  [#:camera camera    
  #:renderers renderers])  pict?
  state : scene-state?
  camera : camera? = default-camera
  renderers : pict-renderer-list? = default-pict-renderers
Creates a fixed-size Pict for state. It fills the background, resolves any top-level derived-visual? definitions against this exact state’s named scalars, renders the resulting concrete Visuals in back-to-front order, and places each Visual so its reference position maps through camera. A group occupies one top-level drawing position and recursively applies its own child order. A formula assembly also occupies one top-level position and applies its separate local part order. A zero-opacity Visual remains in semantic order but contributes no visible pixels.

procedure

(scene->pict scene    
  time    
  [#:camera camera    
  #:renderers renderers])  pict?
  scene : scene?
  time : (and/c finite-real? (>=/c 0))
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
Samples scene at time and converts the resulting scene state to a Pict. The same time range rules as scene-sample apply.

When camera is #f, the Visual state and scene camera are sampled together using one easing evaluation. Supplying a camera is a static override: the supplied camera is used instead of the scene-camera timeline for this conversion.

procedure

(scene-frame-count scene [#:fps fps])  exact-nonnegative-integer?

  scene : scene?
  fps : exact-positive-integer? = 30
Returns (ceiling (* (scene-duration scene) fps)). A zero-duration scene has zero frames.

procedure

(frame-index->time frame-index [#:fps fps])

  (and/c rational? (>=/c 0))
  frame-index : exact-nonnegative-integer?
  fps : exact-positive-integer? = 30
Converts a zero-based frame index to the exact time (/ frame-index fps). This procedure does not know a scene and does not check whether the index is in range for one.

procedure

(scene-frame->bitmap scene    
  frame-index    
  [#:fps fps    
  #:camera camera    
  #:renderers renderers])  (is-a?/c bitmap%)
  scene : scene?
  frame-index : exact-nonnegative-integer?
  fps : exact-positive-integer? = 30
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
Renders one in-range scene frame to an aligned bitmap. Valid frame indices run from 0 through one less than (scene-frame-count scene). An out-of-range index raises an exception.

When camera is #f, the camera is sampled from the scene at the frame time. A supplied camera is used as one fixed override for the frame.

21.6 PNG and MP4 Output🔗

The procedures in this section perform external effects. Their names end in ! according to the project house style.

procedure

(render-frames! scene    
  output-directory    
  [#:fps fps    
  #:camera camera    
  #:renderers renderers    
  #:clean? clean?    
  #:workers workers])  (listof path?)
  scene : scene?
  output-directory : path-string?
  fps : exact-positive-integer? = 30
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
  clean? : boolean? = #t
  workers : exact-positive-integer? = 1
Creates output-directory when needed and writes every sampled frame as a PNG file. The returned paths are in frame order. A zero-duration scene writes no frames and returns an empty list, but directory creation and optional cleanup still occur.

When camera is #f, each frame samples the camera stored in the scene timeline. Supplying a camera uses that one static view for every frame and ignores camera pan or zoom requests during rendering. Pixel dimensions remain fixed either way.

When a sampled scene contains a nonempty formula, including a nonempty part of a formula assembly, and the built-in formula renderer is selected, frame rendering can invoke LaTeX and Poppler through latex-pict. A custom renderer placed before the defaults can replace that behavior for a formula leaf or for the complete assembly.

Names use at least six decimal digits:

  • "frame-000000.png"

  • "frame-000001.png"

  • "frame-000002.png"

When clean? is true, the procedure first deletes files in the output directory whose names match frame- followed by at least six digits and .png. Other files are preserved. When clean? is false, no cleanup is performed.

workers is a bounded worker-pool size. Its default, one, retains sequential output. On Racket 8.18 or later with parallelism enabled, more than one worker builds independent frame bitmaps through a parallel thread pool; one ordinary thread then encodes their PNG files, because Racket’s PNG encoder uses callbacks that cannot run in a parallel thread. On the package’s Racket 8.12 baseline, the same argument uses the compatible coroutine-thread implementation. In every case, returned paths remain in frame-index order and each frame keeps its deterministic filename. The built-in renderers synchronize their shared resources. A custom renderer used with more than one worker must itself be safe for concurrent calls.

procedure

(render-frames/report! scene 
  output-directory 
  [#:fps fps 
  #:camera camera 
  #:renderers renderers 
  #:clean? clean? 
  #:workers workers]) 
  render-diagnostics?
  scene : scene?
  output-directory : path-string?
  fps : exact-positive-integer? = 30
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
  clean? : boolean? = #t
  workers : exact-positive-integer? = 1
Writes frames with the same behavior as render-frames!, but returns a render-diagnostics value. Cache counts are deltas collected while this call runs from the built-in image, SVG, text, and formula resource caches; custom renderer caches are intentionally not inspected.

struct

(struct render-diagnostics (paths
    frame-count
    workers
    elapsed-milliseconds
    frame-milliseconds
    cache-hits
    cache-misses
    cache-evictions))
  paths : (listof path?)
  frame-count : exact-nonnegative-integer?
  workers : exact-nonnegative-integer?
  elapsed-milliseconds : (and/c real? (>=/c 0))
  frame-milliseconds : (listof (and/c real? (>=/c 0)))
  cache-hits : exact-nonnegative-integer?
  cache-misses : exact-nonnegative-integer?
  cache-evictions : exact-nonnegative-integer?
{

The report returned by render-frames/report!. paths and frame-milliseconds are both ordered by frame index, not completion order. workers is the active worker count, so a zero-frame render reports zero workers. The elapsed and per-frame durations include sampling, Pict/bitmap conversion, and PNG writing. Cache fields are performance telemetry only; they never affect the sampled scene or output pixels. }

21.6.1 Authored timelines and selected sections🔗

procedure

(section name start end)  authoring-section?

  name : symbol?
  start : finite-real?
  end : finite-real?
Constructs a named half-open authoring interval [start, end). The name is stable metadata; it does not become a scene Visual or change scene sampling. Both times must be finite and nonnegative, and end must be strictly greater than start. The enclosing timeline checks that the interval is inside its scene and does not overlap another section.

procedure

(cue name time)  cue?

  name : symbol?
  time : finite-real?
Constructs a named point marker in scene seconds. A cue is metadata only: it does not draw a marker or affect sampling. make-authored-timeline checks that it lies in the scene timeline.

procedure

(audio-cue source    
  [#:start start    
  #:source-start source-start    
  #:duration duration    
  #:gain gain    
  #:fade-in fade-in    
  #:fade-out fade-out])  audio-cue?
  source : path-string?
  start : finite-real? = 0
  source-start : finite-real? = 0
  duration : (or/c false/c finite-real?) = #f
  gain : finite-real? = 1
  fade-in : finite-real? = 0
  fade-out : finite-real? = 0
Constructs immutable audio-placement metadata. source is deliberately not opened or decoded, so construction and scene rendering remain independent of external codecs and files. start and source-start are nonnegative; when supplied, duration is positive. gain is a nonnegative linear multiplier. Fade lengths are nonnegative; a fade-out needs an explicit duration and neither fade may exceed it. During assemble-authored-mp4! or mux-authored-video!, FFmpeg trims the source, applies gain/fades, delays it to start, mixes all cues, and encodes AAC.

procedure

(subtitle start end text)  subtitle?

  start : finite-real?
  end : finite-real?
  text : string?
Constructs one audience-facing half-open caption interval. Both bounds must be inside the owning scene and end must be greater than start. The text is kept verbatim apart from CR/LF normalization when it is written to SRT or WebVTT.

procedure

(authoring-section? value)  boolean?

  value : any/c
Recognizes an immutable named half-open authoring interval.

procedure

(cue? value)  boolean?

  value : any/c
Recognizes immutable cue metadata.

procedure

(audio-cue? value)  boolean?

  value : any/c
Recognizes immutable audio-placement metadata.

procedure

(subtitle? value)  boolean?

  value : any/c
Recognizes immutable caption metadata.

procedure

(make-authored-timeline scene 
  [#:sections sections 
  #:cues cues 
  #:audio-cues audio-cues 
  #:subtitles subtitles]) 
  authored-timeline?
  scene : scene?
  sections : (listof authoring-section?) = null
  cues : (listof cue?) = null
  audio-cues : (listof audio-cue?) = null
  subtitles : (listof subtitle?) = null
Associates immutable authoring metadata with an ordinary scene. Section names and cue names must be unique. Sections must lie wholly within the scene, non-overlap, and retain their declared order in returned metadata. Cues and audio placements must start no later than the scene endpoint; subtitle ends must also lie inside it. The wrapped scene itself is unchanged and is available through authored-timeline-scene.

procedure

(timeline-section timeline section-or-name)  authoring-section?

  timeline : authored-timeline?
  section-or-name : (or/c symbol? authoring-section?)
Resolves a named section, or checks that a supplied section is one of the exact section values owned by timeline. An unknown name and a section taken from another timeline raise an exception.

procedure

(timeline-section-names timeline)  (listof symbol?)

  timeline : authored-timeline?
Returns section names in declared authoring order.

procedure

(timeline-section-frame-indices timeline 
  section-or-name 
  [#:fps fps]) 
  (listof exact-nonnegative-integer?)
  timeline : authored-timeline?
  section-or-name : (or/c symbol? authoring-section?)
  fps : exact-positive-integer? = 30
Returns the global scene-frame indices whose timestamps lie in the selected section’s half-open interval. At fps, the result begins at (ceiling (* start fps)) and ends before (ceiling (* end fps)), clipped to the scene’s available output frames. This is the same grid as a full render, not a new section-relative sampling grid.

procedure

(timeline-section-frame-count timeline 
  section-or-name 
  [#:fps fps]) 
  exact-nonnegative-integer?
  timeline : authored-timeline?
  section-or-name : (or/c symbol? authoring-section?)
  fps : exact-positive-integer? = 30
Returns the length of timeline-section-frame-indices.

procedure

(timeline-section-cues timeline    
  section-or-name)  (listof cue?)
  timeline : authored-timeline?
  section-or-name : (or/c symbol? authoring-section?)
Returns the timeline’s cues that lie in the selected section’s half-open interval, in their declared order.

procedure

(authored-timeline-metadata timeline)  immutable?

  timeline : authored-timeline?
Returns a renderer-independent immutable hash containing the scene duration and portable section, cue, audio-cue, and subtitle data. The hash intentionally excludes the scene structure, procedures, renderer caches, and decoded audio.

procedure

(authored-timeline? value)  boolean?

  value : any/c
Recognizes an immutable scene together with its authoring metadata.

procedure

(authored-timeline-scene timeline)  scene?

  timeline : authored-timeline?
Returns the ordinary immutable Scene wrapped by timeline.

21.6.1.1 Rendering selected frames and authored sections🔗

procedure

(write-subtitles! timeline    
  output-file    
  [#:format format])  path-string?
  timeline : authored-timeline?
  output-file : path-string?
  format : (or/c 'srt 'webvtt) = 'srt
Writes the timeline’s subtitles as SRT or WebVTT. It preserves internal caption line breaks and returns output-file. The resulting file can be passed to either MP4 assembly procedure; FFmpeg muxes it as an MP4 mov_text subtitle stream rather than drawing it into the video pixels.

procedure

(render-frame-indices! scene    
  frame-indices    
  output-directory    
  [#:fps fps    
  #:camera camera    
  #:renderers renderers    
  #:clean? clean?    
  #:workers workers])  (listof path?)
  scene : scene?
  frame-indices : (listof exact-nonnegative-integer?)
  output-directory : path-string?
  fps : exact-positive-integer? = 30
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
  clean? : boolean? = #t
  workers : exact-positive-integer? = 1
Renders selected global frame indices in the supplied order. The output files are locally numbered from "frame-000000.png", which makes the result directly suitable for encode-mp4!. Indices are validated before the output directory is changed. The camera, renderer, cleanup, worker, and diagnostic behavior is otherwise the same as render-frames!.

procedure

(render-frame-indices/report! scene 
  frame-indices 
  output-directory 
  [#:fps fps 
  #:camera camera 
  #:renderers renderers 
  #:clean? clean? 
  #:workers workers]) 
  render-diagnostics?
  scene : scene?
  frame-indices : (listof exact-nonnegative-integer?)
  output-directory : path-string?
  fps : exact-positive-integer? = 30
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
  clean? : boolean? = #t
  workers : exact-positive-integer? = 1
Like render-frame-indices!, returning normal rendering diagnostics. The report’s paths and per-frame times are ordered by the local output number.

procedure

(render-timeline-section! timeline 
  section-or-name 
  output-directory 
  [#:fps fps 
  #:camera camera 
  #:renderers renderers 
  #:clean? clean? 
  #:workers workers 
  #:cache-key cache-key 
  #:asset-files asset-files]) 
  (listof path?)
  timeline : authored-timeline?
  section-or-name : (or/c symbol? authoring-section?)
  output-directory : path-string?
  fps : exact-positive-integer? = 30
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
  clean? : boolean? = #t
  workers : exact-positive-integer? = 1
  cache-key : (or/c false/c 'auto symbol? string?) = 'auto
  asset-files : (listof path-string?) = null
Renders one named section using its global indices and local output filenames. The default 'auto key fingerprints the serializable scene value, section identity/bounds, FPS, camera/renderers, Racket version, and bytes of the declared asset-files. It reuses a matching ".animate-section-cache.rktd" manifest only if every expected PNG is still present. SCENE-DL built-in rate-function? values remain serializable; if an arbitrary procedure is present in the scene representation, automatic caching is disabled conservatively. An explicit symbol/string remains available for an author-managed key; #f disables caching and removes any existing section cache manifest. External dependencies are not discovered: declare them in asset-files or use a deliberate explicit key.

procedure

(render-timeline-section/report! timeline 
  section-or-name 
  output-directory 
  [#:fps fps 
  #:camera camera 
  #:renderers renderers 
  #:clean? clean? 
  #:workers workers 
  #:cache-key cache-key 
  #:asset-files asset-files]) 
  section-render-report?
  timeline : authored-timeline?
  section-or-name : (or/c symbol? authoring-section?)
  output-directory : path-string?
  fps : exact-positive-integer? = 30
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
  clean? : boolean? = #t
  workers : exact-positive-integer? = 1
  cache-key : (or/c false/c 'auto symbol? string?) = 'auto
  asset-files : (listof path-string?) = null
Like render-timeline-section!, returning a section-render-report. A fresh render contains normal render-diagnostics; a validated cache hit has #f diagnostics.

struct

(struct section-render-report (paths
    source-frame-indices
    cache-hit?
    diagnostics))
  paths : (listof path?)
  source-frame-indices : (listof exact-nonnegative-integer?)
  cache-hit? : boolean?
  diagnostics : (or/c false/c render-diagnostics?)
{

The report for one selected section. paths are locally numbered output paths; source-frame-indices records their corresponding global scene frames. The two lists have the same order and length. }

procedure

(automatic-section-cache-key timeline 
  section 
  #:fps fps 
  #:camera camera 
  #:renderers renderers 
  #:asset-files asset-files) 
  (or/c false/c string?)
  timeline : authored-timeline?
  section : authoring-section?
  fps : exact-positive-integer?
  camera : (or/c camera? false/c)
  renderers : pict-renderer-list?
  asset-files : (listof path-string?)
Computes the conservative automatic key used by selected rendering. It returns #f when the scene contains an arbitrary procedure, because its identity and source cannot be made a reliable content hash. Built-in rate-function? values are represented semantically and remain cacheable. The public rendering procedures normally call it themselves; it is exposed for diagnostics or a custom partial movie workflow.

21.6.2 Mathematical graphs and networks🔗

procedure

(graph-vertex name    
  [#:position position    
  #:label label    
  #:partition partition])  graph-vertex?
  name : symbol?
  position : (or/c vec2? false/c) = #f
  label : (or/c string? false/c) = #f
  partition : (or/c symbol? false/c) = #f
Constructs immutable vertex specification data. A manual graph layout requires a #:position for every vertex. Circle, tree, spring, layered, and planar layouts replace those positions deterministically. The partite layout requires a #:partition for every vertex. An optional string label becomes the ordinary child at the vertex’s 'label path.

procedure

(graph-vertex? value)  boolean?

  value : any/c
Recognizes a graph vertex specification.

procedure

(graph-edge source    
  target    
  [#:id id    
  #:label label    
  #:weight weight    
  #:curvature curvature    
  #:stroke stroke    
  #:stroke-width stroke-width])  graph-edge?
  source : symbol?
  target : symbol?
  id : (or/c symbol? false/c) = #f
  label : (or/c string? false/c) = #f
  weight : finite-real? = 1
  curvature : (or/c finite-real? false/c) = #f
  stroke : any/c = #f
  stroke-width : (or/c finite-real? false/c) = #f
Constructs one immutable edge specification. Source and target must later name declared vertices; they may be equal to make a loop. When #:id is omitted, its stable nested identity is formed as source followed by -> followed by target, such as 'A->B. An optional label follows the sampled straight, cubic, or loop route. weight is a positive finite multiplier for the graph’s default stroke width. A nonfalse curvature explicitly selects a signed cubic bow; otherwise the graph assigns lanes to parallel edges. stroke and stroke-width override their graph-wide defaults for this edge.

procedure

(graph-edge? value)  boolean?

  value : any/c
Recognizes a graph edge specification.

procedure

(graph-layout? value)  boolean?

  value : any/c
Recognizes one of the supported layout modes: 'manual, 'circle, 'tree, 'spring, 'layered, 'partite, or 'planar.

procedure

(graph vertices 
  edges 
  #:id id 
  [#:layout layout 
  #:layout-center layout-center 
  #:layout-radius layout-radius 
  #:tree-root tree-root 
  #:tree-x-spacing tree-x-spacing 
  #:tree-y-spacing tree-y-spacing 
  #:partite-order partite-order 
  #:spring-iterations spring-iterations 
  #:spring-attraction spring-attraction 
  #:spring-repulsion spring-repulsion 
  #:vertex-shape vertex-shape 
  #:vertex-size vertex-size 
  #:vertex-fill vertex-fill 
  #:vertex-stroke vertex-stroke 
  #:vertex-stroke-width vertex-stroke-width 
  #:vertex-label-offset vertex-label-offset 
  #:vertex-label-size vertex-label-size 
  #:vertex-label-color vertex-label-color 
  #:edge-stroke edge-stroke 
  #:edge-stroke-width edge-stroke-width 
  #:edge-curvature edge-curvature 
  #:parallel-edge-separation parallel-edge-separation 
  #:self-loop-radius self-loop-radius 
  #:edge-label-offset edge-label-offset 
  #:edge-label-size edge-label-size 
  #:edge-label-color edge-label-color]) 
  group-visual?
  vertices : (listof graph-vertex?)
  edges : (listof graph-edge?)
  id : symbol?
  layout : graph-layout? = 'manual
  layout-center : vec2? = origin
  layout-radius : finite-real? = 3
  tree-root : (or/c symbol? false/c) = #f
  tree-x-spacing : finite-real? = 3/2
  tree-y-spacing : finite-real? = 3/2
  partite-order : (or/c (listof symbol?) false/c) = #f
  spring-iterations : exact-positive-integer? = 60
  spring-attraction : finite-real? = 1
  spring-repulsion : finite-real? = 1
  vertex-shape : point-marker-shape? = 'circle
  vertex-size : finite-real? = 1/2
  vertex-fill : any/c = "aliceblue"
  vertex-stroke : any/c = "navy"
  vertex-stroke-width : finite-real? = 2
  vertex-label-offset : vec2? = (vec2 0 -2/5)
  vertex-label-size : finite-real? = 1/5
  vertex-label-color : any/c = "midnightblue"
  edge-stroke : any/c = "slategray"
  edge-stroke-width : finite-real? = 2
  edge-curvature : finite-real? = 0
  parallel-edge-separation : finite-real? = 1/3
  self-loop-radius : finite-real? = 4/5
  edge-label-offset : vec2? = (vec2 0 1/5)
  edge-label-size : finite-real? = 1/5
  edge-label-color : any/c = "darkslategray"
Creates an undirected graph as one ordinary immutable group tree. It has named top-level children 'edges and 'vertices. Each vertex is an ordinary group with 'body and optional 'label children. Each edge is a group with a derived 'line child and optional derived label. The normal nested-scene API can therefore target vertices, edges, and labels.

'manual requires positions in all vertex specifications. 'circle places declared vertices counter-clockwise from the positive x axis in list order. 'tree treats edge direction as parent to child: it requires exactly one fewer edge than vertices, one root without an incoming edge (or a matching #:tree-root), one incoming edge for every other vertex, and reachability from that root. Sibling order is declared edge order.

SCENE-DP adds deterministic construction-time layouts. 'spring is a fixed Jacobi force iteration with the supplied positive iteration, attraction, and repulsion values. 'layered is available only on digraph and requires an acyclic edge relation. 'partite puts the declared #:partition columns in #:partite-order or stable first-use order. 'planar searches for a crossing-free circular outerplanar embedding, exhaustively through eight vertices.

All dimensions are positive finite reals except the two stroke widths, which are nonnegative finite reals. #:edge-curvature, #:parallel-edge-separation, and #:self-loop-radius control the derived routes. Vertex and edge labels use the ordinary Pict text backend. Straight lines are shortened by half a vertex marker size at each endpoint; this keeps markers and directed arrowheads legible. Distinct sampled endpoints are required for nonloop edges.

procedure

(digraph vertices 
  edges 
  #:id id 
  [#:layout layout 
  #:layout-center layout-center 
  #:layout-radius layout-radius 
  #:tree-root tree-root 
  #:tree-x-spacing tree-x-spacing 
  #:tree-y-spacing tree-y-spacing 
  #:partite-order partite-order 
  #:spring-iterations spring-iterations 
  #:spring-attraction spring-attraction 
  #:spring-repulsion spring-repulsion 
  #:vertex-shape vertex-shape 
  #:vertex-size vertex-size 
  #:vertex-fill vertex-fill 
  #:vertex-stroke vertex-stroke 
  #:vertex-stroke-width vertex-stroke-width 
  #:vertex-label-offset vertex-label-offset 
  #:vertex-label-size vertex-label-size 
  #:vertex-label-color vertex-label-color 
  #:edge-stroke edge-stroke 
  #:edge-stroke-width edge-stroke-width 
  #:edge-curvature edge-curvature 
  #:parallel-edge-separation parallel-edge-separation 
  #:self-loop-radius self-loop-radius 
  #:edge-label-offset edge-label-offset 
  #:edge-label-size edge-label-size 
  #:edge-label-color edge-label-color]) 
  group-visual?
  vertices : (listof graph-vertex?)
  edges : (listof graph-edge?)
  id : symbol?
  layout : graph-layout? = 'manual
  layout-center : vec2? = origin
  layout-radius : finite-real? = 3
  tree-root : (or/c symbol? false/c) = #f
  tree-x-spacing : finite-real? = 3/2
  tree-y-spacing : finite-real? = 3/2
  partite-order : (or/c (listof symbol?) false/c) = #f
  spring-iterations : exact-positive-integer? = 60
  spring-attraction : finite-real? = 1
  spring-repulsion : finite-real? = 1
  vertex-shape : point-marker-shape? = 'circle
  vertex-size : finite-real? = 1/2
  vertex-fill : any/c = "aliceblue"
  vertex-stroke : any/c = "navy"
  vertex-stroke-width : finite-real? = 2
  vertex-label-offset : vec2? = (vec2 0 -2/5)
  vertex-label-size : finite-real? = 1/5
  vertex-label-color : any/c = "midnightblue"
  edge-stroke : any/c = "slategray"
  edge-stroke-width : finite-real? = 2
  edge-curvature : finite-real? = 0
  parallel-edge-separation : finite-real? = 1/3
  self-loop-radius : finite-real? = 4/5
  edge-label-offset : vec2? = (vec2 0 1/5)
  edge-label-size : finite-real? = 1/5
  edge-label-color : any/c = "darkslategray"
Like graph, but each derived line is an ordinary arrow whose direction is the declared source to target order. The layout and style keywords have the same meaning as for graph.

procedure

(graph-vertex-partition vertex)  (or/c symbol? false/c)

  vertex : graph-vertex?
Returns the vertex’s optional partite-layout partition name.

procedure

(graph-edge-weight edge)  finite-real?

  edge : graph-edge?
Returns the edge’s positive stroke-weight multiplier.

procedure

(graph-edge-curvature edge)  (or/c finite-real? false/c)

  edge : graph-edge?
Returns the optional explicit signed curvature. #f selects automatic parallel-edge routing.

procedure

(graph-edge-stroke edge)  any/c

  edge : graph-edge?
Returns the optional per-edge stroke override.

procedure

(graph-edge-stroke-width edge)  any/c

  edge : graph-edge?
Returns the optional per-edge cosmetic stroke-width override.

procedure

(graph-vertices-path graph-id)  visual-path?

  graph-id : symbol?
Returns (list graph-id 'vertices).

procedure

(graph-edges-path graph-id)  visual-path?

  graph-id : symbol?
Returns (list graph-id 'edges).

procedure

(graph-vertex-path graph-id vertex-id)  visual-path?

  graph-id : symbol?
  vertex-id : symbol?
Returns (list graph-id 'vertices vertex-id), the ordinary target for operations such as move-to.

procedure

(graph-edge-path graph-id edge-or-id)  visual-path?

  graph-id : symbol?
  edge-or-id : (or/c graph-edge? symbol?)
Returns (list graph-id 'edges edge-id), using an edge specification’s stable identity when one is supplied.

procedure

(graph-bfs edges    
  source    
  [#:directed? directed?])  (listof symbol?)
  edges : (listof graph-edge?)
  source : symbol?
  directed? : boolean? = #t
Returns the stable breadth-first vertex visitation order from source. The declared edge-list order breaks ties. With #:directed? #f, every edge contributes both adjacency directions. This creates no mutation or animation request.

procedure

(graph-dfs edges    
  source    
  [#:directed? directed?])  (listof symbol?)
  edges : (listof graph-edge?)
  source : symbol?
  directed? : boolean? = #t
Returns the stable depth-first vertex visitation order using declared edge-list order for neighbours.

procedure

(graph-shortest-path edges 
  source 
  target 
  [#:directed? directed?]) 
  (or/c (listof symbol?) false/c)
  edges : (listof graph-edge?)
  source : symbol?
  target : symbol?
  directed? : boolean? = #t
Returns one declaration-order tie-broken unweighted shortest path, including its source and target, or #f when no path exists.

Graph edge computation is a pure sampled dependency: it reads the current world positions of its named vertex groups and reconstructs local straight, cubic, or loop geometry. It therefore works at an arbitrary requested scene time and does not depend on previously rendered frames. Whole-graph affine transforms are composed once into both vertices and edges. A graph currently must be a top-level scene Visual; an outer arbitrary group cannot yet rewrite the graph’s stored endpoint paths. }

21.6.3 MP4 encoding and media assembly🔗

procedure

(encode-mp4! frames-directory    
  output-file    
  [#:fps fps])  path-string?
  frames-directory : path-string?
  output-file : path-string?
  fps : exact-positive-integer? = 30
Runs the ffmpeg executable found on PATH. It reads "frame-%06d.png" from frames-directory and writes an H.264 MP4 file with yuv420p pixel format. An existing output file is overwritten.

The input sequence should start at "frame-000000.png" and be contiguous. render-frames! produces the expected sequence.

The procedure returns output-file after FFmpeg succeeds. It raises an exception when FFmpeg is not found or the process fails.

procedure

(assemble-authored-mp4! timeline 
  frames-directory 
  output-file 
  [#:fps fps 
  #:subtitle-file subtitle-file]) 
  path-string?
  timeline : authored-timeline?
  frames-directory : path-string?
  output-file : path-string?
  fps : exact-positive-integer? = 30
  subtitle-file : (or/c false/c path-string?) = #f
Encodes one locally numbered PNG sequence and applies the authored timeline’s audio cues in the same FFmpeg invocation. Each cue can select a source offset and duration, apply gain/fades, and delay itself on the output timeline. When a supplied SRT/WebVTT subtitle file is supplied, it becomes an MP4 mov_text stream. The visual sequence must begin at "frame-000000.png"; source audio and subtitle files are checked when this external operation runs.

procedure

(mux-authored-video! timeline 
  input-video 
  output-file 
  [#:subtitle-file subtitle-file]) 
  path-string?
  timeline : authored-timeline?
  input-video : path-string?
  output-file : path-string?
  subtitle-file : (or/c false/c path-string?) = #f
Applies the same authored audio and captions to an existing visual MP4 without re-encoding its video stream. It maps the input’s visual stream only: any pre-existing audio in input-video is intentionally replaced by the timeline’s mixed audio (or omitted when the timeline has no audio cues).

procedure

(concatenate-mp4! partial-movies    
  output-file)  path-string?
  partial-movies : (non-empty-listof path-string?)
  output-file : path-string?
Uses FFmpeg’s concat demuxer to stream-copy compatible partial MP4 files into one visual movie. Partials must have matching codecs and stream layout; the visual-only files made by encode-mp4! meet that requirement.

procedure

(render-authored-mp4! timeline 
  work-directory 
  output-file 
  [#:fps fps 
  #:camera camera 
  #:renderers renderers 
  #:workers workers 
  #:cache-key cache-key 
  #:asset-files asset-files 
  #:subtitle-file subtitle-file 
  #:subtitle-format subtitle-format]) 
  path-string?
  timeline : authored-timeline?
  work-directory : path-string?
  output-file : path-string?
  fps : exact-positive-integer? = 30
  camera : (or/c camera? false/c) = #f
  renderers : pict-renderer-list? = default-pict-renderers
  workers : exact-positive-integer? = 1
  cache-key : (or/c false/c 'auto symbol? string?) = 'auto
  asset-files : (listof path-string?) = null
  subtitle-file : (or/c false/c 'auto path-string?) = 'auto
  subtitle-format : (or/c 'srt 'webvtt) = 'srt
Renders a complete authored production incrementally. The timeline must have at least one named section; sorted sections must begin at zero, be contiguous, and end at the scene duration. Each section is rendered into a stable local subdirectory of work-directory. A valid PNG cache plus matching partial-MP4 manifest reuses that section’s visual movie; an invalidated section alone is rendered and encoded again. The visual partials are concatenated, then the final movie receives all authored audio. With the default 'auto subtitle-file, nonempty timeline subtitles are written below the work directory in the requested format and muxed automatically. Pass #f to omit captions or a path to use a prewritten file.

Automatic reuse deliberately shares the selected-section cache’s conservative boundary: it fingerprints declared assets but cannot discover arbitrary files, font/TeX inputs, or an FFmpeg build, and cannot safely hash procedures. Use #:asset-files, a versioned explicit key, or #f according to the production’s dependency model.

21.6.4 Project execution🔗

procedure

(execute-prepared-project! 
  prepared 
  [#:protected-frame-roots protected-frame-roots 
  #:open-after? open-after?]) 
  project-execution-report?
  prepared : prepared-project?
  protected-frame-roots : (listof path?) = '()
  open-after? : boolean? = #t
Executes a prepared project through its already normalized frame, cache, encoder, media, and output plans. Directories are created lazily. The result records rendered/reused frames and segments, media work, cache events, tools, warnings, and the atomically installed artifact paths.

procedure

(project-execution-report? value)  boolean?

  value : any/c
Recognizes the immutable outcome of a completed project render.

21.7 Errors and Validation🔗

Most public constructors and operations check their arguments and raise contract exceptions for invalid input. Important checks include:

  • World coordinates, rotations, times, dimensions, and path fractions must be finite.

  • Path fractions must lie from zero through one, with start no greater than end.

  • A non-full partial path needs a finite computed total length.

  • Path interpolation progress must lie from zero through one.

  • Strictly morphing paths must have corresponding subpath counts, closure values, segment counts, and segment kinds.

  • Normalized morphing still requires equal subpath counts, corresponding closure values, and corresponding point-only or nonempty status.

  • Limited normalization does not reverse traversal, rotate a closed starting point, reorder subpaths, change closure, or add drawn geometry to a point-only subpath.

  • Shape dimensions, text font sizes, and scale factors must be positive.

  • An arrow needs distinct finite endpoints. Tip length and tip width must be positive finite values; stroke width must be nonnegative.

  • An axis range needs finite bounds with minimum less than maximum, a positive finite computed span, zero in the interval, and a positive finite tick step.

  • Axes x and y lengths, resulting unit lengths, and tip dimensions must be positive finite values. Tick size and stroke width must be nonnegative, and tip flags must be Boolean.

  • Arrow point-at progress must lie from zero through one. Axes coordinate inputs and inverse-conversion points must be finite.

  • Function sampling requires an axes Visual, a procedure accepting one argument, a finite increasing x interval, an exact sample count of at least two, a Boolean clipping flag, either #f or a nonnegative finite maximum jump, and a documented interpolation symbol.

  • A sampled function result must be a real number or #f. Non-finite real results and #f create gaps. Another result, or an exception from the procedure, is reported with the sample x value.

  • A parameter range needs distinct finite endpoints whose ordered difference remains a nonzero finite real. Increasing and decreasing endpoint order are both valid.

  • Parametric sampling requires an axes Visual, a procedure accepting one argument, a parameter range, an exact sample count of at least two, a Boolean clipping flag, an optional nonnegative finite maximum distance, and a documented interpolation symbol.

  • A parametric sample must be one vec2 or #f. Another result, an invalid result count, or an exception is reported with the corresponding parameter value.

  • A data series must be a proper ordered list of vec2 values and #f gaps. Its maximum-distance option must be #f or a nonnegative finite real.

  • Coordinate-curve interpolation must be 'linear or 'smooth.

  • Plain-text content must be a string without carriage returns or newline characters. An empty string is allowed.

  • A text font face must be a string or #f. Font family, style, weight, and horizontal and vertical alignments must use the documented symbols.

  • Formula source and preamble must be strings. Formula mode and anchor alignment must use the documented symbols. Multiline and empty formula source are valid.

  • Formula document-class and Preview options must be ordered lists of symbols or strings. The document-class options may select at most one distinct standard size among 10pt, 11pt, and 12pt.

  • A formula-part name must be a symbol and must equal the identity of its formula Visual.

  • Formula-part names must be unique within one formula assembly, and the assembly identity must differ from every local part name. A formula assembly’s own scale must be uniform.

  • A formula correspondence requires source and destination formula assemblies. Every match must name an existing part on both sides, and no source or destination name may be reused.

  • transform-formula-parts requires the correspondence source identity to name a present formula assembly. Its current ordered local names must equal the correspondence source names exactly.

  • The correspondence destination parts must be valid under the current source assembly identity. In particular, no destination part may reuse that top-level identity.

  • Rendering a nonempty formula can fail when latex-pict, LaTeX, Poppler, a requested document class, or a requested LaTeX package is unavailable, or when the source is invalid LaTeX.

  • Formula source and preamble are passed to an external TeX process. The library does not sandbox untrusted LaTeX input.

  • A group accepts only affine children. Its own scale must be uniform.

  • Every identity in a built-in group tree must be a symbol. Direct siblings must be distinct, and a group identity must differ from every descendant. Equal local identities in separate branches are allowed; complete nested paths remain distinct. Custom affine Visuals are treated as leaves.

  • A custom affine child used in a group must return an affine transform, keep its reference position consistent with the transform translation, preserve identity during transform replacement, and install the exact requested transform.

  • Global opacity must be a finite real from zero through one.

  • Stroke widths must be nonnegative.

  • Path subpaths and segments must use supported semantic path values.

  • Cubic segment controls and endpoints must be vec2 values.

  • Polyline paths need at least two points; polygon paths need at least three; cubic-bezier-path needs at least one cubic segment.

  • A line Visual needs two distinct endpoints in one containing coordinate system.

  • Empty path geometry has no bounds or center.

  • Top-level Visual identities must be symbols and unique within a scene state. Each built-in group tree requires distinct direct siblings and no reuse of an ancestor identity. A custom affine Visual is treated as one leaf.

  • A create or fade-in identity must be absent before its play clip.

  • Other animation targets must be present in the prepared clip start state.

  • create and uncreate require built-in path Visuals with finite computed local lengths.

  • morph-to requires a present built-in path Visual and strictly compatible destination geometry.

  • morph-to-normalized requires a present built-in path Visual and a destination supported by limited normalization.

  • morph-to-aligned requires a present built-in path Visual and one positive finite closed source/destination loop for automatic correspondence before normalization.

  • morph-to-open-aligned requires a present built-in path Visual and one positive finite open source/destination subpath for automatic endpoint-direction correspondence before normalization.

  • morph-to-open-compound-aligned requires a present built-in path Visual, equal nonzero source/destination subpath counts, and positive finite open subpaths throughout before global pairing and normalization.

  • morph-to-compound-aligned requires a present built-in path Visual, equal nonzero source/destination subpath counts, and positive finite closed loops throughout before global pairing and normalization.

  • Rotation and scale requests require an affine Visual. A built-in group accepts only a uniform scale endpoint.

  • Opacity requests require a Visual implementing gen:opacity-visual. Its opacity must satisfy opacity?.

  • A custom visual-with-opacity result must remain a Visual, preserve identity, implement the opacity protocol, and install the requested numeric opacity.

  • Two simultaneous requests cannot change the same target component. Presence conflicts are checked as well as value-component conflicts.

  • Camera pan centers and deltas must be vec2 values. Camera zoom targets and factors must be positive finite reals. A relative zoom must also produce a positive finite visible world width.

  • One pan and one zoom may share a play clip. Two pan requests or two zoom requests in one clip are rejected as duplicate camera components.

  • A renderer support result must be Boolean.

  • A Pict renderer result must be a Pict.

  • A layout box needs finite coordinates with left no greater than right and bottom no greater than top. Layout gaps must be finite and nonnegative.

  • Layout operations require a valid camera, an ordered renderer list, and Visuals whose position updates preserve identity and install the exact requested vec2 position.

  • Layout alignment symbols must be 'left, 'center, or 'right horizontally and 'bottom, 'center, or 'top vertically.

  • Scene sample times and frame indices must be in range.

Style values such as fill, stroke, and camera background are deliberately opaque at the model boundary. A rendering adapter may reject them later.

21.8 Determinism and Immutability🔗

The built-in coordinate, path, transform, camera, Visual, arrow, axis-range, axes, parameter-range, sampled-graph, parametric-curve, data-plot, plain-text, formula, formula-part, formula-assembly, formula-correspondence, group, layout-box, scene-state, visual animation request, camera-animation request, and scene values are immutable. Group child order, formula part and match order, opacity interpolation, formula-part transition planning, path interpolation, path length, partial extraction, and morph normalization depend only on explicit model values and significant stored order.

Cubic length approximation uses fixed tolerances, fixed midpoint subdivision, and a fixed maximum depth. Morph normalization always converts lines with the same one-third and two-thirds controls. It then splits the longest current cubic at parameter one half. Equal approximate lengths are resolved by taking the earliest segment in traversal order. The same numeric inputs therefore produce the same normalized model values.

Plain-text content, font requests, color, alignment, and transforms are explicit immutable values. Repeated text rendering is deterministic within one fixed Racket, operating-system, font-installation, and rendering environment. Exact font substitution, glyph metrics, hinting, and rasterized pixels can differ between platforms or when installed fonts change. The semantic text value does not hide that platform dependency.

Formula source, mode, size, preamble, ordered options, alignment, and transforms are explicit immutable values. Repeated formula rendering is deterministic only within one fixed Racket, latex-pict, LaTeX, Poppler, document-class, package, font, and rendering environment. Different tool versions can change spacing, glyph outlines, metrics, or rasterized pixels. The semantic formula value does not hide those external dependencies.

Formula assemblies keep an explicit local part order and perform no automatic spacing or token matching. Formula correspondences keep an explicit ordered one-to-one match list and perform no same-name inference. Unmatched-name queries therefore depend only on the two stored part orders and the stored match list.

Formula-part transition layer order is fixed: unmatched source parts, explicit matches, then unmatched destination parts. Temporary names are allocated from a fixed prefix and deterministic numeric sequence while avoiding endpoint names. A changed match always places its moving source layer before its moving destination layer. The same current source assembly and correspondence therefore produce the same sampled semantic part values.

Arrow endpoint order, midpoint anchoring, tip flags, and tip dimensions are explicit immutable values. Axis bounds, tick steps, tick order, local interval lengths, and coordinate conversion are likewise explicit. The same range and step always produce the same ordered nonzero tick values. Coordinate conversion uses only the stored transform and lengths; rotated inverse conversions may be inexact because they use trigonometric operations.

Coordinate-curve sampling uses explicit closed domains, exact sample counts, clipping flags, distance rules, and interpolation symbols. Function samples are processed in increasing x order. Parametric samples follow the stored parameter order, which may increase or decrease. Data samples follow their explicit list order. Sampling procedures are called only during construction and are not retained. The same deterministic procedures, point values, and options therefore produce the same semantic path geometry; a procedure that depends on hidden mutable state is outside that guarantee.

Linear interpolation stores accepted line segments directly. Smooth interpolation uses fixed Catmull-Rom-to-cubic formulas, a fixed two-point rule, and deterministic control clamping after clipping. The same accepted coordinate runs therefore produce the same line or cubic model values.

Relative layout is deterministic when the selected camera, renderer list, and Visual implementations are deterministic. It measures complete local Pict extents, not hidden ink bounds, and computes all displacements from explicit world-coordinate boxes. Different fonts, TeX installations, custom renderer metrics, or camera-dependent renderers can produce different boxes. Use the same rendering environment for layout and final output.

Sampling is deterministic when custom Visual methods, easing procedures, and renderers are deterministic. Fade introduction and removal use explicit structural endpoint rules; they do not depend on hidden clocks or renderer state. The library cannot force a third-party Visual or renderer implementation to be immutable or deterministic. Custom implementations should return fresh values from update methods and should not depend on hidden mutable state.

Nested group transforms are resolved from explicit parent and child values in significant tree order. The same renderer list is propagated recursively. The library does not use a process-global Visual identity counter or a mutable renderer registry. Renderer order, top-level drawing order, and group child order are explicit values.

Every scene clip stores complete Visual and camera start states. Camera pan and zoom are sampled only from those explicit values, clip progress, and easing. Rendering with no camera override samples that timeline; rendering with an override uses one explicit fixed camera. Neither mode depends on an earlier rendered frame.

Filesystem output and FFmpeg invocation are isolated in procedures ending in !.