All skills
hyperb1iss avatar

/rgb-effect-design

@05acaca

This skill should be used when creating, modifying, or debugging RGB lighting effects for Hypercolor or LightScript-compatible engines. Triggers on "create an effect", "write a lighting effect", "design LED colors", "fix washed out colors", "port a shader to LEDs", "why does this look bad on LEDs", "color palette for RGB", "effect looks white", "colors too bright", "effect flickering", "design a palette for keyboard", "LED animation", or any work involving HTML canvas effects, LED color science, gamma correction, or the Hypercolor SDK effect pipeline.

  • 3 files
  • 32.2 KB
  • Updated last month
  • GitHub

Use this Skill: https://skilld.dev/gh/hyperb1iss/hypercolor/rgb-effect-design

This session only. Nothing lands on disk.

SKILL.md

β‰ˆ144 tokens always: the name and description. β‰ˆ2.2k when used: this file. β‰ˆ5.9k more on demand in 2 files.

RGB Effect Design for LED Hardware

Practical guidance for creating high-quality lighting effects on physical RGB LEDs β€” keyboards, strips, fans, and other addressable hardware. Derived from analysis of 210+ community effects and LED color science research.

Core Principle

LEDs are discrete point light sources separated by physical space. There is no sub-pixel blending, no backlight diffusion. Design with bold strokes, high saturation, and low spatial frequency.

Color Rules

Saturation: High or Nothing

LED hardware rewards binary saturation. Use 85-100% for vivid colors, 0% for intentional white. Avoid the 20-70% range β€” it produces muddy, indistinct results on RGB LEDs without a dedicated white channel.

Blowout Prevention

Keep the whiteness ratio below 0.3:

whiteness_ratio = min(R, G, B) / max(R, G, B)
  • Never run all three channels above 200/255 unless white is intended
  • HSL lightness above 60% washes out to white on LEDs
  • For vivid colors, at least one RGB channel should be near 0

Hue Quality

Tier Hues Notes
1 (best) Red(0), Green(120), Blue(240), Cyan(180), Magenta(300) Single die or clean mix
2 Orange(25), Purple(270), Rose(330), Azure(210), Amber(35) Excellent with tuning
3 Yellow(60), Warm White, Pastels Tend to wash out
4 Brown, Gray Impossible in isolation

Safe vivid range: 180-330 (cyan through magenta). Danger zone: 30-90 (orange through yellow-green).

Fixing Yellow

Never use pure yellow (255,255,0) β€” shift to gold (255,190,0) or amber (255,140,0) by pulling green below red.

Color Spaces

Task Use Why
Hue cycling / rainbow HSV Increment H; fast and clean
Gradients between colors Oklab No muddy midpoints
Palette generation OKLCH Equal perceptual weight across hues
Brightness control HSV (V channel) Maps to LED PWM
Internal blending Linear RGB or Oklab Never blend in sRGB

Do not use HSL for LED work. Its lightness model causes yellow to appear 6x brighter than blue at equal L values.

Patterns That Work on LEDs

High success: Sine plasma, expanding rings, particle systems, noise fields (simplex/Perlin), linear/radial gradients, wave sweeps, Voronoi cells, metaballs.

Fail on LEDs: Bloom/glow post-processing, ray marching, film grain, fine fractals, thin lines, text rendering. Detail below ~3 LED widths is wasted.

Animation Techniques

Trail/Fade (The Universal Technique)

ctx.fillStyle = "rgba(0, 0, 0, 0.15)"; // alpha controls trail length
ctx.fillRect(0, 0, canvas.width, canvas.height);
  • 0.05-0.10: long trails (comets)
  • 0.10-0.20: standard (most effects)
  • 0.20-0.40: snappy (reactive effects)

Timing

  • Ambient: 1-3s transitions
  • Breathing: 2-4s cycle, sinusoidal easing
  • Reactive: 50-100ms onset, 300-500ms decay
  • Minimum transition: 200ms (below = flicker)

Always Use Delta-Time

const dt = (performance.now() - lastTime) / 1000;
position += velocity * dt;

Composition

  • Use darkness: 30-50% of LEDs off or very dim often looks better than everything lit
  • Color count: 1-2 coordinated colors > rainbow everything. Max 3-4 for tasteful results
  • Hot spots: Single bright LED surrounded by dim ones creates intentional focal points
  • Spatial frequency: Waves should span 10-20+ LEDs minimum

Gamma Correction

