From b116f768ca973a0fd6bbfe1aec8bb2333960da89 Mon Sep 17 00:00:00 2001 From: aidosmf Date: Tue, 19 May 2026 18:43:00 +0500 Subject: [PATCH 1/2] feat: clarify op exclusive semantics --- docs/specs/composition.md | 15 +++++++++++++++ docs/specs/layers.md | 13 +++++++++++-- schema/composition/animation.json | 7 ++++--- schema/layers/layer.json | 4 ++-- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/docs/specs/composition.md b/docs/specs/composition.md index 619ec3aa..f5b52f48 100644 --- a/docs/specs/composition.md +++ b/docs/specs/composition.md @@ -6,6 +6,21 @@ {schema_object:composition/animation} +### Time and Duration + +The animation's playable frame range is defined by `ip` (In Point, inclusive) +and `op` (Out Point, exclusive). The frame at `op` is NOT rendered; the +animation loops or stops at that boundary. + +The total duration in frames is `op - ip`, and the duration in seconds is +`(op - ip) / fr`. + +Implementations MUST treat `op` as an exclusive boundary. `op` MUST be +strictly greater than `ip`. + +Example: `ip: 0`, `op: 30`, `fr: 30` defines a 30-frame, 1-second animation +playing frames `0..29`. + ### Versioning Guidelines The Lottie specification version number uses a semantic versioning system, diff --git a/docs/specs/layers.md b/docs/specs/layers.md index adbaa8dc..b2fb3f14 100644 --- a/docs/specs/layers.md +++ b/docs/specs/layers.md @@ -12,6 +12,15 @@ The `ty` property defines the specific layer type based on the following values: {schema_subtype_table:layers/all-layers:ty} +#### Visibility Range + +A layer is visible on frame `t` when `ip <= t < op`. The `ip` (In Point) boundary is +inclusive, and the `op` (Out Point) boundary is exclusive — the frame at `op` is NOT +rendered. This matches the Animation-level [`ip`/`op`](composition.md#animation) +semantics. + +`op` MUST be strictly greater than `ip`. +

Visual Layer

{schema_string:layers/visual-layer/description} @@ -143,10 +152,10 @@ The `tm` property specifies a time remap function as an animatable property, all over the precomp timeline (subset, speedup/slowdown, reverse, frame-freeze, or any other arbitrary transformation). -It maps the current layer time (in the frame index $[ip \ldots op]$ domain) to a precomp time +It maps the current layer time (in the half-open frame index $[ip, op)$ domain) to a precomp time expressed in seconds, and evaluates all animatable precomp properties based on the new time value: -$$tm \colon \left[ip \ldots op\right] \mapsto seconds$$ +$$tm \colon \left[ip, op\right) \mapsto seconds$$ $$t\prime = tm(t) \cdot FPS$$ Note: the global frame rate factor $FPS$ ([Animation](composition.md#Animation) `fr` property) is diff --git a/schema/composition/animation.json b/schema/composition/animation.json index b6df275e..776dc274 100644 --- a/schema/composition/animation.json +++ b/schema/composition/animation.json @@ -24,13 +24,14 @@ }, "ip": { "title": "In Point", - "description": "Frame the animation starts at (usually 0)", + "description": "Frame the animation starts at (inclusive; usually 0)", "type": "number" }, "op": { "title": "Out Point", - "description": "Frame the animation stops/loops at, which makes this the duration in frames when `ip` is 0", - "type": "number" + "description": "Frame the animation stops/loops at (exclusive). The frame at `op` is NOT rendered; the animation duration in frames is `op - ip`.", + "type": "number", + "exclusiveMinimum": 0 }, "w": { "title": "Width", diff --git a/schema/layers/layer.json b/schema/layers/layer.json index 697a91cb..2c259333 100644 --- a/schema/layers/layer.json +++ b/schema/layers/layer.json @@ -32,12 +32,12 @@ }, "ip": { "title": "In Point", - "description": "Frame when the layer becomes visible", + "description": "Frame when the layer becomes visible (inclusive).", "type": "number" }, "op": { "title": "Out Point", - "description": "Frame when the layer becomes invisible", + "description": "Frame when the layer becomes invisible (exclusive). The layer is visible while `ip <= t < op`.", "type": "number" } }, From 1d577c25c146b4e691a3b0231a98ca37c010d935 Mon Sep 17 00:00:00 2001 From: aidosmf Date: Wed, 20 May 2026 17:06:07 +0500 Subject: [PATCH 2/2] docs(layers): imprve op > ip message --- docs/specs/layers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/specs/layers.md b/docs/specs/layers.md index b2fb3f14..db2bf8d3 100644 --- a/docs/specs/layers.md +++ b/docs/specs/layers.md @@ -19,7 +19,7 @@ inclusive, and the `op` (Out Point) boundary is exclusive — the frame at `op` rendered. This matches the Animation-level [`ip`/`op`](composition.md#animation) semantics. -`op` MUST be strictly greater than `ip`. +`op` MUST NOT be less than `ip`.

Visual Layer