Properties & time

A Property is a named, time-aware Value

Where a Value is a bare datum, a Property is a Value at a name on an Element, optionally carrying time samples. An Element's Properties are how it holds state (radius, albedo, position), and every one of them can either be a constant or vary over time.

def object "ball" {
    float radius = 1.5                  # a constant property
    float3 position = {                 # an animated property: keyframed samples
        0:  (0, 0, 0)
        24: (0, 5, 0)
        48: (0, 0, 0)
    }
}

Resolving at a time

Reading a Property means asking for its Value at a time:

doc.edit(Path("/world/ball"))
   .animate("position", {{0, Float3(0,0,0)}, {24, Float3(0,5,0)}, {48, Float3(0,0,0)}});

Value p0  = doc.eval(Path("/world/ball.position"), 0);    // (0, 0, 0)
Value p12 = doc.eval(Path("/world/ball.position"), 12);   // (0, 2.5, 0): interpolated

Animation is an axis, not a subsystem

Time in Core is one axis available on every numeric property of every element, in every kind of document. A camera moving in a scene, a layer in an image sequence, a parameter ramping under a slider drag, and a value a generative tool keyframes are all the same mechanism: samples on a Property, resolved at a time.

This is why animation cuts across the content kinds rather than standing beside document, image, and vector. An animated GIF is the image kind plus samples; a moving rig is the scene kind plus samples. The codecs that target those kinds get animation for free, because it lives on the Property, beneath the kind.

Bezier handles

For smooth motion, float keyframes can carry bezier tangent handles (introduced in format v2), so a property eases rather than moving in straight segments. The handles are part of the keyframe data and round-trip through both ASCII and binary encodings. Linear remains the default; handles are opt-in per key.

With values named and time-aware, the last piece is letting one Property's Value come from another: connections and the dataflow graph.