In Hypercolor the engine owns the transfer, so your effect must not apply one. Your canvas is already sRGB-encoded, the way every HTML canvas is, and the daemon's output stage decodes it with the sRGB piecewise curve (IEC 61966-2-1, not a 2.2 power law) before writing linear-light PWM bytes to the device. A gamma pass of your own double-encodes and crushes the midtones.

What that means for authoring is that you design in perceptual space: a color that reads mid-bright on screen lands mid-bright on the strip.

The classic rule applies only when you are writing for an engine that hands your bytes straight to LED PWM with no transfer of its own:

corrected = 255 * (input / 255) ^ 2.2

Perceptual 50% brightness is PWM 56/255 (about 22%), not 128/255.

Rendering Model

The Hypercolor engine renders at 640x480 by default (user-configurable in Settings β†’ Rendering). Effects use Canvas 2D with requestAnimationFrame and must always read ctx.canvas.width / ctx.canvas.height on every frame β€” never hardcode dimensions. The SDK ships a scaleContext(canvas, designBasis?) helper for effects authored against a fixed coordinate system (pass { width: 320, height: 200 } if you're porting an effect designed at the historical SDK grid). Higher canvas resolutions give smoother gradients that survive downsampling to LED positions.

Use globalCompositeOperation = 'lighter' for additive blending of overlapping light sources.

Hypercolor Engine Pipeline

Effect canvas (sRGB u8)
  -> SpatialEngine::sample: zone_local_to_canvas affine, then edge behavior
  -> decode sRGB to linear, resample in linear light
  -> optional FadeToBlack attenuation, still in linear
  -> encode back to sRGB u8 as ZoneColors
  -> BackendManager::write_frame: zone brightness, LED perceptual
     compensation, output brightness, linear-light PWM bytes
  -> device backends (the USB/HID driver families plus the Hue, Nanoleaf,
     WLED, and Govee network drivers)

The sampler does not restyle color. It decodes, resamples in linear light, attenuates for FadeToBlack edges, and re-encodes. A pixel that survives sampling reaches ZoneColors unchanged, so an LED-safe palette has to come from the effect itself. There is no chroma-boost pass in the sampler.

The one place the engine adjusts color is the output stage in BackendManager, which decodes back to linear, applies a bounded perceptual lift for low-luma chromatic colors (blue, cyan, and magenta read dimmer than they should on point-source LEDs), scales by zone and device brightness, and writes linear-light bytes. That final decode is the gamma transfer, which is why your effect must not apply one of its own.

Available color types: Rgba/Rgb (u8 sRGB), LinearRgba (linear f32), Oklab, Oklch. The engine implements correct sRGB transfer functions and Oklab/Oklch math.

Quick Checklist

Before starting:

  • Pick 1-3 colors from Tier 1/2 hues
  • Saturation 85-100%, HSL lightness 40-55%
  • Choose a low-spatial-frequency pattern

While building:

  • Trail/fade overlay for motion
  • Delta-time animation
  • Oklab interpolation for gradients
  • Sinusoidal easing for organic motion
  • Design darkness into the composition

Testing:

  • Whiteness ratio < 0.3 for vivid areas?
  • Any hues in 30-90 danger zone? Test on hardware
  • Transitions > 200ms?
  • Works on both small (keyboard) and large (strip) layouts?

Detailed References

For deeper information, consult:

  • references/color-science.md β€” Full LED color science: saturation ranges, hue tiers, gamma correction, blowout prevention, yellow/brown problem, gradient transitions, per-channel calibration
  • references/effect-design.md β€” Complete effect design theory: noise functions, Voronoi, metaballs, temporal patterns, palette design, shader porting, rendering pipeline details
  • docs/content/effects/color-science.md β€” The shipping guide: hue tiers, saturation strategy, whiteness ratio test, gamma, composite modes, community patterns
  • docs/content/effects/typescript-effects.md, glsl-effects.md, raw-html.md β€” Authoring references for each rendering path
  • docs/content/effects/native-rust-effects.md: the Rust-native path (EffectRenderer, FrameInput, Canvas writes, registration). See also the native-effect-authoring skill
  • docs/content/effects/display-faces.md β€” Display-face authoring: the descriptor contract, layout variants per form factor, typed data sources (media/net/lighting), 15-30fps motion design, the Servo CSS support matrix, and the two-display quality gate

Source: SKILL.md on GitHub

No third-party reports yet.

Signed by skilld at 05acaca. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated last month
version
1.0.0

README badge

README badge for hyperb1iss/hypercolor/rgb-effect-design