Monocurl
Download

std.mesh

mesh.mcl

Reference for the symbols exported by mesh.mcl.

Index

Primitive Constructors

Three D Primitives

Visual / Graphical

Text / Labels

Graphing

Layout / Grouping

Transform Operators

operator shiftimportant Translate a mesh by a vector. operator strokeimportant Set stroke color and optional stroke width. operator fillimportant Set fill color. operator colorimportant Recolor both fill and stroke where applicable. operator tagimportant Replace mesh tags, optionally filtered by existing tags. operator point_mapimportant Map every point of a mesh through a function. operator centerimportant Move a mesh so its center lies at a point. operator to_sideimportant Move a mesh near one side of the camera frame. operator to_cornerimportant Move a mesh near a corner of the camera frame. operator next_toimportant Place a mesh next to a reference mesh. operator tag_filterimportant Keep only mesh leaves matching a tag filter. operator scale Scale a mesh uniformly or per axis. operator rotate Rotate a mesh around an axis and optional pivot. operator fade Multiply mesh opacity by an opacity value. operator dotted Set dotted stroke color. operator normal_hint Override the normal hint used for rendering or strokes. operator textured Apply an image texture to a mesh. operator z_index Assign a draw ordering hint to a mesh. operator gloss Add glossy lighting amount to a mesh. operator color_map Map mesh colors through a function. operator uv_map Map mesh UV coordinates through a function. operator tag_map Map mesh tags through a function. operator subset_map Apply a mapping function only to tag-filtered subsets. operator uprank Promote lower-dimensional topology into higher-dimensional topology. operator downrank Demote higher-dimensional topology into lower-dimensional topology. operator wireframe Convert surface-like geometry to wireframe display. operator dashed Convert strokes to dashed strokes. operator subdivide Subdivide mesh geometry for smoother downstream transforms. operator tesselated Tessellate mesh geometry to the requested depth. operator extrude Extrude a mesh by a delta vector. operator revolve Revolve mesh geometry around an axis rotation. operator camera_transfer Keep a mesh fixed relative to the frame while camera changes. operator orient_to_camera Rotate a mesh tree so its local XY plane faces the camera. operator matched_edge Place one edge of a mesh against an edge of a reference mesh. operator projected Project a screen-space point along a ray into mesh space. operator in_space Interpret a mesh inside a local coordinate space. function tag_split Split a mesh into [matching, non_matching] by tag filter. function mesh_collapse Collapse nested mesh lists into a flatter mesh. operator contour_separate Separate contours so morphing can treat them independently. function trans Compute an intermediate Trans morph value between two meshes. function bend Compute an intermediate Bend morph value between two meshes.

Queries

Primitive Constructors

importantconstructor

A circle centered at the origin in the XY plane. Apply stroke or fill operators to style it, and shift to reposition.

let Circle = |radius, samples = 64| ...
samplesnumber of line segments used to approximate the curve (default 64)
imagedoc-mesh-circle-1.mcl
rendered monocurl scene
mesh c = fill{alpha{0.15} CYAN} stroke{CYAN, 2} Circle(1.4)
importantconstructor

A square centered at the origin with sides parallel to the axes.

let Square = |width| ...
imagedoc-mesh-square-1.mcl
rendered monocurl scene
mesh box = fill{alpha{0.28} ORANGE} stroke{ORANGE, 2} Square(1.7)
importantconstructor

An axis-aligned rectangle centered at the origin.

let Rect = |size| ...
size[width, height]
imagedoc-mesh-rect-1.mcl
rendered monocurl scene
mesh card = fill{alpha{0.22} BLUE} stroke{BLUE, 2} Rect([2.6, 1.4])
importantconstructor

A directed arrow from start to end, with an arrowhead at the tip.

path_arc bends the shaft by rotating along a circular arc instead of a straight segment. Its sign is relative to normal; use 0 for a straight arrow.

let Arrow = |start = [0, 0, 0], end = [1, 0, 0], normal = 1b, path_arc = 0, tip_length = 1, tip_width = 1, double_headed = 0| ...
starttail position, default origin
endtip position, default [1, 0, 0]
normalpreferred plane normal for the arrow body
path_arcsigned arc angle in radians, default 0
tip_lengthmultiplier on the arrowhead length along the shaft (1 = default)
tip_widthmultiplier on the arrowhead width (1 = default)
double_headedtruthy to also draw a mirrored arrowhead at the tail
imagedoc-mesh-arrow-1.mcl
rendered monocurl scene
mesh straight = color{CYAN} Arrow(1.5l + 0.75u, 1.5r + 0.75u)
mesh curved = color{ORANGE} Arrow(1.5l, 1.5r, 1b, PI / 3)
mesh stubby = color{PURPLE} Arrow(1.5l + 0.85d, 1.5r + 0.85d, 1b, 0, 0.6, 1.7)
constructor

A single point in 3-D space, rendered as a viewport-facing dot.

Unlike most line/surface primitives, Dot has a visible default radius; topology dots created internally by other constructors are invisible unless styled.

let Dot = |point = [0, 0, 0]| ...
mesh a = color{RED} Dot(1.5l)
mesh b = color{BLUE} Dot(ORIGIN)
mesh c = color{GREEN} Dot(1.5r)
constructor

A filled annulus between two concentric circles in the XY plane.

The inner loop is authored as a hole, so fill/stroke operators style the ring as one surface with a boundary.

let Annulus = |inner, outer| ...
imagedoc-mesh-annulus-1.mcl
rendered monocurl scene
mesh ring = fill{alpha{0.25} CYAN} stroke{CYAN, 2} Annulus(0.65, 1.15)
constructor

A regular n-gon inscribed in a circle of the given circumradius, centered at the origin.

let RegularPolygon = |n, circumradius| ...
nclamped to at least 3 sides
imagedoc-mesh-regularpolygon-1.mcl
rendered monocurl scene
mesh pentagon = fill{alpha{0.25} TEAL} stroke{TEAL, 2} RegularPolygon(5, 1.3)
constructor

A closed polygon from an ordered list of vertices.

The vertex loop is tessellated into a filled surface. Use Polyline for an open path or downrank{} when you want only the boundary.

let Polygon = |vertices, normal_hint = 1b| ...
normal_hintpreferred face orientation; defaults to 1b
imagedoc-mesh-polygon-1.mcl
rendered monocurl scene
mesh poly = fill{alpha{0.2} GREEN} Polygon([LEFT, UP, RIGHT, DOWN])
constructor

An open polyline through the given vertices.

let Polyline = |vertices, normal_hint = 1b| ...
normal_hintpreferred stroke normal; defaults to 1b
imagedoc-mesh-polyline-1.mcl
rendered monocurl scene
mesh path = stroke{TEAL, 3} Polyline([1.2l, 0.4u, 1.2r])
constructor

A straight line segment between two points.

let Line = |start = [0, 0, 0], end = [1, 0, 0], normal = 1b| ...
normalpreferred stroke normal, used by lighting and topology transforms
imagedoc-mesh-line-1.mcl
rendered monocurl scene
mesh l = stroke{BLUE, 3} Line([-2, -1, 0], [2, 1, 0])
constructor

A straight dashed line segment between two points.

