Add output camera framing

This commit is contained in:
th committed 2026-06-07 23:12:46 +02:00
1 parent 616ced17ce
commit 23a66c6fdf
19 files changed
+1955 -43

No files matched your search

+78
View File
@@ -30,12 +30,14 @@ import {
shouldRotateClipCopies,
} from '@/lib/kaleido'
import { drawButtonFrame, drawSceneFrame, loadSceneImages } from '@/lib/render'
import { sampleCamera } from '@/lib/camera'
import type {
Action,
AnimatableProps,
Asset,
ButtonAsset,
ButtonState,
CameraProps,
ClipInstance,
HitShape,
Keyframe,
@@ -762,6 +764,67 @@ const clipGroupConfig = computed(() => {
}
})
const cameraVisibleInEditor = computed(() => {
if (store.activeClipId || store.activeButtonAssetId || store.activeSvgAssetId) return false
const camera = store.scene.camera
return !!camera && camera.overlayVisible !== false
})
const cameraFrame = computed<CameraProps | null>(() => {
if (!cameraVisibleInEditor.value) return null
return sampleCamera(store.scene, store.playhead)
})
const cameraFrameConfig = computed(() => {
const frame = cameraFrame.value
const camera = store.scene.camera
if (!frame || !camera) return null
const selected = store.selectedCamera
return {
id: 'camera-frame',
name: 'camera-frame',
x: frame.x,
y: frame.y,
width: frame.width,
height: frame.height,
fillEnabled: false,
stroke: selected ? '#38bdf8' : '#0ea5e9',
strokeWidth: (selected ? 2.5 : 1.5) / zoom.value,
strokeScaleEnabled: false,
dash: [10 / zoom.value, 6 / zoom.value],
hitStrokeWidth: Math.max(10 / zoom.value, 8),
listening: true,
draggable: selected && !camera.locked,
}
})
function selectCameraFromStage(e?: Konva.KonvaEventObject<MouseEvent>) {
if (e) e.cancelBubble = true
store.selectCamera(true)
}
function onCameraDragMove(e: Konva.KonvaEventObject<DragEvent>) {
const camera = store.scene.camera
if (!camera || camera.locked) return
const node = e.target
store.upsertCameraKeyframe(store.playhead, {
x: Math.round(node.x()),
y: Math.round(node.y()),
})
}
function onCameraDragEnd(e: Konva.KonvaEventObject<DragEvent>) {
onCameraDragMove(e)
}
function toggleCameraEnabled() {
if (store.scene.camera?.enabled) {
store.disableCamera()
return
}
store.enableCamera()
}
/** Horizontal + vertical centre-crosshair line configs. Null when
* the toggle is off. Lines span the effective canvas so the centre
* is exactly where layer keyframes default to (canvas.width/2,
@@ -4723,6 +4786,13 @@ function onResizeHandlePointerUp(e: PointerEvent) {
<v-line :config="centerCrosshairConfigs.horizontal" />
<v-line :config="centerCrosshairConfigs.vertical" />
</template>
<v-rect
v-if="cameraFrameConfig"
:config="cameraFrameConfig"
@mousedown="selectCameraFromStage"
@dragmove="onCameraDragMove"
@dragend="onCameraDragEnd"
/>
<v-rect
v-for="h in canvasResizeHandles"
:key="`canvas-resize-${h.edge}`"
@@ -4926,6 +4996,14 @@ function onResizeHandlePointerUp(e: PointerEvent) {
>
<PhCursorClick :size="13" />
</button>
<button
class="zc-btn camera-btn"
:class="{ active: store.scene.camera?.enabled, selected: store.selectedCamera }"
v-tooltip="store.scene.camera?.enabled ? t('canvas.cameraOff') : t('canvas.cameraOn')"
@click="toggleCameraEnabled"
>
<PhFrameCorners :size="13" />
</button>
<button
class="zc-btn motion-paths-btn"
:class="{ active: showMotionPaths }"