feat: add animation progress bar for 3D nodes and viewer (#7839)

## Summary
- Add draggable progress bar to AnimationControls component
- Display current time / total duration
- Allow seeking through animations when paused or playing
- Add animation controls to 3D Viewer

fix https://github.com/Comfy-Org/ComfyUI_frontend/issues/7830 and
https://github.com/Comfy-Org/ComfyUI_frontend/issues/7831

## Screenshots (if applicable)


https://github.com/user-attachments/assets/f6d0668c-c7a4-497e-8345-9ef6e47a41c6

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7839-feat-add-animation-progress-bar-for-3D-nodes-and-viewer-2de6d73d36508101ac98f673206b30d9)
by [Unito](https://www.unito.io)
This commit is contained in:
Terry Jia
2026-01-04 08:47:30 -05:00
committed by GitHub
parent 8d1f8edc5a
commit 7fcfa4c201
9 changed files with 280 additions and 27 deletions

View File

@@ -1,4 +1,5 @@
import { toRaw } from 'vue'
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils'
import { nodeToLoad3dMap } from '@/composables/useLoad3d'
import { useLoad3dViewer } from '@/composables/useLoad3dViewer'
@@ -75,13 +76,20 @@ export class Load3dService {
const sourceModel = source.modelManager.currentModel
if (sourceModel) {
// Remove existing model from target scene before adding new one
const existingModel = target.getModelManager().currentModel
if (existingModel) {
target.getSceneManager().scene.remove(existingModel)
}
if (source.isSplatModel()) {
const originalURL = source.modelManager.originalURL
if (originalURL) {
await target.loadModel(originalURL)
}
} else {
const modelClone = sourceModel.clone()
// Use SkeletonUtils.clone for proper skeletal animation support
const modelClone = SkeletonUtils.clone(sourceModel)
target.getModelManager().currentModel = modelClone
target.getSceneManager().scene.add(modelClone)
@@ -105,6 +113,14 @@ export class Load3dService {
target.getModelManager().appliedTexture =
source.getModelManager().appliedTexture
}
// Copy animation state
if (source.hasAnimations()) {
target.animationManager.setupModelAnimations(
modelClone,
sourceOriginalModel
)
}
}
}