Convenience for dashed{lengths, offset} Line(start, end, normal). A scalar lengths uses the same dash and gap length; a [dash, gap] pair sets them independently. The result interpolates from a solid to a dashed line, so animating it dashes in -- a plain dashed{...} Line(...) renders dashed right away instead.

let DashedLine = |start = [0, 0, 0], end = [1, 0, 0], lengths = [0.2, 0.1], offset = 0, normal = 1b| ...
lengthsdash length or [dash, gap]
offsetdash phase offset
normalpreferred stroke normal
mesh guide = stroke{LIGHT_GRAY, 2} Line(1.5l, 1.5r)
slide "dash it in"
    guide = stroke{BLUE, 2} DashedLine(1.5l, 1.5r, [0.15, 0.08])
    play Lerp(0.8, [&guide])
constructor

Circular arc centered at the origin in the XY plane.

theta is [start_angle, end_angle] in radians. The sampled stroke includes both endpoints.

let Arc = |radius = 1, theta = [0, 3.14159265358979]| ...
theta[start, end] angles in radians
imagedoc-mesh-arc-1.mcl
rendered monocurl scene
mesh arc = stroke{CYAN} Arc(1, [0, PI])
constructor

Arc marker for the angle at vertex between the rays toward a and b.

Drawn in the XY plane as a stroke arc of the given radius, sweeping the shorter way from the vertex->a direction to the vertex->b direction. Set reflex truthy to mark the outer (>PI) angle instead. Style it with stroke{...} and pair it with a Tex/Label for the measure.

let Angle = |vertex, a, b, radius = 0.4, samples = 32, reflex = 0| ...
radiusarc radius in scene units
samplesnumber of segments approximating the arc
reflextruthy to mark the reflex (outer) angle instead of the inner one
imagedoc-mesh-angle-1.mcl
rendered monocurl scene
let O = 1.1l
mesh ray_a = stroke{DARK_GRAY, 2} Line(O, O + [2.4, 0, 0])
mesh ray_b = stroke{DARK_GRAY, 2} Line(O, O + [1.7, 1.7, 0])
mesh mark = stroke{CYAN, 3} Angle(O, O + 1r, O + 1u + 1r, 0.55)
constructor

Right-angle (square corner) marker at vertex, between the rays toward a and b.

Two short segments of length size forming an L in the XY plane, for perpendicularity marks on diagrams. Style with stroke{...}. The rays do not need to be exactly perpendicular; the marker is always a square of the given size.

let RightAngle = |vertex, a, b, size = 0.2| ...
sizeleg length of the corner marker in scene units
imagedoc-mesh-rightangle-1.mcl
rendered monocurl scene
let O = 0.7l + 0.7d
mesh ray_a = stroke{DARK_GRAY, 2} Line(O, O + [2.4, 0, 0])
mesh ray_b = stroke{DARK_GRAY, 2} Line(O, O + [0, 2.4, 0])
mesh mark = stroke{CYAN, 3} RightAngle(O, O + 1r, O + 1u, 0.35)
constructor

Rounded filled capsule between two cap centers.

radii may be one number for a constant-width capsule or [start_radius, end_radius] for a tapered capsule.

let Capsule = |start_center, end_center, radii = 0.4, normal = 1b| ...
radiisingle radius or [start_radius, end_radius]
normalpreferred plane normal
imagedoc-mesh-capsule-1.mcl
rendered monocurl scene
mesh pill = fill{alpha{0.18} BLUE} Capsule(LEFT, RIGHT, 0.25)
constructor

Filled triangle from three vertices.

normal_hint controls the preferred winding/lighting side.

let Triangle = |p, q, r, normal_hint = 1b| ...
normal_hintpreferred face orientation
imagedoc-mesh-triangle-1.mcl
rendered monocurl scene
mesh tri = fill{alpha{0.28} PURPLE} stroke{PURPLE, 2} Triangle(1.4l, 1.4r, 1.4u)

Three D Primitives

constructor

3-D sphere centered at the origin.

sample_depth controls subdivision; higher values add triangles quickly.

let Sphere = |radius, sample_depth = 2| ...
sample_depthsubdivision depth, clamped to at least 0
imagedoc-mesh-sphere-1.mcl
rendered monocurl scene
mesh floor = stroke{LIGHT_GRAY, 1} LineGrid([-1.6, 1.6, 9], [-1.6, 1.6, 9])
mesh globe = fill{alpha{0.5} BLUE} stroke{alpha{0.6} BLUE, 1} Sphere(1.1, 3)
camera = Camera([2.7, -2.5, 1.9], [0, 0, 0], [0, 0, 1])
constructor

Rectangular prism centered at the origin.

let RectangularPrism = |dimensions| ...
dimensions[width, height, depth]
constructor

Cylinder oriented along a direction.

The cylinder is centered at the origin. A zero direction falls back to the y axis.

let Cylinder = |radius, height, direction = 1u, sample_count = 32| ...
sample_countradial samples, clamped to at least 3
constructor

Cone from apex to base center.

let Cone = |apex = [0, 1, 0], base = [0, 0, 0], radius = 1, sample_count = 32| ...
sample_countradial samples, clamped to at least 3
constructor

Torus centered at the origin in the XY plane.

let Torus = |radii = [1, 0.3], samples = [48, 24]| ...
radii[major_radius, minor_radius]
samples[major_samples, minor_samples], each clamped to at least 3
constructor

Rectangular plane in the XY plane, offset along 1b.

let Plane = |dist = 0, size = [4, 4]| ...
size[width, height]

Visual / Graphical

importantconstructor

Sample a color function over a rectangular grid.

By default each visible cell gets one flat color sampled at the cell corner. Pass smooth = 1 to color vertices for smooth interpolation, or pass a callable as the fourth argument to use it as the mask while keeping flat colors. color_at receives (pos, [ix, iy]); mask receives pos.

let ColorGrid = |color_at, x_min_max_samples = [-1, 1, 21], y_min_max_samples = [-1, 1, 21], smooth = 0, mask = |pos| 1| ...
color_atfunction from cell 3d position and 2d index to RGBA color
x_min_max_samples[x_min, x_max, samples]
y_min_max_samples[y_min, y_max, samples]
smoothtruthy for vertex color interpolation, falsey for flat cells, or a mask function
maskoptional function deciding which positions render
mesh heat = ColorGrid(|p, idx| hsv(norm(p) / 2, 0.7, 0.9), [-2, 2, 60], [-1, 1, 30])
importantconstructor

Build a rectangular grid of line segments.

The result is one mesh with subdivided line topology, which makes later point_map and Trans operations smoother.

let LineGrid = |x_min_max_samples = [-1, 1, 21], y_min_max_samples = [-1, 1, 21], subdivision = 16| ...
x_min_max_samples[x_min, x_max, samples]
y_min_max_samples[y_min, y_max, samples]
subdivisionsubdivisions per grid segment
imagedoc-mesh-linegrid-1.mcl
rendered monocurl scene
mesh grid = stroke{LIGHT_GRAY} LineGrid([-2, 2, 9], [-1, 1, 5])
importantconstructor

Sample a mesh-producing function over a rectangular field.

