This commit is contained in:
th committed 2026-04-19 19:32:23 +02:00
1 parent 94e9846c13
commit e4aa0dce86
11 files changed
+2227 -32

No files matched your search

+13 -31
View File
@@ -3,6 +3,7 @@ import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { PhArrowsSplit, PhCheck, PhCopy, PhMagnet, PhTrash } from '@phosphor-icons/vue'
import { useSceneStore } from '@/stores/scene'
import { sampleLayer } from '@/lib/interpolate'
import { snapToCandidates } from '@/lib/timelineSnap'
import type { AnimatableProps, Easing, Keyframe, Layer } from '@/types/scene'
interface TimelineTrack {
@@ -51,44 +52,25 @@ const snapEnabled = ref(true)
const SNAP_PX = 8
function allKeyframeTimes(): number[] {
function allKeyframeTimes(ignoreKeyframeId?: string): number[] {
const out: number[] = []
for (const layer of store.scene.layers) {
for (const k of layer.keyframes) out.push(k.time)
if (layer.positionKeyframes) for (const k of layer.positionKeyframes) out.push(k.time)
if (layer.rotationKeyframes) for (const k of layer.rotationKeyframes) out.push(k.time)
for (const k of layer.keyframes) if (k.id !== ignoreKeyframeId) out.push(k.time)
if (layer.positionKeyframes)
for (const k of layer.positionKeyframes) if (k.id !== ignoreKeyframeId) out.push(k.time)
if (layer.rotationKeyframes)
for (const k of layer.rotationKeyframes) if (k.id !== ignoreKeyframeId) out.push(k.time)
}
return out
}
function snapTime(t: number, ignoreKeyframeId?: string): number {
if (!snapEnabled.value) return t
const pps = effectivePxPerSec.value
if (pps <= 0) return t
const thresholdTime = SNAP_PX / pps
let best = t
let bestDist = thresholdTime
const times = ignoreKeyframeId ? keyframeTimesExcept(ignoreKeyframeId) : allKeyframeTimes()
for (const kt of times) {
const d = Math.abs(kt - t)
if (d <= bestDist) {
bestDist = d
best = kt
}
}
return clamp(best, 0, duration.value)
}
function keyframeTimesExcept(id: string): number[] {
const out: number[] = []
for (const layer of store.scene.layers) {
for (const k of layer.keyframes) if (k.id !== id) out.push(k.time)
if (layer.positionKeyframes)
for (const k of layer.positionKeyframes) if (k.id !== id) out.push(k.time)
if (layer.rotationKeyframes)
for (const k of layer.rotationKeyframes) if (k.id !== id) out.push(k.time)
}
return out
return snapToCandidates(t, allKeyframeTimes(ignoreKeyframeId), {
enabled: snapEnabled.value,
pxPerSec: effectivePxPerSec.value,
pixelThreshold: SNAP_PX,
duration: duration.value,
})
}
const TICK_CANDIDATES_SEC = [0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 300]