Progression mechanics for web apps. XP, levels, achievements and daily streaks you can drop into a product, plus the particles, sound and screen shake that make them land.
Every learning platform, habit tracker and onboarding flow eventually rebuilds the same thing: points that accumulate, a level that goes up, a streak that must not be broken, and some visual acknowledgement when it happens. There is no library for that, so teams write it again each time, usually without the timezone handling that makes streaks correct.
DopamineJS is that library. The game engine underneath it is what makes the feedback feel good, not the reason to install it.
- Learning platforms: daily streaks, XP per lesson, achievement unlocks
- Habit and fitness apps: streak preservation, milestone celebrations, progress toward a level
- Onboarding and adoption: progress that feels like something rather than a checklist
- Internal tools: the ones nobody opens voluntarily
- HTML5 games: the original use case, still supported
npm install dopaminejsimport { RewardSystem, DataService } from 'dopaminejs';
const rewards = new RewardSystem(new DataService());
await rewards.init();
rewards.on('LEVEL_UP', ({ level }) => showLevelUpToast(level));
rewards.on('ACHIEVEMENT_UNLOCKED', (achievement) => celebrate(achievement));
// Somewhere in your app, when the user does the thing you want repeated
await rewards.addXP(250);
const { progress, needed } = rewards.getXPForNextLevel();
// progress: 0.75, needed: 50That is the whole integration. Persistence is localStorage by default and swappable,
streaks are computed in the user's local calendar rather than UTC, and nothing renders
until you ask it to.
Want the visuals too:
import { GameUI, ParticleSystem } from 'dopaminejs';
import 'dopaminejs/style.css';
const ui = new GameUI(new ParticleSystem(canvas));
ui.init();
rewards.on('LEVEL_UP', ({ level }) => ui.showLevelUp(level));A daily streak is a calendar question, not a clock question. "Did they come back yesterday"
depends on the user's timezone, and a naive Date comparison breaks for anyone not on UTC,
silently, for a subset of users you will never hear from.
DopamineJS resolves streak boundaries in local time and the test suite is pinned to a non-UTC zone so a regression fails CI instead of passing quietly on a UTC runner.
npm install dopaminejsThe core engine with:
- TypeScript declarations included, no
@typespackage needed - Plugin architecture (Kernel, EventBus, SystemRegistry)
- Default implementations (Canvas particles, Web Audio, basic physics)
- Reward system (XP, levels, achievements)
- Component-based game objects
License: MPL-2.0 (copyleft for core improvements)
Install only what you use. Each plugin is its own package.
| Package | Provides |
|---|---|
dopaminejs-plugin-webgl-particles |
WebGLParticlePlugin - GPU particles (10,000+) |
dopaminejs-plugin-howler-audio |
HowlerAudioPlugin - Advanced audio (Howler.js) |
dopaminejs-plugin-sound-packs |
Sound packs (retro, modern, cute, scifi) |
dopaminejs-plugin-ecosystem |
BattlePassPlugin, LeaderboardPlugin, webhooks |
dopaminejs-plugin-feedback-effects |
Floating text and confetti feedback |
dopaminejs-plugin-debug-overlay |
DebugOverlayPlugin - FPS and system inspector |
npm install dopaminejs-plugin-webgl-particlesThe bundled
dopaminejs-pluginspackage was retired in 2.1.0 and unpublished from npm. Install the individual packages above instead; see docs/MIGRATION.md.
License: MIT (use freely, even commercially)
npm install dopaminejs-themesUI themes:
- Modern, Dark Cyberpunk, Neon, Retro, Cute
- CSS variable-based
- Easy customization
License: MIT (use freely, even commercially)
The engine that powers the effects is exported too, if you are building an actual game rather than adding progression to an app.
import { Game } from 'dopaminejs';
import { WebGLParticlePlugin } from 'dopaminejs-plugin-webgl-particles';
import { themeEngine } from 'dopaminejs-themes';
const game = new Game();
// Add plugins
game.kernel.plugins.use(WebGLParticlePlugin);
// Set theme
themeEngine.setTheme('dark-cyberpunk');
game.start();This is a monorepo using npm workspaces:
# Install all dependencies
npm install
# Build all packages
npm run build
# Test all packages
npm run test
# Work on specific package
cd packages/dopaminejs
npm run devPublishing is automated. There is no manual npm publish step and no npm token
in this repository; GitHub Actions authenticates via npm Trusted Publishing
(OIDC), which also attaches a provenance attestation to every release.
- Bump the version of each package you want to publish.
- Update
CHANGELOG.md. - Tag with the core package's version and push:
git tag v2.1.0
git push origin v2.1.0The Publish workflow (.github/workflows/publish.yml, the filename npm's
Trusted Publisher config is pinned to) verifies manifests, runs the tests, builds every
package, checks the tag matches dopaminejs's version, then publishes only
those packages whose version is not already on npm. Re-running after a partial
failure is safe: already-published packages are skipped.
To preview without publishing, run the workflow manually from the Actions tab with dry run left checked.
If a publish fails with ENEEDAUTH, run the workflow manually with dry run
checked. That runs a per-package OIDC diagnostic and prints the registry's
actual response, which npm publish hides:
HTTP 201- trusted publishing is configured correctly for that packageHTTP 404 "package not found"- no Trusted Publisher record exists for that package name, even though the package itself is on npm. Configure it atnpmjs.com/package/<name>/access.
The filename
publish.ymlis load-bearing. npm matches the OIDC request against the exact workflow filename registered on each package's Trusted Publisher config, so renaming this file breaks publishing until all eight packages are reconfigured on npmjs.com.
- Core (MPL-2.0): Ensures improvements to the core engine are shared back
- Plugins/Themes (MIT): Maximum freedom for extensions and customization
Yes! Both MPL-2.0 and MIT allow commercial use:
- MPL-2.0: You can use the core in commercial projects. If you modify the core files, share those modifications.
- MIT: Plugins and themes have zero restrictions.
- dopaminejs: MPL-2.0
- dopaminejs-themes: MIT
- dopaminejs-plugin-*: MIT
See individual package LICENSE files for details.