mesh_at receives (pos, [ix, iy]); mask receives pos. Calls are batched internally, so this is the preferred way to build repeated arrows/glyphs on a grid.

let Field = |mesh_at, x_min_max_samples = [-1, 1, 21], y_min_max_samples = [-1, 1, 21], mask = |pos| 1| ...
mesh_atfunction from position and index to a mesh
x_min_max_samples[x_min, x_max, samples]
y_min_max_samples[y_min, y_max, samples]
maskoptional function deciding which subset of cells to include
mesh arrows = Field(|p, idx| Arrow(p, p + 0.2 * normalize(p)), [-2, 2, 12], [-1, 1, 7])
importantconstructor

Arrow vector field: an arrow at each grid point for the vector f(pos), with a length-normalisation mode and an optional colour-by-magnitude callback.

Thin wrapper over Field + Arrow. mode controls arrow length: "true" draws the raw vector; "normalized" (default) draws every arrow at length length; "clamped" draws the true direction with length capped at length. color_at receives (pos, magnitude) and returns an RGBA colour; leave it nil to keep the default arrow colour. mask receives pos.

let VectorField = |f, x_min_max_samples = [-1, 1, 11], y_min_max_samples = [-1, 1, 11], mode = "normalized", length = 0.15, color_at = nil, mask = |pos| 1, tip_length = 1, tip_width = 1| ...
ffunction from a 3-D position to a 3-D vector
x_min_max_samples[x_min, x_max, samples]
y_min_max_samples[y_min, y_max, samples]
mode"true", "normalized", or "clamped"
lengtharrow length ("normalized") or maximum length ("clamped"); ignored for "true"
color_atoptional (pos, magnitude) -> RGBA callback
maskoptional pos -> truthy filter
tip_lengthmultiplier on every arrowhead's length (1 = default)
tip_widthmultiplier on every arrowhead's width (1 = default)
imagedoc-mesh-vectorfield-1.mcl
rendered monocurl scene
mesh field = VectorField(|p| [-p[1], p[0], 0], [-2, 2, 13], [-2, 2, 13], "normalized", 0.18, |p, mag| [mag / 3, 0.4, 0.9, 1])
constructor

Bezier curve through control points, sampled as a 64-segment stroke.

With fewer than two control points this returns an empty mesh.

let Bezier = |control_points| ...
imagedoc-mesh-bezier-1.mcl
rendered monocurl scene
mesh curve = stroke{MAGENTA, 3} Bezier([1.4l, 1u, 1.4r])
constructor

Arrow-like vector from a tail by a delta.

The arrowhead and shaft proportions are adjusted for short vectors so fields stay legible.

let Vector = |delta = 1r, tail = [0, 0, 0], normal = 1b, tip_length = 1, tip_width = 1, double_headed = 0| ...
tip_lengthmultiplier on the arrowhead length (1 = default)
tip_widthmultiplier on the arrowhead width (1 = default)
double_headedtruthy to also draw a mirrored arrowhead at the tail
imagedoc-mesh-vector-1.mcl
rendered monocurl scene
mesh v = color{CYAN} Vector(0.8r + 0.4u, ORIGIN)
constructor

Simple line segment from tail to tail + delta.

Use this for dense fields when arrowheads would clutter the scene.

let HalfVector = |tail = [0, 0, 0], delta = 1r, normal = 1b| ...
constructor

Place a bundled or project image into the scene.

The image is rendered as a textured upright rectangle in the XY plane. name may be a bundled asset name or a project-relative path resolved by the runtime. Not available in web runtimes yet.

let Image = |name, center = [0, 0, 0], size = [1, 1]| ...
nameimage asset name or path, relative to the currently invoked scene or library
centerimage center
size[width, height]
mesh logo = Image("monocurl.png", ORIGIN, [1.2, 1.2])
constructor

Import an SVG file into mesh geometry.

filename should be a project-relative .svg file path, passed as a string such as "icons/play.svg" rather than pasted raw SVG markup. File imports resolve supported relative SVG references from the SVG file's folder. The importer handles ordinary solid-color fills and strokes best; unsupported SVG features such as gradients, filters, masks, and raster images may be ignored. SVG coordinates are y-down, so imported geometry is flipped into Monocurl's y-up scene space. At scale = 1, 100 SVG units map to 1 scene unit. Not available in web runtimes yet.

let Svg = |filename, scale = 1| ...
filenameproject-relative .svg file path
scalescene scale where 100 SVG units equal scale scene units
mesh icon = Svg("icons/play.svg", 1.2)

Text / Labels

importantconstructor

Plain text converted to mesh geometry.

Use Text for literal text. It still returns mesh geometry, so Write, Fade, tag_filter, and styling operators all apply. With the default font = nil, text is rendered through the existing LaTeX backend. Passing a string such as "Arial" uses system-font SVG outlines instead; a .ttf, .otf, .ttc, or .otc path is resolved relative to the scene file. Custom/system/font-file text fonts are not available in web runtimes yet; keep font = nil there. Apply text_tag{...} inside the text argument when only part of the rendered text should be addressable; apply tag{...} outside Text when the whole rendered label should share one identity. String escapes use %, not \: write %" for a quote, %% for a literal percent sign, and LaTeX-style backslashes directly.

let Text = |text, scale = 1, font = nil| ...
textstring/list text fragments; use text_tag{...} on fragments that need stable mesh tags after rendering
fontnil for the existing LaTeX-backed renderer, or a system font family / font file path for direct SVG font outlines
imagedoc-mesh-text-1.mcl
rendered monocurl scene
mesh title = center{UP} Text("Monocurl", 0.8)
importantconstructor

Math text converted through TeX into mesh geometry.

Tex renders TeX math (the body is already in math mode -- no $). It takes a raw string or a list of fragments; the list is concatenated with no separator, so write " + " and other spacing as its own fragment. text_tag{...} fragments, and the raw \text_tag{1,2}{...} / \tagN{...} markers, become tagged mesh contours for tag_filter, filtered styling, and TagTrans.

Monocurl strings escape with %, not \, so LaTeX commands are written directly ("\frac{a}{b}"); use %% for a literal percent. For non-math document structure use Latex; for Typst's lighter syntax use Typst.

let Tex = |tex, scale = 1| ...
texa TeX math string, or a list of string / text_tag{...} fragments
scaletext height in scene units
imagedoc-mesh-tex-1.mcl
rendered monocurl scene
mesh eq = center{ORIGIN} Tex("P(A \mid B) = \frac{P(B \mid A)\,P(A)}{P(B)}", 0.9)
importantconstructor

Typst markup and math compiled into mesh geometry (desktop only).

content is compiled by the bundled Typst engine, rendered to SVG, and converted to contours, so Write, Fade, TagTrans, tag_filter, and every styling operator behave exactly as they do for Tex. The page is shrink-wrapped (auto size, zero margin, transparent fill) so the geometry is cropped to the ink. Bundled fonts cover the Typst defaults: New Computer Modern for math, Libertinus Serif for text, DejaVu Sans Mono for code.

Reach for Typst over Tex when you want Typst's lighter math syntax (sum_(i=1)^n, mat(1, 0; 0, 1), cases(...)) or its prose markup (= Heading, *bold*, _italic_). Math lives in $...$; $ x $ with surrounding spaces is display style, $x$ is inline. Typst is not available in web runtimes -- a browser scene must use Tex or Text. #import, Typst packages, and file reads are not available to inline snippets.

