0.15.0: stage context menu + drag-to-resize stage
- Right-clicking the stage opens a small menu with Document settings (pops the document drawer) and Resize stage. Closes on outside click and ESC. - Resize stage drops eight accent-coloured drag handles around the canvas rect (N/NE/E/SE/S/SW/W/NW). East/south handles just grow or shrink the canvas; west/north (and their corners) also shift every scene-world coordinate in lock-step so content stays pinned to its visible position while the canvas re-aligns around it. - Enter forces stage-crop on so the user can see where the new edge lands; exit restores the previous crop setting. Exit paths: Done button in the floating banner, ESC, or the restored crop toggle. - New store action shiftSceneWorldCoords(dx, dy) covers layer base + main/position keyframes + bezier control points + clipInstance x/y across every scene page. Clip-library layers, button assets, hit shapes and polygon vertex clouds stay put — those live in local coord systems, not scene-world space. - Tests: store coverage (shift across pages, positionKeyframes, ctrlX/Y, clipInstance, clip-library untouched, (0,0) no-op) plus UI coverage (context-menu items, Resize stage enters mode + renders 8 handles, ESC and Done both exit, crop forced on and restored). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
9fe86b62b9
commit
827d80bfd0
6 files changed
+847
-3
No files matched your search
@@ -776,6 +776,46 @@ export const useSceneStore = defineStore('scene', {
|
||||
this.project.canvas.width = Math.max(1, Math.round(width))
|
||||
this.project.canvas.height = Math.max(1, Math.round(height))
|
||||
},
|
||||
|
||||
/** Shift every scene-world-space coordinate across the whole project
|
||||
* by (dx, dy). Used by the stage resize drag: when grabbing the
|
||||
* left/top edge the canvas origin effectively slides, and every
|
||||
* element needs to slide the same amount to stay visually pinned.
|
||||
*
|
||||
* What shifts:
|
||||
* - layer.base.{x,y}
|
||||
* - each keyframe.props.{x,y} on the main track
|
||||
* - each keyframe.props.{x,y} on separated position track
|
||||
* - keyframe.ctrlX / ctrlY (bezier handles live in world space)
|
||||
* - clipInstance.{x,y} (static per-instance offset)
|
||||
*
|
||||
* What stays put: clip-library layers (local to the clip instance
|
||||
* origin), button-asset internals (their own canvas), polygon point
|
||||
* clouds on keyframe.props.points (local to the layer origin). */
|
||||
shiftSceneWorldCoords(dx: number, dy: number) {
|
||||
if (dx === 0 && dy === 0) return
|
||||
const shiftProps = (props: Partial<AnimatableProps> | undefined) => {
|
||||
if (!props) return
|
||||
if (typeof props.x === 'number') props.x += dx
|
||||
if (typeof props.y === 'number') props.y += dy
|
||||
}
|
||||
const shiftKeyframe = (kf: Keyframe) => {
|
||||
shiftProps(kf.props)
|
||||
if (typeof kf.ctrlX === 'number') kf.ctrlX += dx
|
||||
if (typeof kf.ctrlY === 'number') kf.ctrlY += dy
|
||||
}
|
||||
for (const page of this.project.scenes) {
|
||||
for (const layer of page.layers) {
|
||||
shiftProps(layer.base)
|
||||
for (const kf of layer.keyframes ?? []) shiftKeyframe(kf)
|
||||
for (const kf of layer.positionKeyframes ?? []) shiftKeyframe(kf)
|
||||
}
|
||||
for (const ci of page.clipInstances ?? []) {
|
||||
if (typeof ci.x === 'number') ci.x += dx
|
||||
if (typeof ci.y === 'number') ci.y += dy
|
||||
}
|
||||
}
|
||||
},
|
||||
setCanvasBackground(color: string) {
|
||||
this.project.canvas.background = color
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user