@apollo-deploy/avatars 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -151,6 +151,57 @@ function drawMeshGradient(ctx, seed, size) {
151
151
  ctx.fillStyle = hg;
152
152
  ctx.fillRect(0, 0, size, size);
153
153
  }
154
+ function createAnimatedSpots(seed, size) {
155
+ const s = toSeed(seed);
156
+ const { colors } = generatePalette(s);
157
+ const random = seededRandom(s * 12345);
158
+ const numSpots = 8 + Math.floor(random() * 5);
159
+ const spots = [];
160
+ for (let i = 0; i < numSpots; i++) {
161
+ const angle = random() * Math.PI * 2;
162
+ const distance = random() * size * 0.4;
163
+ const centerX = size / 2 + Math.cos(angle) * distance;
164
+ const centerY = size / 2 + Math.sin(angle) * distance;
165
+ spots.push({
166
+ x: centerX + (random() - 0.5) * size * 0.3,
167
+ y: centerY + (random() - 0.5) * size * 0.3,
168
+ radius: size * (0.3 + random() * 0.4),
169
+ color: colors[i % colors.length],
170
+ phaseX: random(),
171
+ phaseY: random(),
172
+ amplitude: 0.03 + random() * 0.06
173
+ });
174
+ }
175
+ spots.sort((a, b) => b.radius - a.radius);
176
+ return spots;
177
+ }
178
+ function drawAnimatedSpots(ctx, spots, backgroundColor, size, time) {
179
+ ctx.fillStyle = backgroundColor;
180
+ ctx.fillRect(0, 0, size, size);
181
+ ctx.globalCompositeOperation = "source-over";
182
+ for (const spot of spots) {
183
+ const periodX = 12 + spot.phaseX * 8;
184
+ const periodY = 14 + spot.phaseY * 10;
185
+ const drift = spot.amplitude * size;
186
+ const sx = spot.x + Math.sin(time * (2 * Math.PI / periodX) + spot.phaseX * Math.PI * 2) * drift;
187
+ const sy = spot.y + Math.cos(time * (2 * Math.PI / periodY) + spot.phaseY * Math.PI * 2) * drift;
188
+ const g = ctx.createRadialGradient(sx, sy, 0, sx, sy, spot.radius);
189
+ g.addColorStop(0, `${spot.color}FF`);
190
+ g.addColorStop(0.3, `${spot.color}DD`);
191
+ g.addColorStop(0.6, `${spot.color}88`);
192
+ g.addColorStop(1, `${spot.color}00`);
193
+ ctx.fillStyle = g;
194
+ ctx.fillRect(0, 0, size, size);
195
+ }
196
+ const hSize = size * 0.3;
197
+ const hx = size * 0.35 + Math.sin(time * 0.3) * size * 0.1;
198
+ const hy = size * 0.35 + Math.cos(time * 0.4) * size * 0.1;
199
+ const hg = ctx.createRadialGradient(hx, hy, 0, hx, hy, hSize);
200
+ hg.addColorStop(0, "rgba(255,255,255,0.15)");
201
+ hg.addColorStop(1, "rgba(255,255,255,0)");
202
+ ctx.fillStyle = hg;
203
+ ctx.fillRect(0, 0, size, size);
204
+ }
154
205
  function blurFor(size, blur) {
155
206
  if (blur === 0) return 0;
156
207
  return blur ?? Math.round(size * DEFAULT_BLUR_FRACTION);
@@ -235,8 +286,57 @@ function gradientToBlob(seed, options = {}) {
235
286
  }
236
287
  var RENDER_SIZE = 256;
237
288
  var BLUR_FRACTION = 0.06;
289
+ var REDRAW_MS = 67;
290
+ var subscribers = /* @__PURE__ */ new Set();
291
+ var tickerRaf = null;
292
+ var tickerLast = 0;
293
+ var tickerPaused = false;
294
+ function tick(now) {
295
+ tickerRaf = requestAnimationFrame(tick);
296
+ if (tickerPaused) return;
297
+ if (now - tickerLast < REDRAW_MS) return;
298
+ tickerLast = now;
299
+ for (const draw of subscribers) draw();
300
+ }
301
+ function subscribe(draw) {
302
+ subscribers.add(draw);
303
+ if (subscribers.size === 1 && tickerRaf === null) {
304
+ tickerLast = 0;
305
+ tickerRaf = requestAnimationFrame(tick);
306
+ }
307
+ }
308
+ function unsubscribe(draw) {
309
+ subscribers.delete(draw);
310
+ if (subscribers.size === 0 && tickerRaf !== null) {
311
+ cancelAnimationFrame(tickerRaf);
312
+ tickerRaf = null;
313
+ }
314
+ }
315
+ var io = null;
316
+ function ensureIntersectionObserver() {
317
+ if (io) return io;
318
+ io = new IntersectionObserver(
319
+ (entries) => {
320
+ for (const entry of entries) {
321
+ const el = entry.target;
322
+ el.__oaOnVis?.();
323
+ }
324
+ },
325
+ { threshold: 0 }
326
+ );
327
+ return io;
328
+ }
329
+ var visHandlerInstalled = false;
330
+ function ensureVisibilityHandler() {
331
+ if (visHandlerInstalled || typeof document === "undefined") return;
332
+ visHandlerInstalled = true;
333
+ document.addEventListener("visibilitychange", () => {
334
+ tickerPaused = document.visibilityState === "hidden";
335
+ if (!tickerPaused) tickerLast = 0;
336
+ });
337
+ }
238
338
  var ANIMATED_CLASS = "oa-avatar-canvas--animated";
239
- var STYLE_ELEMENT_ID = "oa-avatar-keyframes";
339
+ var STYLE_ID = "oa-avatar-keyframes";
240
340
  var KEYFRAMES_CSS = `
241
341
  @keyframes oa-avatar-drift {
242
342
  0% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }
@@ -265,12 +365,12 @@ var KEYFRAMES_CSS = `
265
365
  var stylesInjected = false;
266
366
  function ensureAnimationStyles() {
267
367
  if (stylesInjected || typeof document === "undefined") return;
268
- if (document.getElementById(STYLE_ELEMENT_ID)) {
368
+ if (document.getElementById(STYLE_ID)) {
269
369
  stylesInjected = true;
270
370
  return;
271
371
  }
272
372
  const el = document.createElement("style");
273
- el.id = STYLE_ELEMENT_ID;
373
+ el.id = STYLE_ID;
274
374
  el.textContent = KEYFRAMES_CSS;
275
375
  document.head.appendChild(el);
276
376
  stylesInjected = true;
@@ -285,23 +385,68 @@ function GradientAvatar({
285
385
  style
286
386
  }) {
287
387
  const canvasRef = react.useRef(null);
388
+ const wrapperRef = react.useRef(null);
389
+ const startRef = react.useRef(0);
390
+ const visibleRef = react.useRef(true);
391
+ react.useEffect(() => {
392
+ if (animate) {
393
+ ensureAnimationStyles();
394
+ ensureVisibilityHandler();
395
+ }
396
+ }, [animate]);
397
+ const draw = react.useCallback(() => {
398
+ const canvas = canvasRef.current;
399
+ if (!canvas || !visibleRef.current) return;
400
+ const ctx = canvas.getContext("2d");
401
+ if (!ctx) return;
402
+ if (startRef.current === 0) startRef.current = performance.now();
403
+ const elapsed = (performance.now() - startRef.current) / 1e3;
404
+ const time = elapsed * (2 * Math.PI / animationDuration);
405
+ const { colors } = generatePalette(seed);
406
+ const spots = createAnimatedSpots(seed, RENDER_SIZE);
407
+ drawAnimatedSpots(ctx, spots, colors[0], RENDER_SIZE, time);
408
+ }, [seed, animationDuration]);
288
409
  react.useEffect(() => {
289
410
  const canvas = canvasRef.current;
290
411
  if (!canvas) return;
291
412
  const ctx = canvas.getContext("2d");
292
413
  if (!ctx) return;
293
- ctx.clearRect(0, 0, RENDER_SIZE, RENDER_SIZE);
294
- drawMeshGradient(ctx, seed, RENDER_SIZE);
295
- }, [seed]);
414
+ const prefersReduced = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
415
+ if (!animate || prefersReduced) {
416
+ ctx.clearRect(0, 0, RENDER_SIZE, RENDER_SIZE);
417
+ drawMeshGradient(ctx, seed, RENDER_SIZE);
418
+ return;
419
+ }
420
+ startRef.current = 0;
421
+ const { colors } = generatePalette(seed);
422
+ const spots = createAnimatedSpots(seed, RENDER_SIZE);
423
+ drawAnimatedSpots(ctx, spots, colors[0], RENDER_SIZE, 0);
424
+ subscribe(draw);
425
+ return () => {
426
+ unsubscribe(draw);
427
+ };
428
+ }, [seed, animate, draw]);
296
429
  react.useEffect(() => {
297
- if (animate) ensureAnimationStyles();
430
+ const wrapper = wrapperRef.current;
431
+ if (!animate || !wrapper) return;
432
+ const observer = ensureIntersectionObserver();
433
+ wrapper.__oaOnVis = () => {
434
+ visibleRef.current = true;
435
+ };
436
+ observer.observe(wrapper);
437
+ return () => {
438
+ observer.unobserve(wrapper);
439
+ visibleRef.current = false;
440
+ delete wrapper.__oaOnVis;
441
+ };
298
442
  }, [animate]);
299
443
  const blurPx = Math.max(1, Math.round(size * BLUR_FRACTION));
300
444
  const canvasStyle = {
301
445
  width: "100%",
302
446
  height: "100%",
303
447
  display: "block",
304
- filter: `blur(${blurPx}px)`
448
+ filter: `blur(${blurPx}px)`,
449
+ transform: "scale(1.25)"
305
450
  };
306
451
  if (animate) {
307
452
  canvasStyle.animationDuration = `${animationDuration}s`;
@@ -309,6 +454,7 @@ function GradientAvatar({
309
454
  return /* @__PURE__ */ jsxRuntime.jsx(
310
455
  "span",
311
456
  {
457
+ ref: wrapperRef,
312
458
  className,
313
459
  style: {
314
460
  display: "inline-block",
@@ -322,6 +468,8 @@ function GradientAvatar({
322
468
  "canvas",
323
469
  {
324
470
  ref: canvasRef,
471
+ role: "img",
472
+ "aria-label": `Gradient avatar for seed ${seed}`,
325
473
  width: RENDER_SIZE,
326
474
  height: RENDER_SIZE,
327
475
  className: animate ? ANIMATED_CLASS : void 0,
@@ -333,6 +481,8 @@ function GradientAvatar({
333
481
  }
334
482
 
335
483
  exports.GradientAvatar = GradientAvatar;
484
+ exports.createAnimatedSpots = createAnimatedSpots;
485
+ exports.drawAnimatedSpots = drawAnimatedSpots;
336
486
  exports.drawMeshGradient = drawMeshGradient;
337
487
  exports.generatePalette = generatePalette;
338
488
  exports.gradientToBlob = gradientToBlob;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine.ts","../src/index.tsx"],"names":["useRef","useEffect","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Gradient engine for @apollo-deploy/avatars.\n *\n * Framework-agnostic mesh-gradient avatar generator. Every seed (string or\n * number) deterministically produces a unique gradient — no stored images,\n * no network. Pure palette/RNG core plus optional Canvas2D render helpers.\n */\n\nexport type Harmony =\n\t| \"analogous\"\n\t| \"triadic\"\n\t| \"splitComplementary\"\n\t| \"tetradic\"\n\t| \"complementary\";\n\nexport interface GradientPalette {\n\t/** The numeric seed the palette was derived from. */\n\tseed: number;\n\t/** Hex color stops used to paint the mesh. */\n\tcolors: string[];\n\t/** Which color-harmony rule produced the hues. */\n\tharmony: Harmony;\n}\n\nconst HARMONY_TYPES: Harmony[] = [\n\t\"analogous\",\n\t\"triadic\",\n\t\"splitComplementary\",\n\t\"tetradic\",\n\t\"complementary\",\n];\n\nconst GOLDEN_ANGLE = 137.5;\n\n/** Default blur radius as a fraction of the rendered dimension. */\nexport const DEFAULT_BLUR_FRACTION = 0.06;\n\nfunction seededRandom(seed: number): () => number {\n\tlet s = seed;\n\treturn () => {\n\t\ts += 0x6d2b79f5;\n\t\tlet t = s;\n\t\tt = Math.imul(t ^ (t >>> 15), t | 1);\n\t\tt ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\nfunction hslToHex(h: number, s: number, l: number): string {\n\th = ((h % 360) + 360) % 360;\n\ts = Math.max(0, Math.min(100, s)) / 100;\n\tl = Math.max(0, Math.min(100, l)) / 100;\n\n\tconst c = (1 - Math.abs(2 * l - 1)) * s;\n\tconst x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n\tconst m = l - c / 2;\n\n\tlet r = 0;\n\tlet g = 0;\n\tlet b = 0;\n\tif (h < 60) {\n\t\tr = c;\n\t\tg = x;\n\t} else if (h < 120) {\n\t\tr = x;\n\t\tg = c;\n\t} else if (h < 180) {\n\t\tg = c;\n\t\tb = x;\n\t} else if (h < 240) {\n\t\tg = x;\n\t\tb = c;\n\t} else if (h < 300) {\n\t\tr = x;\n\t\tb = c;\n\t} else {\n\t\tr = c;\n\t\tb = x;\n\t}\n\n\tconst toHex = (n: number) => {\n\t\tconst hex = Math.round((n + m) * 255).toString(16);\n\t\treturn hex.length === 1 ? `0${hex}` : hex;\n\t};\n\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();\n}\n\nfunction harmonyHues(baseHue: number, harmony: Harmony): number[] {\n\tswitch (harmony) {\n\t\tcase \"analogous\":\n\t\t\treturn [baseHue, baseHue + 30, baseHue + 60, baseHue - 30];\n\t\tcase \"triadic\":\n\t\t\treturn [baseHue, baseHue + 120, baseHue + 240];\n\t\tcase \"splitComplementary\":\n\t\t\treturn [baseHue, baseHue + 150, baseHue + 210];\n\t\tcase \"tetradic\":\n\t\t\treturn [baseHue, baseHue + 90, baseHue + 180, baseHue + 270];\n\t\tcase \"complementary\":\n\t\t\treturn [baseHue, baseHue + 180, baseHue + 20, baseHue + 200];\n\t}\n}\n\n/**\n * Stable string → 32-bit unsigned hash (FNV-1a + bit-mixing avalanche).\n * Uses the full uint32 range as a seed so similar strings diverge fully.\n */\nexport function seedFromString(input: string): number {\n\tlet h = 2166136261 >>> 0;\n\tfor (let i = 0; i < input.length; i++) {\n\t\th ^= input.charCodeAt(i);\n\t\th = Math.imul(h, 16777619) >>> 0;\n\t}\n\th ^= h >>> 16;\n\th = Math.imul(h, 0x7feb352d) >>> 0;\n\th ^= h >>> 15;\n\th = Math.imul(h, 0x846ca68b) >>> 0;\n\th ^= h >>> 16;\n\treturn h >>> 0;\n}\n\n/** Normalize a string or number seed to the numeric seed used internally. */\nexport function toSeed(seed: number | string): number {\n\tif (typeof seed === \"number\") return seed;\n\treturn seedFromString(seed);\n}\n\n/** Derive the deterministic color palette for a seed. */\nexport function generatePalette(seed: number | string): GradientPalette {\n\tconst s = toSeed(seed);\n\tconst random = seededRandom(s);\n\tconst baseHue = (s * GOLDEN_ANGLE) % 360;\n\tconst harmonyIndex = Math.floor(random() * HARMONY_TYPES.length);\n\tconst harmony = HARMONY_TYPES[harmonyIndex];\n\tconst hues = harmonyHues(baseHue, harmony);\n\tconst colors = hues.map((hue) => {\n\t\tconst saturation = 75 + random() * 25;\n\t\tconst lightness = 50 + random() * 20;\n\t\treturn hslToHex(hue, saturation, lightness);\n\t});\n\treturn { seed: s, colors, harmony };\n}\n\n/**\n * Minimal Canvas2D context surface the renderer needs. Both\n * `HTMLCanvasElement` and `OffscreenCanvas` 2D contexts satisfy it.\n */\nexport type GradientContext = {\n\tfillStyle: string | CanvasGradient | CanvasPattern;\n\tglobalCompositeOperation: GlobalCompositeOperation;\n\tfillRect(x: number, y: number, w: number, h: number): void;\n\tcreateRadialGradient(\n\t\tx0: number,\n\t\ty0: number,\n\t\tr0: number,\n\t\tx1: number,\n\t\ty1: number,\n\t\tr1: number,\n\t): CanvasGradient;\n};\n\n/**\n * Draw the mesh gradient for `seed` into `ctx` at `size` x `size`.\n * The caller is responsible for any blur — apply `filter: blur(…)` on the\n * displayed canvas (≈6% of the rendered dimension) for the signature look,\n * or use {@link renderGradient} / {@link gradientToDataURL} which bake it in.\n */\nexport function drawMeshGradient(\n\tctx: GradientContext,\n\tseed: number | string,\n\tsize: number,\n): void {\n\tconst s = toSeed(seed);\n\tconst { colors } = generatePalette(s);\n\tconst random = seededRandom(s * 12345);\n\n\tctx.fillStyle = colors[0];\n\tctx.fillRect(0, 0, size, size);\n\n\tconst numSpots = 8 + Math.floor(random() * 5);\n\tconst spots: Array<{ x: number; y: number; radius: number; color: string }> =\n\t\t[];\n\n\tfor (let i = 0; i < numSpots; i++) {\n\t\tconst angle = random() * Math.PI * 2;\n\t\tconst distance = random() * size * 0.4;\n\t\tconst centerX = size / 2 + Math.cos(angle) * distance;\n\t\tconst centerY = size / 2 + Math.sin(angle) * distance;\n\t\tspots.push({\n\t\t\tx: centerX + (random() - 0.5) * size * 0.3,\n\t\t\ty: centerY + (random() - 0.5) * size * 0.3,\n\t\t\tradius: size * (0.3 + random() * 0.4),\n\t\t\tcolor: colors[i % colors.length],\n\t\t});\n\t}\n\n\tspots.sort((a, b) => b.radius - a.radius);\n\n\tctx.globalCompositeOperation = \"source-over\";\n\tfor (const spot of spots) {\n\t\tconst g = ctx.createRadialGradient(\n\t\t\tspot.x,\n\t\t\tspot.y,\n\t\t\t0,\n\t\t\tspot.x,\n\t\t\tspot.y,\n\t\t\tspot.radius,\n\t\t);\n\t\tg.addColorStop(0, `${spot.color}FF`);\n\t\tg.addColorStop(0.3, `${spot.color}DD`);\n\t\tg.addColorStop(0.6, `${spot.color}88`);\n\t\tg.addColorStop(1, `${spot.color}00`);\n\t\tctx.fillStyle = g;\n\t\tctx.fillRect(0, 0, size, size);\n\t}\n\n\tconst hx = size * 0.3 + random() * size * 0.2;\n\tconst hy = size * 0.3 + random() * size * 0.2;\n\tconst hg = ctx.createRadialGradient(hx, hy, 0, hx, hy, size * 0.3);\n\thg.addColorStop(0, \"rgba(255,255,255,0.15)\");\n\thg.addColorStop(1, \"rgba(255,255,255,0)\");\n\tctx.fillStyle = hg;\n\tctx.fillRect(0, 0, size, size);\n}\n\nexport interface RenderOptions {\n\t/**\n\t * Blur radius in pixels. Defaults to ~6% of the canvas size for the\n\t * signature soft look. Pass `0` to disable.\n\t */\n\tblur?: number;\n}\n\nfunction blurFor(size: number, blur?: number): number {\n\tif (blur === 0) return 0;\n\treturn blur ?? Math.round(size * DEFAULT_BLUR_FRACTION);\n}\n\n/**\n * Render a seed's gradient into an existing canvas, baking in the soft blur.\n * Draws at the canvas's current `width`/`height`. Browser/OffscreenCanvas only.\n */\nexport function renderGradient(\n\tcanvas: HTMLCanvasElement | OffscreenCanvas,\n\tseed: number | string,\n\toptions: RenderOptions = {},\n): void {\n\tconst size = canvas.width;\n\tconst blur = blurFor(size, options.blur);\n\n\tconst ctx = canvas.getContext(\"2d\") as CanvasRenderingContext2D | null;\n\tif (!ctx) return;\n\n\tif (blur <= 0) {\n\t\tctx.clearRect(0, 0, size, size);\n\t\tdrawMeshGradient(ctx, seed, size);\n\t\treturn;\n\t}\n\n\t// Draw the raw mesh on a scratch canvas, then composite it back with blur\n\t// scaled up slightly so the soft edges fall outside the frame (no ring).\n\tconst scratch = createCanvas(size, size);\n\tconst sctx = scratch.getContext(\"2d\") as CanvasRenderingContext2D | null;\n\tif (!sctx) return;\n\tdrawMeshGradient(sctx, seed, size);\n\n\tconst scaleUp = 1 + (blur / size) * 4;\n\tconst dw = size * scaleUp;\n\tconst offset = (dw - size) / 2;\n\tctx.clearRect(0, 0, size, size);\n\tif (supportsCanvasFilter()) {\n\t\tctx.filter = `blur(${blur}px)`;\n\t\tctx.drawImage(scratch as CanvasImageSource, -offset, -offset, dw, dw);\n\t\tctx.filter = \"none\";\n\t\treturn;\n\t}\n\t// 2D-canvas `filter` is a silent no-op on Safari < 17: approximate the\n\t// gaussian by bouncing through a small canvas. Bilinear resampling on the\n\t// way down and back up smears by roughly the downscale factor, which is\n\t// plenty for a mesh that is already smooth gradients.\n\tconst factor = Math.max(2, Math.min(16, blur / 2));\n\tconst sw = Math.max(1, Math.round(size / factor));\n\tconst small = createCanvas(sw, sw);\n\tconst smallCtx = small.getContext(\"2d\") as CanvasRenderingContext2D | null;\n\tif (!smallCtx) {\n\t\tctx.drawImage(scratch as CanvasImageSource, -offset, -offset, dw, dw);\n\t\treturn;\n\t}\n\tsmallCtx.imageSmoothingEnabled = true;\n\tsmallCtx.imageSmoothingQuality = \"high\";\n\tsmallCtx.drawImage(scratch as CanvasImageSource, 0, 0, sw, sw);\n\tctx.imageSmoothingEnabled = true;\n\tctx.imageSmoothingQuality = \"high\";\n\tctx.drawImage(small as CanvasImageSource, -offset, -offset, dw, dw);\n}\n\n/* Engines that honor 2D-canvas `filter` echo an assigned value back from the\n * property; Safari < 17 ignores the assignment. Probed once, then cached. */\nlet canvasFilterSupport: boolean | null = null;\nfunction supportsCanvasFilter(): boolean {\n\tif (canvasFilterSupport !== null) return canvasFilterSupport;\n\tconst probe = createCanvas(1, 1).getContext(\n\t\t\"2d\",\n\t) as CanvasRenderingContext2D | null;\n\tif (!probe) {\n\t\tcanvasFilterSupport = false;\n\t\treturn canvasFilterSupport;\n\t}\n\tprobe.filter = \"blur(1px)\";\n\tcanvasFilterSupport = probe.filter === \"blur(1px)\";\n\treturn canvasFilterSupport;\n}\n\nfunction createCanvas(\n\tw: number,\n\th: number,\n): HTMLCanvasElement | OffscreenCanvas {\n\tif (typeof OffscreenCanvas !== \"undefined\") {\n\t\treturn new OffscreenCanvas(w, h);\n\t}\n\tconst c = document.createElement(\"canvas\");\n\tc.width = w;\n\tc.height = h;\n\treturn c;\n}\n\nexport interface ExportOptions extends RenderOptions {\n\t/** Output pixel dimensions (square). Default: 512. */\n\tsize?: number;\n\t/** Image MIME type. Default: \"image/png\". */\n\ttype?: string;\n\t/** Quality 0–1 for lossy types. Default: 0.92. */\n\tquality?: number;\n}\n\n/** Render a seed's gradient and return it as a data URL. Browser only. */\nexport function gradientToDataURL(\n\tseed: number | string,\n\toptions: ExportOptions = {},\n): string {\n\tconst { size = 512, type = \"image/png\", quality = 0.92 } = options;\n\tconst canvas = document.createElement(\"canvas\");\n\tcanvas.width = size;\n\tcanvas.height = size;\n\trenderGradient(canvas, seed, options);\n\treturn canvas.toDataURL(type, quality);\n}\n\n/** Render a seed's gradient and resolve a Blob (or null). Browser only. */\nexport function gradientToBlob(\n\tseed: number | string,\n\toptions: ExportOptions = {},\n): Promise<Blob | null> {\n\tconst { size = 512, type = \"image/png\", quality = 0.92 } = options;\n\tconst canvas = document.createElement(\"canvas\");\n\tcanvas.width = size;\n\tcanvas.height = size;\n\trenderGradient(canvas, seed, options);\n\treturn new Promise((resolve) => canvas.toBlob(resolve, type, quality));\n}\n","import type { CSSProperties } from \"react\";\nimport { useEffect, useRef } from \"react\";\nimport { drawMeshGradient } from \"./engine\";\n\nexport interface GradientAvatarProps {\n\t/** Any string or number — each unique seed produces a unique gradient. */\n\tseed: number | string;\n\t/** Rendered size in pixels. Default: 32. */\n\tsize?: number;\n\t/**\n\t * Corner radius. Number = pixels, string = any CSS length.\n\t * Defaults to a full circle; pass `0` for a square or e.g. `12` for a\n\t * rounded square. Default: \"9999px\".\n\t */\n\tradius?: number | string;\n\t/**\n\t * Slowly drift the gradient with a GPU-only CSS animation. The canvas is\n\t * still painted just once — the motion is a compositor transform on the\n\t * cached layer, so there is no per-frame JavaScript, no repaint, and no\n\t * extra memory. Automatically disabled for users who request reduced\n\t * motion. Default: `false`.\n\t */\n\tanimate?: boolean;\n\t/**\n\t * Duration of one full drift cycle in seconds. Slower is subtler and\n\t * cheaper. Only applies when {@link animate} is `true`. Default: `16`.\n\t */\n\tanimationDuration?: number;\n\t/** Additional CSS classes on the wrapper. */\n\tclassName?: string;\n\t/** Extra inline styles merged onto the wrapper. */\n\tstyle?: CSSProperties;\n}\n\n/** Internal render resolution. Higher than display size so the CSS blur is smooth. */\nconst RENDER_SIZE = 256;\n/** Blur radius as a fraction of display size. */\nconst BLUR_FRACTION = 0.06;\n\n/** Class applied to the canvas when animating. Styles injected once, lazily. */\nconst ANIMATED_CLASS = \"oa-avatar-canvas--animated\";\nconst STYLE_ELEMENT_ID = \"oa-avatar-keyframes\";\n\n/**\n * Keyframes for the drift. The canvas is scaled up so that the rotation and\n * translation never expose the clipped container edges, and the whole thing is\n * a single `transform` track so the browser can run it entirely on the\n * compositor thread. `prefers-reduced-motion` opts out with no JS listener.\n */\nconst KEYFRAMES_CSS = `\n@keyframes oa-avatar-drift {\n\t0% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }\n\t20% { transform: scale(1.30) translate(-3%, 2%) rotate(8deg); }\n\t40% { transform: scale(1.22) translate(3%, 3%) rotate(-6deg); }\n\t60% { transform: scale(1.28) translate(2%, -3%) rotate(5deg); }\n\t80% { transform: scale(1.24) translate(-2%, -2%) rotate(-4deg); }\n\t100% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }\n}\n.${ANIMATED_CLASS} {\n\ttransform-origin: center;\n\twill-change: transform;\n\tanimation-name: oa-avatar-drift;\n\tanimation-timing-function: ease-in-out;\n\tanimation-iteration-count: infinite;\n\tanimation-direction: alternate;\n}\n@media (prefers-reduced-motion: reduce) {\n\t.${ANIMATED_CLASS} {\n\t\tanimation: none;\n\t\ttransform: none;\n\t\twill-change: auto;\n\t}\n}\n`;\n\nlet stylesInjected = false;\n\n/** Inject the drift keyframes into the document head exactly once (client-only). */\nfunction ensureAnimationStyles(): void {\n\tif (stylesInjected || typeof document === \"undefined\") return;\n\tif (document.getElementById(STYLE_ELEMENT_ID)) {\n\t\tstylesInjected = true;\n\t\treturn;\n\t}\n\tconst el = document.createElement(\"style\");\n\tel.id = STYLE_ELEMENT_ID;\n\tel.textContent = KEYFRAMES_CSS;\n\tdocument.head.appendChild(el);\n\tstylesInjected = true;\n}\n\n/**\n * Renders a deterministic mesh-gradient avatar on a `<canvas>`.\n * The same seed always produces the same gradient.\n */\nexport function GradientAvatar({\n\tseed,\n\tsize = 32,\n\tradius = \"9999px\",\n\tanimate = false,\n\tanimationDuration = 16,\n\tclassName,\n\tstyle,\n}: GradientAvatarProps) {\n\tconst canvasRef = useRef<HTMLCanvasElement>(null);\n\n\tuseEffect(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\t\tconst ctx = canvas.getContext(\"2d\");\n\t\tif (!ctx) return;\n\t\tctx.clearRect(0, 0, RENDER_SIZE, RENDER_SIZE);\n\t\tdrawMeshGradient(ctx, seed, RENDER_SIZE);\n\t}, [seed]);\n\n\tuseEffect(() => {\n\t\tif (animate) ensureAnimationStyles();\n\t}, [animate]);\n\n\tconst blurPx = Math.max(1, Math.round(size * BLUR_FRACTION));\n\n\tconst canvasStyle: CSSProperties = {\n\t\twidth: \"100%\",\n\t\theight: \"100%\",\n\t\tdisplay: \"block\",\n\t\tfilter: `blur(${blurPx}px)`,\n\t};\n\tif (animate) {\n\t\tcanvasStyle.animationDuration = `${animationDuration}s`;\n\t}\n\n\treturn (\n\t\t<span\n\t\t\tclassName={className}\n\t\t\tstyle={{\n\t\t\t\tdisplay: \"inline-block\",\n\t\t\t\toverflow: \"hidden\",\n\t\t\t\tborderRadius: radius,\n\t\t\t\twidth: size,\n\t\t\t\theight: size,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t>\n\t\t\t<canvas\n\t\t\t\tref={canvasRef}\n\t\t\t\twidth={RENDER_SIZE}\n\t\t\t\theight={RENDER_SIZE}\n\t\t\t\tclassName={animate ? ANIMATED_CLASS : undefined}\n\t\t\t\tstyle={canvasStyle}\n\t\t\t/>\n\t\t</span>\n\t);\n}\n\nexport type {\n\tExportOptions,\n\tGradientPalette,\n\tHarmony,\n\tRenderOptions,\n} from \"./engine\";\nexport {\n\tdrawMeshGradient,\n\tgeneratePalette,\n\tgradientToBlob,\n\tgradientToDataURL,\n\trenderGradient,\n\tseedFromString,\n\ttoSeed,\n} from \"./engine\";\n"]}
1
+ {"version":3,"sources":["../src/engine.ts","../src/index.tsx"],"names":["useRef","useEffect","useCallback","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Gradient engine for @apollo-deploy/avatars.\n *\n * Framework-agnostic mesh-gradient avatar generator. Every seed (string or\n * number) deterministically produces a unique gradient — no stored images,\n * no network. Pure palette/RNG core plus optional Canvas2D render helpers.\n */\n\nexport type Harmony =\n \"analogous\" | \"triadic\" | \"splitComplementary\" | \"tetradic\" | \"complementary\";\n\nexport interface GradientPalette {\n /** The numeric seed the palette was derived from. */\n seed: number;\n /** Hex color stops used to paint the mesh. */\n colors: string[];\n /** Which color-harmony rule produced the hues. */\n harmony: Harmony;\n}\n\nconst HARMONY_TYPES: Harmony[] = [\n \"analogous\",\n \"triadic\",\n \"splitComplementary\",\n \"tetradic\",\n \"complementary\",\n];\n\nconst GOLDEN_ANGLE = 137.5;\n\n/** Default blur radius as a fraction of the rendered dimension. */\nexport const DEFAULT_BLUR_FRACTION = 0.06;\n\nfunction seededRandom(seed: number): () => number {\n let s = seed;\n return () => {\n s += 0x6d2b79f5;\n let t = s;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\nfunction hslToHex(h: number, s: number, l: number): string {\n h = ((h % 360) + 360) % 360;\n s = Math.max(0, Math.min(100, s)) / 100;\n l = Math.max(0, Math.min(100, l)) / 100;\n\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = l - c / 2;\n\n let r = 0;\n let g = 0;\n let b = 0;\n if (h < 60) {\n r = c;\n g = x;\n } else if (h < 120) {\n r = x;\n g = c;\n } else if (h < 180) {\n g = c;\n b = x;\n } else if (h < 240) {\n g = x;\n b = c;\n } else if (h < 300) {\n r = x;\n b = c;\n } else {\n r = c;\n b = x;\n }\n\n const toHex = (n: number) => {\n const hex = Math.round((n + m) * 255).toString(16);\n return hex.length === 1 ? `0${hex}` : hex;\n };\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();\n}\n\nfunction harmonyHues(baseHue: number, harmony: Harmony): number[] {\n switch (harmony) {\n case \"analogous\":\n return [baseHue, baseHue + 30, baseHue + 60, baseHue - 30];\n case \"triadic\":\n return [baseHue, baseHue + 120, baseHue + 240];\n case \"splitComplementary\":\n return [baseHue, baseHue + 150, baseHue + 210];\n case \"tetradic\":\n return [baseHue, baseHue + 90, baseHue + 180, baseHue + 270];\n case \"complementary\":\n return [baseHue, baseHue + 180, baseHue + 20, baseHue + 200];\n }\n}\n\n/**\n * Stable string → 32-bit unsigned hash (FNV-1a + bit-mixing avalanche).\n * Uses the full uint32 range as a seed so similar strings diverge fully.\n */\nexport function seedFromString(input: string): number {\n let h = 2166136261 >>> 0;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = Math.imul(h, 16777619) >>> 0;\n }\n h ^= h >>> 16;\n h = Math.imul(h, 0x7feb352d) >>> 0;\n h ^= h >>> 15;\n h = Math.imul(h, 0x846ca68b) >>> 0;\n h ^= h >>> 16;\n return h >>> 0;\n}\n\n/** Normalize a string or number seed to the numeric seed used internally. */\nexport function toSeed(seed: number | string): number {\n if (typeof seed === \"number\") return seed;\n return seedFromString(seed);\n}\n\n/** Derive the deterministic color palette for a seed. */\nexport function generatePalette(seed: number | string): GradientPalette {\n const s = toSeed(seed);\n const random = seededRandom(s);\n const baseHue = (s * GOLDEN_ANGLE) % 360;\n const harmonyIndex = Math.floor(random() * HARMONY_TYPES.length);\n const harmony = HARMONY_TYPES[harmonyIndex];\n const hues = harmonyHues(baseHue, harmony);\n const colors = hues.map((hue) => {\n const saturation = 75 + random() * 25;\n const lightness = 50 + random() * 20;\n return hslToHex(hue, saturation, lightness);\n });\n return { seed: s, colors, harmony };\n}\n\n/**\n * Minimal Canvas2D context surface the renderer needs. Both\n * `HTMLCanvasElement` and `OffscreenCanvas` 2D contexts satisfy it.\n */\nexport type GradientContext = {\n fillStyle: string | CanvasGradient | CanvasPattern;\n globalCompositeOperation: GlobalCompositeOperation;\n fillRect(x: number, y: number, w: number, h: number): void;\n createRadialGradient(\n x0: number,\n y0: number,\n r0: number,\n x1: number,\n y1: number,\n r1: number,\n ): CanvasGradient;\n};\n\ninterface AnimatedSpot {\n x: number;\n y: number;\n radius: number;\n color: string;\n /** Unique phase offset (0–1) so each spot drifts independently. */\n phaseX: number;\n phaseY: number;\n /** How far the spot can drift from its origin (fraction of size). */\n amplitude: number;\n}\n\n/**\n * Draw the mesh gradient for `seed` into `ctx` at `size` x `size`.\n * The caller is responsible for any blur — apply `filter: blur(…)` on the\n * displayed canvas (≈6% of the rendered dimension) for the signature look,\n * or use {@link renderGradient} / {@link gradientToDataURL} which bake it in.\n */\nexport function drawMeshGradient(\n ctx: GradientContext,\n seed: number | string,\n size: number,\n): void {\n const s = toSeed(seed);\n const { colors } = generatePalette(s);\n const random = seededRandom(s * 12345);\n\n ctx.fillStyle = colors[0];\n ctx.fillRect(0, 0, size, size);\n\n const numSpots = 8 + Math.floor(random() * 5);\n const spots: Array<{ x: number; y: number; radius: number; color: string }> =\n [];\n\n for (let i = 0; i < numSpots; i++) {\n const angle = random() * Math.PI * 2;\n const distance = random() * size * 0.4;\n const centerX = size / 2 + Math.cos(angle) * distance;\n const centerY = size / 2 + Math.sin(angle) * distance;\n spots.push({\n x: centerX + (random() - 0.5) * size * 0.3,\n y: centerY + (random() - 0.5) * size * 0.3,\n radius: size * (0.3 + random() * 0.4),\n color: colors[i % colors.length],\n });\n }\n\n spots.sort((a, b) => b.radius - a.radius);\n\n ctx.globalCompositeOperation = \"source-over\";\n for (const spot of spots) {\n const g = ctx.createRadialGradient(\n spot.x,\n spot.y,\n 0,\n spot.x,\n spot.y,\n spot.radius,\n );\n g.addColorStop(0, `${spot.color}FF`);\n g.addColorStop(0.3, `${spot.color}DD`);\n g.addColorStop(0.6, `${spot.color}88`);\n g.addColorStop(1, `${spot.color}00`);\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, size, size);\n }\n\n const hx = size * 0.3 + random() * size * 0.2;\n const hy = size * 0.3 + random() * size * 0.2;\n const hg = ctx.createRadialGradient(hx, hy, 0, hx, hy, size * 0.3);\n hg.addColorStop(0, \"rgba(255,255,255,0.15)\");\n hg.addColorStop(1, \"rgba(255,255,255,0)\");\n ctx.fillStyle = hg;\n ctx.fillRect(0, 0, size, size);\n}\n\n/**\n * Compute animated spot data for a seed — call once, then pass the result\n * and a changing `time` (elapsed seconds) to {@link drawAnimatedSpots}.\n * This separates setup from the per-frame hot path so the palette and\n * random geometry are only derived once.\n */\nexport function createAnimatedSpots(\n seed: number | string,\n size: number,\n): AnimatedSpot[] {\n const s = toSeed(seed);\n const { colors } = generatePalette(s);\n const random = seededRandom(s * 12345);\n\n const numSpots = 8 + Math.floor(random() * 5);\n const spots: AnimatedSpot[] = [];\n\n for (let i = 0; i < numSpots; i++) {\n const angle = random() * Math.PI * 2;\n const distance = random() * size * 0.4;\n const centerX = size / 2 + Math.cos(angle) * distance;\n const centerY = size / 2 + Math.sin(angle) * distance;\n spots.push({\n x: centerX + (random() - 0.5) * size * 0.3,\n y: centerY + (random() - 0.5) * size * 0.3,\n radius: size * (0.3 + random() * 0.4),\n color: colors[i % colors.length],\n phaseX: random(),\n phaseY: random(),\n amplitude: 0.03 + random() * 0.06,\n });\n }\n\n spots.sort((a, b) => b.radius - a.radius);\n return spots;\n}\n\n/**\n * Draw animated mesh spots into `ctx`. Call on every frame with a monotonically\n * increasing `time` (seconds). Each spot orbits its anchor on a tiny Lissajous\n * path, scaled so the composite result always covers the canvas.\n */\nexport function drawAnimatedSpots(\n ctx: GradientContext,\n spots: AnimatedSpot[],\n backgroundColor: string,\n size: number,\n time: number,\n): void {\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, size, size);\n\n ctx.globalCompositeOperation = \"source-over\";\n for (const spot of spots) {\n // Lissajous drift: each spot moves on its own tiny elliptical path.\n // Different periods per axis keep it from looking like a uniform rotation.\n const periodX = 12 + spot.phaseX * 8;\n const periodY = 14 + spot.phaseY * 10;\n const drift = spot.amplitude * size;\n const sx =\n spot.x +\n Math.sin(time * ((2 * Math.PI) / periodX) + spot.phaseX * Math.PI * 2) *\n drift;\n const sy =\n spot.y +\n Math.cos(time * ((2 * Math.PI) / periodY) + spot.phaseY * Math.PI * 2) *\n drift;\n\n const g = ctx.createRadialGradient(sx, sy, 0, sx, sy, spot.radius);\n g.addColorStop(0, `${spot.color}FF`);\n g.addColorStop(0.3, `${spot.color}DD`);\n g.addColorStop(0.6, `${spot.color}88`);\n g.addColorStop(1, `${spot.color}00`);\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, size, size);\n }\n\n // Subtle highlight that drifts with time.\n const hSize = size * 0.3;\n const hx = size * 0.35 + Math.sin(time * 0.3) * size * 0.1;\n const hy = size * 0.35 + Math.cos(time * 0.4) * size * 0.1;\n const hg = ctx.createRadialGradient(hx, hy, 0, hx, hy, hSize);\n hg.addColorStop(0, \"rgba(255,255,255,0.15)\");\n hg.addColorStop(1, \"rgba(255,255,255,0)\");\n ctx.fillStyle = hg;\n ctx.fillRect(0, 0, size, size);\n}\n\nexport interface RenderOptions {\n /**\n * Blur radius in pixels. Defaults to ~6% of the canvas size for the\n * signature soft look. Pass `0` to disable.\n */\n blur?: number;\n}\n\nfunction blurFor(size: number, blur?: number): number {\n if (blur === 0) return 0;\n return blur ?? Math.round(size * DEFAULT_BLUR_FRACTION);\n}\n\n/**\n * Render a seed's gradient into an existing canvas, baking in the soft blur.\n * Draws at the canvas's current `width`/`height`. Browser/OffscreenCanvas only.\n */\nexport function renderGradient(\n canvas: HTMLCanvasElement | OffscreenCanvas,\n seed: number | string,\n options: RenderOptions = {},\n): void {\n const size = canvas.width;\n const blur = blurFor(size, options.blur);\n\n const ctx = canvas.getContext(\"2d\") as CanvasRenderingContext2D | null;\n if (!ctx) return;\n\n if (blur <= 0) {\n ctx.clearRect(0, 0, size, size);\n drawMeshGradient(ctx, seed, size);\n return;\n }\n\n // Draw the raw mesh on a scratch canvas, then composite it back with blur\n // scaled up slightly so the soft edges fall outside the frame (no ring).\n const scratch = createCanvas(size, size);\n const sctx = scratch.getContext(\"2d\") as CanvasRenderingContext2D | null;\n if (!sctx) return;\n drawMeshGradient(sctx, seed, size);\n\n const scaleUp = 1 + (blur / size) * 4;\n const dw = size * scaleUp;\n const offset = (dw - size) / 2;\n ctx.clearRect(0, 0, size, size);\n if (supportsCanvasFilter()) {\n ctx.filter = `blur(${blur}px)`;\n ctx.drawImage(scratch as CanvasImageSource, -offset, -offset, dw, dw);\n ctx.filter = \"none\";\n return;\n }\n // 2D-canvas `filter` is a silent no-op on Safari < 17: approximate the\n // gaussian by bouncing through a small canvas. Bilinear resampling on the\n // way down and back up smears by roughly the downscale factor, which is\n // plenty for a mesh that is already smooth gradients.\n const factor = Math.max(2, Math.min(16, blur / 2));\n const sw = Math.max(1, Math.round(size / factor));\n const small = createCanvas(sw, sw);\n const smallCtx = small.getContext(\"2d\") as CanvasRenderingContext2D | null;\n if (!smallCtx) {\n ctx.drawImage(scratch as CanvasImageSource, -offset, -offset, dw, dw);\n return;\n }\n smallCtx.imageSmoothingEnabled = true;\n smallCtx.imageSmoothingQuality = \"high\";\n smallCtx.drawImage(scratch as CanvasImageSource, 0, 0, sw, sw);\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = \"high\";\n ctx.drawImage(small as CanvasImageSource, -offset, -offset, dw, dw);\n}\n\n/* Engines that honor 2D-canvas `filter` echo an assigned value back from the\n * property; Safari < 17 ignores the assignment. Probed once, then cached. */\nlet canvasFilterSupport: boolean | null = null;\nfunction supportsCanvasFilter(): boolean {\n if (canvasFilterSupport !== null) return canvasFilterSupport;\n const probe = createCanvas(1, 1).getContext(\n \"2d\",\n ) as CanvasRenderingContext2D | null;\n if (!probe) {\n canvasFilterSupport = false;\n return canvasFilterSupport;\n }\n probe.filter = \"blur(1px)\";\n canvasFilterSupport = probe.filter === \"blur(1px)\";\n return canvasFilterSupport;\n}\n\nfunction createCanvas(\n w: number,\n h: number,\n): HTMLCanvasElement | OffscreenCanvas {\n if (typeof OffscreenCanvas !== \"undefined\") {\n return new OffscreenCanvas(w, h);\n }\n const c = document.createElement(\"canvas\");\n c.width = w;\n c.height = h;\n return c;\n}\n\nexport interface ExportOptions extends RenderOptions {\n /** Output pixel dimensions (square). Default: 512. */\n size?: number;\n /** Image MIME type. Default: \"image/png\". */\n type?: string;\n /** Quality 0–1 for lossy types. Default: 0.92. */\n quality?: number;\n}\n\n/** Render a seed's gradient and return it as a data URL. Browser only. */\nexport function gradientToDataURL(\n seed: number | string,\n options: ExportOptions = {},\n): string {\n const { size = 512, type = \"image/png\", quality = 0.92 } = options;\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n renderGradient(canvas, seed, options);\n return canvas.toDataURL(type, quality);\n}\n\n/** Render a seed's gradient and resolve a Blob (or null). Browser only. */\nexport function gradientToBlob(\n seed: number | string,\n options: ExportOptions = {},\n): Promise<Blob | null> {\n const { size = 512, type = \"image/png\", quality = 0.92 } = options;\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n renderGradient(canvas, seed, options);\n return new Promise((resolve) => canvas.toBlob(resolve, type, quality));\n}\n","import type { CSSProperties } from \"react\";\nimport { useCallback, useEffect, useRef } from \"react\";\nimport {\n createAnimatedSpots,\n drawAnimatedSpots,\n drawMeshGradient,\n generatePalette,\n} from \"./engine\";\n\nexport interface GradientAvatarProps {\n /** Any string or number — each unique seed produces a unique gradient. */\n seed: number | string;\n /** Rendered size in pixels. Default: 32. */\n size?: number;\n /**\n * Corner radius. Number = pixels, string = any CSS length.\n * Defaults to a full circle; pass `0` for a square or e.g. `12` for a\n * rounded square. Default: \"9999px\".\n */\n radius?: number | string;\n /**\n * Animate the gradient with a hybrid approach: CSS keyframes handle the\n * smooth drift (GPU-only, zero JS per frame), and the canvas content is\n * repainted at a low cadence (~15 fps) so the mesh spots evolve slowly.\n * A single shared rAF loop drives all animated instances; the ticker stops\n * when nothing is on screen or the tab is hidden. Automatically disabled\n * for users who request reduced motion. Default: `false`.\n */\n animate?: boolean;\n /**\n * Duration of one full drift cycle in seconds. Slower is subtler and\n * cheaper. Only applies when {@link animate} is `true`. Default: `16`.\n */\n animationDuration?: number;\n /** Additional CSS classes on the wrapper. */\n className?: string;\n /** Extra inline styles merged onto the wrapper. */\n style?: CSSProperties;\n}\n\n/* ------------------------------------------------------------------ */\n/* Shared animation infrastructure (module-level singletons) */\n/* ------------------------------------------------------------------ */\n\n/** Internal render resolution. */\nconst RENDER_SIZE = 256;\n/** Blur radius as a fraction of display size. */\nconst BLUR_FRACTION = 0.06;\n/** Canvas redraw interval (ms). ~15 fps keeps overhead very low. */\nconst REDRAW_MS = 67;\n\ntype DrawFn = () => void;\n\n/** Subscribers to the shared animation ticker. */\nconst subscribers = new Set<DrawFn>();\nlet tickerRaf: number | null = null;\nlet tickerLast = 0;\nlet tickerPaused = false;\n\nfunction tick(now: number): void {\n tickerRaf = requestAnimationFrame(tick);\n if (tickerPaused) return;\n if (now - tickerLast < REDRAW_MS) return;\n tickerLast = now;\n for (const draw of subscribers) draw();\n}\n\nfunction subscribe(draw: DrawFn): void {\n subscribers.add(draw);\n if (subscribers.size === 1 && tickerRaf === null) {\n tickerLast = 0;\n tickerRaf = requestAnimationFrame(tick);\n }\n}\n\nfunction unsubscribe(draw: DrawFn): void {\n subscribers.delete(draw);\n if (subscribers.size === 0 && tickerRaf !== null) {\n cancelAnimationFrame(tickerRaf);\n tickerRaf = null;\n }\n}\n\n/* Shared IntersectionObserver so we don't create one per avatar. */\nlet io: IntersectionObserver | null = null;\nconst visibles = new Set<() => void>();\n\nfunction ensureIntersectionObserver(): IntersectionObserver {\n if (io) return io;\n io = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const el = entry.target as HTMLElement & { __oaOnVis?: () => void };\n el.__oaOnVis?.();\n }\n },\n { threshold: 0 },\n );\n return io;\n}\n\n/* Shared visibilitychange handler. */\nlet visHandlerInstalled = false;\nfunction ensureVisibilityHandler(): void {\n if (visHandlerInstalled || typeof document === \"undefined\") return;\n visHandlerInstalled = true;\n document.addEventListener(\"visibilitychange\", () => {\n tickerPaused = document.visibilityState === \"hidden\";\n if (!tickerPaused) tickerLast = 0;\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* CSS keyframes (injected once, lazily) */\n/* ------------------------------------------------------------------ */\n\nconst ANIMATED_CLASS = \"oa-avatar-canvas--animated\";\nconst STYLE_ID = \"oa-avatar-keyframes\";\n\nconst KEYFRAMES_CSS = `\n@keyframes oa-avatar-drift {\n\t0% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }\n\t20% { transform: scale(1.30) translate(-3%, 2%) rotate(8deg); }\n\t40% { transform: scale(1.22) translate(3%, 3%) rotate(-6deg); }\n\t60% { transform: scale(1.28) translate(2%, -3%) rotate(5deg); }\n\t80% { transform: scale(1.24) translate(-2%, -2%) rotate(-4deg); }\n\t100% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }\n}\n.${ANIMATED_CLASS} {\n\ttransform-origin: center;\n\twill-change: transform;\n\tanimation-name: oa-avatar-drift;\n\tanimation-timing-function: ease-in-out;\n\tanimation-iteration-count: infinite;\n\tanimation-direction: alternate;\n}\n@media (prefers-reduced-motion: reduce) {\n\t.${ANIMATED_CLASS} {\n\t\tanimation: none;\n\t\ttransform: none;\n\t\twill-change: auto;\n\t}\n}\n`;\n\nlet stylesInjected = false;\n\nfunction ensureAnimationStyles(): void {\n if (stylesInjected || typeof document === \"undefined\") return;\n if (document.getElementById(STYLE_ID)) {\n stylesInjected = true;\n return;\n }\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = KEYFRAMES_CSS;\n document.head.appendChild(el);\n stylesInjected = true;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\n/**\n * Renders a deterministic mesh-gradient avatar on a `<canvas>`.\n * The same seed always produces the same gradient.\n *\n * When `animate` is on the gradient comes alive via two complementary\n * mechanisms:\n *\n * 1. **CSS keyframes** — a slow scale+rotate+translate drift that runs\n * entirely on the GPU compositor thread (zero JavaScript, zero repaint).\n * 2. **Low-cadence canvas repaint** — the mesh spots evolve at ~15 fps\n * through a single shared `requestAnimationFrame` loop, so N animated\n * avatars cost 1 rAF callback total. Drawing pauses when the element is\n * off-screen (`IntersectionObserver`) or the tab is hidden.\n */\nexport function GradientAvatar({\n seed,\n size = 32,\n radius = \"9999px\",\n animate = false,\n animationDuration = 16,\n className,\n style,\n}: GradientAvatarProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const wrapperRef = useRef<HTMLSpanElement>(null);\n const startRef = useRef<number>(0);\n const visibleRef = useRef(true);\n\n /* Inject CSS keyframes once (client-only). */\n useEffect(() => {\n if (animate) {\n ensureAnimationStyles();\n ensureVisibilityHandler();\n }\n }, [animate]);\n\n /* Draw loop: subscribe to the shared ticker, unsubscribe on cleanup. */\n const draw = useCallback(() => {\n const canvas = canvasRef.current;\n if (!canvas || !visibleRef.current) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n if (startRef.current === 0) startRef.current = performance.now();\n const elapsed = (performance.now() - startRef.current) / 1000;\n const time = elapsed * ((2 * Math.PI) / animationDuration);\n\n const { colors } = generatePalette(seed);\n const spots = createAnimatedSpots(seed, RENDER_SIZE);\n drawAnimatedSpots(ctx, spots, colors[0], RENDER_SIZE, time);\n }, [seed, animationDuration]);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const prefersReduced =\n typeof window !== \"undefined\" &&\n window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches;\n\n if (!animate || prefersReduced) {\n ctx.clearRect(0, 0, RENDER_SIZE, RENDER_SIZE);\n drawMeshGradient(ctx, seed, RENDER_SIZE);\n return;\n }\n\n /* Paint the initial frame. */\n startRef.current = 0;\n const { colors } = generatePalette(seed);\n const spots = createAnimatedSpots(seed, RENDER_SIZE);\n drawAnimatedSpots(ctx, spots, colors[0], RENDER_SIZE, 0);\n\n subscribe(draw);\n\n return () => {\n unsubscribe(draw);\n };\n }, [seed, animate, draw]);\n\n /* IntersectionObserver: pause redraws when the element scrolls off screen. */\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (!animate || !wrapper) return;\n\n const observer = ensureIntersectionObserver();\n // biome-ignore lint/suspicious/noAssignInExpressions: intentional pattern for attaching per-element callbacks\n (wrapper as HTMLElement & { __oaOnVis?: () => void }).__oaOnVis = () => {\n visibleRef.current = true;\n };\n observer.observe(wrapper);\n\n return () => {\n observer.unobserve(wrapper);\n visibleRef.current = false;\n delete (wrapper as HTMLElement & { __oaOnVis?: () => void }).__oaOnVis;\n };\n }, [animate]);\n\n const blurPx = Math.max(1, Math.round(size * BLUR_FRACTION));\n\n /* Canvas is always scaled 1.25× so drifting spots never expose the edge;\n * the CSS keyframes add their own scale+rotate+translate on top (class). */\n const canvasStyle: CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n filter: `blur(${blurPx}px)`,\n transform: \"scale(1.25)\",\n };\n if (animate) {\n canvasStyle.animationDuration = `${animationDuration}s`;\n }\n\n return (\n <span\n ref={wrapperRef}\n className={className}\n style={{\n display: \"inline-block\",\n overflow: \"hidden\",\n borderRadius: radius,\n width: size,\n height: size,\n ...style,\n }}\n >\n <canvas\n ref={canvasRef}\n role=\"img\"\n aria-label={`Gradient avatar for seed ${seed}`}\n width={RENDER_SIZE}\n height={RENDER_SIZE}\n className={animate ? ANIMATED_CLASS : undefined}\n style={canvasStyle}\n />\n </span>\n );\n}\n\nexport type {\n ExportOptions,\n GradientPalette,\n Harmony,\n RenderOptions,\n} from \"./engine\";\nexport {\n createAnimatedSpots,\n drawAnimatedSpots,\n drawMeshGradient,\n generatePalette,\n gradientToBlob,\n gradientToDataURL,\n renderGradient,\n seedFromString,\n toSeed,\n} from \"./engine\";\n"]}
package/dist/index.d.cts CHANGED
@@ -36,6 +36,17 @@ type GradientContext = {
36
36
  fillRect(x: number, y: number, w: number, h: number): void;
37
37
  createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): CanvasGradient;
38
38
  };
39
+ interface AnimatedSpot {
40
+ x: number;
41
+ y: number;
42
+ radius: number;
43
+ color: string;
44
+ /** Unique phase offset (0–1) so each spot drifts independently. */
45
+ phaseX: number;
46
+ phaseY: number;
47
+ /** How far the spot can drift from its origin (fraction of size). */
48
+ amplitude: number;
49
+ }
39
50
  /**
40
51
  * Draw the mesh gradient for `seed` into `ctx` at `size` x `size`.
41
52
  * The caller is responsible for any blur — apply `filter: blur(…)` on the
@@ -43,6 +54,19 @@ type GradientContext = {
43
54
  * or use {@link renderGradient} / {@link gradientToDataURL} which bake it in.
44
55
  */
45
56
  declare function drawMeshGradient(ctx: GradientContext, seed: number | string, size: number): void;
57
+ /**
58
+ * Compute animated spot data for a seed — call once, then pass the result
59
+ * and a changing `time` (elapsed seconds) to {@link drawAnimatedSpots}.
60
+ * This separates setup from the per-frame hot path so the palette and
61
+ * random geometry are only derived once.
62
+ */
63
+ declare function createAnimatedSpots(seed: number | string, size: number): AnimatedSpot[];
64
+ /**
65
+ * Draw animated mesh spots into `ctx`. Call on every frame with a monotonically
66
+ * increasing `time` (seconds). Each spot orbits its anchor on a tiny Lissajous
67
+ * path, scaled so the composite result always covers the canvas.
68
+ */
69
+ declare function drawAnimatedSpots(ctx: GradientContext, spots: AnimatedSpot[], backgroundColor: string, size: number, time: number): void;
46
70
  interface RenderOptions {
47
71
  /**
48
72
  * Blur radius in pixels. Defaults to ~6% of the canvas size for the
@@ -80,11 +104,12 @@ interface GradientAvatarProps {
80
104
  */
81
105
  radius?: number | string;
82
106
  /**
83
- * Slowly drift the gradient with a GPU-only CSS animation. The canvas is
84
- * still painted just once the motion is a compositor transform on the
85
- * cached layer, so there is no per-frame JavaScript, no repaint, and no
86
- * extra memory. Automatically disabled for users who request reduced
87
- * motion. Default: `false`.
107
+ * Animate the gradient with a hybrid approach: CSS keyframes handle the
108
+ * smooth drift (GPU-only, zero JS per frame), and the canvas content is
109
+ * repainted at a low cadence (~15 fps) so the mesh spots evolve slowly.
110
+ * A single shared rAF loop drives all animated instances; the ticker stops
111
+ * when nothing is on screen or the tab is hidden. Automatically disabled
112
+ * for users who request reduced motion. Default: `false`.
88
113
  */
89
114
  animate?: boolean;
90
115
  /**
@@ -100,7 +125,17 @@ interface GradientAvatarProps {
100
125
  /**
101
126
  * Renders a deterministic mesh-gradient avatar on a `<canvas>`.
102
127
  * The same seed always produces the same gradient.
128
+ *
129
+ * When `animate` is on the gradient comes alive via two complementary
130
+ * mechanisms:
131
+ *
132
+ * 1. **CSS keyframes** — a slow scale+rotate+translate drift that runs
133
+ * entirely on the GPU compositor thread (zero JavaScript, zero repaint).
134
+ * 2. **Low-cadence canvas repaint** — the mesh spots evolve at ~15 fps
135
+ * through a single shared `requestAnimationFrame` loop, so N animated
136
+ * avatars cost 1 rAF callback total. Drawing pauses when the element is
137
+ * off-screen (`IntersectionObserver`) or the tab is hidden.
103
138
  */
104
139
  declare function GradientAvatar({ seed, size, radius, animate, animationDuration, className, style, }: GradientAvatarProps): react_jsx_runtime.JSX.Element;
105
140
 
106
- export { type ExportOptions, GradientAvatar, type GradientAvatarProps, type GradientPalette, type Harmony, type RenderOptions, drawMeshGradient, generatePalette, gradientToBlob, gradientToDataURL, renderGradient, seedFromString, toSeed };
141
+ export { type ExportOptions, GradientAvatar, type GradientAvatarProps, type GradientPalette, type Harmony, type RenderOptions, createAnimatedSpots, drawAnimatedSpots, drawMeshGradient, generatePalette, gradientToBlob, gradientToDataURL, renderGradient, seedFromString, toSeed };
package/dist/index.d.ts CHANGED
@@ -36,6 +36,17 @@ type GradientContext = {
36
36
  fillRect(x: number, y: number, w: number, h: number): void;
37
37
  createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): CanvasGradient;
38
38
  };
39
+ interface AnimatedSpot {
40
+ x: number;
41
+ y: number;
42
+ radius: number;
43
+ color: string;
44
+ /** Unique phase offset (0–1) so each spot drifts independently. */
45
+ phaseX: number;
46
+ phaseY: number;
47
+ /** How far the spot can drift from its origin (fraction of size). */
48
+ amplitude: number;
49
+ }
39
50
  /**
40
51
  * Draw the mesh gradient for `seed` into `ctx` at `size` x `size`.
41
52
  * The caller is responsible for any blur — apply `filter: blur(…)` on the
@@ -43,6 +54,19 @@ type GradientContext = {
43
54
  * or use {@link renderGradient} / {@link gradientToDataURL} which bake it in.
44
55
  */
45
56
  declare function drawMeshGradient(ctx: GradientContext, seed: number | string, size: number): void;
57
+ /**
58
+ * Compute animated spot data for a seed — call once, then pass the result
59
+ * and a changing `time` (elapsed seconds) to {@link drawAnimatedSpots}.
60
+ * This separates setup from the per-frame hot path so the palette and
61
+ * random geometry are only derived once.
62
+ */
63
+ declare function createAnimatedSpots(seed: number | string, size: number): AnimatedSpot[];
64
+ /**
65
+ * Draw animated mesh spots into `ctx`. Call on every frame with a monotonically
66
+ * increasing `time` (seconds). Each spot orbits its anchor on a tiny Lissajous
67
+ * path, scaled so the composite result always covers the canvas.
68
+ */
69
+ declare function drawAnimatedSpots(ctx: GradientContext, spots: AnimatedSpot[], backgroundColor: string, size: number, time: number): void;
46
70
  interface RenderOptions {
47
71
  /**
48
72
  * Blur radius in pixels. Defaults to ~6% of the canvas size for the
@@ -80,11 +104,12 @@ interface GradientAvatarProps {
80
104
  */
81
105
  radius?: number | string;
82
106
  /**
83
- * Slowly drift the gradient with a GPU-only CSS animation. The canvas is
84
- * still painted just once the motion is a compositor transform on the
85
- * cached layer, so there is no per-frame JavaScript, no repaint, and no
86
- * extra memory. Automatically disabled for users who request reduced
87
- * motion. Default: `false`.
107
+ * Animate the gradient with a hybrid approach: CSS keyframes handle the
108
+ * smooth drift (GPU-only, zero JS per frame), and the canvas content is
109
+ * repainted at a low cadence (~15 fps) so the mesh spots evolve slowly.
110
+ * A single shared rAF loop drives all animated instances; the ticker stops
111
+ * when nothing is on screen or the tab is hidden. Automatically disabled
112
+ * for users who request reduced motion. Default: `false`.
88
113
  */
89
114
  animate?: boolean;
90
115
  /**
@@ -100,7 +125,17 @@ interface GradientAvatarProps {
100
125
  /**
101
126
  * Renders a deterministic mesh-gradient avatar on a `<canvas>`.
102
127
  * The same seed always produces the same gradient.
128
+ *
129
+ * When `animate` is on the gradient comes alive via two complementary
130
+ * mechanisms:
131
+ *
132
+ * 1. **CSS keyframes** — a slow scale+rotate+translate drift that runs
133
+ * entirely on the GPU compositor thread (zero JavaScript, zero repaint).
134
+ * 2. **Low-cadence canvas repaint** — the mesh spots evolve at ~15 fps
135
+ * through a single shared `requestAnimationFrame` loop, so N animated
136
+ * avatars cost 1 rAF callback total. Drawing pauses when the element is
137
+ * off-screen (`IntersectionObserver`) or the tab is hidden.
103
138
  */
104
139
  declare function GradientAvatar({ seed, size, radius, animate, animationDuration, className, style, }: GradientAvatarProps): react_jsx_runtime.JSX.Element;
105
140
 
106
- export { type ExportOptions, GradientAvatar, type GradientAvatarProps, type GradientPalette, type Harmony, type RenderOptions, drawMeshGradient, generatePalette, gradientToBlob, gradientToDataURL, renderGradient, seedFromString, toSeed };
141
+ export { type ExportOptions, GradientAvatar, type GradientAvatarProps, type GradientPalette, type Harmony, type RenderOptions, createAnimatedSpots, drawAnimatedSpots, drawMeshGradient, generatePalette, gradientToBlob, gradientToDataURL, renderGradient, seedFromString, toSeed };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useRef, useEffect } from 'react';
1
+ import { useRef, useEffect, useCallback } from 'react';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
 
4
4
  // src/index.tsx
@@ -149,6 +149,57 @@ function drawMeshGradient(ctx, seed, size) {
149
149
  ctx.fillStyle = hg;
150
150
  ctx.fillRect(0, 0, size, size);
151
151
  }
152
+ function createAnimatedSpots(seed, size) {
153
+ const s = toSeed(seed);
154
+ const { colors } = generatePalette(s);
155
+ const random = seededRandom(s * 12345);
156
+ const numSpots = 8 + Math.floor(random() * 5);
157
+ const spots = [];
158
+ for (let i = 0; i < numSpots; i++) {
159
+ const angle = random() * Math.PI * 2;
160
+ const distance = random() * size * 0.4;
161
+ const centerX = size / 2 + Math.cos(angle) * distance;
162
+ const centerY = size / 2 + Math.sin(angle) * distance;
163
+ spots.push({
164
+ x: centerX + (random() - 0.5) * size * 0.3,
165
+ y: centerY + (random() - 0.5) * size * 0.3,
166
+ radius: size * (0.3 + random() * 0.4),
167
+ color: colors[i % colors.length],
168
+ phaseX: random(),
169
+ phaseY: random(),
170
+ amplitude: 0.03 + random() * 0.06
171
+ });
172
+ }
173
+ spots.sort((a, b) => b.radius - a.radius);
174
+ return spots;
175
+ }
176
+ function drawAnimatedSpots(ctx, spots, backgroundColor, size, time) {
177
+ ctx.fillStyle = backgroundColor;
178
+ ctx.fillRect(0, 0, size, size);
179
+ ctx.globalCompositeOperation = "source-over";
180
+ for (const spot of spots) {
181
+ const periodX = 12 + spot.phaseX * 8;
182
+ const periodY = 14 + spot.phaseY * 10;
183
+ const drift = spot.amplitude * size;
184
+ const sx = spot.x + Math.sin(time * (2 * Math.PI / periodX) + spot.phaseX * Math.PI * 2) * drift;
185
+ const sy = spot.y + Math.cos(time * (2 * Math.PI / periodY) + spot.phaseY * Math.PI * 2) * drift;
186
+ const g = ctx.createRadialGradient(sx, sy, 0, sx, sy, spot.radius);
187
+ g.addColorStop(0, `${spot.color}FF`);
188
+ g.addColorStop(0.3, `${spot.color}DD`);
189
+ g.addColorStop(0.6, `${spot.color}88`);
190
+ g.addColorStop(1, `${spot.color}00`);
191
+ ctx.fillStyle = g;
192
+ ctx.fillRect(0, 0, size, size);
193
+ }
194
+ const hSize = size * 0.3;
195
+ const hx = size * 0.35 + Math.sin(time * 0.3) * size * 0.1;
196
+ const hy = size * 0.35 + Math.cos(time * 0.4) * size * 0.1;
197
+ const hg = ctx.createRadialGradient(hx, hy, 0, hx, hy, hSize);
198
+ hg.addColorStop(0, "rgba(255,255,255,0.15)");
199
+ hg.addColorStop(1, "rgba(255,255,255,0)");
200
+ ctx.fillStyle = hg;
201
+ ctx.fillRect(0, 0, size, size);
202
+ }
152
203
  function blurFor(size, blur) {
153
204
  if (blur === 0) return 0;
154
205
  return blur ?? Math.round(size * DEFAULT_BLUR_FRACTION);
@@ -233,8 +284,57 @@ function gradientToBlob(seed, options = {}) {
233
284
  }
234
285
  var RENDER_SIZE = 256;
235
286
  var BLUR_FRACTION = 0.06;
287
+ var REDRAW_MS = 67;
288
+ var subscribers = /* @__PURE__ */ new Set();
289
+ var tickerRaf = null;
290
+ var tickerLast = 0;
291
+ var tickerPaused = false;
292
+ function tick(now) {
293
+ tickerRaf = requestAnimationFrame(tick);
294
+ if (tickerPaused) return;
295
+ if (now - tickerLast < REDRAW_MS) return;
296
+ tickerLast = now;
297
+ for (const draw of subscribers) draw();
298
+ }
299
+ function subscribe(draw) {
300
+ subscribers.add(draw);
301
+ if (subscribers.size === 1 && tickerRaf === null) {
302
+ tickerLast = 0;
303
+ tickerRaf = requestAnimationFrame(tick);
304
+ }
305
+ }
306
+ function unsubscribe(draw) {
307
+ subscribers.delete(draw);
308
+ if (subscribers.size === 0 && tickerRaf !== null) {
309
+ cancelAnimationFrame(tickerRaf);
310
+ tickerRaf = null;
311
+ }
312
+ }
313
+ var io = null;
314
+ function ensureIntersectionObserver() {
315
+ if (io) return io;
316
+ io = new IntersectionObserver(
317
+ (entries) => {
318
+ for (const entry of entries) {
319
+ const el = entry.target;
320
+ el.__oaOnVis?.();
321
+ }
322
+ },
323
+ { threshold: 0 }
324
+ );
325
+ return io;
326
+ }
327
+ var visHandlerInstalled = false;
328
+ function ensureVisibilityHandler() {
329
+ if (visHandlerInstalled || typeof document === "undefined") return;
330
+ visHandlerInstalled = true;
331
+ document.addEventListener("visibilitychange", () => {
332
+ tickerPaused = document.visibilityState === "hidden";
333
+ if (!tickerPaused) tickerLast = 0;
334
+ });
335
+ }
236
336
  var ANIMATED_CLASS = "oa-avatar-canvas--animated";
237
- var STYLE_ELEMENT_ID = "oa-avatar-keyframes";
337
+ var STYLE_ID = "oa-avatar-keyframes";
238
338
  var KEYFRAMES_CSS = `
239
339
  @keyframes oa-avatar-drift {
240
340
  0% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }
@@ -263,12 +363,12 @@ var KEYFRAMES_CSS = `
263
363
  var stylesInjected = false;
264
364
  function ensureAnimationStyles() {
265
365
  if (stylesInjected || typeof document === "undefined") return;
266
- if (document.getElementById(STYLE_ELEMENT_ID)) {
366
+ if (document.getElementById(STYLE_ID)) {
267
367
  stylesInjected = true;
268
368
  return;
269
369
  }
270
370
  const el = document.createElement("style");
271
- el.id = STYLE_ELEMENT_ID;
371
+ el.id = STYLE_ID;
272
372
  el.textContent = KEYFRAMES_CSS;
273
373
  document.head.appendChild(el);
274
374
  stylesInjected = true;
@@ -283,23 +383,68 @@ function GradientAvatar({
283
383
  style
284
384
  }) {
285
385
  const canvasRef = useRef(null);
386
+ const wrapperRef = useRef(null);
387
+ const startRef = useRef(0);
388
+ const visibleRef = useRef(true);
389
+ useEffect(() => {
390
+ if (animate) {
391
+ ensureAnimationStyles();
392
+ ensureVisibilityHandler();
393
+ }
394
+ }, [animate]);
395
+ const draw = useCallback(() => {
396
+ const canvas = canvasRef.current;
397
+ if (!canvas || !visibleRef.current) return;
398
+ const ctx = canvas.getContext("2d");
399
+ if (!ctx) return;
400
+ if (startRef.current === 0) startRef.current = performance.now();
401
+ const elapsed = (performance.now() - startRef.current) / 1e3;
402
+ const time = elapsed * (2 * Math.PI / animationDuration);
403
+ const { colors } = generatePalette(seed);
404
+ const spots = createAnimatedSpots(seed, RENDER_SIZE);
405
+ drawAnimatedSpots(ctx, spots, colors[0], RENDER_SIZE, time);
406
+ }, [seed, animationDuration]);
286
407
  useEffect(() => {
287
408
  const canvas = canvasRef.current;
288
409
  if (!canvas) return;
289
410
  const ctx = canvas.getContext("2d");
290
411
  if (!ctx) return;
291
- ctx.clearRect(0, 0, RENDER_SIZE, RENDER_SIZE);
292
- drawMeshGradient(ctx, seed, RENDER_SIZE);
293
- }, [seed]);
412
+ const prefersReduced = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
413
+ if (!animate || prefersReduced) {
414
+ ctx.clearRect(0, 0, RENDER_SIZE, RENDER_SIZE);
415
+ drawMeshGradient(ctx, seed, RENDER_SIZE);
416
+ return;
417
+ }
418
+ startRef.current = 0;
419
+ const { colors } = generatePalette(seed);
420
+ const spots = createAnimatedSpots(seed, RENDER_SIZE);
421
+ drawAnimatedSpots(ctx, spots, colors[0], RENDER_SIZE, 0);
422
+ subscribe(draw);
423
+ return () => {
424
+ unsubscribe(draw);
425
+ };
426
+ }, [seed, animate, draw]);
294
427
  useEffect(() => {
295
- if (animate) ensureAnimationStyles();
428
+ const wrapper = wrapperRef.current;
429
+ if (!animate || !wrapper) return;
430
+ const observer = ensureIntersectionObserver();
431
+ wrapper.__oaOnVis = () => {
432
+ visibleRef.current = true;
433
+ };
434
+ observer.observe(wrapper);
435
+ return () => {
436
+ observer.unobserve(wrapper);
437
+ visibleRef.current = false;
438
+ delete wrapper.__oaOnVis;
439
+ };
296
440
  }, [animate]);
297
441
  const blurPx = Math.max(1, Math.round(size * BLUR_FRACTION));
298
442
  const canvasStyle = {
299
443
  width: "100%",
300
444
  height: "100%",
301
445
  display: "block",
302
- filter: `blur(${blurPx}px)`
446
+ filter: `blur(${blurPx}px)`,
447
+ transform: "scale(1.25)"
303
448
  };
304
449
  if (animate) {
305
450
  canvasStyle.animationDuration = `${animationDuration}s`;
@@ -307,6 +452,7 @@ function GradientAvatar({
307
452
  return /* @__PURE__ */ jsx(
308
453
  "span",
309
454
  {
455
+ ref: wrapperRef,
310
456
  className,
311
457
  style: {
312
458
  display: "inline-block",
@@ -320,6 +466,8 @@ function GradientAvatar({
320
466
  "canvas",
321
467
  {
322
468
  ref: canvasRef,
469
+ role: "img",
470
+ "aria-label": `Gradient avatar for seed ${seed}`,
323
471
  width: RENDER_SIZE,
324
472
  height: RENDER_SIZE,
325
473
  className: animate ? ANIMATED_CLASS : void 0,
@@ -330,6 +478,6 @@ function GradientAvatar({
330
478
  );
331
479
  }
332
480
 
333
- export { GradientAvatar, drawMeshGradient, generatePalette, gradientToBlob, gradientToDataURL, renderGradient, seedFromString, toSeed };
481
+ export { GradientAvatar, createAnimatedSpots, drawAnimatedSpots, drawMeshGradient, generatePalette, gradientToBlob, gradientToDataURL, renderGradient, seedFromString, toSeed };
334
482
  //# sourceMappingURL=index.js.map
335
483
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine.ts","../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Gradient engine for @apollo-deploy/avatars.\n *\n * Framework-agnostic mesh-gradient avatar generator. Every seed (string or\n * number) deterministically produces a unique gradient — no stored images,\n * no network. Pure palette/RNG core plus optional Canvas2D render helpers.\n */\n\nexport type Harmony =\n\t| \"analogous\"\n\t| \"triadic\"\n\t| \"splitComplementary\"\n\t| \"tetradic\"\n\t| \"complementary\";\n\nexport interface GradientPalette {\n\t/** The numeric seed the palette was derived from. */\n\tseed: number;\n\t/** Hex color stops used to paint the mesh. */\n\tcolors: string[];\n\t/** Which color-harmony rule produced the hues. */\n\tharmony: Harmony;\n}\n\nconst HARMONY_TYPES: Harmony[] = [\n\t\"analogous\",\n\t\"triadic\",\n\t\"splitComplementary\",\n\t\"tetradic\",\n\t\"complementary\",\n];\n\nconst GOLDEN_ANGLE = 137.5;\n\n/** Default blur radius as a fraction of the rendered dimension. */\nexport const DEFAULT_BLUR_FRACTION = 0.06;\n\nfunction seededRandom(seed: number): () => number {\n\tlet s = seed;\n\treturn () => {\n\t\ts += 0x6d2b79f5;\n\t\tlet t = s;\n\t\tt = Math.imul(t ^ (t >>> 15), t | 1);\n\t\tt ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\nfunction hslToHex(h: number, s: number, l: number): string {\n\th = ((h % 360) + 360) % 360;\n\ts = Math.max(0, Math.min(100, s)) / 100;\n\tl = Math.max(0, Math.min(100, l)) / 100;\n\n\tconst c = (1 - Math.abs(2 * l - 1)) * s;\n\tconst x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n\tconst m = l - c / 2;\n\n\tlet r = 0;\n\tlet g = 0;\n\tlet b = 0;\n\tif (h < 60) {\n\t\tr = c;\n\t\tg = x;\n\t} else if (h < 120) {\n\t\tr = x;\n\t\tg = c;\n\t} else if (h < 180) {\n\t\tg = c;\n\t\tb = x;\n\t} else if (h < 240) {\n\t\tg = x;\n\t\tb = c;\n\t} else if (h < 300) {\n\t\tr = x;\n\t\tb = c;\n\t} else {\n\t\tr = c;\n\t\tb = x;\n\t}\n\n\tconst toHex = (n: number) => {\n\t\tconst hex = Math.round((n + m) * 255).toString(16);\n\t\treturn hex.length === 1 ? `0${hex}` : hex;\n\t};\n\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();\n}\n\nfunction harmonyHues(baseHue: number, harmony: Harmony): number[] {\n\tswitch (harmony) {\n\t\tcase \"analogous\":\n\t\t\treturn [baseHue, baseHue + 30, baseHue + 60, baseHue - 30];\n\t\tcase \"triadic\":\n\t\t\treturn [baseHue, baseHue + 120, baseHue + 240];\n\t\tcase \"splitComplementary\":\n\t\t\treturn [baseHue, baseHue + 150, baseHue + 210];\n\t\tcase \"tetradic\":\n\t\t\treturn [baseHue, baseHue + 90, baseHue + 180, baseHue + 270];\n\t\tcase \"complementary\":\n\t\t\treturn [baseHue, baseHue + 180, baseHue + 20, baseHue + 200];\n\t}\n}\n\n/**\n * Stable string → 32-bit unsigned hash (FNV-1a + bit-mixing avalanche).\n * Uses the full uint32 range as a seed so similar strings diverge fully.\n */\nexport function seedFromString(input: string): number {\n\tlet h = 2166136261 >>> 0;\n\tfor (let i = 0; i < input.length; i++) {\n\t\th ^= input.charCodeAt(i);\n\t\th = Math.imul(h, 16777619) >>> 0;\n\t}\n\th ^= h >>> 16;\n\th = Math.imul(h, 0x7feb352d) >>> 0;\n\th ^= h >>> 15;\n\th = Math.imul(h, 0x846ca68b) >>> 0;\n\th ^= h >>> 16;\n\treturn h >>> 0;\n}\n\n/** Normalize a string or number seed to the numeric seed used internally. */\nexport function toSeed(seed: number | string): number {\n\tif (typeof seed === \"number\") return seed;\n\treturn seedFromString(seed);\n}\n\n/** Derive the deterministic color palette for a seed. */\nexport function generatePalette(seed: number | string): GradientPalette {\n\tconst s = toSeed(seed);\n\tconst random = seededRandom(s);\n\tconst baseHue = (s * GOLDEN_ANGLE) % 360;\n\tconst harmonyIndex = Math.floor(random() * HARMONY_TYPES.length);\n\tconst harmony = HARMONY_TYPES[harmonyIndex];\n\tconst hues = harmonyHues(baseHue, harmony);\n\tconst colors = hues.map((hue) => {\n\t\tconst saturation = 75 + random() * 25;\n\t\tconst lightness = 50 + random() * 20;\n\t\treturn hslToHex(hue, saturation, lightness);\n\t});\n\treturn { seed: s, colors, harmony };\n}\n\n/**\n * Minimal Canvas2D context surface the renderer needs. Both\n * `HTMLCanvasElement` and `OffscreenCanvas` 2D contexts satisfy it.\n */\nexport type GradientContext = {\n\tfillStyle: string | CanvasGradient | CanvasPattern;\n\tglobalCompositeOperation: GlobalCompositeOperation;\n\tfillRect(x: number, y: number, w: number, h: number): void;\n\tcreateRadialGradient(\n\t\tx0: number,\n\t\ty0: number,\n\t\tr0: number,\n\t\tx1: number,\n\t\ty1: number,\n\t\tr1: number,\n\t): CanvasGradient;\n};\n\n/**\n * Draw the mesh gradient for `seed` into `ctx` at `size` x `size`.\n * The caller is responsible for any blur — apply `filter: blur(…)` on the\n * displayed canvas (≈6% of the rendered dimension) for the signature look,\n * or use {@link renderGradient} / {@link gradientToDataURL} which bake it in.\n */\nexport function drawMeshGradient(\n\tctx: GradientContext,\n\tseed: number | string,\n\tsize: number,\n): void {\n\tconst s = toSeed(seed);\n\tconst { colors } = generatePalette(s);\n\tconst random = seededRandom(s * 12345);\n\n\tctx.fillStyle = colors[0];\n\tctx.fillRect(0, 0, size, size);\n\n\tconst numSpots = 8 + Math.floor(random() * 5);\n\tconst spots: Array<{ x: number; y: number; radius: number; color: string }> =\n\t\t[];\n\n\tfor (let i = 0; i < numSpots; i++) {\n\t\tconst angle = random() * Math.PI * 2;\n\t\tconst distance = random() * size * 0.4;\n\t\tconst centerX = size / 2 + Math.cos(angle) * distance;\n\t\tconst centerY = size / 2 + Math.sin(angle) * distance;\n\t\tspots.push({\n\t\t\tx: centerX + (random() - 0.5) * size * 0.3,\n\t\t\ty: centerY + (random() - 0.5) * size * 0.3,\n\t\t\tradius: size * (0.3 + random() * 0.4),\n\t\t\tcolor: colors[i % colors.length],\n\t\t});\n\t}\n\n\tspots.sort((a, b) => b.radius - a.radius);\n\n\tctx.globalCompositeOperation = \"source-over\";\n\tfor (const spot of spots) {\n\t\tconst g = ctx.createRadialGradient(\n\t\t\tspot.x,\n\t\t\tspot.y,\n\t\t\t0,\n\t\t\tspot.x,\n\t\t\tspot.y,\n\t\t\tspot.radius,\n\t\t);\n\t\tg.addColorStop(0, `${spot.color}FF`);\n\t\tg.addColorStop(0.3, `${spot.color}DD`);\n\t\tg.addColorStop(0.6, `${spot.color}88`);\n\t\tg.addColorStop(1, `${spot.color}00`);\n\t\tctx.fillStyle = g;\n\t\tctx.fillRect(0, 0, size, size);\n\t}\n\n\tconst hx = size * 0.3 + random() * size * 0.2;\n\tconst hy = size * 0.3 + random() * size * 0.2;\n\tconst hg = ctx.createRadialGradient(hx, hy, 0, hx, hy, size * 0.3);\n\thg.addColorStop(0, \"rgba(255,255,255,0.15)\");\n\thg.addColorStop(1, \"rgba(255,255,255,0)\");\n\tctx.fillStyle = hg;\n\tctx.fillRect(0, 0, size, size);\n}\n\nexport interface RenderOptions {\n\t/**\n\t * Blur radius in pixels. Defaults to ~6% of the canvas size for the\n\t * signature soft look. Pass `0` to disable.\n\t */\n\tblur?: number;\n}\n\nfunction blurFor(size: number, blur?: number): number {\n\tif (blur === 0) return 0;\n\treturn blur ?? Math.round(size * DEFAULT_BLUR_FRACTION);\n}\n\n/**\n * Render a seed's gradient into an existing canvas, baking in the soft blur.\n * Draws at the canvas's current `width`/`height`. Browser/OffscreenCanvas only.\n */\nexport function renderGradient(\n\tcanvas: HTMLCanvasElement | OffscreenCanvas,\n\tseed: number | string,\n\toptions: RenderOptions = {},\n): void {\n\tconst size = canvas.width;\n\tconst blur = blurFor(size, options.blur);\n\n\tconst ctx = canvas.getContext(\"2d\") as CanvasRenderingContext2D | null;\n\tif (!ctx) return;\n\n\tif (blur <= 0) {\n\t\tctx.clearRect(0, 0, size, size);\n\t\tdrawMeshGradient(ctx, seed, size);\n\t\treturn;\n\t}\n\n\t// Draw the raw mesh on a scratch canvas, then composite it back with blur\n\t// scaled up slightly so the soft edges fall outside the frame (no ring).\n\tconst scratch = createCanvas(size, size);\n\tconst sctx = scratch.getContext(\"2d\") as CanvasRenderingContext2D | null;\n\tif (!sctx) return;\n\tdrawMeshGradient(sctx, seed, size);\n\n\tconst scaleUp = 1 + (blur / size) * 4;\n\tconst dw = size * scaleUp;\n\tconst offset = (dw - size) / 2;\n\tctx.clearRect(0, 0, size, size);\n\tif (supportsCanvasFilter()) {\n\t\tctx.filter = `blur(${blur}px)`;\n\t\tctx.drawImage(scratch as CanvasImageSource, -offset, -offset, dw, dw);\n\t\tctx.filter = \"none\";\n\t\treturn;\n\t}\n\t// 2D-canvas `filter` is a silent no-op on Safari < 17: approximate the\n\t// gaussian by bouncing through a small canvas. Bilinear resampling on the\n\t// way down and back up smears by roughly the downscale factor, which is\n\t// plenty for a mesh that is already smooth gradients.\n\tconst factor = Math.max(2, Math.min(16, blur / 2));\n\tconst sw = Math.max(1, Math.round(size / factor));\n\tconst small = createCanvas(sw, sw);\n\tconst smallCtx = small.getContext(\"2d\") as CanvasRenderingContext2D | null;\n\tif (!smallCtx) {\n\t\tctx.drawImage(scratch as CanvasImageSource, -offset, -offset, dw, dw);\n\t\treturn;\n\t}\n\tsmallCtx.imageSmoothingEnabled = true;\n\tsmallCtx.imageSmoothingQuality = \"high\";\n\tsmallCtx.drawImage(scratch as CanvasImageSource, 0, 0, sw, sw);\n\tctx.imageSmoothingEnabled = true;\n\tctx.imageSmoothingQuality = \"high\";\n\tctx.drawImage(small as CanvasImageSource, -offset, -offset, dw, dw);\n}\n\n/* Engines that honor 2D-canvas `filter` echo an assigned value back from the\n * property; Safari < 17 ignores the assignment. Probed once, then cached. */\nlet canvasFilterSupport: boolean | null = null;\nfunction supportsCanvasFilter(): boolean {\n\tif (canvasFilterSupport !== null) return canvasFilterSupport;\n\tconst probe = createCanvas(1, 1).getContext(\n\t\t\"2d\",\n\t) as CanvasRenderingContext2D | null;\n\tif (!probe) {\n\t\tcanvasFilterSupport = false;\n\t\treturn canvasFilterSupport;\n\t}\n\tprobe.filter = \"blur(1px)\";\n\tcanvasFilterSupport = probe.filter === \"blur(1px)\";\n\treturn canvasFilterSupport;\n}\n\nfunction createCanvas(\n\tw: number,\n\th: number,\n): HTMLCanvasElement | OffscreenCanvas {\n\tif (typeof OffscreenCanvas !== \"undefined\") {\n\t\treturn new OffscreenCanvas(w, h);\n\t}\n\tconst c = document.createElement(\"canvas\");\n\tc.width = w;\n\tc.height = h;\n\treturn c;\n}\n\nexport interface ExportOptions extends RenderOptions {\n\t/** Output pixel dimensions (square). Default: 512. */\n\tsize?: number;\n\t/** Image MIME type. Default: \"image/png\". */\n\ttype?: string;\n\t/** Quality 0–1 for lossy types. Default: 0.92. */\n\tquality?: number;\n}\n\n/** Render a seed's gradient and return it as a data URL. Browser only. */\nexport function gradientToDataURL(\n\tseed: number | string,\n\toptions: ExportOptions = {},\n): string {\n\tconst { size = 512, type = \"image/png\", quality = 0.92 } = options;\n\tconst canvas = document.createElement(\"canvas\");\n\tcanvas.width = size;\n\tcanvas.height = size;\n\trenderGradient(canvas, seed, options);\n\treturn canvas.toDataURL(type, quality);\n}\n\n/** Render a seed's gradient and resolve a Blob (or null). Browser only. */\nexport function gradientToBlob(\n\tseed: number | string,\n\toptions: ExportOptions = {},\n): Promise<Blob | null> {\n\tconst { size = 512, type = \"image/png\", quality = 0.92 } = options;\n\tconst canvas = document.createElement(\"canvas\");\n\tcanvas.width = size;\n\tcanvas.height = size;\n\trenderGradient(canvas, seed, options);\n\treturn new Promise((resolve) => canvas.toBlob(resolve, type, quality));\n}\n","import type { CSSProperties } from \"react\";\nimport { useEffect, useRef } from \"react\";\nimport { drawMeshGradient } from \"./engine\";\n\nexport interface GradientAvatarProps {\n\t/** Any string or number — each unique seed produces a unique gradient. */\n\tseed: number | string;\n\t/** Rendered size in pixels. Default: 32. */\n\tsize?: number;\n\t/**\n\t * Corner radius. Number = pixels, string = any CSS length.\n\t * Defaults to a full circle; pass `0` for a square or e.g. `12` for a\n\t * rounded square. Default: \"9999px\".\n\t */\n\tradius?: number | string;\n\t/**\n\t * Slowly drift the gradient with a GPU-only CSS animation. The canvas is\n\t * still painted just once — the motion is a compositor transform on the\n\t * cached layer, so there is no per-frame JavaScript, no repaint, and no\n\t * extra memory. Automatically disabled for users who request reduced\n\t * motion. Default: `false`.\n\t */\n\tanimate?: boolean;\n\t/**\n\t * Duration of one full drift cycle in seconds. Slower is subtler and\n\t * cheaper. Only applies when {@link animate} is `true`. Default: `16`.\n\t */\n\tanimationDuration?: number;\n\t/** Additional CSS classes on the wrapper. */\n\tclassName?: string;\n\t/** Extra inline styles merged onto the wrapper. */\n\tstyle?: CSSProperties;\n}\n\n/** Internal render resolution. Higher than display size so the CSS blur is smooth. */\nconst RENDER_SIZE = 256;\n/** Blur radius as a fraction of display size. */\nconst BLUR_FRACTION = 0.06;\n\n/** Class applied to the canvas when animating. Styles injected once, lazily. */\nconst ANIMATED_CLASS = \"oa-avatar-canvas--animated\";\nconst STYLE_ELEMENT_ID = \"oa-avatar-keyframes\";\n\n/**\n * Keyframes for the drift. The canvas is scaled up so that the rotation and\n * translation never expose the clipped container edges, and the whole thing is\n * a single `transform` track so the browser can run it entirely on the\n * compositor thread. `prefers-reduced-motion` opts out with no JS listener.\n */\nconst KEYFRAMES_CSS = `\n@keyframes oa-avatar-drift {\n\t0% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }\n\t20% { transform: scale(1.30) translate(-3%, 2%) rotate(8deg); }\n\t40% { transform: scale(1.22) translate(3%, 3%) rotate(-6deg); }\n\t60% { transform: scale(1.28) translate(2%, -3%) rotate(5deg); }\n\t80% { transform: scale(1.24) translate(-2%, -2%) rotate(-4deg); }\n\t100% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }\n}\n.${ANIMATED_CLASS} {\n\ttransform-origin: center;\n\twill-change: transform;\n\tanimation-name: oa-avatar-drift;\n\tanimation-timing-function: ease-in-out;\n\tanimation-iteration-count: infinite;\n\tanimation-direction: alternate;\n}\n@media (prefers-reduced-motion: reduce) {\n\t.${ANIMATED_CLASS} {\n\t\tanimation: none;\n\t\ttransform: none;\n\t\twill-change: auto;\n\t}\n}\n`;\n\nlet stylesInjected = false;\n\n/** Inject the drift keyframes into the document head exactly once (client-only). */\nfunction ensureAnimationStyles(): void {\n\tif (stylesInjected || typeof document === \"undefined\") return;\n\tif (document.getElementById(STYLE_ELEMENT_ID)) {\n\t\tstylesInjected = true;\n\t\treturn;\n\t}\n\tconst el = document.createElement(\"style\");\n\tel.id = STYLE_ELEMENT_ID;\n\tel.textContent = KEYFRAMES_CSS;\n\tdocument.head.appendChild(el);\n\tstylesInjected = true;\n}\n\n/**\n * Renders a deterministic mesh-gradient avatar on a `<canvas>`.\n * The same seed always produces the same gradient.\n */\nexport function GradientAvatar({\n\tseed,\n\tsize = 32,\n\tradius = \"9999px\",\n\tanimate = false,\n\tanimationDuration = 16,\n\tclassName,\n\tstyle,\n}: GradientAvatarProps) {\n\tconst canvasRef = useRef<HTMLCanvasElement>(null);\n\n\tuseEffect(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\t\tconst ctx = canvas.getContext(\"2d\");\n\t\tif (!ctx) return;\n\t\tctx.clearRect(0, 0, RENDER_SIZE, RENDER_SIZE);\n\t\tdrawMeshGradient(ctx, seed, RENDER_SIZE);\n\t}, [seed]);\n\n\tuseEffect(() => {\n\t\tif (animate) ensureAnimationStyles();\n\t}, [animate]);\n\n\tconst blurPx = Math.max(1, Math.round(size * BLUR_FRACTION));\n\n\tconst canvasStyle: CSSProperties = {\n\t\twidth: \"100%\",\n\t\theight: \"100%\",\n\t\tdisplay: \"block\",\n\t\tfilter: `blur(${blurPx}px)`,\n\t};\n\tif (animate) {\n\t\tcanvasStyle.animationDuration = `${animationDuration}s`;\n\t}\n\n\treturn (\n\t\t<span\n\t\t\tclassName={className}\n\t\t\tstyle={{\n\t\t\t\tdisplay: \"inline-block\",\n\t\t\t\toverflow: \"hidden\",\n\t\t\t\tborderRadius: radius,\n\t\t\t\twidth: size,\n\t\t\t\theight: size,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t>\n\t\t\t<canvas\n\t\t\t\tref={canvasRef}\n\t\t\t\twidth={RENDER_SIZE}\n\t\t\t\theight={RENDER_SIZE}\n\t\t\t\tclassName={animate ? ANIMATED_CLASS : undefined}\n\t\t\t\tstyle={canvasStyle}\n\t\t\t/>\n\t\t</span>\n\t);\n}\n\nexport type {\n\tExportOptions,\n\tGradientPalette,\n\tHarmony,\n\tRenderOptions,\n} from \"./engine\";\nexport {\n\tdrawMeshGradient,\n\tgeneratePalette,\n\tgradientToBlob,\n\tgradientToDataURL,\n\trenderGradient,\n\tseedFromString,\n\ttoSeed,\n} from \"./engine\";\n"]}
1
+ {"version":3,"sources":["../src/engine.ts","../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Gradient engine for @apollo-deploy/avatars.\n *\n * Framework-agnostic mesh-gradient avatar generator. Every seed (string or\n * number) deterministically produces a unique gradient — no stored images,\n * no network. Pure palette/RNG core plus optional Canvas2D render helpers.\n */\n\nexport type Harmony =\n \"analogous\" | \"triadic\" | \"splitComplementary\" | \"tetradic\" | \"complementary\";\n\nexport interface GradientPalette {\n /** The numeric seed the palette was derived from. */\n seed: number;\n /** Hex color stops used to paint the mesh. */\n colors: string[];\n /** Which color-harmony rule produced the hues. */\n harmony: Harmony;\n}\n\nconst HARMONY_TYPES: Harmony[] = [\n \"analogous\",\n \"triadic\",\n \"splitComplementary\",\n \"tetradic\",\n \"complementary\",\n];\n\nconst GOLDEN_ANGLE = 137.5;\n\n/** Default blur radius as a fraction of the rendered dimension. */\nexport const DEFAULT_BLUR_FRACTION = 0.06;\n\nfunction seededRandom(seed: number): () => number {\n let s = seed;\n return () => {\n s += 0x6d2b79f5;\n let t = s;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\nfunction hslToHex(h: number, s: number, l: number): string {\n h = ((h % 360) + 360) % 360;\n s = Math.max(0, Math.min(100, s)) / 100;\n l = Math.max(0, Math.min(100, l)) / 100;\n\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = l - c / 2;\n\n let r = 0;\n let g = 0;\n let b = 0;\n if (h < 60) {\n r = c;\n g = x;\n } else if (h < 120) {\n r = x;\n g = c;\n } else if (h < 180) {\n g = c;\n b = x;\n } else if (h < 240) {\n g = x;\n b = c;\n } else if (h < 300) {\n r = x;\n b = c;\n } else {\n r = c;\n b = x;\n }\n\n const toHex = (n: number) => {\n const hex = Math.round((n + m) * 255).toString(16);\n return hex.length === 1 ? `0${hex}` : hex;\n };\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();\n}\n\nfunction harmonyHues(baseHue: number, harmony: Harmony): number[] {\n switch (harmony) {\n case \"analogous\":\n return [baseHue, baseHue + 30, baseHue + 60, baseHue - 30];\n case \"triadic\":\n return [baseHue, baseHue + 120, baseHue + 240];\n case \"splitComplementary\":\n return [baseHue, baseHue + 150, baseHue + 210];\n case \"tetradic\":\n return [baseHue, baseHue + 90, baseHue + 180, baseHue + 270];\n case \"complementary\":\n return [baseHue, baseHue + 180, baseHue + 20, baseHue + 200];\n }\n}\n\n/**\n * Stable string → 32-bit unsigned hash (FNV-1a + bit-mixing avalanche).\n * Uses the full uint32 range as a seed so similar strings diverge fully.\n */\nexport function seedFromString(input: string): number {\n let h = 2166136261 >>> 0;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = Math.imul(h, 16777619) >>> 0;\n }\n h ^= h >>> 16;\n h = Math.imul(h, 0x7feb352d) >>> 0;\n h ^= h >>> 15;\n h = Math.imul(h, 0x846ca68b) >>> 0;\n h ^= h >>> 16;\n return h >>> 0;\n}\n\n/** Normalize a string or number seed to the numeric seed used internally. */\nexport function toSeed(seed: number | string): number {\n if (typeof seed === \"number\") return seed;\n return seedFromString(seed);\n}\n\n/** Derive the deterministic color palette for a seed. */\nexport function generatePalette(seed: number | string): GradientPalette {\n const s = toSeed(seed);\n const random = seededRandom(s);\n const baseHue = (s * GOLDEN_ANGLE) % 360;\n const harmonyIndex = Math.floor(random() * HARMONY_TYPES.length);\n const harmony = HARMONY_TYPES[harmonyIndex];\n const hues = harmonyHues(baseHue, harmony);\n const colors = hues.map((hue) => {\n const saturation = 75 + random() * 25;\n const lightness = 50 + random() * 20;\n return hslToHex(hue, saturation, lightness);\n });\n return { seed: s, colors, harmony };\n}\n\n/**\n * Minimal Canvas2D context surface the renderer needs. Both\n * `HTMLCanvasElement` and `OffscreenCanvas` 2D contexts satisfy it.\n */\nexport type GradientContext = {\n fillStyle: string | CanvasGradient | CanvasPattern;\n globalCompositeOperation: GlobalCompositeOperation;\n fillRect(x: number, y: number, w: number, h: number): void;\n createRadialGradient(\n x0: number,\n y0: number,\n r0: number,\n x1: number,\n y1: number,\n r1: number,\n ): CanvasGradient;\n};\n\ninterface AnimatedSpot {\n x: number;\n y: number;\n radius: number;\n color: string;\n /** Unique phase offset (0–1) so each spot drifts independently. */\n phaseX: number;\n phaseY: number;\n /** How far the spot can drift from its origin (fraction of size). */\n amplitude: number;\n}\n\n/**\n * Draw the mesh gradient for `seed` into `ctx` at `size` x `size`.\n * The caller is responsible for any blur — apply `filter: blur(…)` on the\n * displayed canvas (≈6% of the rendered dimension) for the signature look,\n * or use {@link renderGradient} / {@link gradientToDataURL} which bake it in.\n */\nexport function drawMeshGradient(\n ctx: GradientContext,\n seed: number | string,\n size: number,\n): void {\n const s = toSeed(seed);\n const { colors } = generatePalette(s);\n const random = seededRandom(s * 12345);\n\n ctx.fillStyle = colors[0];\n ctx.fillRect(0, 0, size, size);\n\n const numSpots = 8 + Math.floor(random() * 5);\n const spots: Array<{ x: number; y: number; radius: number; color: string }> =\n [];\n\n for (let i = 0; i < numSpots; i++) {\n const angle = random() * Math.PI * 2;\n const distance = random() * size * 0.4;\n const centerX = size / 2 + Math.cos(angle) * distance;\n const centerY = size / 2 + Math.sin(angle) * distance;\n spots.push({\n x: centerX + (random() - 0.5) * size * 0.3,\n y: centerY + (random() - 0.5) * size * 0.3,\n radius: size * (0.3 + random() * 0.4),\n color: colors[i % colors.length],\n });\n }\n\n spots.sort((a, b) => b.radius - a.radius);\n\n ctx.globalCompositeOperation = \"source-over\";\n for (const spot of spots) {\n const g = ctx.createRadialGradient(\n spot.x,\n spot.y,\n 0,\n spot.x,\n spot.y,\n spot.radius,\n );\n g.addColorStop(0, `${spot.color}FF`);\n g.addColorStop(0.3, `${spot.color}DD`);\n g.addColorStop(0.6, `${spot.color}88`);\n g.addColorStop(1, `${spot.color}00`);\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, size, size);\n }\n\n const hx = size * 0.3 + random() * size * 0.2;\n const hy = size * 0.3 + random() * size * 0.2;\n const hg = ctx.createRadialGradient(hx, hy, 0, hx, hy, size * 0.3);\n hg.addColorStop(0, \"rgba(255,255,255,0.15)\");\n hg.addColorStop(1, \"rgba(255,255,255,0)\");\n ctx.fillStyle = hg;\n ctx.fillRect(0, 0, size, size);\n}\n\n/**\n * Compute animated spot data for a seed — call once, then pass the result\n * and a changing `time` (elapsed seconds) to {@link drawAnimatedSpots}.\n * This separates setup from the per-frame hot path so the palette and\n * random geometry are only derived once.\n */\nexport function createAnimatedSpots(\n seed: number | string,\n size: number,\n): AnimatedSpot[] {\n const s = toSeed(seed);\n const { colors } = generatePalette(s);\n const random = seededRandom(s * 12345);\n\n const numSpots = 8 + Math.floor(random() * 5);\n const spots: AnimatedSpot[] = [];\n\n for (let i = 0; i < numSpots; i++) {\n const angle = random() * Math.PI * 2;\n const distance = random() * size * 0.4;\n const centerX = size / 2 + Math.cos(angle) * distance;\n const centerY = size / 2 + Math.sin(angle) * distance;\n spots.push({\n x: centerX + (random() - 0.5) * size * 0.3,\n y: centerY + (random() - 0.5) * size * 0.3,\n radius: size * (0.3 + random() * 0.4),\n color: colors[i % colors.length],\n phaseX: random(),\n phaseY: random(),\n amplitude: 0.03 + random() * 0.06,\n });\n }\n\n spots.sort((a, b) => b.radius - a.radius);\n return spots;\n}\n\n/**\n * Draw animated mesh spots into `ctx`. Call on every frame with a monotonically\n * increasing `time` (seconds). Each spot orbits its anchor on a tiny Lissajous\n * path, scaled so the composite result always covers the canvas.\n */\nexport function drawAnimatedSpots(\n ctx: GradientContext,\n spots: AnimatedSpot[],\n backgroundColor: string,\n size: number,\n time: number,\n): void {\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, size, size);\n\n ctx.globalCompositeOperation = \"source-over\";\n for (const spot of spots) {\n // Lissajous drift: each spot moves on its own tiny elliptical path.\n // Different periods per axis keep it from looking like a uniform rotation.\n const periodX = 12 + spot.phaseX * 8;\n const periodY = 14 + spot.phaseY * 10;\n const drift = spot.amplitude * size;\n const sx =\n spot.x +\n Math.sin(time * ((2 * Math.PI) / periodX) + spot.phaseX * Math.PI * 2) *\n drift;\n const sy =\n spot.y +\n Math.cos(time * ((2 * Math.PI) / periodY) + spot.phaseY * Math.PI * 2) *\n drift;\n\n const g = ctx.createRadialGradient(sx, sy, 0, sx, sy, spot.radius);\n g.addColorStop(0, `${spot.color}FF`);\n g.addColorStop(0.3, `${spot.color}DD`);\n g.addColorStop(0.6, `${spot.color}88`);\n g.addColorStop(1, `${spot.color}00`);\n ctx.fillStyle = g;\n ctx.fillRect(0, 0, size, size);\n }\n\n // Subtle highlight that drifts with time.\n const hSize = size * 0.3;\n const hx = size * 0.35 + Math.sin(time * 0.3) * size * 0.1;\n const hy = size * 0.35 + Math.cos(time * 0.4) * size * 0.1;\n const hg = ctx.createRadialGradient(hx, hy, 0, hx, hy, hSize);\n hg.addColorStop(0, \"rgba(255,255,255,0.15)\");\n hg.addColorStop(1, \"rgba(255,255,255,0)\");\n ctx.fillStyle = hg;\n ctx.fillRect(0, 0, size, size);\n}\n\nexport interface RenderOptions {\n /**\n * Blur radius in pixels. Defaults to ~6% of the canvas size for the\n * signature soft look. Pass `0` to disable.\n */\n blur?: number;\n}\n\nfunction blurFor(size: number, blur?: number): number {\n if (blur === 0) return 0;\n return blur ?? Math.round(size * DEFAULT_BLUR_FRACTION);\n}\n\n/**\n * Render a seed's gradient into an existing canvas, baking in the soft blur.\n * Draws at the canvas's current `width`/`height`. Browser/OffscreenCanvas only.\n */\nexport function renderGradient(\n canvas: HTMLCanvasElement | OffscreenCanvas,\n seed: number | string,\n options: RenderOptions = {},\n): void {\n const size = canvas.width;\n const blur = blurFor(size, options.blur);\n\n const ctx = canvas.getContext(\"2d\") as CanvasRenderingContext2D | null;\n if (!ctx) return;\n\n if (blur <= 0) {\n ctx.clearRect(0, 0, size, size);\n drawMeshGradient(ctx, seed, size);\n return;\n }\n\n // Draw the raw mesh on a scratch canvas, then composite it back with blur\n // scaled up slightly so the soft edges fall outside the frame (no ring).\n const scratch = createCanvas(size, size);\n const sctx = scratch.getContext(\"2d\") as CanvasRenderingContext2D | null;\n if (!sctx) return;\n drawMeshGradient(sctx, seed, size);\n\n const scaleUp = 1 + (blur / size) * 4;\n const dw = size * scaleUp;\n const offset = (dw - size) / 2;\n ctx.clearRect(0, 0, size, size);\n if (supportsCanvasFilter()) {\n ctx.filter = `blur(${blur}px)`;\n ctx.drawImage(scratch as CanvasImageSource, -offset, -offset, dw, dw);\n ctx.filter = \"none\";\n return;\n }\n // 2D-canvas `filter` is a silent no-op on Safari < 17: approximate the\n // gaussian by bouncing through a small canvas. Bilinear resampling on the\n // way down and back up smears by roughly the downscale factor, which is\n // plenty for a mesh that is already smooth gradients.\n const factor = Math.max(2, Math.min(16, blur / 2));\n const sw = Math.max(1, Math.round(size / factor));\n const small = createCanvas(sw, sw);\n const smallCtx = small.getContext(\"2d\") as CanvasRenderingContext2D | null;\n if (!smallCtx) {\n ctx.drawImage(scratch as CanvasImageSource, -offset, -offset, dw, dw);\n return;\n }\n smallCtx.imageSmoothingEnabled = true;\n smallCtx.imageSmoothingQuality = \"high\";\n smallCtx.drawImage(scratch as CanvasImageSource, 0, 0, sw, sw);\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = \"high\";\n ctx.drawImage(small as CanvasImageSource, -offset, -offset, dw, dw);\n}\n\n/* Engines that honor 2D-canvas `filter` echo an assigned value back from the\n * property; Safari < 17 ignores the assignment. Probed once, then cached. */\nlet canvasFilterSupport: boolean | null = null;\nfunction supportsCanvasFilter(): boolean {\n if (canvasFilterSupport !== null) return canvasFilterSupport;\n const probe = createCanvas(1, 1).getContext(\n \"2d\",\n ) as CanvasRenderingContext2D | null;\n if (!probe) {\n canvasFilterSupport = false;\n return canvasFilterSupport;\n }\n probe.filter = \"blur(1px)\";\n canvasFilterSupport = probe.filter === \"blur(1px)\";\n return canvasFilterSupport;\n}\n\nfunction createCanvas(\n w: number,\n h: number,\n): HTMLCanvasElement | OffscreenCanvas {\n if (typeof OffscreenCanvas !== \"undefined\") {\n return new OffscreenCanvas(w, h);\n }\n const c = document.createElement(\"canvas\");\n c.width = w;\n c.height = h;\n return c;\n}\n\nexport interface ExportOptions extends RenderOptions {\n /** Output pixel dimensions (square). Default: 512. */\n size?: number;\n /** Image MIME type. Default: \"image/png\". */\n type?: string;\n /** Quality 0–1 for lossy types. Default: 0.92. */\n quality?: number;\n}\n\n/** Render a seed's gradient and return it as a data URL. Browser only. */\nexport function gradientToDataURL(\n seed: number | string,\n options: ExportOptions = {},\n): string {\n const { size = 512, type = \"image/png\", quality = 0.92 } = options;\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n renderGradient(canvas, seed, options);\n return canvas.toDataURL(type, quality);\n}\n\n/** Render a seed's gradient and resolve a Blob (or null). Browser only. */\nexport function gradientToBlob(\n seed: number | string,\n options: ExportOptions = {},\n): Promise<Blob | null> {\n const { size = 512, type = \"image/png\", quality = 0.92 } = options;\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n renderGradient(canvas, seed, options);\n return new Promise((resolve) => canvas.toBlob(resolve, type, quality));\n}\n","import type { CSSProperties } from \"react\";\nimport { useCallback, useEffect, useRef } from \"react\";\nimport {\n createAnimatedSpots,\n drawAnimatedSpots,\n drawMeshGradient,\n generatePalette,\n} from \"./engine\";\n\nexport interface GradientAvatarProps {\n /** Any string or number — each unique seed produces a unique gradient. */\n seed: number | string;\n /** Rendered size in pixels. Default: 32. */\n size?: number;\n /**\n * Corner radius. Number = pixels, string = any CSS length.\n * Defaults to a full circle; pass `0` for a square or e.g. `12` for a\n * rounded square. Default: \"9999px\".\n */\n radius?: number | string;\n /**\n * Animate the gradient with a hybrid approach: CSS keyframes handle the\n * smooth drift (GPU-only, zero JS per frame), and the canvas content is\n * repainted at a low cadence (~15 fps) so the mesh spots evolve slowly.\n * A single shared rAF loop drives all animated instances; the ticker stops\n * when nothing is on screen or the tab is hidden. Automatically disabled\n * for users who request reduced motion. Default: `false`.\n */\n animate?: boolean;\n /**\n * Duration of one full drift cycle in seconds. Slower is subtler and\n * cheaper. Only applies when {@link animate} is `true`. Default: `16`.\n */\n animationDuration?: number;\n /** Additional CSS classes on the wrapper. */\n className?: string;\n /** Extra inline styles merged onto the wrapper. */\n style?: CSSProperties;\n}\n\n/* ------------------------------------------------------------------ */\n/* Shared animation infrastructure (module-level singletons) */\n/* ------------------------------------------------------------------ */\n\n/** Internal render resolution. */\nconst RENDER_SIZE = 256;\n/** Blur radius as a fraction of display size. */\nconst BLUR_FRACTION = 0.06;\n/** Canvas redraw interval (ms). ~15 fps keeps overhead very low. */\nconst REDRAW_MS = 67;\n\ntype DrawFn = () => void;\n\n/** Subscribers to the shared animation ticker. */\nconst subscribers = new Set<DrawFn>();\nlet tickerRaf: number | null = null;\nlet tickerLast = 0;\nlet tickerPaused = false;\n\nfunction tick(now: number): void {\n tickerRaf = requestAnimationFrame(tick);\n if (tickerPaused) return;\n if (now - tickerLast < REDRAW_MS) return;\n tickerLast = now;\n for (const draw of subscribers) draw();\n}\n\nfunction subscribe(draw: DrawFn): void {\n subscribers.add(draw);\n if (subscribers.size === 1 && tickerRaf === null) {\n tickerLast = 0;\n tickerRaf = requestAnimationFrame(tick);\n }\n}\n\nfunction unsubscribe(draw: DrawFn): void {\n subscribers.delete(draw);\n if (subscribers.size === 0 && tickerRaf !== null) {\n cancelAnimationFrame(tickerRaf);\n tickerRaf = null;\n }\n}\n\n/* Shared IntersectionObserver so we don't create one per avatar. */\nlet io: IntersectionObserver | null = null;\nconst visibles = new Set<() => void>();\n\nfunction ensureIntersectionObserver(): IntersectionObserver {\n if (io) return io;\n io = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const el = entry.target as HTMLElement & { __oaOnVis?: () => void };\n el.__oaOnVis?.();\n }\n },\n { threshold: 0 },\n );\n return io;\n}\n\n/* Shared visibilitychange handler. */\nlet visHandlerInstalled = false;\nfunction ensureVisibilityHandler(): void {\n if (visHandlerInstalled || typeof document === \"undefined\") return;\n visHandlerInstalled = true;\n document.addEventListener(\"visibilitychange\", () => {\n tickerPaused = document.visibilityState === \"hidden\";\n if (!tickerPaused) tickerLast = 0;\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* CSS keyframes (injected once, lazily) */\n/* ------------------------------------------------------------------ */\n\nconst ANIMATED_CLASS = \"oa-avatar-canvas--animated\";\nconst STYLE_ID = \"oa-avatar-keyframes\";\n\nconst KEYFRAMES_CSS = `\n@keyframes oa-avatar-drift {\n\t0% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }\n\t20% { transform: scale(1.30) translate(-3%, 2%) rotate(8deg); }\n\t40% { transform: scale(1.22) translate(3%, 3%) rotate(-6deg); }\n\t60% { transform: scale(1.28) translate(2%, -3%) rotate(5deg); }\n\t80% { transform: scale(1.24) translate(-2%, -2%) rotate(-4deg); }\n\t100% { transform: scale(1.25) translate(0%, 0%) rotate(0deg); }\n}\n.${ANIMATED_CLASS} {\n\ttransform-origin: center;\n\twill-change: transform;\n\tanimation-name: oa-avatar-drift;\n\tanimation-timing-function: ease-in-out;\n\tanimation-iteration-count: infinite;\n\tanimation-direction: alternate;\n}\n@media (prefers-reduced-motion: reduce) {\n\t.${ANIMATED_CLASS} {\n\t\tanimation: none;\n\t\ttransform: none;\n\t\twill-change: auto;\n\t}\n}\n`;\n\nlet stylesInjected = false;\n\nfunction ensureAnimationStyles(): void {\n if (stylesInjected || typeof document === \"undefined\") return;\n if (document.getElementById(STYLE_ID)) {\n stylesInjected = true;\n return;\n }\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = KEYFRAMES_CSS;\n document.head.appendChild(el);\n stylesInjected = true;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\n/**\n * Renders a deterministic mesh-gradient avatar on a `<canvas>`.\n * The same seed always produces the same gradient.\n *\n * When `animate` is on the gradient comes alive via two complementary\n * mechanisms:\n *\n * 1. **CSS keyframes** — a slow scale+rotate+translate drift that runs\n * entirely on the GPU compositor thread (zero JavaScript, zero repaint).\n * 2. **Low-cadence canvas repaint** — the mesh spots evolve at ~15 fps\n * through a single shared `requestAnimationFrame` loop, so N animated\n * avatars cost 1 rAF callback total. Drawing pauses when the element is\n * off-screen (`IntersectionObserver`) or the tab is hidden.\n */\nexport function GradientAvatar({\n seed,\n size = 32,\n radius = \"9999px\",\n animate = false,\n animationDuration = 16,\n className,\n style,\n}: GradientAvatarProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const wrapperRef = useRef<HTMLSpanElement>(null);\n const startRef = useRef<number>(0);\n const visibleRef = useRef(true);\n\n /* Inject CSS keyframes once (client-only). */\n useEffect(() => {\n if (animate) {\n ensureAnimationStyles();\n ensureVisibilityHandler();\n }\n }, [animate]);\n\n /* Draw loop: subscribe to the shared ticker, unsubscribe on cleanup. */\n const draw = useCallback(() => {\n const canvas = canvasRef.current;\n if (!canvas || !visibleRef.current) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n if (startRef.current === 0) startRef.current = performance.now();\n const elapsed = (performance.now() - startRef.current) / 1000;\n const time = elapsed * ((2 * Math.PI) / animationDuration);\n\n const { colors } = generatePalette(seed);\n const spots = createAnimatedSpots(seed, RENDER_SIZE);\n drawAnimatedSpots(ctx, spots, colors[0], RENDER_SIZE, time);\n }, [seed, animationDuration]);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const prefersReduced =\n typeof window !== \"undefined\" &&\n window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches;\n\n if (!animate || prefersReduced) {\n ctx.clearRect(0, 0, RENDER_SIZE, RENDER_SIZE);\n drawMeshGradient(ctx, seed, RENDER_SIZE);\n return;\n }\n\n /* Paint the initial frame. */\n startRef.current = 0;\n const { colors } = generatePalette(seed);\n const spots = createAnimatedSpots(seed, RENDER_SIZE);\n drawAnimatedSpots(ctx, spots, colors[0], RENDER_SIZE, 0);\n\n subscribe(draw);\n\n return () => {\n unsubscribe(draw);\n };\n }, [seed, animate, draw]);\n\n /* IntersectionObserver: pause redraws when the element scrolls off screen. */\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (!animate || !wrapper) return;\n\n const observer = ensureIntersectionObserver();\n // biome-ignore lint/suspicious/noAssignInExpressions: intentional pattern for attaching per-element callbacks\n (wrapper as HTMLElement & { __oaOnVis?: () => void }).__oaOnVis = () => {\n visibleRef.current = true;\n };\n observer.observe(wrapper);\n\n return () => {\n observer.unobserve(wrapper);\n visibleRef.current = false;\n delete (wrapper as HTMLElement & { __oaOnVis?: () => void }).__oaOnVis;\n };\n }, [animate]);\n\n const blurPx = Math.max(1, Math.round(size * BLUR_FRACTION));\n\n /* Canvas is always scaled 1.25× so drifting spots never expose the edge;\n * the CSS keyframes add their own scale+rotate+translate on top (class). */\n const canvasStyle: CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n filter: `blur(${blurPx}px)`,\n transform: \"scale(1.25)\",\n };\n if (animate) {\n canvasStyle.animationDuration = `${animationDuration}s`;\n }\n\n return (\n <span\n ref={wrapperRef}\n className={className}\n style={{\n display: \"inline-block\",\n overflow: \"hidden\",\n borderRadius: radius,\n width: size,\n height: size,\n ...style,\n }}\n >\n <canvas\n ref={canvasRef}\n role=\"img\"\n aria-label={`Gradient avatar for seed ${seed}`}\n width={RENDER_SIZE}\n height={RENDER_SIZE}\n className={animate ? ANIMATED_CLASS : undefined}\n style={canvasStyle}\n />\n </span>\n );\n}\n\nexport type {\n ExportOptions,\n GradientPalette,\n Harmony,\n RenderOptions,\n} from \"./engine\";\nexport {\n createAnimatedSpots,\n drawAnimatedSpots,\n drawMeshGradient,\n generatePalette,\n gradientToBlob,\n gradientToDataURL,\n renderGradient,\n seedFromString,\n toSeed,\n} from \"./engine\";\n"]}
package/package.json CHANGED
@@ -1,69 +1,69 @@
1
1
  {
2
- "name": "@apollo-deploy/avatars",
3
- "version": "0.2.2",
4
- "description": "React component for generative gradient avatars. Every seed renders a unique, deterministic mesh gradient, with no stored images.",
5
- "keywords": [
6
- "avatars",
7
- "generative",
8
- "generative-avatars",
9
- "gradient",
10
- "mesh-gradient",
11
- "avatar-generator",
12
- "react",
13
- "profile-pictures"
14
- ],
15
- "homepage": "https://avatars.outpacestudios.com",
16
- "repository": {
17
- "type": "git",
18
- "url": "https://github.com/outpacelabs/avatars.git",
19
- "directory": "packages/avatars"
20
- },
21
- "bugs": {
22
- "url": "https://github.com/outpacelabs/avatars/issues"
23
- },
24
- "author": "Outpace Studios (https://outpacestudios.com)",
25
- "license": "MIT",
26
- "type": "module",
27
- "sideEffects": false,
28
- "main": "./dist/index.cjs",
29
- "module": "./dist/index.js",
30
- "types": "./dist/index.d.ts",
31
- "exports": {
32
- ".": {
33
- "import": {
34
- "types": "./dist/index.d.ts",
35
- "default": "./dist/index.js"
36
- },
37
- "require": {
38
- "types": "./dist/index.d.cts",
39
- "default": "./dist/index.cjs"
40
- }
41
- },
42
- "./package.json": "./package.json"
43
- },
44
- "files": [
45
- "dist",
46
- "README.md",
47
- "LICENSE"
48
- ],
49
- "scripts": {
50
- "build": "tsup",
51
- "test": "node test/properties.mjs",
52
- "dev": "tsup --watch",
53
- "typecheck": "tsc --noEmit",
54
- "prepublishOnly": "pnpm build"
55
- },
56
- "peerDependencies": {
57
- "react": ">=18"
58
- },
59
- "devDependencies": {
60
- "@types/react": "^19.2.10",
61
- "react": "^19.2.4",
62
- "tsup": "^8.3.5",
63
- "typescript": "^5.9.3"
64
- },
65
- "publishConfig": {
66
- "access": "public",
67
- "registry": "https://registry.npmjs.org/"
68
- }
2
+ "name": "@apollo-deploy/avatars",
3
+ "version": "0.2.3",
4
+ "description": "React component for generative gradient avatars. Every seed renders a unique, deterministic mesh gradient, with no stored images.",
5
+ "keywords": [
6
+ "avatars",
7
+ "generative",
8
+ "generative-avatars",
9
+ "gradient",
10
+ "mesh-gradient",
11
+ "avatar-generator",
12
+ "react",
13
+ "profile-pictures"
14
+ ],
15
+ "homepage": "https://avatars.outpacestudios.com",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/outpacelabs/avatars.git",
19
+ "directory": "packages/avatars"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/outpacelabs/avatars/issues"
23
+ },
24
+ "author": "Outpace Studios (https://outpacestudios.com)",
25
+ "license": "MIT",
26
+ "type": "module",
27
+ "sideEffects": false,
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "import": {
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "require": {
38
+ "types": "./dist/index.d.cts",
39
+ "default": "./dist/index.cjs"
40
+ }
41
+ },
42
+ "./package.json": "./package.json"
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "README.md",
47
+ "LICENSE"
48
+ ],
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "test": "node test/properties.mjs",
52
+ "dev": "tsup --watch",
53
+ "typecheck": "tsc --noEmit",
54
+ "prepublishOnly": "pnpm build"
55
+ },
56
+ "peerDependencies": {
57
+ "react": ">=18"
58
+ },
59
+ "devDependencies": {
60
+ "@types/react": "^19.2.10",
61
+ "react": "^19.2.4",
62
+ "tsup": "^8.3.5",
63
+ "typescript": "^5.9.3"
64
+ },
65
+ "publishConfig": {
66
+ "access": "public",
67
+ "registry": "https://registry.npmjs.org/"
68
+ }
69
69
  }