Monocurl strings escape with %, not \, so Typst source is written directly ("$sum_(i=1)^n i$"); write %% for a literal percent and %n for a newline, since a string cannot span source lines. A list argument is joined with no separator -- ["= A", "= B"] becomes "= AB" -- so put the breaks in yourself: ["= Title", "%n%n", "body text"].

A fragment can be tagged three ways, all yielding ordinary mesh tags usable by tag_filter, filtered styling, and TagTrans:

  • text_tag{...} list fragments ([text_tag{1} "$a^2$", " + ", text_tag{2} "$b^2$"]) -- the portable form shared with Tex, and the only one that accepts a multi-component tag such as text_tag{[2, 7]}.
  • raw \tagN{...} or \text_tag{1,2}{...} markers inside the string.
  • the native Typst helper tag(n, body) supplied by the preamble: "#tag(1)[alpha] beta #tag(2)[gamma]". Inside math keep the # and wrap the body in its own $...$: "$ #tag(1)[$a^2$] + b^2 $". n is a single component in 0..=255.
let Typst = |content, scale = 1| ...
contenta Typst source string, or a list of string / text_tag{...} fragments
scaletext height in scene units; Typst("$x^2$") at scale 1 is close to Tex("x^2") at scale 1
imagedoc-mesh-typst-1.mcl
rendered monocurl scene
# `%n%n` is a paragraph break; a Monocurl string cannot contain a real newline
mesh note = center{ORIGIN} Typst("= Pythagoras%n%nFor a right triangle, $a^2 + b^2 = c^2$.", 0.5)
imagedoc-mesh-typst-2.mcl
rendered monocurl scene
# per-term colour via the native `#tag(n)[...]` helper; note the inner `$...$`
let palette = operator |t|
    color{PURPLE, |g| 3 in g}
    color{ORANGE, |g| 2 in g}
    color{BLUE, |g| 1 in g}
    t
mesh eq = center{ORIGIN} palette{} Typst("$ #tag(1)[$a^2$] + #tag(2)[$b^2$] = #tag(3)[$c^2$] $", 1)
imagedoc-mesh-typst-3.mcl
rendered monocurl scene
# Typst math shines on dense notation
mesh series = center{ORIGIN} Typst("$ sum_(k=1)^n k = (n(n+1)) / 2 $", 1)
importantoperator

Give an equation or label fragment a stable identity before it is rendered to contours.

text_tag{tag} fragment is the tool for equation choreography: it marks a slice of a Text / Tex / Latex / Typst argument so that every contour the backend produces for that slice carries tag. Those tags are then ordinary mesh tags -- tag_filter, filtered color{...} / stroke{...}, and TagTrans all key off them -- so "the x^2 term" stays addressable across a whole slide sequence even as the glyphs move and reshape.

text_tag{...} goes inside the constructor and tags only its fragment; tag{...} goes outside and relabels the entire rendered mesh. A raw string can carry the markers directly instead: \text_tag{1,2}{...} or the shorthand \tagN{...}.

The argument is a list of fragments, and the backend concatenates them with no separator -- ["a", "b"] renders as ab. Put spacing inside the strings (" + ", "%n"), not between list entries.

Nesting is allowed and the innermost tag owns any overlapping contour, so text_tag{1} ["(", text_tag{2} "x", ")"] gives the parentheses tag 1 and the x tag 2. A tag may be a list for several identities at once (text_tag{[2, 10]}); text_tag{[]} is a valid empty tag list.

let text_tag = operator |target, tag| ...
targetthe string-compatible fragment to tag
tagan integer, or a list of integers for multiple identities; [] is allowed
imagedoc-mesh-text-tag-1.mcl
rendered monocurl scene
# one palette keyed purely by tag, reused for every state of the equation
let palette = operator |t|
    color{MAGENTA, |g| 3 in g}
    color{ORANGE, |g| 2 in g}
    color{BLUE, |g| 1 in g}
    t
mesh eq = center{ORIGIN} palette{} Tex([text_tag{1} "x^2", " + ", text_tag{2} "2x", " + ", text_tag{3} "1"], 1)
imagedoc-mesh-text-tag-2.mcl
rendered monocurl scene
# raw markers in a plain string, and a multi-identity tag on the "1"
mesh eq = center{ORIGIN} color{ORANGE, |g| 9 in g} Tex("\tag1{a} + \text_tag{9}{1}", 1)
importantconstructor

Measurement marker drawn next to a target mesh.

Builds a stroke spanning the target's bounds perpendicular to dir, offset by buffer.

let Measure = |target, dir = 1d, buffer = 0.15| ...
mesh width = [seg, Measure(seg, DOWN), Label(seg, "w", DOWN)]
constructor

Full LaTeX fragment converted into mesh geometry.

Use this when the input needs LaTeX body structure beyond a single display formula -- an aligned block, \textbf / \text{} prose, enumerate, a tikzpicture. For a plain formula use Tex (no $, already in math mode). additional_preamble is inserted before \begin{document} for \usepackage{...} and font setup such as \usepackage{fontspec} on the system backend. Latex takes the same text_tag{...} / \tagN{...} markers as Tex.

Not available in web runtimes; a browser scene must use Text or Tex.

let Latex = |latex, scale = 1, additional_preamble = ""| ...
latexLaTeX body content, string/list text fragments, or text_tag{...} fragments
scaletext scale in scene units
additional_preambleextra LaTeX declarations inserted before \begin{document}
imagedoc-mesh-latex-1.mcl
rendered monocurl scene
mesh thm = center{ORIGIN} Latex("\textbf{Theorem.} Every ideal of $\mathbb{Z}$ is principal.", 0.6)
constructor

Curly brace spanning from start to end, bulging to one side, with an optional label.

Sampled as a smooth stroke polyline in the XY plane: it meets both endpoints tangent to the span and swells to depth at the midpoint, where a sharper tip points outward. By default the brace bulges to the right of the start->end direction (its -90 deg normal); pass direction to choose the bulge side explicitly. When label is a string, the result is [brace, text] with the label placed just past the tip.

let Brace = |start, end, depth = 0.25, direction = nil, samples = 101, label = nil, label_scale = 1, label_buffer = 0.12| ...
depthbulge height at the midpoint, in scene units
directionoptional bulge direction; the component along the span is removed
samplesnumber of segments in the brace stroke (clamped to at least 8)
labeloptional label string placed past the brace tip; nil for no label
label_scalelabel text scale
label_buffergap between the brace tip and the label
imagedoc-mesh-brace-1.mcl
rendered monocurl scene
mesh bar = center{0.5u} fill{alpha{0.2} BLUE} stroke{BLUE, 2} Rect([3, 0.7])
mesh bracket = center{0.4d} stroke{CYAN, 2.5} Brace(1.5l, 1.5r, 0.4, DOWN, 101, "width")
constructor

Text label placed relative to a target mesh.

The label is rendered as text, then placed outside the target in dir while staying centered on the target's orthogonal direction. Pass font as a system font name or font filename to use direct font outlines instead of the default LaTeX renderer.

