Skip to content

Add Camera2d.colorMatrix property for built-in color grading#1409

Merged
obiot merged 6 commits intomasterfrom
feat/post-effect-chaining
Apr 22, 2026
Merged

Add Camera2d.colorMatrix property for built-in color grading#1409
obiot merged 6 commits intomasterfrom
feat/post-effect-chaining

Conversation

@obiot
Copy link
Copy Markdown
Member

@obiot obiot commented Apr 21, 2026

Summary

  • Add a public colorMatrix property to Camera2d — a built-in ColorMatrix for convenient color grading (brightness, contrast, saturation, etc.)
  • Always applied as the final post-processing pass, after any effects added via addPostEffect()
  • Zero overhead when identity (default) — the effect is not added to the pipeline
  • The effect is transient: pushed before beginPostEffect, removed after endPostEffect each frame
  • Camera2d uses only the public ColorMatrixEffect API (reset() + multiply()), no internal shader knowledge
  • Platformer example updated to use app.viewport.colorMatrix.contrast(1.1).saturate(1.1) instead of manual ColorMatrixEffect
  • Fix FileReader error handling in RenderTarget.toDataURL()

Closes #1396.

Test plan

  • 203 tests pass (6 new colorMatrix tests)
  • Platformer: vignette + colorMatrix color grading renders correctly
  • Identity colorMatrix = no effect, no FBO overhead
  • clearPostEffects() doesn't break colorMatrix on next frame
  • CodeRabbit review — findings addressed

🤖 Generated with Claude Code

obiot and others added 3 commits April 21, 2026 16:35
…et architecture (#1396)

Replace the single `shader` property on Renderable with a `postEffects` array
supporting multiple shader effects applied in sequence via FBO ping-pong.
Single-effect renderables use a zero-overhead customShader fast path (no FBO).

Introduce an abstract `RenderTarget` base class with `WebGLRenderTarget` and
`CanvasRenderTarget` implementations, and a renderer-agnostic `RenderTargetPool`
using a factory pattern — ready for future WebGPU support.

Extract direct GL state calls from the post-effect pipeline into renderer methods
(setViewport, clearRenderTarget, enableScissor, disableScissor, setBlendEnabled),
all no-ops on the base Renderer, implemented on WebGLRenderer.

Fix WebGL texture unit corruption during FBO resize by explicitly using TEXTURE0.
Fix projection matrix not being saved/restored across post-effect passes.
Fix Canvas renderer not syncing customShader in save/restore.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Clear customShader when no enabled effects or entering FBO path (prevents shader leak to children)
- Reset _activeBase/_previousBase in RenderTargetPool.destroy()
- Guard against nested sprite post-effect passes in RenderTargetPool.begin()
- Handle null blob in toBlob() callbacks (reject instead of resolving null)
- Restore toImageBitmap() fast path on CanvasRenderTarget using createImageBitmap(canvas)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a public `colorMatrix` property to Camera2d — a built-in ColorMatrix
that is always applied as the final post-processing pass, after any effects
added via addPostEffect(). Zero overhead when identity (default).

The effect is transient: pushed to postEffects before beginPostEffect and
removed after endPostEffect each frame. Camera2d uses only the public
ColorMatrixEffect API (reset + multiply), no internal shader knowledge.

Also fix FileReader error handling in RenderTarget.toDataURL().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 12:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends melonJS’s post-processing system by introducing multi-pass post-effect chaining on all renderables and adding a built-in Camera2d.colorMatrix for convenient color grading, backed by a renderer-agnostic RenderTarget/RenderTargetPool abstraction.

Changes:

  • Replace the single Renderable.shader with a postEffects array (+ helper APIs) and implement multi-pass ping-pong post-processing in WebGLRenderer.
  • Add Camera2d.colorMatrix (built-in ColorMatrix) applied as the final transient post-effect pass.
  • Refactor render targets into an abstract RenderTarget base + RenderTargetPool, updating WebGL/Canvas render targets and adding unit tests.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/melonjs/src/renderable/renderable.js Introduces postEffects + helper methods; deprecates shader; integrates renderer-driven post-effect setup/teardown.
packages/melonjs/src/video/webgl/webgl_renderer.js Implements multi-pass post-effect pipeline (FBO ping-pong), render target pooling, and renderer-agnostic state helpers.
packages/melonjs/src/video/rendertarget/render_target_pool.js Adds renderer-agnostic render target pooling for camera and sprite post effects.
packages/melonjs/src/video/rendertarget/rendertarget.ts Adds abstract RenderTarget base class + shared toBlob/toImageBitmap/toDataURL helpers.
packages/melonjs/src/video/rendertarget/webglrendertarget.js Makes WebGL render target extend RenderTarget; adjusts texture unit handling; removes duplicated export helpers.
packages/melonjs/src/video/rendertarget/canvasrendertarget.js Makes Canvas render target extend RenderTarget; optimizes toDataURL/toBlob/toImageBitmap.
packages/melonjs/src/video/renderer.js Updates base renderer post-effect hooks and adds new renderer-agnostic state method stubs.
packages/melonjs/src/video/canvas/canvas_renderer.js Ensures customShader participates in save/restore to prevent shader state leakage in Canvas mode.
packages/melonjs/src/camera/camera2d.ts Adds colorMatrix + transient internal ColorMatrixEffect appended after user post effects.
packages/melonjs/src/index.ts Exports new RenderTarget base class.
packages/melonjs/tests/renderable.spec.js Adds tests for postEffects API + Canvas fast-path customShader behavior and cleanup.
packages/melonjs/tests/camera.spec.js Adds tests for Camera2d.colorMatrix identity/creation/lifecycle behavior.
packages/melonjs/tests/renderTargetPool.spec.js Adds unit coverage for RenderTargetPool behavior (mock + WebGL-backed).
packages/melonjs/tests/renderTarget.spec.js Adds coverage for RenderTarget + Canvas/WebGL implementations.
packages/melonjs/CHANGELOG.md Documents new post-effect chaining, camera colorMatrix, and render target abstractions.
packages/examples/src/examples/platformer/play.ts Updates platformer to use addPostEffect + viewport.colorMatrix for color grading.
packages/examples/src/examples/platformer/entities/minimap.ts Updates minimap camera to use addPostEffect instead of shader.
packages/examples/src/examples/platformer/entities/coin.ts Updates coin effect hookup to use addPostEffect.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/melonjs/src/video/rendertarget/rendertarget.ts
Comment thread packages/melonjs/src/video/rendertarget/render_target_pool.js
Comment thread packages/melonjs/src/video/webgl/webgl_renderer.js
Comment thread packages/melonjs/src/video/rendertarget/webglrendertarget.js
Comment thread packages/melonjs/src/video/rendertarget/webglrendertarget.js
obiot and others added 2 commits April 22, 2026 07:20
- Save/restore active texture unit in WebGLRenderTarget constructor and resize()
  to keep the batcher's currentTextureUnit cache in sync (TEXTURE0 fix preserved)
- Handle null 2d context in RenderTarget.toBlob() fallback paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolve conflicts: keep colorMatrix property, Copilot review fixes
(active texture save/restore, null context handling).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 23:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/melonjs/src/camera/camera2d.ts
Comment thread packages/melonjs/src/video/rendertarget/rendertarget.ts Outdated
onloadend fires on success, error, and abort — could resolve with null.
onload only fires on success. Also handle onabort explicitly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@obiot obiot merged commit bc81635 into master Apr 22, 2026
6 checks passed
@obiot obiot deleted the feat/post-effect-chaining branch April 22, 2026 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add multi-pass shader effect chaining on renderables

2 participants