Scalar values and expressions
ClipAsm evaluates numbers and durations exactly rather than with binary floating point.
Numbers and integers
ClipAsm represents Number values as reduced rational values. Integer literals, decimals, percentages, arithmetic, and scalar references remain exact:
param by: Number = 8%
param count: Integer = 6 / 2
image("title.png", 1s)
zoom_in($by)
repeat($count)
Operators use this precedence from loosest to tightest:
- the TimeRange operator
.. - addition and subtraction
- multiplication and division
- unary
+and- - postfix
%,ms,s, andf - primary values and parenthesized expressions
Postfix operators may repeat. % divides a Number by 100, so 800%%, 8%,
0.08, and 2 / 25 are the same exact value and have the same semantic
identity.
Integer is the refinement of Number whose exact reduced denominator is one. Constraints apply after evaluation:
repeat(6 / 2) # valid: evaluates to Integer 3
repeat(5 / 2) # error: evaluates to 2.5, exactly 5/2
Durations
ms, s, and f require an Integer result and construct Duration. They bind
to the immediately preceding expression:
image("short.png", (6 / 2)ms) # 3ms
image("card.png", 15f) # exactly 15 project video frames
image("bad.png", (5 / 2)ms) # error: ms requires Integer
image("bad.png", 5 / 2ms) # error: Number / Duration is undefined
ClipAsm resolves f on the configured project video frame grid. It is useful
for machine-generated edits. Boundaries remain exact even when the nanosecond
authoring grid cannot represent one frame:
config { video { fps = 30 } }
image("card.png", 15f)
trim(3f..15f)
flash_cut(3f)
ClipAsm uses a project-frame range directly for Video. For Audio, each frame
boundary maps to the corresponding boundary on the configured project sample
grid. At 30 fps and 48 kHz, 3f..8f maps exactly to samples 4800..12800.
Cumulative boundaries do not drift.
Duration is distinct from Number. Both unit families support unary signs, addition, and subtraction, but one expression cannot mix wall-clock and project-frame values:
image("long.png", 100s - 100ms)
offset = -5f
image("exact.png", $offset + 20f)
during((1s + 500ms)..3s) { repeat(2) }
image("bad.png", 1s + 3f) # error: Duration families differ
Intermediate scalar results can be negative. At a program parameter boundary, wall-clock Duration must be nonnegative. It must also have an exact representation on ClipAsm’s nanosecond authoring grid. Project-frame Duration must be a nonnegative integer within the supported frame count. Both endpoints of a range must use the same unit family.
Either family may offset a timeline coordinate. Project-frame offsets remain on the frame grid until the final Video frame or Audio sample boundary is resolved:
trim(
range=($edit::start + 3f)..($edit::end - 3f),
)
See the normative grammar for the complete syntax.
Scalar aliases
Immutable scalar aliases name inferred scalar expressions without adding a value to the media stack:
length = 500ms
count = 6 / 2
image("card.png", $length)
repeat($count)
Each program body is a scalar scope. Aliases in that body may refer forward to one another. Aliases from enclosing bodies remain visible. A nested alias does not escape its body. Sibling bodies may reuse the same name.
An alias cannot shadow a visible alias. It also cannot collide with a program input, parameter, or named graph value.
When the compiler checks aliases
The compiler checks the structure of every alias in a body. References must resolve, operators must type-check, and the compiler rejects dependency cycles. These checks also apply to unused aliases. Exact evaluation occurs only when a scalar use reaches the alias. Errors such as unused division by zero do not occur until use. The same rule applies to mixed timeline roots, out-of-bounds coordinates, and destination parameter failures.
Timeline selectors in aliases may capture lexical body inputs. They do not borrow a contextual timeline root from a later invocation.
See Timeline selectors and ranges for placement selectors, timeline coordinates, and marker arithmetic.