let Label = |target, str, dir = 1u, scale = 1, buffer = 0.1, font = nil| ...
bufferdistance from target
fontoptional system font name or font filename; custom fonts are native-only and are not available on web
mesh labeled = [seg, Label(seg, "length", UP)]
constructor

Number rendered as text with optional formatting.

With decimal_places = nil, formatting uses compact %g-style output. Set include_sign truthy for a leading plus sign on positive values. Passing a system font family or font-file path renders direct font outlines rather than the built-in number glyphs; custom fonts are native-only and are not available on web.

let Number = |value, decimal_places = nil, include_sign = 0, font = nil| ...
decimal_placesoptional fixed decimal count
include_signinclude plus sign for positive values
fontoptional system font name or font filename
mesh n = Number(value, 2, 1, "Arial")

Graphing

importantoperator

Pre-fill axis options on an axis constructor.

This is a configuration operator; compose it before Axis1d, Axis2d, or Axis3d. It uses set_default internally, so axis settings interpolate cleanly when the axis is animated.

let axis_style = operator |target, axis, min, max, axis_title = nil, tick_spacing = 0.25, major_tick_rate = 4, label_map = (|x| x), arrow_extrusion = 0.2, tick_placement = nil| ...
axis"x", "y", or "z"
tick_spacingdistance between ticks in axis coordinates, or a list of exact tick positions (each drawn as a major tick, clipped to the axis range)
major_tick_rateevery nth tick is drawn/labelled as major (ignored when tick_spacing is an explicit list)
label_mapfunction from value to tick label
arrow_extrusionarrowhead length in scene units, or nil to hide the axis arrowheads entirely
tick_placementwhere tick marks sit relative to the axis line: "both" (default), "positive", "negative", or "centered" (half-length, straddling); nil means "both"
mesh axes = axis_style{"x", 0, 4, "x"} axis_style{"y", 0, 3, "y"} Axis2d()
mesh one_sided = axis_style{"x", 0, 4, "x", 1, 1, (|x| x), 0.2, "positive"} Axis2d()
importantconstructor

A labelled number line: a friendlier Axis1d where every tick is labelled by default.

Thin convenience over Axis1d. Unlike Axis1d/Axis2d, major_tick_rate defaults to 1, so every tick gets a number. Pass label_map = nil for an unlabelled ruler, or a |value| ... callable (for example |x| Number(x, 1)) for custom tick text. Set axis_title for a label at the positive end.

let NumberLine = |min = -5, max = 5, tick_spacing = 1, major_tick_rate = 1, axis_title = nil, label_map = (|x| x), basis = 1r, color = [0, 0, 0, 1]| ...
minleft end of the line in axis coordinates
maxright end of the line in axis coordinates
tick_spacingdistance between ticks, or a list of exact tick positions
major_tick_rateevery nth tick is drawn/labelled as major
axis_titleoptional title placed past the positive end
label_mapnil for no labels, or a function from value to tick label
basisscene-space direction and unit length of one axis step
coloraxis color
imagedoc-mesh-numberline-1.mcl
rendered monocurl scene
mesh line = center{0.6u} NumberLine(-3, 3, 1)
mesh titled = center{0.9d} NumberLine(-3, 3, 1, 3, "t")
importantconstructor

Two-dimensional coordinate axes, optionally with grid lines.

basis gives the scene-space x/y unit vectors for the graph. Use grid_color to draw grid lines; leave it nil for ticks only. Grid lines are already split into major/minor by each axis's major_tick_rate. In each axis style list, set the last slot (arrow_extrusion) to nil to hide that axis's arrowheads.

let Axis2d = |basis = [1r, 1u], color = [0, 0, 0, 1], grid_color = nil, x_axis = [-5, 5, nil, 0.25, 4, |x| x, 0.2], y_axis = [-5, 5, nil, 0.25, 4, |x| x, 0.2]| ...
imagedoc-mesh-axis2d-1.mcl
rendered monocurl scene
mesh axes = axis_style{"x", -2, 2, "x"} axis_style{"y", -1, 3, "f(x)"} Axis2d()
importantconstructor

Sample y = f(x) as a polyline in the XY plane.

Endpoints are included. Use in_space{...} to embed the graph into a custom axes coordinate system. Set fill to an RGBA colour to also shade the area between the curve and the x axis (this is ExplicitFuncDiff(f, |x| 0, ...) under the hood). Set endpoint_dots truthy to append visible Dots at the two ends. When either is used the result is a mesh list [ (fill,) curve (, dots) ] rather than a bare polyline. Where f(x) returns nil or a non-finite number (a pole, a hole, a piecewise gap), both the curve and the optional fill are split into separate pieces around the gap instead of drawing a vertical jump.

let ExplicitFunc = |f, x_min_max_samples = [-5, 5, 128], endpoint_dots = 0, fill = nil| ...
x_min_max_samples[x_min, x_max, samples]
endpoint_dotstruthy to append visible Dots at the curve endpoints
filloptional RGBA colour to shade the area between the curve and the x axis
imagedoc-mesh-explicitfunc-1.mcl
rendered monocurl scene
mesh graph = stroke{CYAN} ExplicitFunc(|x| sin(x), [-PI, PI, 160])
mesh shaded = stroke{CYAN} ExplicitFunc(|x| sin(x), [0, PI, 160], 0, [0.2, 0.6, 0.9, 0.4])
constructor

One-dimensional axis mesh along a basis vector.

Usually configured through axis_style{"x", ...} rather than by manually editing the compact x_axis style list. In the style list, tick_spacing may be a list of exact tick positions instead of a step, arrow_extrusion may be nil to hide the axis arrowheads, label_map may be nil to hide tick labels, and an 8th slot sets tick_placement ("both" / "positive" / "negative" / "centered").

let Axis1d = |basis = 1r, normal = 1b, color = [0, 0, 0, 1], x_axis = [-5, 5, nil, 0.25, 4, |x| x, 0.2]| ...
constructor

Three-dimensional coordinate axes, optionally with grid lines.

label_up controls how tick labels and titles are oriented per axis; pass three up vectors when default text orientation is not readable from the active camera.

let Axis3d = |basis = [1r, 1u, 1b], color = [0, 0, 0, 1], grid_color = nil, label_up = [1u, 1u, 1b], x_axis = [-5, 5, nil, 0.25, 4, |x| x, 0.2], y_axis = [-5, 5, nil, 0.25, 4, |x| x, 0.2], z_axis = [-5, 5, nil, 0.25, 4, |x| x, 0.2]| ...
mesh axes = axis_style{"z", 0, 2, "z"} Axis3d(label_up: [1u, 1u, 1b])
constructor

Polar coordinate axis mesh.

theta and radius are [min, max, unit, tick_step]; radius values are clamped to non-negative.

let PolarAxis = |center = [0, 0, 0], theta = [-5, 5, 1, 1], radius = [0, 5, 1, 1]| ...
constructor

Sample a 3-D parametric curve function.

The function receives t and returns a 3-D point. Endpoints are included. Where f(t) returns nil or a point with a non-finite component, the curve is split into separate contours rather than jumping across the gap.

