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
procedure
(pict-renderer? value) → boolean?
value : any/c
procedure
(pict-renderer-supports? renderer visual) → boolean?
renderer : pict-renderer? visual : visual?
procedure
(pict-renderer-render renderer visual camera) → pict? renderer : pict-renderer? visual : visual? camera : camera?
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
value
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?
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
'left 'center 'right
These symbols select a horizontal coordinate of a layout box.
procedure
(layout-vertical-alignment? value) → boolean?
value : any/c
'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?
procedure
(layout-box-height box) → (and/c finite-real? (>=/c 0))
box : layout-box?
procedure
(layout-box-center box) → vec2?
box : layout-box?
procedure
(layout-box-anchor? value) → boolean?
value : any/c
'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?
procedure
(visual-layout-box visual [ #:camera camera #:renderers renderers]) → layout-box? visual : visual? camera : camera? = default-camera renderers : pict-renderer-list? = default-pict-renderers
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
procedure
(indicate-request? value) → boolean?
value : any/c
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
procedure
(flash-request? value) → boolean?
value : any/c
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
procedure
(focus-on-request? value) → boolean?
value : any/c
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
procedure
(show-passing-flash-request? value) → boolean?
value : any/c
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
procedure
(grow-from-center visual) → grow-from-center-request?
visual : (and/c visual? affine-visual? opacity-visual?)
procedure
(grow-from-center-request? value) → boolean?
value : any/c
procedure
(grow-arrow visual) → grow-arrow-request?
visual : arrow-visual?
procedure
(grow-arrow-request? value) → boolean?
value : any/c
procedure
(draw-border-then-fill visual) → draw-border-then-fill-request?
visual : path-visual?
procedure
(draw-border-then-fill-request? value) → boolean?
value : any/c
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
procedure
(transform-from-copy-request? value) → boolean?
value : any/c
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
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
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
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
procedure
(frame-index->time frame-index [#:fps fps])
→ (and/c rational? (>=/c 0)) frame-index : exact-nonnegative-integer? fps : exact-positive-integer? = 30
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
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
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
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?
procedure
name : symbol? time : finite-real?
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
procedure
start : finite-real? end : finite-real? text : string?
procedure
(authoring-section? value) → boolean?
value : any/c
procedure
(audio-cue? value) → boolean?
value : any/c
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
procedure
(timeline-section timeline section-or-name) → authoring-section?
timeline : authored-timeline? section-or-name : (or/c symbol? authoring-section?)
procedure
(timeline-section-names timeline) → (listof symbol?)
timeline : authored-timeline?
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
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
procedure
(timeline-section-cues timeline section-or-name) → (listof cue?) timeline : authored-timeline? section-or-name : (or/c symbol? authoring-section?)
procedure
(authored-timeline-metadata timeline) → immutable?
timeline : authored-timeline?
procedure
(authored-timeline? value) → boolean?
value : any/c
procedure
(authored-timeline-scene timeline) → scene?
timeline : authored-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
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
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
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
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
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?)
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
procedure
(graph-vertex? value) → boolean?
value : any/c
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
procedure
(graph-edge? value) → boolean?
value : any/c
procedure
(graph-layout? value) → boolean?
value : any/c
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"
'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"
procedure
(graph-vertex-partition vertex) → (or/c symbol? false/c)
vertex : graph-vertex?
procedure
(graph-edge-weight edge) → finite-real?
edge : graph-edge?
procedure
(graph-edge-curvature edge) → (or/c finite-real? false/c)
edge : graph-edge?
procedure
(graph-edge-stroke edge) → any/c
edge : graph-edge?
procedure
(graph-edge-stroke-width edge) → any/c
edge : graph-edge?
procedure
(graph-vertices-path graph-id) → visual-path?
graph-id : symbol?
procedure
(graph-edges-path graph-id) → visual-path?
graph-id : symbol?
procedure
(graph-vertex-path graph-id vertex-id) → visual-path?
graph-id : symbol? vertex-id : symbol?
procedure
(graph-edge-path graph-id edge-or-id) → visual-path?
graph-id : symbol? edge-or-id : (or/c graph-edge? symbol?)
procedure
(graph-bfs edges source [ #:directed? directed?]) → (listof symbol?) edges : (listof graph-edge?) source : symbol? directed? : boolean? = #t
procedure
(graph-dfs edges source [ #:directed? directed?]) → (listof symbol?) edges : (listof graph-edge?) source : symbol? directed? : boolean? = #t
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
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
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
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
procedure
(concatenate-mp4! partial-movies output-file) → path-string? partial-movies : (non-empty-listof path-string?) output-file : path-string?
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
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
procedure
(project-execution-report? value) → boolean?
value : any/c
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 !.