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:
1 parent
03b1147a93
commit
a05396e734
12 files changed
+611
-173
No files matched your search
+50
-1
@@ -247,7 +247,7 @@ export const useSceneStore = defineStore('scene', {
|
||||
if (asset.kind === 'rect' || asset.kind === 'image') {
|
||||
layer.offsetX = asset.width / 2
|
||||
layer.offsetY = asset.height / 2
|
||||
} else if (asset.kind === 'circle' || asset.kind === 'text') {
|
||||
} else if (asset.kind === 'circle' || asset.kind === 'text' || asset.kind === 'polygon') {
|
||||
layer.offsetX = 0
|
||||
layer.offsetY = 0
|
||||
}
|
||||
@@ -465,6 +465,55 @@ export const useSceneStore = defineStore('scene', {
|
||||
kf.props = { ...kf.props, x: curX + dx, y: curY + dy }
|
||||
}
|
||||
},
|
||||
movePolygonVertex(layerId: string, pointIndex: number, x: number, y: number, time?: number) {
|
||||
const layer = this.activeLayers.find((l) => l.id === layerId)
|
||||
if (!layer) return
|
||||
const asset = this.scene.assets.find((a) => a.id === layer.assetId)
|
||||
if (!asset || asset.kind !== 'polygon') return
|
||||
if (pointIndex < 0 || pointIndex >= asset.points.length) return
|
||||
const t = time ?? this.playhead
|
||||
const sampled = sampleLayer(layer, t)
|
||||
const current = sampled.points ?? asset.points
|
||||
const next = current.map((p, i) => (i === pointIndex ? { x, y } : { x: p.x, y: p.y }))
|
||||
this.upsertKeyframe(layerId, t, { points: next })
|
||||
},
|
||||
addPolygonPoint(assetId: string, atIndex: number, point: { x: number; y: number }) {
|
||||
const asset = this.scene.assets.find((a) => a.id === assetId)
|
||||
if (!asset || asset.kind !== 'polygon') return
|
||||
const insertAt = Math.max(0, Math.min(atIndex, asset.points.length))
|
||||
asset.points.splice(insertAt, 0, { x: point.x, y: point.y })
|
||||
const layersUsing = this.scene.layers.filter((l) => l.assetId === assetId)
|
||||
for (const layer of layersUsing) {
|
||||
for (const arr of [layer.keyframes, layer.positionKeyframes, layer.rotationKeyframes]) {
|
||||
if (!arr) continue
|
||||
for (const kf of arr) {
|
||||
if (!kf.props.points) continue
|
||||
const pts = kf.props.points.slice()
|
||||
pts.splice(insertAt, 0, { x: point.x, y: point.y })
|
||||
kf.props = { ...kf.props, points: pts }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
removePolygonPoint(assetId: string, pointIndex: number) {
|
||||
const asset = this.scene.assets.find((a) => a.id === assetId)
|
||||
if (!asset || asset.kind !== 'polygon') return
|
||||
if (asset.points.length <= 3) return
|
||||
if (pointIndex < 0 || pointIndex >= asset.points.length) return
|
||||
asset.points.splice(pointIndex, 1)
|
||||
const layersUsing = this.scene.layers.filter((l) => l.assetId === assetId)
|
||||
for (const layer of layersUsing) {
|
||||
for (const arr of [layer.keyframes, layer.positionKeyframes, layer.rotationKeyframes]) {
|
||||
if (!arr) continue
|
||||
for (const kf of arr) {
|
||||
if (!kf.props.points) continue
|
||||
const pts = kf.props.points.slice()
|
||||
if (pointIndex < pts.length) pts.splice(pointIndex, 1)
|
||||
kf.props = { ...kf.props, points: pts }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setLayerMask(layerId: string, isMask: boolean, mode?: MaskMode) {
|
||||
const layer = this.activeLayers.find((l) => l.id === layerId)
|
||||
if (!layer) return
|
||||
|
||||
Reference in new issue
Block a user