From 320e43223f292219a031560afe2e0e2a91a39496 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 3 Mar 2026 16:02:59 +0100 Subject: [PATCH] Editor: Improve animation panel. (#33110) --- editor/js/Animation.js | 48 +++++++++++++++++++++------ editor/js/commands/SetSceneCommand.js | 1 + 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/editor/js/Animation.js b/editor/js/Animation.js index 7be0cb1f04426d..adad37911cac20 100644 --- a/editor/js/Animation.js +++ b/editor/js/Animation.js @@ -1,10 +1,12 @@ -import { UIPanel, UIText, UIButton } from './libs/ui.js'; +import { UIPanel, UIText, UIButton, UINumber } from './libs/ui.js'; import { AnimationPathHelper } from 'three/addons/helpers/AnimationPathHelper.js'; function Animation( editor ) { const signals = editor.signals; + const strings = editor.strings; + const mixer = editor.mixer; const container = new UIPanel(); container.setId( 'animation' ); @@ -33,9 +35,9 @@ function Animation( editor ) { container.add( controlsPanel ); // SVG icons - const playIcon = ``; - const pauseIcon = ``; - const stopIcon = ``; + const playIcon = ''; + const pauseIcon = ''; + const stopIcon = ''; const playButton = new UIButton(); playButton.dom.innerHTML = playIcon; @@ -130,6 +132,17 @@ function Animation( editor ) { const durationText = new UIText( '0.00' ).setWidth( '36px' ); timeDisplay.appendChild( durationText.dom ); + // Time Scale + const mixerTimeScaleNumber = new UINumber( 1 ).setWidth( '60px' ).setRange( - 10, 10 ); + mixerTimeScaleNumber.onChange( function () { + + mixer.timeScale = mixerTimeScaleNumber.getValue(); + + } ); + + controlsPanel.add( new UIText( strings.getKey( 'sidebar/animations/timescale' ) ).setClass( 'Label' ) ); + controlsPanel.add( mixerTimeScaleNumber ); + // Timeline area with track rows const timelineArea = document.createElement( 'div' ); timelineArea.style.flex = '1'; @@ -440,6 +453,7 @@ function Animation( editor ) { trackTimeline.appendChild( keyframe ); } + trackRow.appendChild( trackTimeline ); // Hover on position tracks to show path helper @@ -485,13 +499,27 @@ function Animation( editor ) { } - // Select clip without playing - currentClip = clip; - currentRoot = root; - currentAction = editor.mixer.clipAction( clip, root ); + if ( currentClip === clip ) { - // Update duration display - durationText.setValue( clip.duration.toFixed( 2 ) ); + // Unselect clip + currentAction = null; + currentClip = null; + currentRoot = null; + + timeText.setValue( '0.00' ); + durationText.setValue( '0.00' ); + + } else { + + // Select clip without playing + currentClip = clip; + currentRoot = root; + currentAction = editor.mixer.clipAction( clip, root ); + + // Update duration display + durationText.setValue( clip.duration.toFixed( 2 ) ); + + } } diff --git a/editor/js/commands/SetSceneCommand.js b/editor/js/commands/SetSceneCommand.js index 284c7ad07dcaed..56338a11e02446 100644 --- a/editor/js/commands/SetSceneCommand.js +++ b/editor/js/commands/SetSceneCommand.js @@ -24,6 +24,7 @@ class SetSceneCommand extends Command { this.cmdArray.push( new SetUuidCommand( this.editor, this.editor.scene, scene.uuid ) ); this.cmdArray.push( new SetValueCommand( this.editor, this.editor.scene, 'name', scene.name ) ); this.cmdArray.push( new SetValueCommand( this.editor, this.editor.scene, 'userData', JSON.parse( JSON.stringify( scene.userData ) ) ) ); + this.cmdArray.push( new SetValueCommand( this.editor, this.editor.scene, 'animations', scene.animations ) ); while ( scene.children.length > 0 ) {