Skip to content
Merged
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"lefthook": "^2.1.5",
"tsconfig": "workspace:^",
"tsx": "^4.21.0",
"turbo": "^2.9.4",
"turbo": "^2.9.5",
"typescript": "^6.0.2",
"typescript-eslint": "^8.58.0",
"vitest": "^4.1.2"
Expand Down
1 change: 1 addition & 0 deletions packages/melonjs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- **BREAKING**: `Text.draw()` and `BitmapText.draw()` no longer accept `text`, `x`, `y` parameters — standalone draw without a parent container is removed (deprecated since 10.6.0)
- **BREAKING**: `Text.measureText()` no longer takes a `renderer` parameter (was unused)
- **BREAKING**: `UITextButton` settings `backgroundColor` and `hoverColor` removed — use `hoverOffColor` and `hoverOnColor` instead
- **BREAKING**: `Tween` no longer adds itself to `game.world` — uses event-based lifecycle (`TICK`, `GAME_AFTER_UPDATE`, `STATE_PAUSE`, `STATE_RESUME`, `GAME_RESET`) instead. Public API unchanged. `isPersistent` and `updateWhenPaused` properties still supported.

### Fixed
- WebGL: depth buffer now correctly used for 3D mesh rendering with `gl.LESS` depth function
Expand Down
7 changes: 5 additions & 2 deletions packages/melonjs/src/system/eventEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,20 @@ export class EventEmitter<Events extends EventsMap = DefaultEvents> {
emit<E extends keyof Events>(event: E, ...args: Parameters<Events[E]>) {
const listeners = this.eventListeners[event];
if (listeners) {
for (const entry of listeners) {
// iterate over a copy so that removeListener during emit is safe
const snapshot = listeners.slice();
for (const entry of snapshot) {
entry.fn.apply(entry.ctx, args);
Comment on lines 90 to 96
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emit() now allocates a new array (listeners.slice()) for every emission. Since hot-path events like TICK fire every frame, this can create avoidable allocations/GC pressure. Consider an alternative that keeps iteration safe without per-emit copying (e.g., index-based loop with a mutation-safe strategy, or only snapshotting when a mutation is detected).

Copilot uses AI. Check for mistakes.
}
}

const listenersOnce = this.eventListenersOnce[event];
if (listenersOnce) {
// clear before invoking so re-entrant addListenerOnce is safe
this.eventListenersOnce[event] = [];
for (const entry of listenersOnce) {
entry.fn.apply(entry.ctx, args);
}
this.eventListenersOnce[event] = [];
}
}

Expand Down
57 changes: 23 additions & 34 deletions packages/melonjs/src/tweens/easing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,29 @@
*/

/**
* Easing Function :<br>
* <p>
* Easing.Linear.None<br>
* Easing.Quadratic.In<br>
* Easing.Quadratic.Out<br>
* Easing.Quadratic.InOut<br>
* Easing.Cubic.In<br>
* Easing.Cubic.Out<br>
* Easing.Cubic.InOut<br>
* Easing.Quartic.In<br>
* Easing.Quartic.Out<br>
* Easing.Quartic.InOut<br>
* Easing.Quintic.In<br>
* Easing.Quintic.Out<br>
* Easing.Quintic.InOut<br>
* Easing.Sinusoidal.In<br>
* Easing.Sinusoidal.Out<br>
* Easing.Sinusoidal.InOut<br>
* Easing.Exponential.In<br>
* Easing.Exponential.Out<br>
* Easing.Exponential.InOut<br>
* Easing.Circular.In<br>
* Easing.Circular.Out<br>
* Easing.Circular.InOut<br>
* Easing.Elastic.In<br>
* Easing.Elastic.Out<br>
* Easing.Elastic.InOut<br>
* Easing.Back.In<br>
* Easing.Back.Out<br>
* Easing.Back.InOut<br>
* Easing.Bounce.In<br>
* Easing.Bounce.Out<br>
* Easing.Bounce.InOut
* </p>
* Easing functions for use with {@link Tween}.
* Each family provides `In` (accelerate), `Out` (decelerate), and `InOut` (both) variants.
*
* Available families:
* - `Linear.None` — constant speed
* - `Quadratic` — power of 2
* - `Cubic` — power of 3
* - `Quartic` — power of 4
* - `Quintic` — power of 5
* - `Sinusoidal` — sine wave
* - `Exponential` — base-2 exponential
* - `Circular` — circular arc
* - `Elastic` — spring overshoot
* - `Back` — slight overshoot before settling
* - `Bounce` — bouncing ball effect
* @example
* // use with Tween
* new me.Tween(obj).to({ x: 100 }, {
* duration: 1000,
* easing: me.Tween.Easing.Bounce.Out,
* }).start();
* @see https://easings.net/ for visual reference
* @category Tweens
*/

export type EasingFunction = (t: number) => number;
Expand Down
32 changes: 32 additions & 0 deletions packages/melonjs/src/tweens/interpolation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,29 @@ const catmullRom = (

export type InterpolationFunction = (v: number[], k: number) => number;

/**
* Interpolation functions for tweening through arrays of values.
* Used when a tween target property is an array (e.g. a path of waypoints).
*
* Available functions:
* - `Linear` — straight-line interpolation between consecutive values
* - `Bezier` — smooth Bezier curve through all values
* - `CatmullRom` — smooth Catmull-Rom spline through all values (best for paths)
* @example
* // tween through waypoints using CatmullRom spline
* new me.Tween(obj).to({ x: [100, 200, 300, 400] }, {
* duration: 2000,
* interpolation: me.Tween.Interpolation.CatmullRom,
* }).start();
* @see {@link Tween}
* @category Tweens
*/
export const Interpolation = {
/**
* Piecewise linear interpolation between consecutive array values.
* @param v - array of values
* @param k - interpolation factor (0 to 1)
*/
Linear: (v: number[], k: number) => {
const m = v.length - 1;
const f = m * k;
Expand All @@ -61,6 +83,11 @@ export const Interpolation = {

return linear(v[i], v[i + 1 > m ? m : i + 1], f - i);
},
/**
* Smooth Bezier curve interpolation through all array values.
* @param v - array of values
* @param k - interpolation factor (0 to 1)
*/
Bezier: (v: number[], k: number) => {
let b = 0;
const n = v.length - 1;
Expand All @@ -71,6 +98,11 @@ export const Interpolation = {

return b;
},
/**
* Smooth Catmull-Rom spline interpolation — best for path-following tweens.
* @param v - array of values
* @param k - interpolation factor (0 to 1)
*/
CatmullRom: (v: number[], k: number) => {
const m = v.length - 1;
let f = m * k;
Expand Down
Loading
Loading