tactica
v0.0.1
Published
A mobile-first, browser-based 2D game engine built with TypeScript. Zero external runtime dependencies, pure Web APIs.
Maintainers
Readme
Tactica
A mobile-first, browser-based 2D game engine built with TypeScript. Designed for touch-enabled devices with a focus on performance, accessibility, and developer experience.
Features
- Mobile-First Input - Touch gestures, multi-touch, haptic feedback, virtual joystick, action buttons
- Canvas Rendering - Hardware-accelerated 2D graphics with camera, sprites, tilemaps, layer management
- Camera Effects - Shake, flash, fade, zoom effects for visual polish
- Entity System - Flexible entity-component architecture
- Scene Management - Multiple scenes with smooth transitions (fade, slide, zoom, wipe)
- Physics & Collision - Simple physics with spatial partitioning
- Particle System - Particle emitters with configurable behaviors
- Tweening - Smooth animations with 30+ easing functions
- UI Components - Canvas-based UI: buttons, sliders, panels, progress bars, toasts, modals, tooltips
- Audio System - Sound playback, volume control, crossfade
- State Management - Reactive stores with undo/redo support
- Persistence - LocalStorage and IndexedDB backends with data migrations
- Timer System - Game-time-aware timers with pause/resume support
- Performance - Frame budget tracking, debug overlay, screenshot capture
- PWA Support - Installable, offline-capable
- Accessibility - Screen reader announcements, reduced motion support
Installation
npm install tacticaQuick Start
import {
createEngine,
createScene,
createEntity,
createInputSystem,
} from 'tactica'
// Create canvas
const canvas = document.getElementById('game') as HTMLCanvasElement
// Initialize engine
const engine = createEngine({
canvas,
width: 480,
height: 800,
backgroundColor: '#1a1a2e',
})
// Create input system
const input = createInputSystem(canvas)
// Create a scene
const gameScene = createScene({ name: 'game' })
// Create player entity
const player = createEntity({
id: 'player',
x: 240,
y: 700,
width: 40,
height: 40,
})
gameScene.addEntity(player)
// Handle touch input
input.onTap((x, y) => {
player.setPosition(x, y)
})
// Start game loop
engine.onBeforeUpdate((deltaTime) => {
gameScene.update(deltaTime)
})
engine.onBeforeRender((ctx) => {
gameScene.render(ctx)
})
engine.start()Documentation
For comprehensive documentation, see the Tactica Guide.
Development
# Clone repository
git clone https://github.com/mikesaintsg/tactica.git
cd tactica
# Install dependencies
npm install
# Start development server
npm run dev
# Run type checking
npm run check
# Run tests
npm test
# Build library
npm run build
# Build showcase
npm run showFactory Functions
Core Engine
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createEngine(options) | Create game engine with canvas |
| createScene(options) | Create a game scene |
| createSceneManager(options) | Manage multiple scenes |
| createEntity(options) | Create game entities |
| createTimerManager(options) | Game-time timers |
Rendering
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createCamera(options) | Create camera with follow/shake |
| createCameraEffects(camera) | Camera effects (shake, flash, fade, zoom) |
| createRenderer(context, options) | Create renderer with batching |
| createViewport(options) | Viewport with scaling modes |
| createSpriteSheet(options) | Sprite sheet for animations |
| createAnimationPlayer(options) | Animation playback controller |
| createTilemap(options) | Tile-based level rendering |
| createLayerManager(options) | Render layer management |
| createSpriteBatch(context, assets, options) | Batched sprite rendering |
| createTrailRenderer(options) | Visual trails behind objects |
| createShapeRenderer(options) | Geometric primitive drawing |
| createPostProcessManager(options) | Screen-wide visual effects |
| createCullingSystem(options) | Frustum/distance culling |
| createLODSystem(options) | Level of detail management |
| createTransitionManager(sceneManager, options) | Screen transitions |
Input
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createInputSystem(canvas, options) | Touch/mouse input handling |
| createKeyboardManager(options) | Keyboard input with combos |
| createGamepadManager(options) | Controller input support |
| createInputActionSystem(options) | Unified input with rebinding |
| createVirtualJoystick(options) | Virtual joystick for mobile |
| createActionButton(options) | Touch action button with cooldown |
Audio
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createAudioManager(options) | Sound playback |
| createMusicPlaylist(options) | Sequential music playback |
| createSoundVariantPool(options) | Random sound variations |
| createAudioZoneManager(options) | Spatial audio zones |
Physics & Animation
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createPhysicsWorld(options) | Physics simulation |
| createCollisionSystem() | Collision detection |
| createTweenManager(options) | Animation tweens |
| createParticleSystem(options) | Particle effects |
UI Components
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createUIManager(options) | Canvas-based UI components |
| createToastManager(options) | Toast notifications |
| createModal(options) | Individual modal dialog |
| createModalManager(options) | Modal dialogs (alert/confirm/prompt) |
| createTooltipManager(options) | Tooltip system |
| createTextInput(options) | Text input field |
| createRadialMenu(options) | Circular selection menu |
| createMinimap(options) | World overview minimap |
| createNotificationManager(options) | In-game notifications |
Storage & State
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createStore(options) | Reactive state management |
| createComputed(compute) | Derived state values |
| createDatabase(config) | IndexedDB database wrapper |
| createStateManager(config) | Game state with save/load |
| createSchema(options) | Data validation schema |
| createLocalStorageBackend(options) | localStorage persistence |
| createIndexedDBBackend(options) | IndexedDB persistence |
| createMigrationRunner(options) | Data migrations |
| createTabSyncManager(channelName) | Cross-tab synchronization |
Platform & Assets
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createAssetManager(options) | Asset loading |
| createMobileManager(options) | Mobile device features |
| createAccessibilityManager(options) | Accessibility support |
| createPWAManager(options) | PWA install/update |
| createNetworkManager(options) | Network/multiplayer client |
Debug & Performance
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createPerformanceMonitor(options) | FPS and metrics |
| createDebugTools() | Debug logging |
| createDebugOverlay(options) | Visual debug overlay |
| createFrameBudget(options) | Frame timing budget |
| createScreenshotManager(canvas) | Screenshot capture |
| createEntityInspector(options) | Entity property inspector |
| createCommandConsole(options) | Developer command console |
Game Systems
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| createBuffSystem(options) | Stackable buffs/debuffs with duration |
| createHealthSystem(options) | Entity health, damage, invincibility |
| createFloatingTextSystem(options) | Animated damage/pickup text |
| createCollectibleSystem(options) | Pickups with drop tables and magnetism |
| createSpawnerSystem(options) | Entity spawning with zones and waves |
| createEffectZoneSystem(options) | Areas that trigger effects on entry |
| createExperienceSystem(options) | XP tracking and level progression |
| createStatisticsSystem(options) | Game stats and milestone tracking |
| createObjectiveSystem(options) | Goals and progress tracking |
| createStateMachine(options) | State transitions for game flow |
| createBackgroundSystem(options) | Layered backgrounds with parallax |
| createCrosshairSystem(options) | Desktop aiming cursor |
| createEntityRendererRegistry() | Procedural entity rendering registry |
| createInventorySystem(options) | Item and equipment management |
| createDialogueSystem(options) | Conversation trees with branching |
| createQuestSystem(options) | Quest tracking with objectives |
| createCraftingSystem(options) | Item crafting with recipes |
Helper Functions
Tactica includes a comprehensive set of helper functions for game development:
Type Guards
| Function | Description |
|---------------------------|--------------------------------------|
| isString(value) | Check if value is a string |
| isNonEmptyString(value) | Check if value is a non-empty string |
| isNumber(value) | Check if value is a number (not NaN) |
| isFiniteNumber(value) | Check if value is a finite number |
| isBoolean(value) | Check if value is a boolean |
| isNullish(value) | Check if value is null or undefined |
| isDefined(value) | Check if value is defined |
| isObject(value) | Check if value is a plain object |
| isArray(value) | Check if value is an array |
| isNonEmptyArray(value) | Check if value is a non-empty array |
| isFunction(value) | Check if value is a function |
| isOk(result) | Check if result is successful |
| isErr(result) | Check if result is an error |
Browser & Storage Guards
| Function | Description |
|--------------------------------|---------------------------------------|
| hasDeviceMemory(nav) | Check for deviceMemory API |
| hasGetBattery(nav) | Check for Battery API |
| hasNetworkConnection(nav) | Check for Network Information API |
| hasVibrate(nav) | Check for Vibration API |
| hasIndexedDB() | Check if IndexedDB is available |
| isIDBValidKey(value) | Check if value is valid IndexedDB key |
| hasId(obj) | Check if object has id property |
| hasVersion(obj) | Check if object has version property |
| hasTimestamp(obj) | Check if object has timestamp |
Distance & Vectors
| Function | Description |
|-----------------------------------|---------------------------------------|
| distance(x1, y1, x2, y2) | Calculate distance between two points |
| distanceSquared(x1, y1, x2, y2) | Squared distance (faster, no sqrt) |
| distanceVec(a, b) | Distance between two vectors |
| distanceVecSquared(a, b) | Squared distance between two vectors |
| normalize(x, y) | Normalize a vector to unit length |
| normalizeVec(v) | Normalize a vector object |
| magnitude(x, y) | Get the length of a vector |
| magnitudeVec(v) | Get the length of a vector object |
| angleBetween(x1, y1, x2, y2) | Angle between two points in radians |
| angleOf(x, y) | Angle from origin to point |
| fromAngle(angle, length) | Create vector from angle and length |
| addVec(a, b) | Add two vectors |
| subVec(a, b) | Subtract vector b from a |
| scaleVec(v, scalar) | Scale a vector |
| dotVec(a, b) | Dot product of two vectors |
| crossVec(a, b) | Cross product (z-component) |
| rotateVec(v, angle) | Rotate a vector by angle |
| perpVec(v) | Get perpendicular vector |
| reflectVec(v, normal) | Reflect vector off surface |
Interpolation & Easing
| Function | Description |
|----------------------------------------------|--------------------------------------|
| lerp(start, end, t) | Linear interpolation |
| lerpVec(a, b, t) | Linear interpolation between vectors |
| smoothstep(t) | Smooth step (ease in-out) |
| smootherstep(t) | Ken Perlin's smoother step |
| inverseLerp(a, b, value) | Find t given value between a and b |
| remap(value, inMin, inMax, outMin, outMax) | Remap value between ranges |
| approach(current, target, step) | Approach target by fixed step |
| damp(current, target, smoothing, dt) | Damped approach (exponential decay) |
| dampVec(current, target, smoothing, dt) | Damped approach for vectors |
Clamping & Bounds
| Function | Description |
|--------------------------------------------------|-------------------------------------------|
| clamp(value, min, max) | Clamp number between min and max |
| clampToRectangle(x, y, minX, minY, maxX, maxY) | Clamp position to rectangle |
| clampToWorld(x, y, entitySize, width, height) | Clamp position accounting for entity size |
| wrap(value, min, max) | Wrap value within range |
| wrapToWorld(x, y, width, height) | Wrap position within world bounds |
Random
| Function | Description |
|-----------------------------------------------------|-----------------------------------|
| randomRange(min, max) | Random float between min and max |
| randomInt(min, max) | Random integer (inclusive) |
| randomElement(array) | Random element from array |
| randomPosition(minX, maxX, minY, maxY) | Random position in rectangle |
| randomEdgePosition(width, height, margin, offset) | Random position on rectangle edge |
| randomInCircle(cx, cy, radius) | Random point inside circle |
| randomOnCircle(cx, cy, radius) | Random point on circle edge |
| randomDirection() | Random unit vector |
| randomSign() | Random -1 or 1 |
| randomBool(probability) | Random boolean |
Collision Detection
| Function | Description |
|-----------------------------------------------------|---------------------------------------|
| circlesOverlap(x1, y1, r1, x2, y2, r2) | Check if two circles overlap |
| pointInCircle(px, py, cx, cy, radius) | Check if point is in circle |
| pointInRectangle(px, py, rx, ry, rw, rh) | Check if point is in rectangle |
| rectsOverlap(x1, y1, w1, h1, x2, y2, w2, h2) | Check if rectangles overlap |
| circleRectangleOverlap(cx, cy, r, rx, ry, rw, rh) | Check if circle and rectangle overlap |
Angle Utilities
| Function | Description |
|------------------------------------------|------------------------------------|
| degToRad(degrees) | Convert degrees to radians |
| radToDeg(radians) | Convert radians to degrees |
| normalizeAngle(angle) | Normalize angle to [-π, π] |
| angleDifference(from, to) | Shortest angular distance |
| lerpAngle(from, to, t) | Interpolate angles (shortest path) |
| rotateToward(current, target, maxStep) | Rotate toward target by max step |
Utility Functions
| Function | Description |
|-------------------------------------------|-----------------------------------|
| generateId() | Generate UUID v4 |
| now() | Current timestamp in milliseconds |
| deepClone(obj) | Deep clone object (JSON-safe) |
| shallowEqual(a, b) | Shallow equality check |
| debounce(fn, delay) | Debounce a function |
| throttle(fn, limit) | Throttle a function |
| createSpacing(value) | Create UI spacing object |
| createError(path, message, code, value) | Create validation error |
| validateField(field, value, path) | Validate field against definition |
Project Structure
tactica/
├── src/
│ ├── index.ts # Public API exports
│ ├── factories.ts # Factory functions
│ ├── types.ts # Type definitions (source of truth)
│ ├── constants.ts # Default values
│ ├── helpers.ts # Utility functions
│ ├── core/
│ │ ├── engine/ # Engine, Scene, Entity, SceneManager, TimerManager, TransitionManager
│ │ ├── rendering/ # Camera, Renderer, Sprites, Tilemap, LayerManager, SpriteBatch, CameraEffects, TrailRenderer, ShapeRenderer, PostProcessManager, CullingSystem, LODSystem, Viewport
│ │ ├── input/ # InputSystem, KeyboardManager, GamepadManager, InputActionSystem
│ │ ├── audio/ # AudioManager, MusicPlaylist, SoundVariantPool, AudioZoneManager
│ │ ├── physics/ # PhysicsWorld, CollisionSystem, Quadtree, SpatialGrid
│ │ ├── animation/ # AnimationPlayer, TweenManager, ParticleSystem
│ │ ├── gameplay/ # BuffSystem, HealthSystem, FloatingTextSystem, CollectibleSystem, SpawnerSystem, EffectZoneSystem, BackgroundSystem, ExperienceSystem, StatisticsSystem, ObjectiveSystem, StateMachine, CrosshairSystem, EntityRendererRegistry, InventorySystem, DialogueSystem, QuestSystem, CraftingSystem
│ │ ├── ui/ # UIManager, Button, Slider, Panel, ProgressBar, Text, Checkbox, Toggle, UIImage, TextInput, ToastManager, Modal, ModalManager, TooltipManager, VirtualJoystick, ActionButton, RadialMenu, Minimap, NotificationManager
│ │ ├── storage/ # Store, Computed, StateManager, Database, Schema, TabSyncManager, LocalStorageBackend, IndexedDBBackend, MigrationRunner, Cache
│ │ ├── asset/ # AssetManager, ResourceManager, ObjectPool
│ │ ├── platform/ # MobileManager, AccessibilityManager, PWAManager
│ │ ├── debug/ # DebugTools, DebugOverlay, PerformanceMonitor, ScreenshotManager, FrameBudget, EntityInspector, CommandConsole
│ │ └── network/ # NetworkManager
│ └── schemas/ # State validation schemas (PlayerState, WorldState, InventoryState, SettingsState)
├── tests/ # Unit tests (mirrors src/)
├── showcase/ # Demo game
├── configs/ # Build configs
└── guides/ # DocumentationDevelopment
# Type check
npm run check
# Lint and format
npm run format
# Run tests
npm test
# Build library
npm run build
# Development server (showcase)
npm run dev
# Build showcase to single HTML
npm run showBrowser Support
- Chrome 80+
- Firefox 78+
- Safari 14+
- Edge 80+
Mobile browsers with touch support are the primary target.
License
MIT
