Act as an expert technical artist. I am building a custom RGB Keyboard Lighting Engine using JavaScript.
I need you to write a mathematical lighting effect based on my request.
This is an AMBIENT effect: it plays continuously, driven only by time and key position — it has no idea when keys are pressed.
### ⚙️ ENGINE SPECS
You only need to write the logic for a single keycap, called every frame. You have access to:
1. `nx` (0.0 left to 1.0 right), `ny` (0.0 top to 1.0 bottom)
2. `t` (Continuous time in seconds)
3. `params` (Object containing GUI variables)
4. `fmod(a,b)` (Use this instead of the % operator for floats)
### 🎛️ GUI PARAMETERS (MANDATORY)
You MUST ALWAYS include a JSON block at the VERY TOP of your code wrapped in `/*CONFIG` and `CONFIG*/` to expose settings to the user.
Supported types: "slider", "color", "select".
Example:
/*CONFIG
{
"speed": { "type": "slider", "min": 0, "max": 10, "value": 2.5, "step": 0.1 },
"color": { "type": "color", "value": "#00ffcc" },
"direction": { "type": "select", "options": {"Left": 1, "Right": -1}, "value": 1 }
}
CONFIG*/
### 📜 STRICT RULES
- Write pure JavaScript. No external libraries.
- DO NOT use the `**` operator. Use `Math.pow(base, exp)`.
- DO NOT use the `%` operator. Use `fmod(a, b)`.
- Write all numbers with a decimal point (e.g., `1.0` instead of `1`) for safe C-transpilation.
- Use `params.speed` or `params.color` inside your code.
- End your code by returning a valid CSS color string (e.g., `rgba(r,g,b,a)`, `hsl(h,s,l)`, `rgb(r,g,b)`, or hex), or return 'transparent' to leave the key unlit.
- Helper functions can be defined at the bottom.
### 🎯 MY REQUEST
I want an ambient effect that looks like: [INSERT EFFECT]
⚡ Reactive Effect — AI Prompt
Act as an expert technical artist. I am building a custom RGB Keyboard Lighting Engine using JavaScript.
I need you to write a REACTIVE lighting effect: it fires from the physical key(s) the user actually presses, and fades out over time. It runs alongside (or instead of) an Ambient layer.
### ⚙️ ENGINE SPECS
You write the logic for a single keycap, called every frame. You have access to:
1. `nx` (0.0 left to 1.0 right), `ny` (0.0 top to 1.0 bottom) — this key's own position
2. `t` (Continuous time in seconds)
3. `params` (Object containing GUI variables)
4. `fmod(a,b)` (Use this instead of the % operator for floats)
5. `reactive` — info about recent key presses, shaped like this:
- `reactive.held` — true if THIS exact key is currently being physically held down
- `reactive.count` — number of currently active (not-yet-decayed) presses
- `reactive.nearest` — closest active press to this key, or null if none:
{ dist, age, dx, dy }
- dist: distance (same 0–1 scale as nx/ny) from this key to the pressed key
- age: seconds since that key was pressed (0 = just now, grows every frame)
- dx, dy: signed offset (this key minus the pressed key), for directional effects
- `reactive.presses` — ALL active presses in the same shape as `reactive.nearest`, sorted nearest-first (use this to support chords / multiple simultaneous keys)
### 🎛️ GUI PARAMETERS (MANDATORY)
Same as ambient — a `/*CONFIG ... CONFIG*/` JSON block at the very top exposing "slider", "color", or "select" controls.
### 📜 STRICT RULES
- Write pure JavaScript. No external libraries.
- DO NOT use the `**` operator. Use `Math.pow(base, exp)`.
- DO NOT use the `%` operator. Use `fmod(a, b)`.
- Always guard against `reactive.nearest` being null (or `reactive.count` being 0) before using it, and return 'transparent' when there's nothing to show — this lets the layer underneath (Ambient, or the dark background) show through.
- Use `age` to fade the effect out over a duration you expose as a `params` slider (e.g. `params.duration`).
- End your code by returning a valid CSS color string, or 'transparent'.
- Helper functions can be defined at the bottom.
### 🎯 MY REQUEST
I want a reactive (keypress-triggered) effect that looks like: [INSERT EFFECT]
⌨️ Type on your keyboard to trigger Reactive effects
🌊 Ambient Controls
⚡ Reactive Controls
⚙️ ZMK Procedural: Auto-calibrating C-Code for the Ambient layer only. Generates dynamic math directly in Zephyr. Save this code as custom_rgb.c in your ZMK config repository.
⚡ About Reactive export: Reactive (keypress-triggered) lighting is currently a live browser preview only — it isn't transpiled to firmware here, since real per-keypress firmware lighting is normally wired up through ZMK's own key-event/behavior APIs rather than a per-frame math function. Ask if you'd like help sketching that integration separately.
🔥 The Animation Baker: Bypasses code translation entirely for the Ambient layer. We simulate the logic in the browser and pack the exact frames into a hex array. 100% accurate!