vivid-tui
v1.0.1
Published
A framework for building TUI games
Downloads
4
Readme
Vivid TUI
A powerful framework for building Terminal User Interface (TUI) games with physics, audio, particles, and more.
Features
- 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
Installation
npm install vivid-tuiQuick Start
const { 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();Core Concepts
Game Engine
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
});Entities
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
}
});Physics System
Gravity and Forces
// Create object with gravity
const ball = game.createEntity(10, 5, 3, 3, {
hasGravity: true
});
// Apply forces
game.screen.key(['space'], () => {
ball.applyForce({ x: 0, y: -8 }); // Jump
});
game.screen.key(['left'], () => {
ball.applyForce({ x: -2, y: 0 }); // Move left
});Collision Detection
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';
}
});Camera System
Following Camera
// Set camera to follow an entity
game.setCameraTarget(player);
// Cycle through camera modes
game.screen.key(['c'], () => {
const newMode = game.cycleCameraMode();
console.log('Camera mode:', newMode);
});Camera modes:
- Static - Fixed camera position
- Following - Smooth camera tracking
Particle System
Built-in Explosions
game.screen.key(['space'], () => {
game.createExplosion(x, y);
});Custom Particle Effects
// 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);Particle Trails
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);
}
};Audio System
Loading Audio
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');Playing Audio
// Play music
game.screen.key(['1'], async () => {
await game.playMusic('background');
});
// Stop music
game.screen.key(['2'], () => {
game.stopMusic();
});
// Play sound effects
game.screen.key(['3'], () => {
game.playSound('explosion');
});
// Toggle mute
game.screen.key(['m'], () => {
const muted = game.audio.toggleMute();
console.log(muted ? 'Muted' : 'Unmuted');
});Sprite Animations
Creating Animated Sprites
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;
};Game State Management
Setting Up Game State
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);Using Game State
// 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();HUD Display
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}`);
}Scene Management
Creating Scenes
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();
}
}
};Managing Scenes
// 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'], () => game.scenes.switchTo('menu'));
game.screen.key(['2'], () => game.scenes.switchTo('gameplay'));Input Handling
// Keyboard input
game.screen.key(['up', 'w'], () => {
player.applyForce({ x: 0, y: -5 });
});
game.screen.key(['space'], () => {
// Jump or shoot
});
// Multiple key options
game.screen.key(['left', 'a'], () => {
player.applyForce({ x: -2, y: 0 });
});Game Loop
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 > 3.0) {
// Do something every 3 seconds
timer = 0;
}
};Complete Example
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'], () => {
player.applyForce({ x: 0, y: -8 });
game.createExplosion(player.position.x, player.position.y);
});
game.screen.key(['left'], () => {
player.applyForce({ x: -2, y: 0 });
});
game.screen.key(['right'], () => {
player.applyForce({ x: 2, y: 0 });
});
// Start game
game.addGameObject(player);
game.addGameObject(platform);
game.start();API Reference
GameEngine
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
GameState
Methods:
set(key, value)- Set state valueget(key)- Get state valuesetGameOver(boolean)- Set game over statereset()- Reset all state
Particle System
Methods:
particles.emit(x, y, count, options)- Emit particlesparticles.addToScreen(screen)- Add particles to screen