let ParametricFunc = |f, t_min_max_samples = [0, 1, 64], endpoint_dots = 0| ...
t_min_max_samples[t_min, t_max, samples]
endpoint_dotstruthy to append visible Dots at the two curve endpoints
imagedoc-mesh-parametricfunc-1.mcl
rendered monocurl scene
mesh spiral = stroke{CYAN, 3} ParametricFunc(|t| [t / 9 * cos(t), t / 9 * sin(t), 0], [0, TAU * 3, 220])
constructor

Sample z = f(x, y) as a 3-D surface.

The function receives (x, y) and returns z. The domain lists are [min, max, samples]. Pass color_at as a |x, y, z| ... callback returning an RGBA colour to shade the surface per vertex (for height maps / gradients); leave it nil for the default flat surface colour.

let ExplicitFunc2d = |f, x_min_max_samples = [-1, 1, 21], y_min_max_samples = [-1, 1, 21], color_at = nil| ...
color_atoptional (x, y, z) -> RGBA per-vertex colour callback
imagedoc-mesh-explicitfunc2d-1.mcl
rendered monocurl scene
mesh bowl = fill{alpha{0.3} BLUE} stroke{alpha{0.5} BLUE, 1} ExplicitFunc2d(|x, y| 0.6 * (x * x + y * y) - 0.6, [-1.3, 1.3, 19], [-1.3, 1.3, 19])
camera = Camera([2.8, -2.6, 2.1], [0, 0, 0], [0, 0, 1])
imagedoc-mesh-explicitfunc2d-2.mcl
rendered monocurl scene
# colour-by-height via the color_at callback
mesh heat = ExplicitFunc2d(|x, y| 0.5 * (x * x + y * y) - 0.6, [-1.2, 1.2, 25], [-1.2, 1.2, 25], |x, y, z| keyframe_lerp([0 -> BLUE, 0.5 -> CYAN, 1 -> ORANGE], z + 0.6))
camera = Camera([2.8, -2.6, 2.2], [0, 0, 0], [0, 0, 1])
constructor

Sample an implicit 2-D contour around f(x, y) <= 0.

Uses a padded rectangular sign grid and extracts the boundary of the non-positive region as linked stroke loops; increase sample counts for sharper features.

let ImplicitFunc2d = |f, x_min_max_samples = [-1, 1, 65], y_min_max_samples = [-1, 1, 65]| ...
imagedoc-mesh-implicitfunc2d-1.mcl
rendered monocurl scene
mesh level = stroke{CYAN} ImplicitFunc2d(|x, y| x * x + y * y - 1)
constructor

Fill the signed area between two explicit functions.

Returns two tagged filled regions, one for where f is below g and one for where it is above. This is useful for shaded inequalities or visualizing approximation error. Where either f or g returns nil or a non-finite number, that column is a gap and the fill and outline are split around it.

let ExplicitFuncDiff = |f, g, x_min_max_samples = [-5, 5, 128], fills = [[0.3, 0.8, 0.3, 0.5], [0.8, 0.3, 0.3, 0.5]], tags = [[], []]| ...
x_min_max_samples[x_min, x_max, samples]
fills[lower_fill, upper_fill]
tagstags assigned to the two filled regions
imagedoc-mesh-explicitfuncdiff-1.mcl
rendered monocurl scene
mesh diff = ExplicitFuncDiff(|x| sin(x), |x| 0, [-PI, PI, 160])

Layout / Grouping

constructor

Lay meshes out in a line along a direction.

Items are placed touching along dir with a small built-in gap. align_dir can pin one side of each item to a common line.

let Stack = |meshes, dir, align_dir = [0, 0, 0]| ...
align_diroptional direction whose extreme edge should be aligned
imagedoc-mesh-stack-1.mcl
rendered monocurl scene
mesh row = XStack([Circle(0.2), Square(0.4), Text("x")])
constructor

Stack meshes along the x axis.

let XStack = |meshes, align_dir = [0, 0, 0]| Stack(meshes, 1r, align_dir)
constructor

Stack meshes along the y axis.

let YStack = |meshes, align_dir = [0, 0, 0]| Stack(meshes, 1u, align_dir)
constructor

Stack meshes along the z axis.

let ZStack = |meshes, align_dir = [0, 0, 0]| Stack(meshes, 1b, align_dir)
constructor

Return a nested mesh list unchanged for grid-style grouping.

Currently this is a semantic wrapper around nested mesh lists; it does not auto-position cells.

let Grid = |mesh_array| ...
constructor

Return a nested mesh list unchanged for table-style grouping.

Currently aliases Grid.

let Table = |mesh_array| ...
constructor

Rectangle around the visible bounds of a mesh.

Builds a filled rectangle in the XY plane at the target bounds' z value. Style it with fill{CLEAR}/stroke{...} for an outline.

let BoundingBox = |target, buffer = 0.1| ...
mesh boxed = [label, fill{CLEAR} stroke{CYAN} BoundingBox(label, 0.08)]

Transform Operators

importantoperator

Translate a mesh by a vector.

Most primitive constructors are authored at the origin; shift is the lightweight way to place them without changing their local parameters.

let shift = operator |target, delta, filter = nil| ...
filteroptional tag predicate applied to mesh leaves
imagedoc-mesh-shift-1.mcl
rendered monocurl scene
mesh home = fill{alpha{0.1} GRAY} stroke{GRAY, 2} Circle(0.5)
mesh moved = fill{alpha{0.28} CYAN} stroke{CYAN, 2} shift{1.9r + 0.9u} Circle(0.5)
importantoperator

Set stroke color and optional stroke width.

If stroke_width is nil, existing stroke widths are preserved. When you need a filter and no width change, call stroke{color, nil, filter}.

let stroke = operator |target, color, stroke_width = nil, filter = nil| ...
stroke_widthoptional width; nil preserves existing width
filteroptional tag predicate
imagedoc-mesh-stroke-1.mcl
rendered monocurl scene
mesh outline = fill{CLEAR} stroke{CYAN, 2} Circle(1)
importantoperator

Set fill color.

Applies to filled surfaces and dots; use color{...} when you want to recolor fill, stroke, and dots together.

let fill = operator |target, color, filter = nil| ...
filteroptional tag predicate
imagedoc-mesh-fill-1.mcl
rendered monocurl scene
mesh disk = fill{alpha{0.2} BLUE} Circle(1)
importantoperator

Recolor both fill and stroke where applicable.

Useful for fading a whole mesh tree into a muted state without separately touching fill and stroke.

let color = operator |target, color, filter = nil| ...
mesh muted = color{LIGHT_GRAY, |tags| not (2 in tags)} group
importantoperator

Replace mesh tags, optionally filtered by existing tags.

Tags are stable identities for filters and tag-aware animations. A scalar tag becomes a one-element tag list; a list can give one mesh several identities. Use tag{...} after construction for whole mesh leaves. For text/Tex/LaTeX fragments, prefer text_tag{...} inside the constructor so only the generated contours for that fragment receive the tag.

