# Melonjs Lighting

Use this skill for 2D dynamic lighting in melonJS, Light2d, ambient light on a Stage...

- Repository: https://github.com/melonjs/melonJS (6430 stars)
- Category: Engineering
- License: MIT
- Last updated: 2026-11-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add melonjs/melonJS --skill melonjs-lighting -g -a claude-code -y`
Codex: `npx skills add melonjs/melonJS --skill melonjs-lighting -g -a codex -y`
Cursor: `npx skills add melonjs/melonJS --skill melonjs-lighting -g -a cursor -y`
Gemini CLI: `npx skills add melonjs/melonJS --skill melonjs-lighting -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add melonjs/melonJS`

## Description

Use this skill for 2D dynamic lighting in melonJS, Light2d, ambient light on a Stage, multiple lights, and per-pixel normal-mapped sprites authored in SpriteIlluminator. Covers specular highlights via shininess, the ambient-cutout model, which parts need a GPU backend, and why Light2d does not survive a Camera3d. Triggers on: Light2d, specular, shininess, highlight, glint, lighting, ambientLight, ambientLightingColor, normalMap, SpriteIlluminator, per-pixel lighting, drawLight, torch, glow, darkness.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# 2D dynamic lighting

> `Light2d` is a world renderable that cuts through a stage's ambient darkness.
> The glow and the cutout work on every backend; only per-pixel normal-map
> shading needs a GPU one. It is 2D-only.

## The model: ambient darkness plus cutouts

The `Stage` holds an ambient colour, a dark sheet painted over the scene after
the world is drawn, and each active `Light2d` punches a hole in it at its
visible area. The lights themselves are drawn additively on top.

```js
class PlayScreen extends Stage {
    onResetEvent(app) {
        this.ambientLight.parseCSS("#1a1a2e");     // the darkness

        app.world.addChild(new Light2d(x, y, radiusX, radiusY, "#ffddaa", 0.9));
    }
}
```

The constructor is `Light2d(x, y, radiusX, radiusY = radiusX, color = "#FFF",
intensity = 0.7)`, and `pos` is the light's **centre**, its `anchorPoint` is
`(0.5, 0.5)`, and `centerX` / `centerY` are overridden to return `pos` directly.
Give `radiusY` a different value for a stretched, elliptical light.

A `Light2d` added to the world **registers itself with the stage's ambient
overlay on activate**, so you add it like any other renderable and it takes part
in the lighting pass. It draws additively (`blendMode = "lighter"`); set
`light.illuminationOnly = true` to suppress the visible glow while still lighting
normal-mapped sprites.

`Stage.ambientLight` defaults to fully transparent black, and `drawLighting()`
returns immediately while its alpha is 0, so with no ambient colour set there
is nothing to cut through and the lights just look like soft additive blobs.

## Soft edges: `softness`

A light's hole in the darkness is hard-edged by default: full light inside its
radius, full darkness outside. `light.softness` (0 to 1) fades it instead:

```js
const torch = new Light2d(x, y, 220, 220, "#ffb46a", 0.4);
torch.softness = 0.8;      // lit core of 20% of the radius, then fading out
```

The rest: https://github.com/melonjs/melonJS/blob/HEAD/packages/melonjs/skills/melonjs-lighting/SKILL.md
