Skip to content

Showcase: Logo reveal

The brand wordmark itself, on a seamless loop: the colored E-bars ignite out of shadow, the cream letterforms rise behind them, three specular shines rake across the locked lockup, then it settles back and repeats. Where the other four showcases carry heavy custom simulation or procedural generation on a thin engine seam, this one asks the opposite question — how little do you need? — and answers it with a pure, unit-tested timeline and one hand-written Skia shader. It’s the taste-over-spectacle piece, and the smallest engine footprint of the five.

The least of all five: just GameLoop (@flare-engine/core) for a pause-correct clock, and the post-FX finish (@flare-engine/postfx). No ECS, no particles, no simulation — not even the math package. Everything else is yours — the geometry, the timeline, the shader, and the compositing. It’s the proof that the same seam that carries an N-body merger also carries a three-rect logo without ceremony.

No raster asset goes through Skia. The cream letterforms are a single Path.MakeFromSVGString of the wordmark’s d; the six EƎ bars are rects. A small Mark bundles the viewBox, the (optional) letter path, and the cream/colored bars, so one renderer drives either the full lockup or the compact monogram:

const letterPath = mark.letterPathD ? kit.Path.MakeFromSVGString(mark.letterPathD) : null;
// six bars: left column cream, right column cyan / magenta / lime — drawn as rects, tintable per-bar

Colors come from the frozen palette that mirrors tokens.css, and a fit transform centres the mark in the canvas. One detail matters: keep Skia’s default Winding fill rule, or the counters of the A/R/E letterforms invert.

timeline.ts is a pure function, logoState(t) — no Skia, no mutable state, just numbers. The loop is seamless by construction: it opens and closes on a flat “ember” rest (every reveal envelope saturated or zero, with zero slope), so value and velocity match across the wrap. That invariant is unit-tested, not eyeballed:

// the visible state matches across the seam (position + velocity), so the hero never hitches
expect(visible(LOOP_PERIOD - 1e-6)).toBeCloseTo(visible(0));

The beats: colored bars ignite staggered (cyan → magenta → lime), the cream emerges from shadow (blur → 0 as it sharpens), three shines sweep across (R→L, L→R, R→L), then it drains back to ember. logoState returns the bar alphas, the cream alpha/blur, and the active shine’s position, direction, and strength — the renderer knows nothing about timing, and the tests know nothing about Skia.

The bespoke shine: a hand-written Skia shader

Section titled “The bespoke shine: a hand-written Skia shader”

The star of the piece. The specular sheen is a real RuntimeEffect (SkSL) — not a moving gradient. It rakes a feathered band along a diagonal axis and samples that band at ±uDisp per channel, so the edges throw a cyan/magenta prism fringe that peaks with the flash and collapses to nothing at rest — the engine’s own light-split brand, expressed in a fragment shader:

half4 main(float2 coord) {
float base = dot(coord - uPivot, uDir) - uOffset; // signed distance along the sweep axis
float r = bandAt(base - uDisp); // R/G/B sampled with a dispersion offset
float g = bandAt(base);
float b = bandAt(base + uDisp);
half3 col = half3(r, g, b) * uStrength;
return half4(col, max(col.r, max(col.g, col.b))); // additive light, premultiplied
}

Because a runtime shader is evaluated in local space, coord arrives in the mark’s own viewBox units — the sweep is resolution-independent and looks identical at any canvas size. And if the shader won’t compile on a given GPU driver, the renderer falls back to an equivalent linear-gradient band: the shine degrades, it never breaks.

A white sheen drawn over the cyan bar would wash it toward white. So the white shine is clipped to the cream only; each colored bar instead brightens in its own palette color as the band crosses it — an analytic copy of the shader’s band falloff, evaluated at the bar’s projection on the sweep axis. Additive Plus blending keeps the hue: the bar shines bluer, never whiter.

The flash is just the composite intensity. composite(baseBloom + bloom · sheenStrength) spikes the engine bloom as each shine crosses centre, and a heavily-blurred additive re-draw of the lit mark spreads a real halo outward — the stock bloom only boosts bright pixels in place, so the spread is worth the extra pass.

No simulation means no onFixedUpdate, no ECS, no pool — just a clock and a draw:

const loop = new GameLoop({ fixedDt: 1 / 60, maxDt: 0.1 });
let t = 0;
loop.onUpdate.add((dt) => { t = (t + dt) % period; }); // pause-correct: dt only accrues while running
loop.onPreRender.add(() => renderer.draw(t));

The instance exposes only the six required contract members plus a handful of live dev-panel knobs (shine glow, width, prism split, bloom, and shine speed). And the details that make it ship: it renders at up to 2× device pixels so the letters stay crisp on retina (backing store only — the canvas CSS size is untouched), swaps to the compact monogram below 480 px, and — like every hero — is never instantiated under prefers-reduced-motion, where the static wordmark already in the page DOM is the reduced story.

  1. The brand wordmark as Skia geometry — a parsed letter path + six tintable rects, no raster asset.
  2. A pure, unit-tested logoState(t) — seamless by construction, with an ember rest at both ends.
  3. A bespoke SkSL RuntimeEffect for the specular sweep + prism dispersion, with a gradient fallback.
  4. Hue-preserving per-bar shine (own-colour additive) + a spreading bloom halo for the flash.
  5. The thinnest engine seam of the five: just GameLoop and the post-FX finish.

No simulation, a pure timeline, and one hand-written shader — the light showcase that proves the same seam carrying the heavy pieces carries this too.