let tag = operator |target, tag, filter = nil| [target, __monocurl__native__ op_retagged(target, |old| ...
mesh a = tag{1} fill{alpha{0.2} CYAN} Circle(0.6)
mesh b = tag{2} fill{alpha{0.2} ORANGE} shift{2r} Square(0.9)
slide "swap identities"
    a = tag{1} fill{alpha{0.2} CYAN} shift{2r} Circle(0.6)
    b = tag{2} fill{alpha{0.2} ORANGE} Square(0.9)
    play TagTrans(1)
importantoperator

Map every point of a mesh through a function.

The callback receives a 3-D point and should return a 3-D point. Callback invocations are batched internally for mesh-sized transforms.

let point_map = operator |target, f, filter = nil| ...
imagedoc-mesh-point-map-1.mcl
rendered monocurl scene
mesh lifted = point_map{|p| [p[0], p[1], p[0] * p[0]]} LineGrid()
importantoperator

Move a mesh so its center lies at a point.

Centers by bounding-box center, not by centroid.

let center = operator |target, center, filter = nil| ...
imagedoc-mesh-center-1.mcl
rendered monocurl scene
mesh title = center{1.2u} Text("Title", 0.8)
importantoperator

Move a mesh near one side of the camera frame.

Placement is camera-aware, so to_side{UP} means the top of the rendered frame rather than global +y when a camera is supplied.

let to_side = operator |target, dir = [0, 0, 0], buffer = 0.1, camera = nil, filter = nil| ...
dirside direction, such as 1u or 1d
bufferdistance from the side
cameraoptional camera, default current camera
mesh caption = to_side{DOWN, 0.2} Text("caption", 0.5)
importantoperator

Move a mesh near a corner of the camera frame.

dir chooses the corner by signs, for example UP + RIGHT or [1, 1, 0].

let to_corner = operator |target, dir = [1, 1, 0], buffer = 0.1, camera = nil, filter = nil| ...
mesh badge = to_corner{UP + RIGHT, 0.2} Text("1")
importantoperator

Place a mesh next to a reference mesh.

Like matched_edge, but adds buffer spacing between the two bounding boxes.

let next_to = operator |target, ref, dir = 1r, buffer = 0.1, filter = nil| ...
buffergap between meshes
mesh label = next_to{base, RIGHT, 0.2} Text("area")
importantoperator

Keep only mesh leaves matching a tag filter.

A scalar or list filter matches leaves containing any requested tag. A predicate filter receives the full tag list for each mesh leaf, not one tag at a time. Tags produced by text_tag{...} are ordinary mesh tags here, so this can select individual text or formula fragments after rendering.

let tag_filter = operator |target, filter| ...
mesh selected = tag_filter{|tags| 2 in tags} group
mesh warm_terms = tag_filter{[2, 3]} equation
operator

Scale a mesh uniformly or per axis.

A scalar factor scales all coordinates. A 3-list scales x/y/z independently. Scaling is centered on the affected mesh tree's bounding-box center.

let scale = operator |target, factor = 1, filter = nil| ...
factorscalar or vector scale
filteroptional tag predicate applied to mesh leaves
imagedoc-mesh-scale-1.mcl
rendered monocurl scene
mesh unit = fill{alpha{0.1} GRAY} stroke{GRAY, 2} Circle(0.7)
mesh wide = fill{alpha{0.28} ORANGE} stroke{ORANGE, 2} scale{[2.2, 0.55, 1]} Circle(0.7)
operator

Rotate a mesh around an axis and optional pivot.

Rotation is interpolatable because the operator supplies identity and target rotation states to Lerp.

let rotate = operator |target, radians, axis = 1b, pivot = nil, filter = nil| ...
axisrotation axis, default 1b
pivotoptional point to rotate around; defaults to the affected mesh tree's bounding-box center
imagedoc-mesh-rotate-1.mcl
rendered monocurl scene
mesh axis_aligned = fill{alpha{0.1} GRAY} stroke{GRAY, 2} Square(1.4)
mesh spun = fill{alpha{0.28} ORANGE} stroke{ORANGE, 2} rotate{PI / 5, 1b} Square(1.4)
operator

Multiply mesh opacity by an opacity value.

This scales existing alpha channels; it does not replace them.

let fade = operator |target, opacity, filter = nil| ...
operator

Set dotted stroke color.

Dots are rendered at line vertices; this is separate from dashed, which rewrites line geometry into dash segments.

let dotted = operator |target, color, filter = nil| ...
operator

Override the normal hint used for rendering or strokes.

This changes normal hints on dots and lines. It is useful after custom geometry mapping if lighting or stroke orientation looks wrong.

let normal_hint = operator |target, normal, filter = nil| ...
operator

Apply an image texture to a mesh.

Usually used by Image; applying it manually expects the mesh to have meaningful UV coordinates. Not available in web runtimes yet.

let textured = operator |target, image, filter = nil| ...
operator

Assign a draw ordering hint to a mesh.

Higher z-index values draw later among otherwise comparable meshes.

let z_index = operator |target, z_index, filter = nil| ...
operator

Add glossy lighting amount to a mesh.

Mainly visible on filled 3-D surfaces.

let gloss = operator |target, amount = 0.5, filter = nil| ...
operator

Map mesh colors through a function.

The callback receives an RGBA color and should return an RGBA color.

let color_map = operator |target, f, filter = nil| ...
operator

Map mesh UV coordinates through a function.

The callback receives a UV pair and should return a UV pair; mostly useful for textured meshes.

let uv_map = operator |target, f, filter = nil| ...
operator

Map mesh tags through a function.

The callback receives the full tag list for each mesh leaf and should return a replacement tag or tag list.

let tag_map = operator |target, f| ...
operator

Apply a mapping function only to tag-filtered subsets.

The filter selects mesh leaves by their tag list; the mapper receives each selected leaf as a mesh value and should return the replacement mesh.

let subset_map = operator |target, filter, f| ...
mesh emphasized = subset_map{|tags| 2 in tags, |m| scale{1.2} m} group
operator

Promote lower-dimensional topology into higher-dimensional topology.

uprank turns point chains into line segments and closed line contours into tessellated filled surfaces. It is useful before operations that expect surfaces, such as extrude, or when a closed outline should become fillable.

let uprank = operator |target, filter = nil| ...
imagedoc-mesh-uprank-1.mcl
rendered monocurl scene
mesh loop = stroke{CYAN, 2.5} uprank{} Polyline([1.3l, 1.3u, 1.3r, 1.3d, 1.3l])
operator

Demote higher-dimensional topology into lower-dimensional topology.

downrank turns surfaces into boundary strokes and strokes into endpoint dots. Use it for outlines/wire geometry, or to expose a filled shape's boundary for stroke-only proofs and construction diagrams.

let downrank = operator |target, filter = nil| ...
imagedoc-mesh-downrank-1.mcl
rendered monocurl scene
mesh outline = stroke{BLUE, 3} downrank{} Rect([2.6, 1.5])
operator

Convert surface-like geometry to wireframe display.

Alias for downrank.

let wireframe = operator |target, filter = nil| ...
operator

Convert strokes to dashed strokes.

Rewrites line geometry into dash segments while preserving fills and dots in the same mesh tree. A scalar lengths value uses the same dash and gap length.

let dashed = operator |target, lengths = [0.2, 0.1], offset = 0, filter = nil| ...
lengthsdash length or [dash, gap]
offsetphase offset
filteroptional tag predicate
imagedoc-mesh-dashed-1.mcl
rendered monocurl scene
mesh guide = dashed{[0.15, 0.08]} stroke{LIGHT_GRAY} Line(1.5l, 1.5r)
operator

Subdivide mesh geometry for smoother downstream transforms.

Adds intermediate samples to lines/surfaces without changing the intended shape. Useful before point_map, Trans, or nonlinear deformations.

let subdivide = operator |target, factor = 2, filter = nil| ...
operator

Tessellate mesh geometry to the requested depth.

Splits surface triangles repeatedly; use it before curved point_map deformations.

let tesselated = operator |target, depth = 1, filter = nil| ...
operator

Extrude a mesh by a delta vector.

Builds side walls from surface boundaries. Standalone closed line loops must be uprank{}ed first so the extruder sees a surface.

let extrude = operator |target, delta, filter = nil| ...
imagedoc-mesh-extrude-1.mcl
rendered monocurl scene
mesh bar = fill{alpha{0.35} BLUE} stroke{BLUE, 1.5} extrude{1.3b} Square(1.1)
camera = Camera([2.4, -2.2, 1.7], [0, 0, 0], [0, 0, 1])
operator

Revolve mesh geometry around an axis rotation.

Sweeps geometry around the rotation vector; larger rotation magnitude sweeps farther around the axis.

let revolve = operator |target, rotation, filter = nil| ...
operator

Keep a mesh fixed relative to the frame while camera changes.

Remaps mesh positions from original_camera to live_camera so the mesh keeps the same apparent screen placement during camera motion. Use this for overlays, labels, and callouts that should not drift while the camera lerps.

let camera_transfer = operator |target, original_camera, live_camera, filter = nil| ...
original_cameracamera used when the mesh was authored
live_cameracurrent or stateful camera, often $camera
mesh hud = camera_transfer{camera, $camera} to_side{UP} Text("fixed")
operator

Rotate a mesh tree so its local XY plane faces the camera.

Keeps the affected mesh tree's bounding-box center fixed, then interprets each vertex offset from that center in a camera-facing local basis. The local y axis follows the camera up direction projected perpendicular to the view direction, and the local x axis is chosen to preserve a right-handed local frame. Use this for labels, panels, and flat mesh trees that should turn toward the camera without changing their center.

let orient_to_camera = operator |target, camera, filter = nil| ...
cameracamera to face
mesh label = orient_to_camera{$camera} center{[1, 0, 0]} Text("A")
operator

Place one edge of a mesh against an edge of a reference mesh.

Moves the target so its -dir edge sits on the reference mesh's dir edge.

let matched_edge = operator |target, ref, dir, filter = nil| ...
operator

Project a screen-space point along a ray into mesh space.

Casts from each target point along ray and snaps to the nearest triangle hit in the screen mesh. Points that miss are unchanged.

let projected = operator |target, screen, ray = 1b, filter = nil| ...
operator

Interpret a mesh inside a local coordinate space.

Maps each point p to axis_center + x_unit * p.x + y_unit * p.y + z_unit * p.z, and remaps dot/line normal hints through the same basis. This is commonly used to build graphs in axis coordinates and then embed them into global scene coordinates.

let in_space = operator |target, axis_center = [0, 0, 0], x_unit = 1r, y_unit = 1u, z_unit = 1b, filter = nil| ...
axis_centerlocal origin
x_unitlocal x basis
y_unitlocal y basis
z_unitlocal z basis
imagedoc-mesh-in-space-1.mcl
rendered monocurl scene
mesh frame = stroke{LIGHT_GRAY, 2} downrank{} Rect([3, 3])
mesh graph = stroke{CYAN, 2} in_space{ORIGIN, 1.3r, 1.3u} ExplicitFunc(|x| x * x, [-1, 1, 60])
function

Split a mesh into [matching, non_matching] by tag filter.

Useful for transfer animations and custom progressors that need to move part of a mesh tree. The filter rules match tag_filter, including text tags recovered from Text, Tex, and Latex.

let tag_split = |target, filter = nil| ...
function

Collapse nested mesh lists into a flatter mesh.

Preserves geometry while reducing mesh-tree nesting.

let mesh_collapse = |target| ...
operator

Separate contours so morphing can treat them independently.

Flattens contour-separated leaves and tags them [0], [1], ... in output order, making later tag_filter selections deterministic.

let contour_separate = operator |target| ...
function

Compute an intermediate Trans morph value between two meshes.

This is the pure value form behind the Trans animation. path_arc bends point paths through circular arcs; pass 0 for straight-line motion or a 3-vector whose direction chooses the arc plane and whose length is the arc angle in radians.

let trans = |start, end, t, path_arc = 0, similar_topo_hint = 0| ...
path_arc0 or a 3-vector arc control
similar_topo_hinttruthy to try exact topology matching first
let halfway = trans(Square(1), Circle(0.7), 0.5, 0.6b)
function

Compute an intermediate Bend morph value between two meshes.

Pure value form behind Bend; best for line/path geometry where local tangent rotation matters.

let bend = |start, end, t| ...

Queries

function

Left x bound of a mesh.

let mesh_left = |target| ...
function

Right x bound of a mesh.

let mesh_right = |target| ...
function

Up y bound of a mesh.

let mesh_up = |target| ...
function

Down y bound of a mesh.

let mesh_down = |target| ...
function

Forward z bound of a mesh.

let mesh_forward = |target| ...
function

Backward z bound of a mesh.

let mesh_backward = |target| ...
function

Extreme bound of a mesh along a direction.

let mesh_direc = |target, direc| ...
function

Width of a mesh bounding box.

let mesh_width = |target| ...
function

Height of a mesh bounding box.

let mesh_height = |target| ...
function

Center of a mesh bounding box.

let mesh_center = |target| ...
function

Topological rank of a mesh: 0 for dots, 1 for lines, 2 for surfaces.

uprank and downrank move geometry between these ranks.

let mesh_rank = |target| ...
function

Tags present in a mesh.

let mesh_tags = |target| ...
function

Sample a point on a mesh at normalized position t.

Samples by authored geometry order; for multi-contour meshes, use contour_separate{} first when each contour needs its own sampling domain.

let mesh_sample = |target, t| ...
function

Sample a normal on a mesh at normalized position t.

let mesh_normal = |target, t| ...
function

Sample a tangent on a mesh at normalized position t.

let mesh_tangent = |target, t| ...
function

Test whether a mesh contains a point.

Primarily meaningful for filled planar/surface geometry.

let mesh_contains = |target, point| ...
function

Distance from a point to a mesh.

let mesh_dist = |target, test_point| ...
function

Raycast against a mesh from a source along a direction.

Returns the closest hit point along the ray when a triangle is hit.

let mesh_raycast = |target, src, direction| ...
function

Raw vertex set of a mesh.

Low-level topology inspection; prefer bounds and sampling helpers for ordinary layout.

let mesh_vertex_set = |target| ...
function

Raw edge set of a mesh.

Low-level topology inspection.

let mesh_edge_set = |target| ...
function

Raw triangle set of a mesh.

Low-level topology inspection.

let mesh_triangle_set = |target| ...
function

Number of contours in a mesh.

let mesh_contour_count = |target| ...