0.2.0: polygon tool, mask editor preview, collapsible properties

- Polygon asset type with per-vertex animation: new sidebar button inserts a
  hexagon; vertex handles in the editor write per-keyframe `points` arrays
  that interpolate between keyframes (requires matching point counts).
- Canvas mask preview: toggle in the zoom toolbar switches the stage
  between the editable ghost view and a rendered view that applies the
  actual masking via the shared canvas 2D path.
- Properties panel is grouped into collapsible sections (Transform, Text,
  Appearance, Shadow, Mask) with per-section open/closed state persisted
  to localStorage.
- Sidebar shape buttons are icon-only to reclaim width for the Polygon
  entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.7 committed 2026-04-20 01:29:27 +02:00
1 parent 03b1147a93
commit a05396e734
12 files changed
+611 -173

No files matched your search

+10
View File
@@ -62,6 +62,16 @@ function lerpProps(a: AnimatableProps, b: AnimatableProps, t: number): Animatabl
if (a.shadowColor && b.shadowColor) out.shadowColor = lerpColor(a.shadowColor, b.shadowColor, t)
else if (b.shadowColor) out.shadowColor = b.shadowColor
else if (a.shadowColor) out.shadowColor = a.shadowColor
if (a.points && b.points && a.points.length === b.points.length) {
out.points = a.points.map((pa, i) => {
const pb = b.points![i]
return { x: lerp(pa.x, pb.x, t), y: lerp(pa.y, pb.y, t) }
})
} else if (b.points) {
out.points = b.points.map((p) => ({ ...p }))
} else if (a.points) {
out.points = a.points.map((p) => ({ ...p }))
}
return out
}