The procedural-glyph-engine dep pointed at a non-portable file:/private/tmp/orby-pkg
path, breaking npm ci in Docker and every main deploy since v0.20.0 (the build
cache masked it until it busted ~Aug 5). Vendor Orby v5.0.0 into web/vendor/,
switch the dep to file:../vendor, and use npm install in the web Dockerfile
(file: deps need install, not ci). Cherry-picked from 3cd4cf9.
1767 lines
44 KiB
JavaScript
1767 lines
44 KiB
JavaScript
/**
|
|
* Immutable semantic recipes for Orby.
|
|
*
|
|
* A sprite is intentionally data, not a baked animation. Renderers combine its
|
|
* glyph silhouette, field stack, switching operator, transition contract, and
|
|
* interaction mappings. This keeps the catalogue portable across Canvas 2D,
|
|
* WebGL, SVG exporters, sprite-sheet bakers, and reduced-motion renderers.
|
|
*/
|
|
|
|
const deepFreeze = (value, seen = new WeakSet()) => {
|
|
if (
|
|
value === null ||
|
|
(typeof value !== "object" && typeof value !== "function") ||
|
|
seen.has(value)
|
|
) {
|
|
return value;
|
|
}
|
|
seen.add(value);
|
|
for (const child of Object.values(value)) deepFreeze(child, seen);
|
|
return Object.freeze(value);
|
|
};
|
|
|
|
export const FIELD_IDS = Object.freeze([
|
|
"fbm",
|
|
"ridged",
|
|
"domain-warp",
|
|
"curl",
|
|
"flow",
|
|
"worley",
|
|
"voronoi",
|
|
"plasma",
|
|
"interference",
|
|
"vortex",
|
|
"metaballs",
|
|
"caustics",
|
|
"strata",
|
|
"radar",
|
|
"constellation",
|
|
"liquid",
|
|
"electric",
|
|
"ripple",
|
|
"kaleidoscope",
|
|
]);
|
|
|
|
const FIELD_ID_SET = new Set(FIELD_IDS);
|
|
|
|
const PALETTE_SOURCE = {
|
|
neutral: {
|
|
name: "neutral",
|
|
background: "#07090c",
|
|
shadow: "#1b222b",
|
|
ink: "#eef3f8",
|
|
accent: "#93cfff",
|
|
},
|
|
info: {
|
|
name: "info",
|
|
background: "#071019",
|
|
shadow: "#15344a",
|
|
ink: "#edf8ff",
|
|
accent: "#4fc3ff",
|
|
},
|
|
success: {
|
|
name: "success",
|
|
background: "#07110e",
|
|
shadow: "#16392d",
|
|
ink: "#f0fff9",
|
|
accent: "#54d99b",
|
|
},
|
|
warning: {
|
|
name: "warning",
|
|
background: "#151006",
|
|
shadow: "#493514",
|
|
ink: "#fff9e9",
|
|
accent: "#f5b94c",
|
|
},
|
|
danger: {
|
|
name: "danger",
|
|
background: "#15090b",
|
|
shadow: "#4c1c25",
|
|
ink: "#fff2f4",
|
|
accent: "#ff647c",
|
|
},
|
|
celebration: {
|
|
name: "celebration",
|
|
background: "#100a19",
|
|
shadow: "#352052",
|
|
ink: "#fff7ff",
|
|
accent: "#cf86ff",
|
|
},
|
|
};
|
|
|
|
export const PALETTES = deepFreeze(PALETTE_SOURCE);
|
|
|
|
function layer(field, weight, scale, blend = "add", options = {}) {
|
|
if (!FIELD_ID_SET.has(field)) {
|
|
throw new TypeError(`Unknown field "${field}" in built-in sprite recipe.`);
|
|
}
|
|
return {
|
|
field,
|
|
weight,
|
|
scale,
|
|
blend,
|
|
...(Number.isFinite(options.segments)
|
|
? { segments: Math.round(options.segments) }
|
|
: {}),
|
|
phase: options.phase ?? 0,
|
|
speed: options.speed ?? 1,
|
|
contrast: options.contrast ?? 1,
|
|
warp: options.warp ?? 0,
|
|
};
|
|
}
|
|
|
|
const defaultPointer = {
|
|
enabled: true,
|
|
minSize: 20,
|
|
effect: "steer-light",
|
|
strength: 0.16,
|
|
reducedMotion: false,
|
|
};
|
|
|
|
const defaultPress = {
|
|
enabled: true,
|
|
effect: "spring-compress",
|
|
strength: 0.07,
|
|
durationMs: 180,
|
|
};
|
|
|
|
function defineSprite({
|
|
id,
|
|
category,
|
|
meaning,
|
|
glyph,
|
|
field,
|
|
fieldMix,
|
|
composition = {},
|
|
palette = "neutral",
|
|
threshold = 0.5,
|
|
density = 0.72,
|
|
speed = 1,
|
|
pixelShape = "rounded-square",
|
|
pixelGap = 0.12,
|
|
pixelScale = 0.94,
|
|
silhouetteFloor = 0.38,
|
|
pixelSwitch = {},
|
|
timeline = {},
|
|
transition = {},
|
|
interactions = {},
|
|
reducedMotion = {},
|
|
labels,
|
|
terminal = false,
|
|
urgency = "normal",
|
|
}) {
|
|
if (!FIELD_ID_SET.has(field)) {
|
|
throw new TypeError(`Unknown primary field "${field}" for "${id}".`);
|
|
}
|
|
if (!labels?.default) {
|
|
throw new TypeError(`Sprite "${id}" must define labels.default.`);
|
|
}
|
|
|
|
const mix = fieldMix?.length
|
|
? fieldMix
|
|
: [layer(field, 1, 1, "replace")];
|
|
const totalWeight = mix.reduce((sum, item) => sum + item.weight, 0);
|
|
const compositionConfig =
|
|
typeof composition === "string"
|
|
? { mode: composition }
|
|
: composition && typeof composition === "object"
|
|
? composition
|
|
: {};
|
|
|
|
const recipe = {
|
|
schemaVersion: 1,
|
|
id,
|
|
semantic: {
|
|
category,
|
|
meaning,
|
|
terminal,
|
|
urgency,
|
|
announce: labels.live ?? (urgency === "high" ? "assertive" : "polite"),
|
|
decorativeCanvas: true,
|
|
monochromeSafe: true,
|
|
minimumReadableSize: 16,
|
|
},
|
|
glyph,
|
|
field,
|
|
composition: {
|
|
mode: "glyph",
|
|
...compositionConfig,
|
|
},
|
|
fieldMix: mix.map((item) => ({
|
|
...item,
|
|
weight: totalWeight > 0 ? item.weight / totalWeight : 0,
|
|
})),
|
|
palette: PALETTES[palette] ?? PALETTES.neutral,
|
|
threshold,
|
|
density,
|
|
speed,
|
|
pixel: {
|
|
shape: pixelShape,
|
|
gap: pixelGap,
|
|
scale: pixelScale,
|
|
quantize: "1bit",
|
|
silhouetteFloor,
|
|
},
|
|
pixelSwitch: {
|
|
mode: pixelSwitch.mode ?? "threshold-hysteresis",
|
|
dither: pixelSwitch.dither ?? "bayer8",
|
|
hysteresis: pixelSwitch.hysteresis ?? 0.055,
|
|
temporalRate: pixelSwitch.temporalRate ?? speed,
|
|
neighborhood: pixelSwitch.neighborhood ?? 0,
|
|
direction: pixelSwitch.direction ?? "field",
|
|
monotonic: pixelSwitch.monotonic ?? false,
|
|
maxContrastFlashesPerSecond:
|
|
pixelSwitch.maxContrastFlashesPerSecond ?? 3,
|
|
},
|
|
timeline: {
|
|
mode: timeline.mode ?? "loop",
|
|
durationMs: timeline.durationMs ?? Math.round(1000 / Math.max(speed, 0.01)),
|
|
macroCycleMs: timeline.macroCycleMs ?? null,
|
|
holdMs: timeline.holdMs ?? 0,
|
|
replay: timeline.replay ?? "continuous",
|
|
next: timeline.next ?? null,
|
|
},
|
|
transition: {
|
|
enter: transition.enter ?? "field-morph",
|
|
exit: transition.exit ?? "field-morph",
|
|
durationMs: transition.durationMs ?? 360,
|
|
exitDurationMs:
|
|
transition.exitDurationMs ?? transition.durationMs ?? 360,
|
|
preservePhase: transition.preservePhase ?? true,
|
|
preserveBuffer: transition.preserveBuffer ?? false,
|
|
interruptible: transition.interruptible ?? true,
|
|
},
|
|
interactions: {
|
|
pointer: {
|
|
...defaultPointer,
|
|
...(interactions.pointer ?? {}),
|
|
},
|
|
press: {
|
|
...defaultPress,
|
|
...(interactions.press ?? {}),
|
|
},
|
|
signals: interactions.signals ?? [],
|
|
},
|
|
reducedMotion: {
|
|
mode: reducedMotion.mode ?? "representative-phase",
|
|
phase: reducedMotion.phase ?? 0.25,
|
|
speed: 0,
|
|
transition: reducedMotion.transition ?? "crossfade",
|
|
transitionMs: reducedMotion.transitionMs ?? 120,
|
|
pointer: false,
|
|
spatialMotion: false,
|
|
representation:
|
|
reducedMotion.representation ?? `static ${labels.default.toLowerCase()} glyph`,
|
|
dataUpdates: reducedMotion.dataUpdates ?? "discrete",
|
|
},
|
|
labels: {
|
|
default: labels.default,
|
|
aria: labels.aria ?? labels.default,
|
|
live: labels.live ?? (urgency === "high" ? "assertive" : "polite"),
|
|
value: labels.value ?? null,
|
|
variants: labels.variants ?? null,
|
|
},
|
|
};
|
|
|
|
return deepFreeze(recipe);
|
|
}
|
|
|
|
const RECIPES = [
|
|
defineSprite({
|
|
id: "ai.idle",
|
|
category: "presence",
|
|
meaning: "ready and available",
|
|
glyph: "idle",
|
|
field: "fbm",
|
|
composition: {
|
|
gestaltBoundary: true,
|
|
gestaltOpenness: 0.58,
|
|
},
|
|
fieldMix: [
|
|
layer("fbm", 0.72, 1.15, "replace", { speed: 0.2, contrast: 0.9 }),
|
|
layer("caustics", 0.28, 1.7, "soft-light", {
|
|
speed: -0.09,
|
|
phase: 0.19,
|
|
}),
|
|
],
|
|
palette: "neutral",
|
|
threshold: 0.51,
|
|
density: 0.68,
|
|
speed: 0.14,
|
|
pixelShape: "rounded-square",
|
|
pixelSwitch: {
|
|
mode: "ordered-dither",
|
|
dither: "bayer8",
|
|
hysteresis: 0.045,
|
|
temporalRate: 0.1,
|
|
direction: "field",
|
|
},
|
|
timeline: {
|
|
durationMs: 7200,
|
|
macroCycleMs: 14400,
|
|
replay: "continuous",
|
|
},
|
|
transition: {
|
|
enter: "field-morph",
|
|
exit: "field-morph",
|
|
durationMs: 520,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "steer-highlight", strength: 0.14 },
|
|
press: { effect: "spring-compress", strength: 0.055 },
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.18,
|
|
representation: "static side-lit lunar sphere with a persistent rim",
|
|
},
|
|
labels: { default: "Ready", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.ambient-idle",
|
|
category: "ambient",
|
|
meaning: "calm field-only presence",
|
|
glyph: "idle",
|
|
field: "fbm",
|
|
composition: {
|
|
mode: "field-orb",
|
|
gestaltBoundary: true,
|
|
gestaltOpenness: 0.46,
|
|
lighting: "crescent",
|
|
radius: 0.88,
|
|
fieldContrast: 1.26,
|
|
fieldDetail: 0.86,
|
|
lightOrbit: 0.1,
|
|
breathe: 0.045,
|
|
rim: 0.055,
|
|
},
|
|
fieldMix: [
|
|
layer("fbm", 0.62, 1.14, "replace", {
|
|
speed: 0.18,
|
|
contrast: 1.24,
|
|
}),
|
|
layer("caustics", 0.38, 2.05, "soft-light", {
|
|
speed: -0.11,
|
|
contrast: 1.08,
|
|
phase: 0.31,
|
|
}),
|
|
],
|
|
palette: "neutral",
|
|
threshold: 0.49,
|
|
density: 0.76,
|
|
speed: 0.22,
|
|
pixelShape: "rounded-square",
|
|
pixelScale: 0.9,
|
|
pixelSwitch: {
|
|
mode: "ordered-dither",
|
|
dither: "bayer8",
|
|
hysteresis: 0.045,
|
|
temporalRate: 0.18,
|
|
direction: "surface-drift",
|
|
},
|
|
timeline: {
|
|
durationMs: 7200,
|
|
macroCycleMs: 14400,
|
|
replay: "continuous",
|
|
},
|
|
transition: {
|
|
enter: "field-morph",
|
|
exit: "field-morph",
|
|
durationMs: 520,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "steer-light", strength: 0.18 },
|
|
press: { effect: "surface-ripple", strength: 0.09 },
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.18,
|
|
representation: "static side-lit dithered field orb",
|
|
},
|
|
labels: { default: "Ambient ready", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.ambient-thinking",
|
|
category: "ambient",
|
|
meaning: "reasoning expressed only through an animated field",
|
|
glyph: "thinking",
|
|
field: "domain-warp",
|
|
composition: {
|
|
mode: "field-orb",
|
|
gestaltBoundary: true,
|
|
gestaltOpenness: 0.62,
|
|
lighting: "sphere",
|
|
radius: 0.84,
|
|
fieldContrast: 1.48,
|
|
fieldDetail: 0.96,
|
|
lightOrbit: 0.2,
|
|
breathe: 0.09,
|
|
rim: 0.045,
|
|
},
|
|
fieldMix: [
|
|
layer("domain-warp", 0.46, 1.08, "replace", {
|
|
speed: 0.52,
|
|
contrast: 1.34,
|
|
warp: 0.7,
|
|
}),
|
|
layer("curl", 0.32, 1.52, "add", {
|
|
speed: -0.38,
|
|
contrast: 1.22,
|
|
}),
|
|
layer("ridged", 0.22, 2.18, "soft-light", {
|
|
speed: 0.24,
|
|
contrast: 1.36,
|
|
}),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.5,
|
|
density: 0.8,
|
|
speed: 0.72,
|
|
pixelShape: "rounded-square",
|
|
pixelScale: 0.89,
|
|
pixelSwitch: {
|
|
mode: "temporal-blue-noise",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.048,
|
|
temporalRate: 0.68,
|
|
direction: "counter-flow",
|
|
},
|
|
timeline: {
|
|
durationMs: 4600,
|
|
macroCycleMs: 9200,
|
|
replay: "continuous",
|
|
},
|
|
transition: {
|
|
enter: "radial-cascade",
|
|
exit: "field-morph",
|
|
durationMs: 460,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "bend-flow-and-light", strength: 0.16 },
|
|
press: { effect: "damped-vortex", strength: 0.18, durationMs: 460 },
|
|
signals: [
|
|
{ name: "reasoning.depth", mapsTo: "shellEnergy", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.34,
|
|
representation: "static front-lit dithered reasoning field",
|
|
},
|
|
labels: { default: "Ambient thinking", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.ambient-thinking-symmetric",
|
|
category: "ambient",
|
|
meaning: "reasoning expressed through a clean, symmetrical animated field",
|
|
glyph: "thinking",
|
|
field: "kaleidoscope",
|
|
composition: {
|
|
mode: "field-orb",
|
|
lighting: "flat",
|
|
radius: 0.87,
|
|
fieldContrast: 1.32,
|
|
fieldDetail: 0.84,
|
|
lightOrbit: 0,
|
|
breathe: 0.045,
|
|
rim: 0.04,
|
|
},
|
|
fieldMix: [
|
|
layer("kaleidoscope", 0.74, 0.82, "replace", {
|
|
segments: 8,
|
|
speed: 0.2,
|
|
contrast: 1.25,
|
|
}),
|
|
layer("kaleidoscope", 0.26, 1.42, "soft-light", {
|
|
segments: 8,
|
|
speed: -0.12,
|
|
contrast: 1.08,
|
|
}),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.5,
|
|
density: 0.78,
|
|
speed: 0.5,
|
|
pixelShape: "square",
|
|
pixelGap: 0.14,
|
|
pixelScale: 0.9,
|
|
pixelSwitch: {
|
|
mode: "threshold-hysteresis",
|
|
dither: "bayer8",
|
|
hysteresis: 0.058,
|
|
temporalRate: 0.34,
|
|
direction: "radial",
|
|
},
|
|
timeline: {
|
|
durationMs: 6400,
|
|
macroCycleMs: 12800,
|
|
replay: "continuous",
|
|
},
|
|
transition: {
|
|
enter: "radial-cascade",
|
|
exit: "field-morph",
|
|
durationMs: 500,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { enabled: false },
|
|
press: { enabled: false },
|
|
signals: [
|
|
{ name: "reasoning.depth", mapsTo: "shellEnergy", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.25,
|
|
representation: "static symmetrical reasoning field",
|
|
},
|
|
labels: { default: "Ambient thinking — symmetric", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.ambient-speaking",
|
|
category: "ambient",
|
|
meaning: "voice output expressed only through an animated field",
|
|
glyph: "speaking",
|
|
field: "interference",
|
|
composition: {
|
|
mode: "field-orb",
|
|
gestaltBoundary: true,
|
|
gestaltOpenness: 0.5,
|
|
lighting: "gibbous",
|
|
radius: 0.87,
|
|
fieldContrast: 1.38,
|
|
fieldDetail: 0.92,
|
|
lightOrbit: 0.13,
|
|
breathe: 0.065,
|
|
voice: 0.2,
|
|
rim: 0.05,
|
|
},
|
|
fieldMix: [
|
|
layer("interference", 0.46, 1.26, "replace", {
|
|
speed: 1.05,
|
|
contrast: 1.28,
|
|
}),
|
|
layer("plasma", 0.34, 1.7, "screen", {
|
|
speed: -0.72,
|
|
contrast: 1.18,
|
|
}),
|
|
layer("ripple", 0.2, 1.12, "add", {
|
|
speed: 0.82,
|
|
contrast: 1.24,
|
|
}),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.48,
|
|
density: 0.82,
|
|
speed: 1.02,
|
|
pixelShape: "circle",
|
|
pixelScale: 0.9,
|
|
pixelSwitch: {
|
|
mode: "ordered-dither",
|
|
dither: "bayer8",
|
|
hysteresis: 0.042,
|
|
temporalRate: 0.96,
|
|
direction: "audio-surface",
|
|
},
|
|
timeline: {
|
|
mode: "signal-reactive",
|
|
durationMs: 1900,
|
|
macroCycleMs: 5700,
|
|
},
|
|
transition: {
|
|
enter: "radial-cascade",
|
|
exit: "field-morph",
|
|
durationMs: 300,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "steer-light", strength: 0.13 },
|
|
press: { enabled: false },
|
|
signals: [
|
|
{
|
|
name: "audio.level",
|
|
mapsTo: "envelope",
|
|
range: [0, 1],
|
|
decayMs: 220,
|
|
},
|
|
{ name: "audio.syllable", mapsTo: "bandEnergy", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
mode: "data-step",
|
|
phase: 0.38,
|
|
representation: "static gibbous field with discrete audio levels",
|
|
dataUpdates: "three-level-step",
|
|
},
|
|
labels: { default: "Ambient speaking", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.listening",
|
|
category: "activity",
|
|
meaning: "capturing voice or input",
|
|
glyph: "listening",
|
|
field: "interference",
|
|
fieldMix: [
|
|
layer("interference", 0.46, 1.4, "replace", {
|
|
speed: 0.68,
|
|
contrast: 1.18,
|
|
}),
|
|
layer("radar", 0.32, 1.05, "add", { speed: -0.46 }),
|
|
layer("liquid", 0.22, 1.8, "soft-light", { speed: 0.3 }),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.48,
|
|
density: 0.77,
|
|
speed: 0.78,
|
|
pixelShape: "circle",
|
|
pixelSwitch: {
|
|
mode: "radial-cascade",
|
|
dither: "bayer8",
|
|
hysteresis: 0.05,
|
|
direction: "inward",
|
|
},
|
|
timeline: { durationMs: 2400, macroCycleMs: 4800 },
|
|
transition: {
|
|
enter: "sdf-wavefront",
|
|
exit: "radial-cascade",
|
|
durationMs: 340,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "ripple-bias", strength: 0.12 },
|
|
press: { effect: "emit-inbound-ripple", strength: 0.18 },
|
|
signals: [
|
|
{ name: "audio.level", mapsTo: "energy", range: [0, 1], decayMs: 90 },
|
|
{ name: "input.pulse", mapsTo: "ripple", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.36,
|
|
representation: "static listening ring with discrete level steps",
|
|
dataUpdates: "three-level-step",
|
|
},
|
|
labels: { default: "Listening", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.thinking",
|
|
category: "activity",
|
|
meaning: "reasoning",
|
|
glyph: "thinking",
|
|
field: "flow",
|
|
fieldMix: [
|
|
layer("flow", 0.47, 1.35, "replace", {
|
|
speed: 0.82,
|
|
contrast: 1.08,
|
|
}),
|
|
layer("vortex", 0.35, 1.05, "add", { speed: -0.62, warp: 0.22 }),
|
|
layer("fbm", 0.18, 2.1, "soft-light", { speed: 0.25 }),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.5,
|
|
density: 0.74,
|
|
speed: 0.92,
|
|
pixelShape: "rounded-square",
|
|
pixelSwitch: {
|
|
mode: "temporal-blue-noise",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.062,
|
|
temporalRate: 0.82,
|
|
},
|
|
timeline: { durationMs: 3100, macroCycleMs: 6200 },
|
|
transition: {
|
|
enter: "field-morph",
|
|
exit: "field-morph",
|
|
durationMs: 430,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "bend-flow", strength: 0.13 },
|
|
press: { effect: "damped-vortex", strength: 0.2, durationMs: 460 },
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.3,
|
|
representation: "static faceted spiral",
|
|
},
|
|
labels: { default: "Thinking", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.thinking-deep",
|
|
category: "activity",
|
|
meaning: "deliberate extended reasoning",
|
|
glyph: "thinking-deep",
|
|
field: "domain-warp",
|
|
fieldMix: [
|
|
layer("domain-warp", 0.46, 0.95, "replace", {
|
|
speed: 0.34,
|
|
warp: 0.48,
|
|
}),
|
|
layer("ridged", 0.31, 1.8, "multiply", {
|
|
speed: 0.18,
|
|
contrast: 1.24,
|
|
}),
|
|
layer("vortex", 0.23, 0.72, "add", { speed: -0.27 }),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.52,
|
|
density: 0.79,
|
|
speed: 0.38,
|
|
pixelShape: "diamond",
|
|
pixelGap: 0.1,
|
|
pixelSwitch: {
|
|
mode: "neighbor-propagation",
|
|
dither: "bayer8",
|
|
hysteresis: 0.07,
|
|
temporalRate: 0.36,
|
|
neighborhood: 8,
|
|
direction: "shell-to-shell",
|
|
},
|
|
timeline: {
|
|
durationMs: 9600,
|
|
macroCycleMs: 19200,
|
|
replay: "continuous",
|
|
},
|
|
transition: {
|
|
enter: "field-morph",
|
|
exit: "field-morph",
|
|
durationMs: 680,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "separate-shells", strength: 0.09 },
|
|
press: { effect: "pinch-core", strength: 0.16, durationMs: 520 },
|
|
signals: [
|
|
{
|
|
name: "reasoning.depth",
|
|
mapsTo: "shellEnergy",
|
|
range: [0, 1],
|
|
},
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.42,
|
|
representation: "static nested rings with a brighter inner core",
|
|
},
|
|
labels: { default: "Reasoning deeply", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.still-working",
|
|
category: "activity",
|
|
meaning: "work is taking longer than expected",
|
|
glyph: "still-working",
|
|
field: "strata",
|
|
fieldMix: [
|
|
layer("strata", 0.44, 1.2, "replace", {
|
|
speed: 0.21,
|
|
contrast: 1.08,
|
|
}),
|
|
layer("radar", 0.34, 0.82, "add", { speed: 0.17 }),
|
|
layer("flow", 0.22, 1.55, "soft-light", { speed: 0.18 }),
|
|
],
|
|
palette: "neutral",
|
|
threshold: 0.5,
|
|
density: 0.71,
|
|
speed: 0.24,
|
|
pixelShape: "rounded-square",
|
|
pixelSwitch: {
|
|
mode: "radial-cascade",
|
|
dither: "bayer8",
|
|
hysteresis: 0.055,
|
|
temporalRate: 0.62,
|
|
direction: "outward-beacon",
|
|
},
|
|
timeline: {
|
|
durationMs: 3200,
|
|
macroCycleMs: 3200,
|
|
replay: "continuous",
|
|
},
|
|
transition: {
|
|
enter: "field-morph",
|
|
exit: "field-morph",
|
|
durationMs: 560,
|
|
preservePhase: false,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "expand-beacon", strength: 0.1 },
|
|
press: { effect: "host-action", strength: 0.05 },
|
|
signals: [
|
|
{ name: "latency.elapsed", mapsTo: "beaconEnergy", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.46,
|
|
representation: "upright hourglass with settled sand and flip guides",
|
|
},
|
|
labels: { default: "Still working", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.loading",
|
|
category: "activity",
|
|
meaning: "indeterminate startup or wait",
|
|
glyph: "loading",
|
|
field: "plasma",
|
|
fieldMix: [
|
|
layer("plasma", 0.58, 1.15, "replace", {
|
|
speed: 1.15,
|
|
contrast: 1.16,
|
|
}),
|
|
layer("flow", 0.42, 1.65, "add", { speed: 0.88 }),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.52,
|
|
density: 0.7,
|
|
speed: 1.38,
|
|
pixelShape: "square",
|
|
pixelSwitch: {
|
|
mode: "ordered-dither",
|
|
dither: "bayer8",
|
|
hysteresis: 0.052,
|
|
temporalRate: 1.3,
|
|
direction: "radial-tail",
|
|
},
|
|
timeline: { durationMs: 1440, macroCycleMs: 5760 },
|
|
transition: {
|
|
enter: "radial-cascade",
|
|
exit: "field-morph",
|
|
durationMs: 280,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "steer-highlight", strength: 0.08 },
|
|
press: { enabled: false },
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.63,
|
|
representation: "static segmented loading ring",
|
|
},
|
|
labels: { default: "Loading", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.progress",
|
|
category: "activity",
|
|
meaning: "determinate completion progress",
|
|
glyph: "progress",
|
|
field: "strata",
|
|
fieldMix: [
|
|
layer("strata", 0.54, 1.25, "replace", {
|
|
speed: 0.25,
|
|
contrast: 1.1,
|
|
}),
|
|
layer("constellation", 0.46, 1.9, "add", {
|
|
speed: 0.1,
|
|
phase: 0.37,
|
|
}),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.47,
|
|
density: 0.84,
|
|
speed: 0.32,
|
|
pixelShape: "circle",
|
|
pixelSwitch: {
|
|
mode: "temporal-blue-noise",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.045,
|
|
temporalRate: 0.28,
|
|
direction: "contour-forward",
|
|
monotonic: true,
|
|
},
|
|
timeline: { mode: "data-driven", durationMs: 240, replay: "on-update" },
|
|
transition: {
|
|
enter: "contour-trace",
|
|
exit: "path-draw",
|
|
durationMs: 320,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "reveal-value", strength: 0 },
|
|
press: { effect: "spring-compress", strength: 0.045 },
|
|
signals: [
|
|
{
|
|
name: "progress",
|
|
mapsTo: "progress",
|
|
range: [0, 1],
|
|
monotonic: true,
|
|
},
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
mode: "data-step",
|
|
phase: 0,
|
|
representation: "static progress contour updated from data",
|
|
dataUpdates: "discrete-monotonic",
|
|
},
|
|
labels: {
|
|
default: "In progress",
|
|
value: "{percent}% complete",
|
|
live: "polite",
|
|
},
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.generating",
|
|
category: "activity",
|
|
meaning: "producing content",
|
|
glyph: "generating",
|
|
field: "electric",
|
|
fieldMix: [
|
|
layer("electric", 0.4, 1.75, "replace", {
|
|
speed: 0.84,
|
|
contrast: 1.23,
|
|
}),
|
|
layer("metaballs", 0.34, 1.1, "add", {
|
|
speed: 0.54,
|
|
warp: 0.18,
|
|
}),
|
|
layer("constellation", 0.26, 2.05, "screen", {
|
|
speed: 0.38,
|
|
}),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.5,
|
|
density: 0.78,
|
|
speed: 0.88,
|
|
pixelShape: "diamond",
|
|
pixelSwitch: {
|
|
mode: "curl-advect",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.058,
|
|
temporalRate: 0.8,
|
|
neighborhood: 4,
|
|
direction: "core-to-target",
|
|
},
|
|
timeline: {
|
|
mode: "signal-reactive",
|
|
durationMs: 3600,
|
|
macroCycleMs: 7200,
|
|
},
|
|
transition: {
|
|
enter: "seeded-dissolve",
|
|
exit: "field-morph",
|
|
durationMs: 460,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "attract-unlocked-pixels", strength: 0.11 },
|
|
press: { effect: "core-pulse", strength: 0.08 },
|
|
signals: [
|
|
{ name: "token", mapsTo: "spark", range: [0, 1], bounded: true },
|
|
{ name: "chunk", mapsTo: "spark", range: [0, 1], bounded: true },
|
|
{ name: "frame", mapsTo: "spark", range: [0, 1], bounded: true },
|
|
{ name: "stream.energy", mapsTo: "activity", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
mode: "data-step",
|
|
phase: 0.72,
|
|
representation: "target glyph filled in non-moving chunks",
|
|
dataUpdates: "chunked-fill",
|
|
},
|
|
labels: { default: "Generating", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.searching",
|
|
category: "activity",
|
|
meaning: "searching or retrieving information",
|
|
glyph: "searching",
|
|
field: "radar",
|
|
fieldMix: [
|
|
layer("radar", 0.53, 0.95, "replace", {
|
|
speed: 0.72,
|
|
contrast: 1.18,
|
|
}),
|
|
layer("worley", 0.29, 1.62, "add", { speed: 0.2 }),
|
|
layer("caustics", 0.18, 2.1, "screen", { speed: 0.16 }),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.49,
|
|
density: 0.73,
|
|
speed: 0.74,
|
|
pixelShape: "circle",
|
|
pixelSwitch: {
|
|
mode: "sdf-wavefront",
|
|
dither: "bayer8",
|
|
hysteresis: 0.057,
|
|
temporalRate: 0.72,
|
|
direction: "radar-sweep",
|
|
},
|
|
timeline: { durationMs: 3300, macroCycleMs: 6600 },
|
|
transition: {
|
|
enter: "radial-cascade",
|
|
exit: "field-morph",
|
|
durationMs: 380,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "bias-decorative-beam", strength: 0.1 },
|
|
press: { enabled: false },
|
|
signals: [
|
|
{
|
|
name: "search.hit",
|
|
mapsTo: "worleyBloom",
|
|
range: [0, 1],
|
|
decayMs: 620,
|
|
},
|
|
{ name: "search.results", mapsTo: "hitCount", range: [0, 8] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.2,
|
|
representation: "static magnifier with discrete result dots",
|
|
dataUpdates: "result-dot",
|
|
},
|
|
labels: { default: "Searching", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.tool-use",
|
|
category: "activity",
|
|
meaning: "executing a tool or action",
|
|
glyph: "tool-use",
|
|
field: "strata",
|
|
fieldMix: [
|
|
layer("strata", 0.43, 1.3, "replace", {
|
|
speed: 0.46,
|
|
contrast: 1.12,
|
|
}),
|
|
layer("electric", 0.34, 1.8, "add", { speed: 0.68 }),
|
|
layer("voronoi", 0.23, 1.05, "multiply", { speed: 0.22 }),
|
|
],
|
|
palette: "neutral",
|
|
threshold: 0.52,
|
|
density: 0.8,
|
|
speed: 0.68,
|
|
pixelShape: "square",
|
|
pixelSwitch: {
|
|
mode: "neighbor-propagation",
|
|
dither: "bayer8",
|
|
hysteresis: 0.062,
|
|
temporalRate: 0.62,
|
|
neighborhood: 6,
|
|
direction: "gear-step",
|
|
},
|
|
timeline: {
|
|
mode: "signal-reactive",
|
|
durationMs: 2400,
|
|
macroCycleMs: 7200,
|
|
},
|
|
transition: {
|
|
enter: "axis-flip",
|
|
exit: "field-morph",
|
|
durationMs: 420,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "tilt-light", strength: 0.13 },
|
|
press: { effect: "mechanism-compress", strength: 0.09 },
|
|
signals: [
|
|
{ name: "tool.step", mapsTo: "toothPulse", range: [0, 1] },
|
|
{ name: "tool.wait", mapsTo: "stepHold", range: [0, 1] },
|
|
{ name: "tool.result", mapsTo: "coreState", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.125,
|
|
representation: "static gear with data-driven step dots",
|
|
dataUpdates: "step-dot",
|
|
},
|
|
labels: { default: "Using a tool", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.speaking",
|
|
category: "activity",
|
|
meaning: "producing voice output",
|
|
glyph: "speaking",
|
|
field: "interference",
|
|
fieldMix: [
|
|
layer("interference", 0.44, 1.2, "replace", {
|
|
speed: 1.05,
|
|
contrast: 1.16,
|
|
}),
|
|
layer("plasma", 0.33, 1.62, "add", { speed: 0.74 }),
|
|
layer("liquid", 0.23, 0.92, "soft-light", {
|
|
speed: 0.55,
|
|
warp: 0.2,
|
|
}),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.47,
|
|
density: 0.81,
|
|
speed: 1.08,
|
|
pixelShape: "circle",
|
|
pixelSwitch: {
|
|
mode: "radial-cascade",
|
|
dither: "bayer8",
|
|
hysteresis: 0.05,
|
|
temporalRate: 1.02,
|
|
direction: "outward-audio",
|
|
},
|
|
timeline: {
|
|
mode: "signal-reactive",
|
|
durationMs: 1900,
|
|
macroCycleMs: 5700,
|
|
},
|
|
transition: {
|
|
enter: "sdf-wavefront",
|
|
exit: "radial-cascade",
|
|
durationMs: 260,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "steer-light", strength: 0.11 },
|
|
press: { enabled: false },
|
|
signals: [
|
|
{
|
|
name: "audio.level",
|
|
mapsTo: "envelope",
|
|
range: [0, 1],
|
|
decayMs: 240,
|
|
},
|
|
{ name: "audio.syllable", mapsTo: "bandEnergy", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
mode: "data-step",
|
|
phase: 0.38,
|
|
representation: "static speaker with three discrete level states",
|
|
dataUpdates: "three-level-step",
|
|
},
|
|
labels: { default: "Speaking", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "ai.awaiting-input",
|
|
category: "activity",
|
|
meaning: "user action is required",
|
|
glyph: "awaiting-input",
|
|
field: "fbm",
|
|
fieldMix: [
|
|
layer("fbm", 0.72, 0.92, "replace", {
|
|
speed: 0.18,
|
|
contrast: 0.94,
|
|
}),
|
|
layer("caustics", 0.28, 1.55, "soft-light", {
|
|
speed: 0.1,
|
|
contrast: 0.9,
|
|
}),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.48,
|
|
density: 0.8,
|
|
speed: 0.22,
|
|
pixelShape: "rounded-square",
|
|
pixelSwitch: {
|
|
mode: "threshold-hysteresis",
|
|
dither: "bayer8",
|
|
hysteresis: 0.052,
|
|
temporalRate: 0.08,
|
|
direction: "focus",
|
|
},
|
|
timeline: {
|
|
mode: "hold",
|
|
durationMs: 1800,
|
|
macroCycleMs: 10800,
|
|
replay: "two-pulses-then-hold",
|
|
},
|
|
transition: {
|
|
enter: "radial-cascade",
|
|
exit: "field-morph",
|
|
durationMs: 420,
|
|
preservePhase: false,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "turn-aperture", strength: 0.1 },
|
|
press: {
|
|
effect: "acknowledge",
|
|
strength: 0.06,
|
|
durationMs: 160,
|
|
emits: "activate",
|
|
},
|
|
signals: [{ name: "activate", mapsTo: "acknowledgement", range: [0, 1] }],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.44,
|
|
representation: "static question mark inside a firefly focus ring",
|
|
},
|
|
labels: { default: "Your input is needed", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "status.success",
|
|
category: "status",
|
|
meaning: "completed successfully",
|
|
glyph: "success",
|
|
field: "caustics",
|
|
fieldMix: [
|
|
layer("caustics", 0.57, 1.3, "replace", {
|
|
speed: 0.72,
|
|
contrast: 1.15,
|
|
}),
|
|
layer("constellation", 0.43, 1.75, "screen", { speed: 0.35 }),
|
|
],
|
|
palette: "success",
|
|
threshold: 0.46,
|
|
density: 0.9,
|
|
speed: 0.82,
|
|
pixelShape: "rounded-square",
|
|
pixelSwitch: {
|
|
mode: "path-draw",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.042,
|
|
temporalRate: 1,
|
|
direction: "tail-to-head",
|
|
monotonic: false,
|
|
},
|
|
timeline: {
|
|
mode: "one-shot",
|
|
durationMs: 500,
|
|
holdMs: 800,
|
|
replay: "on-enter",
|
|
},
|
|
transition: {
|
|
enter: "path-draw",
|
|
exit: "field-morph",
|
|
durationMs: 500,
|
|
exitDurationMs: 300,
|
|
preservePhase: false,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "edge-sparkle", strength: 0.04 },
|
|
press: { enabled: false },
|
|
},
|
|
reducedMotion: {
|
|
mode: "static",
|
|
phase: 1,
|
|
representation: "static checkmark",
|
|
transitionMs: 120,
|
|
},
|
|
labels: { default: "Completed", aria: "Completed successfully", live: "polite" },
|
|
terminal: true,
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "status.warning",
|
|
category: "status",
|
|
meaning: "attention is needed for a nonfatal issue",
|
|
glyph: "warning",
|
|
field: "strata",
|
|
fieldMix: [
|
|
layer("strata", 0.58, 1.18, "replace", {
|
|
speed: 0.38,
|
|
contrast: 1.22,
|
|
}),
|
|
layer("interference", 0.42, 1.55, "add", { speed: 0.33 }),
|
|
],
|
|
palette: "warning",
|
|
threshold: 0.49,
|
|
density: 0.86,
|
|
speed: 0.42,
|
|
pixelShape: "diamond",
|
|
pixelSwitch: {
|
|
mode: "contour-trace",
|
|
dither: "bayer8",
|
|
hysteresis: 0.065,
|
|
temporalRate: 0.38,
|
|
direction: "bottom-to-contour",
|
|
},
|
|
timeline: {
|
|
mode: "one-shot-hold",
|
|
durationMs: 1100,
|
|
holdMs: 1600,
|
|
replay: "two-pulses-then-hold",
|
|
},
|
|
transition: {
|
|
enter: "sdf-wavefront",
|
|
exit: "field-morph",
|
|
durationMs: 430,
|
|
preservePhase: false,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "lean-highlight", strength: 0.08 },
|
|
press: { effect: "contained-ripple", strength: 0.08 },
|
|
},
|
|
reducedMotion: {
|
|
mode: "static",
|
|
phase: 1,
|
|
representation: "static outlined triangle and exclamation",
|
|
},
|
|
labels: { default: "Warning", live: "polite" },
|
|
urgency: "medium",
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "status.error",
|
|
category: "status",
|
|
meaning: "operation failed",
|
|
glyph: "error",
|
|
field: "electric",
|
|
fieldMix: [
|
|
layer("electric", 0.61, 1.4, "replace", {
|
|
speed: 0.82,
|
|
contrast: 1.3,
|
|
}),
|
|
layer("ridged", 0.39, 1.85, "multiply", {
|
|
speed: 0.35,
|
|
contrast: 1.22,
|
|
}),
|
|
],
|
|
palette: "danger",
|
|
threshold: 0.51,
|
|
density: 0.88,
|
|
speed: 0.78,
|
|
pixelShape: "square",
|
|
pixelSwitch: {
|
|
mode: "axis-flip",
|
|
dither: "bayer8",
|
|
hysteresis: 0.055,
|
|
temporalRate: 0.9,
|
|
direction: "diagonal-fracture",
|
|
},
|
|
timeline: {
|
|
mode: "one-shot-hold",
|
|
durationMs: 410,
|
|
holdMs: 1200,
|
|
replay: "on-enter",
|
|
},
|
|
transition: {
|
|
enter: "axis-flip",
|
|
exit: "seeded-dissolve",
|
|
durationMs: 410,
|
|
preservePhase: false,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "edge-repel", strength: 0.055 },
|
|
press: { enabled: false },
|
|
},
|
|
reducedMotion: {
|
|
mode: "static",
|
|
phase: 1,
|
|
representation: "static X",
|
|
transitionMs: 100,
|
|
},
|
|
labels: { default: "Error", aria: "Operation failed", live: "assertive" },
|
|
terminal: true,
|
|
urgency: "high",
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "status.paused",
|
|
category: "status",
|
|
meaning: "work is suspended and can resume",
|
|
glyph: "paused",
|
|
field: "fbm",
|
|
fieldMix: [
|
|
layer("fbm", 0.55, 1.1, "replace", { speed: 0 }),
|
|
layer("strata", 0.45, 1.4, "multiply", { speed: 0 }),
|
|
],
|
|
palette: "neutral",
|
|
threshold: 0.5,
|
|
density: 0.9,
|
|
speed: 0,
|
|
pixelShape: "rounded-square",
|
|
pixelSwitch: {
|
|
mode: "axis-flip",
|
|
dither: "bayer8",
|
|
hysteresis: 0.08,
|
|
temporalRate: 0,
|
|
direction: "columns",
|
|
},
|
|
timeline: {
|
|
mode: "hold",
|
|
durationMs: 1,
|
|
replay: "resume-reversible",
|
|
},
|
|
transition: {
|
|
enter: "axis-flip",
|
|
exit: "axis-flip",
|
|
durationMs: 280,
|
|
preservePhase: true,
|
|
preserveBuffer: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "steer-light-only", strength: 0.06 },
|
|
press: { effect: "bar-squeeze", strength: 0.045 },
|
|
signals: [{ name: "resume", mapsTo: "reverseTransition", range: [0, 1] }],
|
|
},
|
|
reducedMotion: {
|
|
mode: "static",
|
|
phase: 1,
|
|
representation: "static pause bars",
|
|
},
|
|
labels: { default: "Paused", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "status.cancelled",
|
|
category: "status",
|
|
meaning: "operation was stopped",
|
|
glyph: "cancelled",
|
|
field: "vortex",
|
|
fieldMix: [
|
|
layer("vortex", 0.57, 0.88, "replace", {
|
|
speed: -0.68,
|
|
contrast: 1.12,
|
|
}),
|
|
layer("metaballs", 0.43, 1.25, "add", { speed: -0.42 }),
|
|
],
|
|
palette: "neutral",
|
|
threshold: 0.52,
|
|
density: 0.85,
|
|
speed: 0.62,
|
|
pixelShape: "square",
|
|
pixelSwitch: {
|
|
mode: "seeded-dissolve",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.065,
|
|
temporalRate: 0.72,
|
|
direction: "reverse-to-center",
|
|
},
|
|
timeline: {
|
|
mode: "one-shot-hold",
|
|
durationMs: 360,
|
|
holdMs: 900,
|
|
replay: "on-enter",
|
|
},
|
|
transition: {
|
|
enter: "seeded-dissolve",
|
|
exit: "seeded-dissolve",
|
|
durationMs: 360,
|
|
preservePhase: false,
|
|
},
|
|
interactions: {
|
|
pointer: { enabled: false },
|
|
press: { effect: "spring-compress", strength: 0.035 },
|
|
},
|
|
reducedMotion: {
|
|
mode: "static",
|
|
phase: 1,
|
|
representation: "static stop square",
|
|
},
|
|
labels: { default: "Cancelled", live: "polite" },
|
|
terminal: true,
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "status.offline",
|
|
category: "status",
|
|
meaning: "disconnected or unavailable",
|
|
glyph: "offline",
|
|
field: "radar",
|
|
fieldMix: [
|
|
layer("radar", 0.56, 0.72, "replace", {
|
|
speed: 0.16,
|
|
contrast: 1.16,
|
|
}),
|
|
layer("electric", 0.44, 1.55, "add", { speed: 0.11 }),
|
|
],
|
|
palette: "neutral",
|
|
threshold: 0.53,
|
|
density: 0.72,
|
|
speed: 0.18,
|
|
pixelShape: "rounded-square",
|
|
pixelSwitch: {
|
|
mode: "path-draw",
|
|
dither: "bayer8",
|
|
hysteresis: 0.075,
|
|
temporalRate: 0.16,
|
|
direction: "bridge-and-retreat",
|
|
},
|
|
timeline: {
|
|
mode: "signal-reactive",
|
|
durationMs: 4200,
|
|
macroCycleMs: 8400,
|
|
replay: "continuous",
|
|
},
|
|
transition: {
|
|
enter: "contour-trace",
|
|
exit: "field-morph",
|
|
durationMs: 480,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "weak-echo", strength: 0.045 },
|
|
press: { effect: "host-retry", strength: 0.04 },
|
|
signals: [
|
|
{ name: "network.retry", mapsTo: "retryEnergy", range: [0, 1] },
|
|
{ name: "network.strength", mapsTo: "signalStrength", range: [0, 1] },
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.31,
|
|
representation: "static broken ring with a diagonal disconnect mark",
|
|
dataUpdates: "retry-dot",
|
|
},
|
|
labels: { default: "Offline", live: "polite" },
|
|
urgency: "medium",
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "transfer.active",
|
|
category: "workflow",
|
|
meaning: "uploading, downloading, or synchronizing data",
|
|
glyph: "transfer",
|
|
field: "flow",
|
|
fieldMix: [
|
|
layer("flow", 0.46, 1.15, "replace", {
|
|
speed: 0.88,
|
|
contrast: 1.14,
|
|
}),
|
|
layer("liquid", 0.31, 1.55, "add", { speed: 0.65 }),
|
|
layer("strata", 0.23, 1.9, "multiply", { speed: 0.44 }),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.48,
|
|
density: 0.79,
|
|
speed: 0.9,
|
|
pixelShape: "square",
|
|
pixelSwitch: {
|
|
mode: "axis-flip",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.052,
|
|
temporalRate: 0.85,
|
|
direction: "data-direction",
|
|
monotonic: false,
|
|
},
|
|
timeline: {
|
|
mode: "data-or-loop",
|
|
durationMs: 2200,
|
|
macroCycleMs: 6600,
|
|
},
|
|
transition: {
|
|
enter: "axis-flip",
|
|
exit: "field-morph",
|
|
durationMs: 380,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "lateral-wind", strength: 0.07, minSize: 28 },
|
|
press: { effect: "spring-compress", strength: 0.045 },
|
|
signals: [
|
|
{
|
|
name: "progress",
|
|
mapsTo: "progress",
|
|
range: [0, 1],
|
|
monotonic: true,
|
|
},
|
|
{
|
|
name: "direction",
|
|
mapsTo: "direction",
|
|
values: ["up", "down", "sync"],
|
|
},
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
mode: "data-step",
|
|
phase: 0.5,
|
|
representation: "static directional arrow with data-driven fill",
|
|
dataUpdates: "discrete-monotonic",
|
|
},
|
|
labels: {
|
|
default: "Transferring",
|
|
live: "polite",
|
|
value: "{percent}% transferred",
|
|
variants: {
|
|
up: "Uploading",
|
|
down: "Downloading",
|
|
sync: "Syncing",
|
|
},
|
|
},
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "workflow.handoff",
|
|
category: "workflow",
|
|
meaning: "passing work to another agent or person",
|
|
glyph: "handoff",
|
|
field: "flow",
|
|
fieldMix: [
|
|
layer("flow", 0.44, 1.02, "replace", {
|
|
speed: 0.66,
|
|
contrast: 1.1,
|
|
}),
|
|
layer("constellation", 0.34, 1.6, "screen", { speed: 0.31 }),
|
|
layer("metaballs", 0.22, 0.85, "add", { speed: 0.38 }),
|
|
],
|
|
palette: "info",
|
|
threshold: 0.49,
|
|
density: 0.77,
|
|
speed: 0.68,
|
|
pixelShape: "circle",
|
|
pixelSwitch: {
|
|
mode: "path-draw",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.055,
|
|
temporalRate: 0.62,
|
|
direction: "source-to-destination",
|
|
},
|
|
timeline: {
|
|
mode: "signal-reactive",
|
|
durationMs: 3000,
|
|
macroCycleMs: 6000,
|
|
replay: "loop-until-accepted",
|
|
},
|
|
transition: {
|
|
enter: "field-morph",
|
|
exit: "path-draw",
|
|
durationMs: 460,
|
|
preservePhase: true,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "bend-path-midpoint", strength: 0.09 },
|
|
press: { enabled: false },
|
|
signals: [
|
|
{
|
|
name: "handoff.accepted",
|
|
mapsTo: "accepted",
|
|
range: [0, 1],
|
|
latches: true,
|
|
},
|
|
],
|
|
},
|
|
reducedMotion: {
|
|
phase: 0.58,
|
|
representation: "two static nodes joined by a directional arrow",
|
|
dataUpdates: "destination-highlight",
|
|
},
|
|
labels: { default: "Handing off", live: "polite" },
|
|
}),
|
|
|
|
defineSprite({
|
|
id: "status.celebration",
|
|
category: "status",
|
|
meaning: "a milestone or high-value success",
|
|
glyph: "celebration",
|
|
field: "constellation",
|
|
fieldMix: [
|
|
layer("constellation", 0.45, 1.45, "replace", {
|
|
speed: 0.92,
|
|
contrast: 1.2,
|
|
}),
|
|
layer("caustics", 0.31, 1.9, "screen", { speed: 0.62 }),
|
|
layer("electric", 0.24, 2.2, "add", { speed: 0.74 }),
|
|
],
|
|
palette: "celebration",
|
|
threshold: 0.45,
|
|
density: 0.88,
|
|
speed: 1,
|
|
pixelShape: "diamond",
|
|
pixelSwitch: {
|
|
mode: "radial-cascade",
|
|
dither: "blue-noise64",
|
|
hysteresis: 0.045,
|
|
temporalRate: 1.1,
|
|
direction: "bounded-burst",
|
|
},
|
|
timeline: {
|
|
mode: "one-shot",
|
|
durationMs: 700,
|
|
holdMs: 900,
|
|
replay: "on-enter-once",
|
|
next: "status.success",
|
|
},
|
|
transition: {
|
|
enter: "radial-cascade",
|
|
exit: "field-morph",
|
|
durationMs: 700,
|
|
preservePhase: false,
|
|
},
|
|
interactions: {
|
|
pointer: { effect: "push-fragments", strength: 0.06, minSize: 32 },
|
|
press: { enabled: false },
|
|
},
|
|
reducedMotion: {
|
|
mode: "static",
|
|
phase: 1,
|
|
representation: "static star with a central success mark",
|
|
transitionMs: 120,
|
|
},
|
|
labels: {
|
|
default: "Milestone completed",
|
|
aria: "Milestone completed successfully",
|
|
live: "polite",
|
|
},
|
|
terminal: true,
|
|
}),
|
|
];
|
|
|
|
export const SPRITES = deepFreeze(
|
|
Object.fromEntries(RECIPES.map((recipe) => [recipe.id, recipe])),
|
|
);
|
|
|
|
export const SPRITE_IDS = Object.freeze(RECIPES.map((recipe) => recipe.id));
|
|
const SPRITE_LIST = Object.freeze([...RECIPES]);
|
|
|
|
export const SPRITE_ALIASES = Object.freeze({
|
|
idle: "ai.idle",
|
|
ready: "ai.idle",
|
|
ambient: "ai.ambient-idle",
|
|
"ambient-idle": "ai.ambient-idle",
|
|
"field-idle": "ai.ambient-idle",
|
|
"ambient-thinking": "ai.ambient-thinking",
|
|
"field-thinking": "ai.ambient-thinking",
|
|
"ambient-thinking-symmetric": "ai.ambient-thinking-symmetric",
|
|
"field-thinking-symmetric": "ai.ambient-thinking-symmetric",
|
|
"symmetric-thinking": "ai.ambient-thinking-symmetric",
|
|
"ambient-speaking": "ai.ambient-speaking",
|
|
"field-speaking": "ai.ambient-speaking",
|
|
listening: "ai.listening",
|
|
thinking: "ai.thinking",
|
|
"thinking-deep": "ai.thinking-deep",
|
|
"deep-thinking": "ai.thinking-deep",
|
|
"still-working": "ai.still-working",
|
|
working: "ai.still-working",
|
|
loading: "ai.loading",
|
|
progress: "ai.progress",
|
|
generating: "ai.generating",
|
|
searching: "ai.searching",
|
|
"tool-use": "ai.tool-use",
|
|
tool: "ai.tool-use",
|
|
speaking: "ai.speaking",
|
|
"awaiting-input": "ai.awaiting-input",
|
|
prompt: "ai.awaiting-input",
|
|
success: "status.success",
|
|
warning: "status.warning",
|
|
error: "status.error",
|
|
paused: "status.paused",
|
|
cancelled: "status.cancelled",
|
|
offline: "status.offline",
|
|
transfer: "transfer.active",
|
|
upload: "transfer.active",
|
|
download: "transfer.active",
|
|
sync: "transfer.active",
|
|
handoff: "workflow.handoff",
|
|
celebration: "status.celebration",
|
|
});
|
|
|
|
export function resolveSpriteId(id) {
|
|
const normalized = String(id ?? "").trim().toLowerCase();
|
|
if (Object.prototype.hasOwnProperty.call(SPRITES, normalized)) {
|
|
return normalized;
|
|
}
|
|
return SPRITE_ALIASES[normalized];
|
|
}
|
|
|
|
export function getSprite(id) {
|
|
const resolved = resolveSpriteId(id);
|
|
return resolved ? SPRITES[resolved] : undefined;
|
|
}
|
|
|
|
export function listSprites() {
|
|
return SPRITE_LIST;
|
|
}
|
|
|
|
export function hasSprite(id) {
|
|
return resolveSpriteId(id) !== undefined;
|
|
}
|
|
|
|
export default SPRITES;
|