AlterProgramming's picture
Initial venture-studio deploy: pixel_cursor + studio + app.py
1e3ce4c verified
Raw
History Blame Contribute Delete
2.65 kB
"""Timing primitives from classical animation (the A1 layer).
These compile a sparse sequence of keyframe-cursor states into a dense 24fps
frame stream by interpolating between pinned states with classical-animation rules:
eases, stride (on-twos), and moving-hold micro-vibration.
This is what makes the cursor's temporal layer load-bearing for animation
specifically rather than decoration around a video-generation model.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Callable, Optional
import math
Curve = Callable[[float], float]
def linear(t: float) -> float:
return t
def ease_in_out_cubic(t: float) -> float:
return 4 * t * t * t if t < 0.5 else 1 - (-2 * t + 2) ** 3 / 2
def ease_in_quad(t: float) -> float:
return t * t
def ease_out_quad(t: float) -> float:
return 1 - (1 - t) ** 2
def spring(t: float, tension: float = 0.3) -> float:
return 1 - math.cos(t * math.pi * (1 + tension)) * math.exp(-3 * t)
CURVES: dict[str, Curve] = {
"linear": linear,
"ease": ease_in_out_cubic,
"ease-in": ease_in_quad,
"ease-out": ease_out_quad,
"spring": lambda t: spring(t),
}
@dataclass(frozen=True, slots=True)
class AnimationSegment:
"""A compiled keyframe→keyframe segment. Intent, not rendered pixels."""
start_frame: int
end_frame: int
curve_name: str
stride: int = 2
micro_profile: Optional[str] = None
def ease_between(
start_frame: int,
end_frame: int,
curve: str = "ease",
stride: int = 2,
) -> AnimationSegment:
if curve not in CURVES:
raise ValueError(f"Unknown curve {curve!r}; choices: {sorted(CURVES)}")
if stride < 1:
raise ValueError(f"stride must be >= 1; got {stride}")
return AnimationSegment(start_frame, end_frame, curve, stride)
def step_on_stride(start_frame: int, end_frame: int, stride: int = 2) -> list[int]:
"""Return the per-frame *sample frame index* under stride-N discipline.
On-twos: every 2 frames advance; intermediate frame holds the prior sample.
"""
out = []
for f in range(start_frame, end_frame):
rel = f - start_frame
sample_rel = (rel // stride) * stride
out.append(start_frame + sample_rel)
return out
def hold_with_micro(
start_frame: int, duration: int, micro: str = "breath"
) -> AnimationSegment:
"""A moving-hold: spatial pin + micro-vibration to signal life over long holds."""
return AnimationSegment(start_frame, start_frame + duration, "linear", 1, micro)
def interp_t(curve_name: str, t: float) -> float:
return CURVES[curve_name](max(0.0, min(1.0, t)))