UNPKG

@kya-os/cli

Version:

CLI for MCP-I setup and management

254 lines 7.01 kB
/** * Scene-Based Animation Engine for Terminal Effects * Provides sophisticated animation capabilities with scenes, frames, and events */ /** * Sync metric for scene timing */ export var SyncMetric; (function (SyncMetric) { /** Sync to time */ SyncMetric["TIME"] = "time"; /** Sync to motion distance */ SyncMetric["DISTANCE"] = "distance"; /** Sync to motion steps */ SyncMetric["STEP"] = "step"; })(SyncMetric || (SyncMetric = {})); /** * Animation scene - a sequence of frames */ export class Scene { constructor(id) { this.frames = []; // @ts-ignore - Used internally this.currentFrameIndex = 0; // @ts-ignore - Used internally this.frameStartTime = 0; this._isLooping = false; this._isComplete = false; /** Sync metric for timing */ this.syncMetric = SyncMetric.TIME; this.id = id; } /** * Add a frame to the scene */ addFrame(symbol, duration, colors) { this.frames.push({ symbol, duration, colors }); } /** * Apply gradient to symbols across multiple frames */ applyGradientToSymbols(symbol, duration, gradient, _direction) { const spectrum = gradient.getSpectrum(); const frameDuration = Math.floor(duration / spectrum.length); for (const color of spectrum) { this.addFrame(symbol, frameDuration, { fg: color, bg: null }); } } /** * Set looping behavior */ setLooping(isLooping) { this._isLooping = isLooping; } /** * Get current frame based on elapsed time */ getCurrentFrame(elapsedTime) { if (this.frames.length === 0) return null; if (this._isComplete && !this._isLooping) { return this.frames[this.frames.length - 1]; } let totalDuration = 0; let targetTime = elapsedTime; // Handle looping if (this._isLooping) { const sceneDuration = this.frames.reduce((sum, frame) => sum + frame.duration, 0); targetTime = elapsedTime % sceneDuration; } // Find the current frame for (let i = 0; i < this.frames.length; i++) { totalDuration += this.frames[i].duration; if (targetTime < totalDuration) { this.currentFrameIndex = i; return this.frames[i]; } } // Scene complete this._isComplete = true; if (this._isLooping) { this.currentFrameIndex = 0; this._isComplete = false; return this.frames[0]; } return this.frames[this.frames.length - 1]; } /** * Reset the scene */ reset() { this.currentFrameIndex = 0; this.frameStartTime = 0; this._isComplete = false; } /** * Check if scene is complete */ isComplete() { return this._isComplete && !this._isLooping; } /** * Get total duration of the scene */ getTotalDuration() { return this.frames.reduce((sum, frame) => sum + frame.duration, 0); } /** * Get frame count */ getFrameCount() { return this.frames.length; } /** * Get current frame index */ getCurrentFrameIndex() { return this.currentFrameIndex; } } /** * Event types for character animation */ export var AnimationEvent; (function (AnimationEvent) { AnimationEvent["SCENE_COMPLETE"] = "scene_complete"; AnimationEvent["SCENE_ACTIVATED"] = "scene_activated"; AnimationEvent["FRAME_CHANGE"] = "frame_change"; })(AnimationEvent || (AnimationEvent = {})); /** * Character animation manager */ export class CharacterAnimation { constructor(inputColors) { this.scenes = new Map(); this.activeScene = null; this.sceneStartTime = 0; this.eventHandlers = []; this.inputFgColor = inputColors?.fg; this.inputBgColor = inputColors?.bg; } /** * Create a new scene */ newScene(sceneId) { const scene = new Scene(sceneId); this.scenes.set(sceneId, scene); return scene; } /** * Get a scene by ID */ queryScene(sceneId) { return this.scenes.get(sceneId); } /** * Activate a scene */ activateScene(scene) { if (this.activeScene && this.activeScene !== scene) { this.triggerEvent(AnimationEvent.SCENE_COMPLETE, this.activeScene.id); } this.activeScene = scene; this.sceneStartTime = Date.now(); scene.reset(); this.triggerEvent(AnimationEvent.SCENE_ACTIVATED, scene.id); } /** * Update animation and get current visual */ update() { if (!this.activeScene) return null; const elapsedTime = Date.now() - this.sceneStartTime; const frame = this.activeScene.getCurrentFrame(elapsedTime); if (!frame) return null; // Check for scene completion if (this.activeScene.isComplete()) { this.triggerEvent(AnimationEvent.SCENE_COMPLETE, this.activeScene.id); } return { symbol: frame.symbol, colors: frame.colors || { fg: this.inputFgColor || null, bg: this.inputBgColor || null }, }; } /** * Register an event handler */ registerEvent(event, sceneId, callback) { this.eventHandlers.push({ event, sceneId, callback }); } /** * Trigger an event */ triggerEvent(event, sceneId) { for (const handler of this.eventHandlers) { if (handler.event === event && handler.sceneId === sceneId) { handler.callback(); } } } /** * Reset all scenes */ reset() { this.scenes.forEach(scene => scene.reset()); this.activeScene = null; this.sceneStartTime = 0; } } /** * Enhanced character with animation capabilities */ export class AnimatedCharacter { constructor(id, symbol, inputColors) { /** Layer for z-ordering (higher = on top) */ this.layer = 0; /** Visibility flag */ this.isVisible = true; this.id = id; this.originalSymbol = symbol; this.animation = new CharacterAnimation(inputColors); this.visual = { symbol, colors: { fg: inputColors?.fg || null, bg: inputColors?.bg || null, }, }; } /** * Update character animation */ update() { const newVisual = this.animation.update(); if (newVisual) { this.visual = newVisual; } } /** * Set character layer */ setLayer(layer) { this.layer = layer; } /** * Set visibility */ setVisibility(isVisible) { this.isVisible = isVisible; } } //# sourceMappingURL=animation-engine.js.map