Skip to content

Migration

Arnel Robles edited this page Oct 2, 2026 · 3 revisions

Migration

To 2.4.0

No breaking changes. Code that worked around the old behaviour can drop the workaround.

Before 2.4.0
Nothing emitted collision_enter or collision_exit Physics emits both on the kernel event bus with { a, b }
plugins.remove(name) left the plugin's systems registered Systems registered during init() are unregistered. A systems.unregister call after it is now a no-op
preloadSounds before the audio context did not register its keys Keys are registered and load when the context starts

dopaminejs-plugin-webgl-particles 1.1.2 changes one log line: without WebGL it no longer says a canvas fallback is used.

To 2.3.1

Types only. The engine declarations now match the runtime, so TypeScript code written against the old ones stops compiling at these points. That code was already reading undefined when run.

Was declared Now declared
GameObject.position: Vector2, scale: Vector2 x, y, scale: { x, y }, parent
Collider.getBounds() as { x, y, width, height } { left, right, top, bottom } for a box, { x, y, radius } for a circle
Physics.checkOverlap(source, targetTag): GameObject | null checkOverlap(source, targetTag?): Collider[]

Also declared now: Collider.tag, ParticleConfig.angle, and ParticleConfig.color as a string or a list of strings.

To 2.3.0

The core changes are additive. Three behaviours changed that code may depend on.

Before Now
recordGame accepted any name and any score Throws a TypeError for an empty, non-string or reserved name, a non-object result, or a score that is not a finite number
A negative score took XP away It earns the base 10 XP
addXP or recordGame before init() threw a null TypeError Throws an error that says init() must be awaited
The XP bar filled by lifetime XP It fills by progress inside the current level
showNotification wrapped rare and legendary messages in combo text The message is shown as written

New in 2.3.0: Dopamine.destroy(), SoundManager.destroy(), the streak_updated and save_failed events, promise-returning storage, maxParticles and respectReducedMotion on ParticleSystem.

dopaminejs-plugin-ecosystem 1.x to 2.0.0

Breaking. Needs dopaminejs 2.3.0 or newer.

Rotate your webhook secret. The 1.x "signature" was the secret itself, base64 encoded together with the payload, in a header and in the body. Anything that saw a request saw the secret.

1.x 2.0.0
Body carried a signature field Body is { event, data, timestamp }
Signature was btoa(secret + ':' + payload) Header X-Dopamine-Signature: sha256=<hex HMAC-SHA256 of the body>
LeaderboardPlugin had a placeholder URL and a built-in secret Sends nothing until LeaderboardPlugin.configure({ webhookUrl, secret, playerId })
BattlePassPlugin logged tiers to the console Emits battlepass:tier-unlocked on the kernel bus and on window

Update your receiver to verify the header against the raw body. See Plugin: Ecosystem.

Both plugins now need the reward system to publish on the kernel bus:

const rewards = new RewardSystem(new DataService(), { events: game.kernel.events });

Off dopaminejs-plugins

The bundle dopaminejs-plugins was unpublished from npm on 2026-01-01 and removed from the repo in 2.1.0. Install the package that owns each export.

Was imported from dopaminejs-plugins Now install
WebGLParticlePlugin, WebGLParticleSystem dopaminejs-plugin-webgl-particles
HowlerAudioPlugin dopaminejs-plugin-howler-audio
getSoundPack, listSoundPacks, SoundPacks dopaminejs-plugin-sound-packs
BattlePassPlugin, LeaderboardPlugin, RewardMiddleware, WebhookIntegration dopaminejs-plugin-ecosystem
DebugOverlayPlugin dopaminejs-plugin-debug-overlay
CustomPhysicsPlugin Not published. Copy it from examples/plugins/CustomPhysicsPlugin.js.

Sound packs are tone definitions, not file URLs. Do not pass one as customSounds. See Plugin: Sound Packs.

v1 to v2

v2 put a kernel under the engine. v1 code keeps running.

The globals

GlobalPhysics, GlobalInput and GlobalLoader still work and warn once on first use. They will be removed in a major version. Move to the kernel:

// v1
import { GlobalPhysics, GlobalInput } from 'dopaminejs';
GlobalPhysics.add(collider);

// v2, in a component
class Player extends Component {
    update(dt) {
        if (this.input.isKeyDown('ArrowLeft')) this.gameObject.x -= 200 * dt;
    }
}

// v2, outside a component
game.kernel.physics.add(collider);

A Collider added to a game object registers itself with the kernel's physics. You rarely call physics.add by hand.

Game

new Game(), game.start() and game.setScene(scene) work as before. The kernel is at game.kernel.

The default export

import Dopamine from 'dopaminejs' still works. New code uses the named exports. See Dopamine Facade.

Names that never existed

Older docs used some names the code does not have:

Wrong Right
scene.addGameObject(obj) scene.add(obj)
game.changeScene(scene) game.setScene(scene)
gameObject.position.x gameObject.x
new ParticleSystem(canvas) new ParticleSystem(config)
events.on('LEVEL_UP', ...) events.on('level_up', ...)
soundManager.setSoundPack(name) no such method

Clone this wiki locally