Skip to content

NullCipherr/grit-engine

GRIT Engine Logo

GRIT Engine

A high-performance WebGL2 particle engine for real-time interactive simulations

TypeScript WebGL2 License


Documentation

Technical docs are organized by topic for faster onboarding and easier maintenance. English is the primary language for this repository.


Overview

GRIT Engine is a framework-agnostic simulation core that encapsulates:

  • Particle lifecycle and force integration;
  • Spatial partitioning for neighbor lookup optimization;
  • WebGL2 renderer with instancing and optional bloom;
  • Imperative runtime API (start, stop, resize, updateSettings, etc.);
  • TypeScript-first contracts for safe integration.

It is designed to be consumed by wrappers in React, Vue, Svelte, or vanilla JavaScript.


Features

  • Framework-agnostic runtime with no React dependency.
  • Typed integration API via GritEngine, GritEngineOptions, and SimConfig.
  • High-capacity simulation tuned for tens of thousands of particles.
  • Spatial hashing for efficient flocking and collision neighborhoods.
  • GPU instanced rendering with additive bloom mode support.
  • Pointer-ready interactions (spawn, obstacles, attract/repulse).
  • DPR-aware resize pipeline for visual quality and performance balance.
  • Deterministic seed mode for reproducible sessions.
  • Optional worker ticker mode for experimental scheduling.
  • Plugin system for custom forces and constraints.
  • External simulation mode via externalFrameProvider for domain-specific engines.
  • External Simulation API v2 with descriptor/capabilities and packed buffers.
  • Multi-rate scheduler for independent simulation and external update frequencies.
  • Pluggable spatial backends (grid, bruteforce) for domain trade-offs.
  • Job system foundation with batched execution API and runtime metrics.
  • Subsystem telemetry (plugins/simulation/external/spatial/render/jobs).
  • Quality governor policy for adaptive degradation and recovery.
  • Plugin stage pipeline (pre-sim, post-sim, render-prep, render).
  • Replay/deterministic snapshot for debugging and reproducibility.
  • Control Center UI para inspeção e controle de runtime em desenvolvimento.
  • Optional WASM simulation path with safe JS fallback.
  • Multiple rendering backends (webgl2, canvas2d, and experimental offscreen-worker).
  • Execution presets (performance, balanced, quality) and adaptive particle budget.
  • Hybrid adaptive runtime with local telemetry-based preset recommendation.
  • Runtime backend fallback policy for context/runtime failures (offscreen-worker -> webgl2 -> canvas2d).
  • Optional worker transport compression (quantized16) for offscreen render payloads.

Architecture

Main runtime flow:

  1. Consumer creates a GritEngine instance with canvas and optional overlayCanvas.
  2. Engine bootstraps simulation state (particles, obstacles, grid).
  3. Render loop advances simulation at requestAnimationFrame cadence.
  4. SpatialGrid provides local neighborhoods for flocking/collision logic.
  5. WebGLRenderer uploads per-instance attributes and draws the frame.
  6. Optional onStats callback exposes FPS, frame-time percentiles, adaptive budget and memory telemetry when available.

Performance Notes

Current performance-focused decisions:

  • Grid-based neighborhood search instead of O(n²) scans.
  • Neighbor caps for flocking and collision passes.
  • Reused hot-path arrays to reduce GC pressure.
  • CPU-to-GPU payload minimized to compact instance tuples.
  • Interval-based stats emission to avoid unnecessary UI churn.

For deep details, see Performance.


API Snapshot

import { GritEngine, DEFAULT_SIM_CONFIG, type GritEngineOptions, type SimConfig } from '@nullcipherr/grit-engine';

const engine = new GritEngine({
  canvas,
  overlayCanvas,
  seed: 42,
  executionMode: 'main-thread',
  config: DEFAULT_SIM_CONFIG,
  externalFrameProvider: null
});

engine.start();
engine.updateSettings({ attraction: 12, collisions: true });

Main methods:

  • start()
  • stop()
  • dispose()
  • resize()
  • updateSettings(partialConfig)
  • setPaused(boolean)
  • setPointer(x, y)
  • clearPointer()
  • setExternalFrameProvider(provider | null)
  • setExternalSimulation(simulation | null)
  • getExternalSimulationDescriptor()
  • setSimulationStepHz(number)
  • setExternalStepHz(number)
  • getSchedulerConfig()
  • getExternalFrameProviderEnabled()
  • setSpatialBackend(type)
  • getSpatialBackend()
  • getJobSystemSnapshot()
  • setQualityGovernorPolicy(partialPolicy)
  • getQualityGovernorPolicy()
  • startReplayRecording(maxFrames?)
  • stopReplayRecording()
  • playReplay(tape, loop?)
  • stopReplayPlayback()
  • isReplayPlaybackEnabled()
  • getDeterministicSnapshot()
  • spawnAt(x, y)
  • addObstacle(x, y)
  • clear()
  • getStats()
  • setSeed(seed)
  • getSeed()
  • setPerformancePreset(preset)
  • setAdaptiveBudgetEnabled(boolean)

Tech Stack

  • Language: TypeScript 5.8
  • Renderer: WebGL2
  • Build: Vite 6 (Library Mode)
  • Output: ESM + UMD + declaration files (.d.ts)

Project Structure

.
├── docs/
│   ├── README.md
│   ├── assets/
│   │   └── README.md
│   └── en/
│       ├── ARCHITECTURE.md
│       ├── DEPLOYMENT.md
│       ├── INTEGRATIONS.md
│       ├── OPERATIONS.md
│       ├── PERFORMANCE.md
│       ├── ROADMAP.md
│       ├── SIMULATION.md
│       └── TESTING.md
├── examples/
│   ├── react/
│   ├── svelte/
│   ├── vanilla/
│   └── vue/
├── scripts/
│   ├── benchmark.mjs
│   └── profile.mjs
├── tests/
│   └── core/
├── src/
│   ├── core/
│   │   ├── Obstacle.ts
│   │   ├── Particle.ts
│   │   ├── SpatialGrid.ts
│   │   └── WebGLRenderer.ts
│   ├── GritEngine.ts
│   ├── index.ts
│   └── types.ts
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── SECURITY.md
├── package.json
├── tsconfig.build.json
├── tsconfig.json
└── vite.config.ts

Getting Started

Prerequisites

  • Node.js 18+
  • npm 9+

Install

npm install

Build

npm run build

Type Check

npm run typecheck

Watch Build

npm run dev

Browser Demo

npm run demo

Then open http://localhost:5173/ (or the URL shown by Vite) to test:

  • Spawn burst, pause/resume, and clear simulation;
  • Switch render backend (auto, webgl2, canvas2d);
  • Switch simulation backend (auto, wasm, js);
  • Toggle post-processing (bloom, vignette, trail strength);
  • Enable/disable plugin force and plugin constraint behaviors.

Test

npm run test

Benchmark / Profile

npm run benchmark
npm run benchmark:browser
npm run profile
npm run perf:check

Distribution

package.json exports:

  • import: dist/index.js
  • require: dist/index.umd.js
  • types: dist/types/index.d.ts

You can consume this package via:

  1. Local file dependency (file:../grit-engine)
  2. Git URL dependency
  3. Private package registry

License

This project is distributed under a source-available license. It is not an OSI open-source license.

See LICENSE for full terms.


Contributing and Security

About

This repository contains a WebGL2 particle engine in TypeScript for real-time simulations. Features spatial hashing, GPU instancing, and adaptive performance.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors