@@ -36,6 +36,10 @@ const editorHistory = {
3636 redoStack : [ ] ,
3737 undoStack : [ ] ,
3838} ;
39+ const animationPreview = {
40+ frameIndex : 0 ,
41+ timerId : null ,
42+ } ;
3943
4044function gridLabel ( size ) {
4145 return `Sprite Creator ${ size } by ${ size } pixel canvas` ;
@@ -467,12 +471,12 @@ function renderPixelsToCanvas(canvas, paintedPixels, gridSize) {
467471 }
468472}
469473
470- function renderPreview ( ) {
474+ function renderPreview ( frame = currentFrame ( ) ) {
471475 const canvas = document . querySelector ( "[data-sprites-preview-canvas]" ) ;
472476 if ( ! canvas ) {
473477 return ;
474478 }
475- renderPixelsToCanvas ( canvas , editorState . paintedPixels , editorState . gridSize ) ;
479+ renderPixelsToCanvas ( canvas , frame . paintedPixels , editorState . gridSize ) ;
476480}
477481
478482function renderFrameStrip ( ) {
@@ -558,6 +562,63 @@ function deleteFrame() {
558562 updateHistoryControls ( ) ;
559563}
560564
565+ function updateAnimationControls ( isPlaying ) {
566+ const playButton = document . querySelector ( "[data-sprites-play-animation]" ) ;
567+ const stopButton = document . querySelector ( "[data-sprites-stop-animation]" ) ;
568+ if ( playButton ) {
569+ playButton . disabled = isPlaying ;
570+ }
571+ if ( stopButton ) {
572+ stopButton . disabled = ! isPlaying ;
573+ }
574+ }
575+
576+ function animationStatusText ( prefix , frameIndex = editorState . activeFrameIndex ) {
577+ return `${ prefix } Frame ${ frameIndex + 1 } of ${ editorState . frames . length } . Unsaved preview only.` ;
578+ }
579+
580+ function showAnimationFrame ( frameIndex ) {
581+ const normalizedIndex = frameIndex % editorState . frames . length ;
582+ animationPreview . frameIndex = normalizedIndex ;
583+ renderPreview ( editorState . frames [ normalizedIndex ] ) ;
584+ const status = document . querySelector ( "[data-sprites-animation-status]" ) ;
585+ if ( status ) {
586+ status . textContent = animationStatusText ( "Playing" , normalizedIndex ) ;
587+ }
588+ }
589+
590+ function stopAnimationPreview ( message = "Animation preview stopped." ) {
591+ if ( animationPreview . timerId ) {
592+ clearInterval ( animationPreview . timerId ) ;
593+ animationPreview . timerId = null ;
594+ }
595+ renderPreview ( currentFrame ( ) ) ;
596+ updateAnimationControls ( false ) ;
597+ const status = document . querySelector ( "[data-sprites-animation-status]" ) ;
598+ if ( status ) {
599+ status . textContent = `${ message } Selected Frame ${ currentFrame ( ) . frameNumber } is shown.` ;
600+ }
601+ }
602+
603+ function playAnimationPreview ( ) {
604+ const status = document . querySelector ( "[data-sprites-animation-status]" ) ;
605+ if ( editorState . frames . length < 2 ) {
606+ if ( status ) {
607+ status . textContent = "Animation preview needs at least two unsaved frames." ;
608+ }
609+ return ;
610+ }
611+ if ( animationPreview . timerId ) {
612+ clearInterval ( animationPreview . timerId ) ;
613+ }
614+ animationPreview . frameIndex = 0 ;
615+ updateAnimationControls ( true ) ;
616+ showAnimationFrame ( animationPreview . frameIndex ) ;
617+ animationPreview . timerId = setInterval ( ( ) => {
618+ showAnimationFrame ( ( animationPreview . frameIndex + 1 ) % editorState . frames . length ) ;
619+ } , DEFAULT_FRAME_DURATION_MS ) ;
620+ }
621+
561622function exportPreviewPng ( ) {
562623 const canvas = document . querySelector ( "[data-sprites-preview-canvas]" ) ;
563624 const status = document . querySelector ( "[data-sprites-export-status]" ) ;
@@ -701,6 +762,18 @@ function wireFrameActions() {
701762 }
702763}
703764
765+ function wireAnimationActions ( ) {
766+ const playButton = document . querySelector ( "[data-sprites-play-animation]" ) ;
767+ if ( playButton ) {
768+ playButton . addEventListener ( "click" , playAnimationPreview ) ;
769+ }
770+
771+ const stopButton = document . querySelector ( "[data-sprites-stop-animation]" ) ;
772+ if ( stopButton ) {
773+ stopButton . addEventListener ( "click" , ( ) => stopAnimationPreview ( ) ) ;
774+ }
775+ }
776+
704777function wireHistoryActions ( ) {
705778 const undoButton = document . querySelector ( "[data-sprites-undo]" ) ;
706779 if ( undoButton ) {
@@ -741,6 +814,7 @@ wireDrawingTools();
741814wirePaletteButtons ( ) ;
742815wireCanvasActions ( ) ;
743816wireFrameActions ( ) ;
817+ wireAnimationActions ( ) ;
744818wireHistoryActions ( ) ;
745819wireZoomControls ( ) ;
746820wireExportButton ( ) ;
@@ -751,3 +825,4 @@ setZoomLevel(editorState.zoomLevel);
751825updateHistoryControls ( ) ;
752826renderPreview ( ) ;
753827renderFrameStrip ( ) ;
828+ updateAnimationControls ( false ) ;
0 commit comments