"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_primordials_error = require('../primordials/error.js');
const require_primordials_math = require('../primordials/math.js');
const require_primordials_array = require('../primordials/array.js');

//#region src/effects/shimmer.ts
/**
* @file Shimmer animation engine — pure functions, zero deps. Animates a "wave"
*   of color sweeping across a string. Designed for terminal spinners but the
*   engine output is just `RGB[]`, so adapters can render to ANSI, SVG
*   keyframes, Ink components, or anything else. The engine is one function:
*   `frameColors(spec, length, frame) → RGB[]`. It is pure — same inputs
*   produce the same output, no shared state. A {@link ShimmerSpec} bundles
*   three orthogonal pieces:
*
*   1. `positionAt(frame)` — the wave's center at frame N (in char units; negative
*      = off-screen left, > textLength = off-screen right). Built-ins:
*      {@link ltrSweep}, {@link rtlSweep}, {@link bidirectionalSweep},
*      {@link randomSweep}, {@link noSweep}.
*   2. `kernel(signedDistance, ctx)` — given a char's signed distance from the
*      wave center, produce its color. Built-ins: {@link blockKernel} (hard
*      on/off) and {@link smoothKernel} (soft glow).
*   3. `baseColor(i)` / `highlightColor(i)` — per-char palette anchors fed to the
*      kernel as `ctx.baseColor` and `ctx.highlightColor`. Build these with
*      {@link solidColor} (one color for every char) or {@link gradient} (cycle
*      through a palette). Most callers don't build a spec by hand.
*      {@link configToSpec} translates the flat {@link ShimmerConfig} (`{
*      color, dir, speed, … }`) into a spec using sensible defaults. The
*      spinner uses this internally. Adapters in `shimmer-terminal.ts` and
*      `shimmer-keyframes.ts` consume the engine's `RGB[]` output and render it
*      to ANSI escape sequences or SVG SMIL keyframes respectively.
*
* @example
*   Smooth socket-lib-style shimmer over a single color:
*   ```ts
*   import { configToSpec, frameColors } from '@socketsecurity/lib/effects/shimmer'
*   const spec = configToSpec({ color: [140, 82, 255], dir: 'ltr' }, 'Loading'.length)
*   const colorsAtFrame0 = frameColors(spec, 7, 0)
*   ```
*
* @example
*   Discrete claude-code-style shimmer with a rainbow gradient:
*   ```ts
*   import { configToSpec } from '@socketsecurity/lib/effects/shimmer'
*   import { RAINBOW_GRADIENT } from '@socketsecurity/lib/themes/resolve'
*   const spec = configToSpec(
*   { color: RAINBOW_GRADIENT, dir: 'ltr', kernel: 'block' },
*   'ultrathink'.length,
*   )
*   ```
*/
/**
* Default base color used by {@link configToSpec} when `color` is omitted.
* Socket purple — matches the spinner's default color.
*/
const DEFAULT_BASE_COLOR = [
	140,
	82,
	255
];
/**
* Default highlight color used by {@link configToSpec} when `highlight` is
* omitted. Pure white.
*/
const WHITE = [
	255,
	255,
	255
];
/**
* Build a position function for bidirectional motion: the wave does one
* left-to-right pass, then one right-to-left pass, then loops.
*
* @default padding=2
*
* @param textLength Number of chars in the target string.
* @param padding Off-screen chars on each side.
*/
function bidirectionalSweep(textLength, padding = 2) {
	const cycle = textLength + 2 * padding;
	const fullCycle = cycle * 2;
	return (frame) => {
		const f = (frame % fullCycle + fullCycle) % fullCycle;
		if (f < cycle) return f - padding;
		return textLength + padding - 1 - (f - cycle);
	};
}
/**
* Linearly interpolate between two RGB colors. `t` is clamped to [0, 1].
*
* @param a Color at `t=0`
* @param b Color at `t=1`
* @param t Blend factor; values outside [0, 1] are clamped.
*
* @returns Blended RGB with each channel rounded to integer
*/
function blendRgb(a, b, t) {
	const k = t < 0 ? 0 : t > 1 ? 1 : t;
	return [
		require_primordials_math.MathRound(a[0] + (b[0] - a[0]) * k),
		require_primordials_math.MathRound(a[1] + (b[1] - a[1]) * k),
		require_primordials_math.MathRound(a[2] + (b[2] - a[2]) * k)
	];
}
/**
* Discrete on/off kernel — each char is either fully `highlightColor` (within
* `halfWidth` of the wave center) or fully `baseColor`. No blend.
*
* Matches claude-code's spinner behavior at `halfWidth=1` (a 3-char bright
* zone: the char at the wave center plus its left and right neighbors).
*
* @default halfWidth=1
*
* @param halfWidth Chars on each side of the wave center to highlight.
*/
function blockKernel(halfWidth = 1) {
	return (d, ctx) => require_primordials_math.MathAbs(d) <= halfWidth ? ctx.highlightColor : ctx.baseColor;
}
/**
* Translate a flat {@link ShimmerConfig} into a {@link ShimmerSpec}. Applies
* defaults for omitted fields; resolves `color` and `highlight` (which may be a
* single RGB or a palette) into per-char palette functions.
*
* The spinner uses this internally; callers who only need the standard shape
* can call this directly. Advanced callers can construct a `ShimmerSpec` by
* hand to plug in custom kernels or position generators.
*/
function configToSpec(config, textLength) {
	const dir = config.dir ?? "ltr";
	const padding = config.padding ?? 2;
	const speed = config.speed ?? 1 / 3;
	const baseColor = resolvePalette(config.color, DEFAULT_BASE_COLOR);
	const highlightColor = resolvePalette(config.highlight, WHITE);
	const kernel = config.kernel === "block" ? blockKernel(1) : smoothKernel(config.width ?? 2.5);
	const sweep = directionToSweep(dir, textLength, padding);
	return {
		positionAt: (frame) => sweep(frame * speed),
		kernel,
		baseColor,
		highlightColor
	};
}
/**
* Translate a {@link ShimmerDirection} string to its position-generator
* function. Used by {@link configToSpec}; exported for callers that want to swap
* kernel or palette while keeping the standard sweep mapping.
*/
function directionToSweep(dir, textLength, padding) {
	switch (dir) {
		case "rtl": return rtlSweep(textLength, padding);
		case "bi": return bidirectionalSweep(textLength, padding);
		case "random": return randomSweep(textLength, padding);
		case "none": return noSweep();
		default: return ltrSweep(textLength, padding);
	}
}
/**
* Compute per-character colors for a single frame. This is the engine.
*
* @example
*   ;```ts
*   const colors = frameColors(spec, 'Loading'.length, frameCounter)
*   // colors[0] = the color of 'L' at this frame
*   // colors[6] = the color of 'g' at this frame
*   ```
*
* @param spec Functional shimmer specification.
* @param textLength Number of chars to color.
* @param frame Caller-controlled frame counter (any number; the position
*   generator handles wrapping)
*
* @returns One RGB tuple per char index, in order
*/
function frameColors(spec, textLength, frame) {
	const wavePos = spec.positionAt(frame);
	const out = [];
	for (let i = 0; i < textLength; i++) {
		const ctx = {
			__proto__: null,
			baseColor: spec.baseColor(i),
			highlightColor: spec.highlightColor(i)
		};
		out.push(spec.kernel(i - wavePos, ctx));
	}
	return out;
}
/**
* Build a per-char palette function that cycles through a fixed palette: `(i)
* => palette[i % palette.length]`.
*
* @throws {Error} If `palette` is empty
*/
function gradient(palette) {
	if (palette.length === 0) throw new require_primordials_error.ErrorCtor("gradient palette must not be empty");
	return (i) => palette[i % palette.length];
}
/**
* Build a position function for left-to-right motion: the wave starts at
* `-padding` (off-screen left), advances by 1 per frame, exits at `textLength +
* padding`, then wraps.
*
* @default padding=2
*
* @param textLength Number of chars in the target string.
* @param padding Off-screen chars on each side.
*/
function ltrSweep(textLength, padding = 2) {
	const cycle = textLength + 2 * padding;
	return (frame) => (frame % cycle + cycle) % cycle - padding;
}
/**
* Build a position function that hides the wave forever. Returns `-Infinity`
* for every frame so the kernel always sees `signedDistance` > `halfWidth` and
* produces base colors. Used by `configToSpec` when `dir: 'none'`.
*/
function noSweep() {
	return () => -Infinity;
}
/**
* Build a position function that randomly picks LTR or RTL at each cycle
* boundary. The PRNG is configurable (defaults to `Math.random`) so callers can
* seed it for reproducible animations.
*
* @default padding=2, random=Math.random
*
* @param textLength Number of chars in the target string.
* @param padding Off-screen chars on each side.
* @param random PRNG returning [0, 1); defaults to `Math.random`
*/
function randomSweep(textLength, padding = 2, random = Math.random) {
	const cycle = textLength + 2 * padding;
	let dir = random() < .5 ? "ltr" : "rtl";
	let lastCycleIndex = 0;
	return (frame) => {
		const f = (frame % (cycle * 2 ** 30) + cycle * 2 ** 30) % (cycle * 2 ** 30);
		const cycleIndex = require_primordials_math.MathFloor(f / cycle);
		if (cycleIndex !== lastCycleIndex) {
			dir = random() < .5 ? "ltr" : "rtl";
			lastCycleIndex = cycleIndex;
		}
		const inCycle = f % cycle;
		return dir === "ltr" ? inCycle - padding : textLength + padding - 1 - inCycle;
	};
}
/**
* Resolve a {@link ShimmerConfig.color}-shaped input into a per-char palette
* function. Accepts a single RGB tuple, an ordered palette, or `undefined` (in
* which case `defaultColor` is used).
*
* Used internally by {@link configToSpec}; exported so callers can build partial
* specs that share the same input-shape rules.
*/
function resolvePalette(source, defaultColor) {
	if (source === void 0) return solidColor(defaultColor);
	if (require_primordials_array.ArrayIsArray(source[0])) return gradient(source);
	return solidColor(source);
}
/**
* Build a position function for right-to-left motion: the wave starts at the
* right edge, decreases by 1 per frame, exits at `-padding` left of char 0,
* then wraps.
*
* @default padding=2
*
* @param textLength Number of chars in the target string.
* @param padding Off-screen chars on each side.
*/
function rtlSweep(textLength, padding = 2) {
	const cycle = textLength + 2 * padding;
	return (frame) => textLength + padding - 1 - (frame % cycle + cycle) % cycle;
}
/**
* Smooth blend kernel — char's color blends from `baseColor` toward
* `highlightColor` as it approaches the wave center. Falloff curve is `(1 -
* |d|/halfWidth)^falloff`, giving a soft glow with a wider radius than
* `blockKernel`.
*
* Matches socket-lib's previous default at `halfWidth=2.5, falloff=2.5`.
*
* @default halfWidth=2.5, falloff=2.5
*
* @param halfWidth Chars on each side affected by the wave.
* @param falloff Intensity exponent (higher = sharper peak)
*/
function smoothKernel(halfWidth = 2.5, falloff = 2.5) {
	return (d, ctx) => {
		const dist = require_primordials_math.MathAbs(d);
		if (dist >= halfWidth) return ctx.baseColor;
		const t = (1 - dist / halfWidth) ** falloff;
		return blendRgb(ctx.baseColor, ctx.highlightColor, t);
	};
}
/**
* Build a per-char palette function that returns the same color for every char
* index. Useful when shimmering text with a single base color.
*/
function solidColor(color) {
	return () => color;
}

//#endregion
exports.DEFAULT_BASE_COLOR = DEFAULT_BASE_COLOR;
exports.WHITE = WHITE;
exports.bidirectionalSweep = bidirectionalSweep;
exports.blendRgb = blendRgb;
exports.blockKernel = blockKernel;
exports.configToSpec = configToSpec;
exports.directionToSweep = directionToSweep;
exports.frameColors = frameColors;
exports.gradient = gradient;
exports.ltrSweep = ltrSweep;
exports.noSweep = noSweep;
exports.randomSweep = randomSweep;
exports.resolvePalette = resolvePalette;
exports.rtlSweep = rtlSweep;
exports.smoothKernel = smoothKernel;
exports.solidColor = solidColor;