Skip to content

feat(envelope): per-macrozone interpolation in mixed envelopes #64

@DMGiulioRomano

Description

@DMGiulioRomano

Summary

Allow a different interp (linear / cubic / step) to be specified per breakpoint macrozone, not just per loop block. Today only loop blocks carry an interp; standalone BP runs in a mixed envelope can only fall back to linear.

Current behaviour (envelopes-reference §2 + §5)

Shape Interp Combinable with loops?
[item, item, …] (mixed array) per loop block (item[3]) yes
{type, points: [[t,v]…]} (typed) one global interp for ALL points no
  • Pure-BP envelope: one interp for the whole curve.
  • Mixed envelope (BPs + loops): interp on each loop, but every standalone BP run is implicitly linear.
  • Two BP macrozones in the same envelope cannot have different interps.

Goal

Two BP macrozones in the same envelope should interpolate differently. Example: cubic fade-in → step ladder → linear tail, possibly with a loop block between them.

# illustrative
density_env:
  - [0.0, 0]
  - [0.2, 12]            # group A — wants cubic
  - [0.4, 8]
  - [[[0,8],[50,18],[100,8]], 0.7, 4, 'linear', 'linear']  # loop
  - [0.75, 6]            # group B — wants step
  - [0.9, 6]
  - [1.0, 0]

Proposed data model — Option 2 (preferred)

Wrap a run of BPs in a compact group carrying its own interp, symmetric with loop blocks:

# [points, interp]  — a "BP group" item
- [[[0.0, 0], [0.2, 12], [0.4, 8]], 'cubic']
- [[[0,8],[50,18],[100,8]], 0.7, 4, 'linear', 'linear']   # loop block, unchanged
- [[[0.75, 6], [0.9, 6], [1.0, 0]], 'step']

Tuple length discriminates BP group (2 elements: points + interp) from loop block (4–5 elements). Needs a new check in isCompactBlock / isBPGroup.

Alternative options considered

Option 1 — interp sentinel item

- {interp: cubic}
- [0.0, 0]
- [0.2, 12]
- {interp: step}
- [0.75, 6]

Backward compatible, but mixes dicts into the list array.

Option 3 — typed dict nested inside mixed array

- {type: cubic, points: [[0.0,0],[0.2,12]]}
- {type: step,  points: [[0.75,6],[0.9,6]]}

Reuses existing shape but risks ambiguity at top level.

Compatibility & migration

  • Existing [item, item, …] envelopes: unchanged. Bare BPs keep linear.
  • Existing {type, points} envelopes: unchanged (pure-BP global-interp form still valid).
  • fmtEnvInline needs an emitter branch for the new BP-group form.
  • parseEnvLiteral needs a shape check / isBPGroup helper.

UI consequences (PGE-ui)

  1. Per-BP-macrozone interp selector in the macro-zones bar (same control loop blocks already have).
  2. Drop the top-right global interp selector when the envelope contains more than one macrozone.
  3. expandMixed must propagate per-zone interp so the curve renders with the right per-segment interpolation.

Acceptance criteria

  • Renderer reads BP-group form without breaking existing fixtures.
  • Round-trip stability: YAML → parse → emit reproduces the source.
  • Editor exposes per-zone interp selector and writes the new form.
  • cubic BP groups use PCHIP (Fritsch–Carlson monotone) — same as editor preview.
  • Discontinuities at zone boundaries follow existing DISCONTINUITY_OFFSET rule.

Out of scope

  • Per-segment interpolation inside a BP zone.
  • Per-cycle interpolation inside a loop.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions