A powerful framework for building Terminal User Interface (TUI) games with physics, audio, particles, and more.
- Physics Engine - Gravity, collisions, forces, and realistic movement
- Audio System - Music and sound effects with WAV support
- Particle Effects - Explosions, trails, and customizable visual effects
- Camera System - Static and following camera modes with smooth tracking
- Sprite Animations - Frame-based animations with customizable timing
- Scene Management - Easy scene transitions and lifecycle management
- Game State - Centralized state management for scores, lives, and progression
npm install vivid-tuiconst { GameEngine } = require('vivid-tui');
const game = new GameEngine({ title: 'My Game' });
const player = game.createEntity(10, 10, 3, 3, {
style: { fg: 'white', bg: 'blue' },
content: 'P'
});
game.addGameObject(player);
game.start();Create a game instance with optional configuration:
const game = new GameEngine({
title: 'My Game',
audio: true, // Enable audio system
effects: true, // Enable particle effects
scenes: true // Enable scene management
});Create game objects with position, size, and styling:
const player = game.createEntity(x, y, width, height, {
style: { fg: 'white', bg: 'blue' },
content: 'P',
hasGravity: true, // Apply physics
isStatic: true, // Static objects don't move
onCollision: function(other) {
// Handle collisions
}
});// Create object with gravity
const ball = game.createEntity(10, 5, 3, 3, {
hasGravity: true
});
// Apply forces
game.screen.key(['space'], () =>gt; {
ball.applyForce({ x: 0, y: -8 }); // Jump
});
game.screen.key(['left'], () =>gt; {
ball.applyForce({ x: -2, y: 0 }); // Move left
});const platform = game.createEntity(5, 13, 20, 2, {
isStatic: true,
onCollision: function(other) {
console.log('Collision detected!');
// Change appearance on collision
this.element.style.bg = 'yellow';
}
});// Set camera to follow an entity
game.setCameraTarget(player);
// Cycle through camera modes
game.screen.key(['c'], () =>gt; {
const newMode = game.cycleCameraMode();
console.log('Camera mode:', newMode);
});Camera modes:
- Static - Fixed camera position
- Following - Smooth camera tracking
game.screen.key(['space'], () =>gt; {
game.createExplosion(x, y);
});// Emit custom particles
game.particles.emit(x, y, 20, {
content: ['○', '●', '◎'], // Particle characters
style: { fg: 'cyan' },
life: 2.0 // Duration in seconds
});
game.particles.addToScreen(game.screen);let trailEnabled = false;
player.update = function(deltaTime) {
// ... existing update code
if (trailEnabled) {
game.particles.emit(this.position.x, this.position.y, 2, {
content: ['.', '·'],
style: { fg: 'gray' },
life: 0.5
});
game.particles.addToScreen(game.screen);
}
};const game = new GameEngine({ audio: true });
// Load music (looping background audio)
await game.loadMusic('background', './assets/music.wav', {
loop: true,
volume: 0.7
});
// Load sound effects
await game.loadSound('explosion', './assets/explosion.wav');
await game.loadSound('beep', './assets/beep.wav');// Play music
game.screen.key(['1'], async () =>gt; {
await game.playMusic('background');
});
// Stop music
game.screen.key(['2'], () =>gt; {
game.stopMusic();
});
// Play sound effects
game.screen.key(['3'], () =>gt; {
game.playSound('explosion');
});
// Toggle mute
game.screen.key(['m'], () =>gt; {
const muted = game.audio.toggleMute();
console.log(muted ? 'Muted' : 'Unmuted');
});const walker = game.createSprite(x, y, width, height, {
frames: ['>O>'O>', '|O|', ', '|O|'], // Animation frames
frameDelay: 0.2, // Seconds per frame
style: { fg: 'green', bg: 'black' }
});
// Add custom update logic
walker.onUpdate = function() {
this.position.x = 5 + Math.sin(Date.now() / 1000) * 10;
}; const { GameEngine, GameState } = require('vivid-tui');
const game = new GameEngine({ title: 'My Game' });
game.gameState = new GameState();
// Initialize state values
game.gameState.set('score', 0);
game.gameState.set('lives', 3);
game.gameState.set('level', 1);// Get values
const score = game.gameState.get('score');
// Update values
game.gameState.set('score', score + 10);
// Game over state
game.gameState.setGameOver(true);
if (game.gameState.isGameOver) {
console.log('Game Over!');
}
// Reset state
game.gameState.reset();const hud = game.createEntity(2, 18, 50, 1, {
style: { fg: 'white', bg: 'black' },
content: 'Score: 0 | Lives: 3 | Level: 1',
isStatic: true
});
function updateHUD() {
const score = game.gameState.get('score') || 0;
const lives = game.gameState.get('lives') || 0;
const level = game.gameState.get('level') || 1;
hud.element.setContent(`Score: ${score} | Lives: ${lives} | Level: ${level}`);
}const game = new GameEngine({ scenes: true });
const menuScene = {
name: 'menu',
onEnter: function() {
console.log('Menu loaded');
// Create menu objects
const title = game.createEntity(10, 5, 20, 5, {
style: { fg: 'white', bg: 'red' },
content: 'MAIN MENU',
isStatic: true
});
game.addGameObject(title);
this.title = title;
},
onExit: function() {
// Clean up scene objects
if (this.title &∓& this.title.element) {
this.title.element.detach();
}
}
};// Add scenes
game.scenes.addScene('menu', menuScene);
game.scenes.addScene('gameplay', gameplayScene);
game.scenes.addScene('gameover', gameoverScene);
// Switch scenes
game.scenes.switchTo('menu');
// Switch with keyboard
game.screen.key(['1'], () =>gt; game.scenes.switchTo('menu'));
game.screen.key(['2'], () =>gt; game.scenes.switchTo('gameplay'));// Keyboard input
game.screen.key(['up', 'w'], () =>gt; {
player.applyForce({ x: 0, y: -5 });
});
game.screen.key(['space'], () =>gt; {
// Jump or shoot
});
// Multiple key options
game.screen.key(['left', 'a'], () =>gt; {
player.applyForce({ x: -2, y: 0 });
});The engine handles the game loop automatically. You can hook into updates:
// Custom update logic
const originalUpdate = game.update.bind(game);
game.update = function(deltaTime) {
originalUpdate(deltaTime);
// Your custom update code
if (timer >gt; 3.0) {
// Do something every 3 seconds
timer = 0;
}
};const { GameEngine, GameState } = require('vivid-tui');
const game = new GameEngine({
title: 'Platform Game',
audio: true,
effects: true
});
game.gameState = new GameState();
game.gameState.set('score', 0);
// Player
const player = game.createEntity(10, 10, 3, 3, {
style: { fg: 'white', bg: 'blue' },
content: 'P',
hasGravity: true
});
// Platform
const platform = game.createEntity(0, 15, 80, 2, {
style: { fg: 'white', bg: 'gray' },
isStatic: true
});
// Camera follows player
game.setCameraTarget(player);
// Controls
game.screen.key(['space'], () =>gt; {
player.applyForce({ x: 0, y: -8 });
game.createExplosion(player.position.x, player.position.y);
});
game.screen.key(['left'], () =>gt; {
player.applyForce({ x: -2, y: 0 });
});
game.screen.key(['right'], () =>gt; {
player.applyForce({ x: 2, y: 0 });
});
// Start game
game.addGameObject(player);
game.addGameObject(platform);
game.start();Constructor Options:
title- Window titleaudio- Enable audio systemeffects- Enable particle effectsscenes- Enable scene management
Methods:
createEntity(x, y, width, height, options)- Create game objectcreateSprite(x, y, width, height, options)- Create animated spriteaddGameObject(entity)- Add entity to gamestart()- Start game loopsetCameraTarget(entity)- Set camera follow targetcycleCameraMode()- Switch camera modescreateExplosion(x, y)- Create explosion effectloadMusic(name, path, options)- Load music fileloadSound(name, path)- Load sound effectplayMusic(name)- Play loaded musicstopMusic()- Stop musicplaySound(name)- Play sound effect
Methods:
set(key, value)- Set state valueget(key)- Get state valuesetGameOver(boolean)- Set game over statereset()- Reset all state
Methods:
particles.emit(x, y, count, options)- Emit particlesparticles.addToScreen(screen)- Add particles to screen