ink-motion 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -6,7 +6,7 @@ Beautiful, performant text effects and animations for [Ink](https://github.com/v
6
6
 
7
7
  - ðŸŽĻ **Rich text effects**: Shimmer, Typewriter, Fade, Wave, Flash
8
8
  - ⚡ **Performant**: Optimised animations with minimal re-renders
9
- - 🔧 **Highly customisable**: Control colours, speed, intensity, and more
9
+ - 🔧 **Highly customisable**: Control colors, speed, intensity, and more
10
10
  - ðŸ“Ķ **Type-safe**: Full TypeScript support with strict types
11
11
  - ðŸŠķ **Lightweight**: Minimal dependencies
12
12
 
@@ -23,7 +23,6 @@ pnpm add ink-motion
23
23
  ```tsx
24
24
  import { render } from 'ink'
25
25
  import { Shimmer, Typewriter } from 'ink-motion'
26
- import React from 'react'
27
26
 
28
27
  function App() {
29
28
  return (
package/dist/index.cjs CHANGED
@@ -70,6 +70,8 @@ function hexToRgb(hex) {
70
70
  if (!result)
71
71
  return null;
72
72
  const [, redHex, greenHex, blueHex] = result;
73
+ if (!redHex || !greenHex || !blueHex)
74
+ return null;
73
75
  return [
74
76
  Number.parseInt(redHex, HEX_BASE),
75
77
  Number.parseInt(greenHex, HEX_BASE),
@@ -85,6 +87,8 @@ function colorize(text, color) {
85
87
  if (!match || match.length < MIN_RGB_COMPONENTS)
86
88
  return text;
87
89
  const [redStr, greenStr, blueStr] = match;
90
+ if (!redStr || !greenStr || !blueStr)
91
+ return text;
88
92
  const red = Number.parseInt(redStr, DECIMAL_BASE);
89
93
  const green = Number.parseInt(greenStr, DECIMAL_BASE);
90
94
  const blue = Number.parseInt(blueStr, DECIMAL_BASE);
@@ -136,11 +140,17 @@ var easeOut = (time) => time * (2 - time);
136
140
  var easeInOut = (time) => {
137
141
  return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time;
138
142
  };
143
+ var sineIn = (time) => 1 - Math.cos(time * Math.PI / 2);
144
+ var sineOut = (time) => Math.sin(time * Math.PI / 2);
145
+ var sineInOut = (time) => -(Math.cos(Math.PI * time) - 1) / 2;
139
146
  var easingFunctions = {
140
147
  "linear": linear,
141
148
  "ease-in": easeIn,
142
149
  "ease-out": easeOut,
143
- "ease-in-out": easeInOut
150
+ "ease-in-out": easeInOut,
151
+ "sine-in": sineIn,
152
+ "sine-out": sineOut,
153
+ "sine-in-out": sineInOut
144
154
  };
145
155
  function getEasingFunction(name = "linear") {
146
156
  return easingFunctions[name];
@@ -151,7 +161,7 @@ function clamp(value, min, max) {
151
161
  var DEFAULT_FROM = 0;
152
162
  var DEFAULT_TO = 1;
153
163
  var DEFAULT_DURATION_MS = 1e3;
154
- var DEFAULT_EASING = "ease-out";
164
+ var DEFAULT_EASING = "sine-in-out";
155
165
  var DEFAULT_LOOP = false;
156
166
  var DEFAULT_SPEED = 1;
157
167
  function calculateOpacity(elapsedTime, duration, from, to, easing) {
@@ -183,10 +193,20 @@ function Fade({
183
193
  }
184
194
  }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete]);
185
195
  const fadedText = react.useMemo(() => {
186
- const effectiveTime = loop ? elapsedTime % duration : Math.min(elapsedTime, duration);
196
+ let effectiveTime = elapsedTime;
197
+ if (loop) {
198
+ const cycleTime = elapsedTime % (duration * 2);
199
+ effectiveTime = cycleTime > duration ? duration * 2 - cycleTime : cycleTime;
200
+ } else {
201
+ effectiveTime = Math.min(elapsedTime, duration);
202
+ }
187
203
  const opacity = calculateOpacity(effectiveTime, duration, from, to, easing);
204
+ if (opacity < 0.01) {
205
+ return "";
206
+ }
188
207
  const baseColor = color ?? "#ffffff";
189
- const fadedColor = applyOpacity(baseColor, opacity);
208
+ const elegantOpacity = opacity ** 1.5;
209
+ const fadedColor = interpolateColor("#000000", baseColor, elegantOpacity);
190
210
  return colorize(children, fadedColor);
191
211
  }, [children, elapsedTime, duration, from, to, easing, color, loop]);
192
212
  return /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: fadedText });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useAnimationFrame.ts","../src/hooks/useElapsedTime.ts","../src/utils/colors.ts","../src/utils/easing.ts","../src/components/Fade.tsx","../src/components/Flash.tsx","../src/utils/text.ts","../src/components/Shimmer.tsx","../src/hooks/useCursorBlink.ts","../src/hooks/useTypewriterProgress.ts","../src/components/Typewriter.tsx","../src/components/Wave.tsx"],"names":["useRef","useEffect","useState","chalk","useMemo","jsx","Text","DEFAULT_DURATION_MS","DEFAULT_SPEED","MIN_INTENSITY","MAX_INTENSITY","FIRST_CHARACTER_INDEX","DEFAULT_COLORS","FULL_CIRCLE_RADIANS","SINE_WAVE_OFFSET","SINE_WAVE_NORMALIZE"],"mappings":"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","file":"index.cjs","sourcesContent":["import { useEffect, useRef } from 'react'\n\nconst TARGET_FPS = 60\nconst FRAME_INTERVAL_MS = 1000 / TARGET_FPS\n\n/**\n * Runs a callback on every animation frame using setInterval\n *\n * @param callback - Function called each frame with delta time in ms\n * @param enabled - Whether animation is active\n */\nexport function useAnimationFrame(\n callback: (deltaTime: number) => void,\n enabled: boolean = true,\n): void {\n const intervalRef = useRef<Timer>()\n const previousTimeRef = useRef<number>()\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n previousTimeRef.current = undefined\n return\n }\n\n intervalRef.current = setInterval(() => {\n const currentTime = Date.now()\n if (previousTimeRef.current !== undefined) {\n const deltaTime = currentTime - previousTimeRef.current\n callbackRef.current(deltaTime)\n }\n previousTimeRef.current = currentTime\n }, FRAME_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [enabled])\n}\n","import { useState } from 'react'\nimport { useAnimationFrame } from './useAnimationFrame.js'\n\n/**\n * Hook that tracks elapsed time since mount or last reset\n *\n * @param enabled - Whether to track time\n * @param speed - Speed multiplier (default: 1)\n * @returns Elapsed time in milliseconds\n */\nexport function useElapsedTime(\n enabled: boolean = true,\n speed: number = 1,\n): number {\n const [elapsedTime, setElapsedTime] = useState(0)\n\n useAnimationFrame((deltaTime) => {\n setElapsedTime(prev => prev + deltaTime * speed)\n }, enabled)\n\n return elapsedTime\n}\n","import type { Colour } from '../types/index.js'\nimport chalk from 'chalk'\n\nconst HEX_BASE = 16\nconst DECIMAL_BASE = 10\nconst HEX_BYTE_LENGTH = 2\nconst HEX_PAD_CHARACTER = '0'\nconst MIN_RGB_COMPONENTS = 3\nconst INTERPOLATION_MIDPOINT = 0.5\n\nconst HEX_COLOR_REGEX = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i\nconst RGB_NUMBERS_REGEX = /\\d+/g\n\nfunction rgbToHex(red: number, green: number, blue: number): string {\n const redHex = red.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const greenHex = green.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const blueHex = blue.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n return `#${redHex}${greenHex}${blueHex}`\n}\n\n/**\n * Converts a hex color string to RGB values\n *\n * @param hex - Hex color string (with or without #)\n * @returns Tuple of [red, green, blue] values (0-255) or null if invalid\n */\nexport function hexToRgb(hex: string): [number, number, number] | null {\n const result = HEX_COLOR_REGEX.exec(hex)\n if (!result)\n return null\n\n const [, redHex, greenHex, blueHex] = result\n return [\n Number.parseInt(redHex, HEX_BASE),\n Number.parseInt(greenHex, HEX_BASE),\n Number.parseInt(blueHex, HEX_BASE),\n ]\n}\n\n/**\n * Applies color to text using chalk\n *\n * @param text - Text to colorize\n * @param color - Color as hex (#ff0000), rgb(255,0,0), or named color (red, blue, etc)\n * @returns Colorized text with ANSI escape codes\n */\nexport function colorize(text: string, color: Colour): string {\n try {\n if (color.startsWith('#'))\n return chalk.hex(color)(text)\n\n if (color.startsWith('rgb')) {\n const match = color.match(RGB_NUMBERS_REGEX)\n if (!match || match.length < MIN_RGB_COMPONENTS)\n return text\n\n const [redStr, greenStr, blueStr] = match\n const red = Number.parseInt(redStr, DECIMAL_BASE)\n const green = Number.parseInt(greenStr, DECIMAL_BASE)\n const blue = Number.parseInt(blueStr, DECIMAL_BASE)\n\n if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue))\n return text\n\n return chalk.rgb(red, green, blue)(text)\n }\n\n const chalkColor = chalk[color as keyof typeof chalk]\n if (typeof chalkColor === 'function')\n return chalkColor(text)\n\n return text\n }\n catch {\n return text\n }\n}\n\n/**\n * Applies opacity to a hex color by darkening it\n * Note: Terminal approximation - true opacity not possible in most terminals\n *\n * @param color - Hex color string\n * @param opacity - Opacity value from 0 (transparent/black) to 1 (fully opaque)\n * @returns Adjusted hex color or original color if not hex format\n */\nexport function applyOpacity(color: Colour, opacity: number): Colour {\n if (!color.startsWith('#'))\n return color\n\n const rgb = hexToRgb(color)\n if (!rgb)\n return color\n\n const [red, green, blue] = rgb\n const adjustedRed = Math.round(red * opacity)\n const adjustedGreen = Math.round(green * opacity)\n const adjustedBlue = Math.round(blue * opacity)\n\n return rgbToHex(adjustedRed, adjustedGreen, adjustedBlue)\n}\n\n/**\n * Interpolates between two colors\n *\n * @param color1 - Starting color\n * @param color2 - Ending color\n * @param progress - Interpolation progress from 0 to 1\n * @returns Interpolated color (hex if both inputs are hex, otherwise snaps to nearest)\n */\nexport function interpolateColor(\n color1: Colour,\n color2: Colour,\n progress: number,\n): Colour {\n const isColor1Hex = color1.startsWith('#')\n const isColor2Hex = color2.startsWith('#')\n\n if (!isColor1Hex || !isColor2Hex)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const rgb1 = hexToRgb(color1)\n const rgb2 = hexToRgb(color2)\n\n if (!rgb1 || !rgb2)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const [red1, green1, blue1] = rgb1\n const [red2, green2, blue2] = rgb2\n\n const red = Math.round(red1 + (red2 - red1) * progress)\n const green = Math.round(green1 + (green2 - green1) * progress)\n const blue = Math.round(blue1 + (blue2 - blue1) * progress)\n\n return rgbToHex(red, green, blue)\n}\n","import type { EasingFunction, EasingName } from '../types/index.js'\n\nexport const linear: EasingFunction = time => time\n\nexport const easeIn: EasingFunction = time => time * time\n\nexport const easeOut: EasingFunction = time => time * (2 - time)\n\nexport const easeInOut: EasingFunction = (time) => {\n return time < 0.5\n ? 2 * time * time\n : -1 + (4 - 2 * time) * time\n}\n\nexport const easingFunctions: Record<EasingName, EasingFunction> = {\n 'linear': linear,\n 'ease-in': easeIn,\n 'ease-out': easeOut,\n 'ease-in-out': easeInOut,\n}\n\nexport function getEasingFunction(name: EasingName = 'linear'): EasingFunction {\n return easingFunctions[name]\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n return clamp((value - min) / (max - min), 0, 1)\n}\n\nexport function lerp(start: number, end: number, progress: number): number {\n return start + (end - start) * progress\n}\n","import type { BaseEffectProps, Colour, EasingName } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { getEasingFunction } from '../utils/easing.js'\n\ninterface FadeProps extends BaseEffectProps {\n /**\n * Text colour\n * @default '#ffffff'\n * @example 'yellow'\n */\n color?: Colour\n\n /**\n * Starting opacity (0-1)\n * @default 0\n */\n from?: number\n\n /**\n * Ending opacity (0-1)\n * @default 1\n */\n to?: number\n\n /**\n * Duration in milliseconds\n * @default 1000\n */\n duration?: number\n\n /**\n * Easing function\n * @default 'ease-out'\n */\n easing?: EasingName\n\n /**\n * Loop animation continuously\n * @default false\n */\n loop?: boolean\n}\n\nconst DEFAULT_FROM = 0\nconst DEFAULT_TO = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_EASING: EasingName = 'ease-out'\nconst DEFAULT_LOOP = false\nconst DEFAULT_SPEED = 1\n\nfunction calculateOpacity(\n elapsedTime: number,\n duration: number,\n from: number,\n to: number,\n easing: EasingName,\n): number {\n const progress = Math.min(elapsedTime / duration, 1)\n const easedProgress = getEasingFunction(easing)(progress)\n return from + (to - from) * easedProgress\n}\n\n/**\n * Fade effect component that smoothly transitions text opacity\n *\n * Animates text from one opacity to another using configurable easing functions.\n * Can loop continuously or run once.\n *\n * @example\n * ```tsx\n * <Fade color=\"yellow\" from={0} to={1} duration={500} easing=\"ease-in\">\n * Success!\n * </Fade>\n * ```\n */\nexport function Fade({\n children,\n color,\n from = DEFAULT_FROM,\n to = DEFAULT_TO,\n duration = DEFAULT_DURATION_MS,\n easing = DEFAULT_EASING,\n loop = DEFAULT_LOOP,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: FadeProps) {\n const [hasCompleted, setHasCompleted] = useState(false)\n const elapsedTime = useElapsedTime(enabled && !hasCompleted, speed)\n\n useEffect(() => {\n if (!enabled)\n return\n\n const isComplete = elapsedTime >= duration\n\n if (isComplete && !loop && !hasCompleted) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: prevents calling onComplete multiple times by setting completion flag once\n setHasCompleted(true)\n onComplete?.()\n }\n }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete])\n\n const fadedText = useMemo(() => {\n const effectiveTime = loop ? elapsedTime % duration : Math.min(elapsedTime, duration)\n const opacity = calculateOpacity(effectiveTime, duration, from, to, easing)\n\n const baseColor = color ?? '#ffffff'\n const fadedColor = applyOpacity(baseColor, opacity)\n\n return colorize(children, fadedColor)\n }, [children, elapsedTime, duration, from, to, easing, color, loop])\n\n return <Text>{fadedText}</Text>\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\n\ninterface FlashProps extends BaseEffectProps {\n /**\n * Text colour\n * @default '#ffffff'\n * @example 'cyan'\n */\n color?: Colour\n\n /**\n * Minimum brightness (0-1)\n * @default 0.3\n */\n minIntensity?: number\n\n /**\n * Maximum brightness (0-1)\n * @default 1\n */\n maxIntensity?: number\n\n /**\n * Flash cycle duration in milliseconds\n * @default 1000\n */\n duration?: number\n}\n\nconst DEFAULT_COLOR = '#ffffff'\nconst DEFAULT_MIN_INTENSITY = 0.3\nconst DEFAULT_MAX_INTENSITY = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\nfunction calculateFlashIntensity(\n time: number,\n duration: number,\n minIntensity: number,\n maxIntensity: number,\n): number {\n const clampedMin = clamp(minIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const clampedMax = clamp(maxIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const normalizedTime = time / duration\n const phase = normalizedTime * FULL_CIRCLE_RADIANS\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const intensityRange = clampedMax - clampedMin\n return clampedMin + normalizedSine * intensityRange\n}\n\n/**\n * Flash effect component that creates a pulsing neon-like glow\n *\n * Animates text with a continuous brightness pulse that oscillates\n * between minimum and maximum intensity levels, creating a flashing\n * or glowing neon effect.\n *\n * @example\n * ```tsx\n * <Flash color=\"cyan\" minIntensity={0.3} maxIntensity={1} duration={800}>\n * ⚡ NEON GLOW ⚡\n * </Flash>\n * ```\n */\nexport function Flash({\n children,\n color = DEFAULT_COLOR,\n minIntensity = DEFAULT_MIN_INTENSITY,\n maxIntensity = DEFAULT_MAX_INTENSITY,\n duration = DEFAULT_DURATION_MS,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: FlashProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const cycleTime = elapsedTime % duration\n\n const flashText = useMemo(() => {\n const intensity = calculateFlashIntensity(cycleTime, duration, minIntensity, maxIntensity)\n const adjustedColor = applyOpacity(color, intensity)\n return colorize(children, adjustedColor)\n }, [children, cycleTime, duration, minIntensity, maxIntensity, color])\n\n return <Text>{flashText}</Text>\n}\n","export function splitChars(text: string): string[] {\n return [...text]\n}\n\nexport function getTextLength(text: string): number {\n return [...text].length\n}\n\nexport function mapChars(\n text: string,\n fn: (char: string, index: number) => string,\n): string {\n return splitChars(text).map(fn).join('')\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo, useState } from 'react'\nimport { useAnimationFrame } from '../hooks/useAnimationFrame.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { getTextLength, mapChars } from '../utils/text.js'\n\ntype ShimmerDirection = 'left' | 'right'\n\ninterface ShimmerProps extends BaseEffectProps {\n /**\n * Gradient colours for the shimmer effect [start, peak, end]\n * @default ['#666666', '#ffffff', '#666666']\n * @example ['#60a5fa', '#3b82f6', '#60a5fa']\n */\n colors?: [Colour, Colour, Colour]\n\n /**\n * Width of the shimmer band in characters\n * @default 4\n */\n width?: number\n\n /**\n * Brightness multiplier (0-1)\n * @default 1\n */\n intensity?: number\n\n /**\n * Direction of shimmer movement\n * @default 'right'\n */\n direction?: ShimmerDirection\n}\n\nconst DEFAULT_COLORS: [Colour, Colour, Colour] = ['#666666', '#ffffff', '#666666']\nconst DEFAULT_WIDTH = 4\nconst DEFAULT_INTENSITY = 1\nconst DEFAULT_DIRECTION: ShimmerDirection = 'right'\nconst DEFAULT_SPEED = 1\nconst ANIMATION_CYCLE_MS = 2000\nconst COLOUR_TRANSITION_MIDPOINT = 0.5\nconst COLOUR_PROGRESS_MULTIPLIER = 2\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\n/**\n * Shimmer effect component that creates a moving highlight across text\n *\n * Creates a shimmering animation by interpolating through a gradient of colours\n * that sweeps across the text from left to right or right to left.\n *\n * @example\n * ```tsx\n * <Shimmer colors={['#60a5fa', '#3b82f6', '#60a5fa']} intensity={0.8}>\n * Loading...\n * </Shimmer>\n * ```\n */\nexport function Shimmer({\n children,\n colors = DEFAULT_COLORS,\n width = DEFAULT_WIDTH,\n intensity = DEFAULT_INTENSITY,\n direction = DEFAULT_DIRECTION,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: ShimmerProps) {\n const [offset, setOffset] = useState(0)\n const textLength = getTextLength(children)\n const totalWidth = textLength + width\n\n useAnimationFrame((deltaTime) => {\n setOffset((previousOffset) => {\n const movement = (deltaTime / ANIMATION_CYCLE_MS) * speed * totalWidth\n const newOffset = direction === 'right'\n ? previousOffset + movement\n : previousOffset - movement\n\n const hasCompletedCycle = Math.abs(newOffset) >= totalWidth\n if (hasCompletedCycle) {\n onComplete?.()\n return 0\n }\n\n return newOffset\n })\n }, enabled)\n\n const shimmerText = useMemo(() => {\n return mapChars(children, (char, index) => {\n const normalizedOffset = direction === 'right' ? offset : totalWidth - offset\n const distance = Math.abs(index - normalizedOffset)\n\n const isWithinShimmerWidth = distance < width\n const colorProgress = isWithinShimmerWidth\n ? distance / width\n : 1\n\n const [startColor, peakColor, endColor] = colors\n const adjustedIntensity = clamp(intensity, MIN_INTENSITY, MAX_INTENSITY)\n\n const isFirstHalf = colorProgress < COLOUR_TRANSITION_MIDPOINT\n const currentColor = isFirstHalf\n ? interpolateColor(\n startColor,\n peakColor,\n colorProgress * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n : interpolateColor(\n peakColor,\n endColor,\n (colorProgress - COLOUR_TRANSITION_MIDPOINT) * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n\n return colorize(char, currentColor)\n })\n }, [children, offset, colors, width, intensity, direction, totalWidth])\n\n return <Text>{shimmerText}</Text>\n}\n","import { useEffect, useRef, useState } from 'react'\n\nconst CURSOR_BLINK_INTERVAL_MS = 500\n\ninterface UseCursorBlinkOptions {\n enabled: boolean\n isComplete: boolean\n}\n\n/**\n * Hook that manages cursor blinking state\n *\n * @param options - Configuration for cursor blink\n * @param options.enabled - Whether cursor blinking is enabled\n * @param options.isComplete - Whether typing is complete\n * @returns Whether cursor should be visible\n */\nexport function useCursorBlink({\n enabled,\n isComplete,\n}: UseCursorBlinkOptions): boolean {\n const [showCursor, setShowCursor] = useState(true)\n const intervalRef = useRef<Timer>()\n\n useEffect(() => {\n if (!enabled || isComplete) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: synchronizing cursor visibility with prop changes\n setShowCursor(false)\n return\n }\n\n intervalRef.current = setInterval(() => {\n setShowCursor(previous => !previous)\n }, CURSOR_BLINK_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current)\n clearInterval(intervalRef.current)\n }\n }, [enabled, isComplete])\n\n return showCursor\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { clamp } from '../utils/easing.js'\n\nconst BASE_CHARACTER_DELAY_MS = 80\nconst MIN_VARIANCE = 0\nconst MAX_VARIANCE = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction calculateCharacterDelay(\n speed: number,\n variance: number,\n): number {\n const clampedVariance = clamp(variance, MIN_VARIANCE, MAX_VARIANCE)\n const randomVariance = (Math.random() - 0.5) * clampedVariance\n return (BASE_CHARACTER_DELAY_MS / speed) * (1 + randomVariance)\n}\n\ninterface UseTypewriterProgressOptions {\n totalCharacters: number\n speed: number\n variance: number\n initialDelay: number\n enabled: boolean\n onComplete?: () => void\n}\n\n/**\n * Hook that manages typewriter character reveal timing\n *\n * @param options - Configuration for typewriter progress\n * @param options.totalCharacters - Total number of characters to reveal\n * @param options.speed - Animation speed multiplier\n * @param options.variance - Typing variance for human-like timing (0-1)\n * @param options.initialDelay - Delay before typing starts in milliseconds\n * @param options.enabled - Whether the animation is enabled\n * @param options.onComplete - Callback when typing completes\n * @returns Number of characters to display\n */\nexport function useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay,\n enabled,\n onComplete,\n}: UseTypewriterProgressOptions): number {\n const [visibleCharacters, setVisibleCharacters] = useState(0)\n const timeoutRef = useRef<Timer>()\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n\n useEffect(() => {\n if (!enabled)\n return\n\n if (hasCompletedTyping) {\n onComplete?.()\n return\n }\n\n const characterDelay = calculateCharacterDelay(speed, variance)\n const isFirstCharacter = visibleCharacters === FIRST_CHARACTER_INDEX\n const totalDelay = isFirstCharacter ? initialDelay + characterDelay : characterDelay\n\n timeoutRef.current = setTimeout(() => {\n setVisibleCharacters(previous => previous + 1)\n }, totalDelay)\n\n return () => {\n if (timeoutRef.current)\n clearTimeout(timeoutRef.current)\n }\n }, [visibleCharacters, enabled, speed, variance, initialDelay, hasCompletedTyping, onComplete])\n\n return visibleCharacters\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useCursorBlink } from '../hooks/useCursorBlink.js'\nimport { useTypewriterProgress } from '../hooks/useTypewriterProgress.js'\nimport { colorize } from '../utils/colors.js'\nimport { getTextLength, splitChars } from '../utils/text.js'\n\ninterface TypewriterProps extends BaseEffectProps {\n /**\n * Text colour\n * @default undefined (inherits)\n * @example 'green'\n */\n color?: Colour\n\n /**\n * Cursor character or false to disable\n * @default '▋'\n * @example '█'\n */\n cursor?: string | boolean\n\n /**\n * Cursor colour (defaults to text colour)\n * @default undefined\n * @example 'cyan'\n */\n cursorColor?: Colour\n\n /**\n * Typing speed randomness (0-1) for more human-like typing\n * @default 0.3\n */\n variance?: number\n\n /**\n * Initial delay before typing starts (ms)\n * @default 0\n */\n delay?: number\n}\n\nconst DEFAULT_CURSOR = '▋'\nconst DEFAULT_VARIANCE = 0.3\nconst DEFAULT_DELAY = 0\nconst DEFAULT_SPEED = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction getCursorCharacter(cursor: string | boolean): string {\n return typeof cursor === 'string' ? cursor : DEFAULT_CURSOR\n}\n\nfunction formatCursor(\n cursorCharacter: string,\n cursorColor: Colour | undefined,\n textColor: Colour | undefined,\n): string {\n if (cursorColor)\n return colorize(cursorCharacter, cursorColor)\n\n if (textColor)\n return colorize(cursorCharacter, textColor)\n\n return cursorCharacter\n}\n\n/**\n * Typewriter effect component that reveals text character by character\n *\n * Simulates typing text with configurable speed, variance for realistic timing,\n * and an optional cursor. The cursor blinks while typing is in progress.\n *\n * @example\n * ```tsx\n * <Typewriter color=\"green\" cursor=\"█\" variance={0.5} speed={2}>\n * npm install ink-motion\n * </Typewriter>\n * ```\n */\nexport function Typewriter({\n children,\n color,\n cursor = DEFAULT_CURSOR,\n cursorColor,\n variance = DEFAULT_VARIANCE,\n delay = DEFAULT_DELAY,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: TypewriterProps) {\n const characters = splitChars(children)\n const totalCharacters = getTextLength(children)\n\n const visibleCharacters = useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay: delay,\n enabled,\n onComplete,\n })\n\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n const isCursorEnabled = cursor !== false\n\n const showCursor = useCursorBlink({\n enabled: enabled && isCursorEnabled,\n isComplete: hasCompletedTyping,\n })\n\n const displayText = useMemo(() => {\n const visibleText = characters.slice(FIRST_CHARACTER_INDEX, visibleCharacters).join('')\n const coloredText = color ? colorize(visibleText, color) : visibleText\n\n const shouldShowCursor = isCursorEnabled && showCursor && !hasCompletedTyping\n if (!shouldShowCursor)\n return coloredText\n\n const cursorCharacter = getCursorCharacter(cursor)\n const cursorText = formatCursor(cursorCharacter, cursorColor, color)\n\n return coloredText + cursorText\n }, [characters, visibleCharacters, color, cursor, cursorColor, showCursor, hasCompletedTyping, isCursorEnabled])\n\n return <Text>{displayText}</Text>\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { mapChars } from '../utils/text.js'\n\ntype WaveType = 'brightness' | 'vertical'\n\ninterface WaveProps extends BaseEffectProps {\n /**\n * Gradient colours for the wave [dark, bright]\n * @default ['#888888', '#ffffff']\n * @example ['#ec4899', '#8b5cf6']\n */\n colors?: [Colour, Colour]\n\n /**\n * Wave height (0-1)\n * @default 0.5\n */\n amplitude?: number\n\n /**\n * Number of wave cycles across text\n * @default 2\n */\n frequency?: number\n\n /**\n * Wave effect type\n * @default 'brightness'\n */\n type?: WaveType\n}\n\nconst DEFAULT_COLORS: [Colour, Colour] = ['#888888', '#ffffff']\nconst DEFAULT_AMPLITUDE = 0.5\nconst DEFAULT_FREQUENCY = 2\nconst DEFAULT_TYPE: WaveType = 'brightness'\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst WAVE_PERIOD_MS = 2000\nconst MIN_AMPLITUDE = 0\nconst MAX_AMPLITUDE = 1\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst VERTICAL_SHIFT_THRESHOLD = 0.5\n\nfunction calculateWaveValue(\n characterIndex: number,\n time: number,\n frequency: number,\n amplitude: number,\n): number {\n const clampedAmplitude = clamp(amplitude, MIN_AMPLITUDE, MAX_AMPLITUDE)\n const safeFrequency = frequency || DEFAULT_FREQUENCY\n const waveLength = FULL_CIRCLE_RADIANS / safeFrequency\n const spatialComponent = (characterIndex / waveLength) * FULL_CIRCLE_RADIANS\n const temporalComponent = time * FULL_CIRCLE_RADIANS\n const phase = spatialComponent - temporalComponent\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const amplitudeComplement = MAX_AMPLITUDE - clampedAmplitude\n return normalizedSine * clampedAmplitude + amplitudeComplement\n}\n\n/**\n * Wave effect component that creates a wave motion through text\n *\n * Animates text with a sine wave pattern that can affect brightness or vertical position.\n * The wave continuously flows through the text.\n *\n * @example\n * ```tsx\n * <Wave colors={['#ec4899', '#8b5cf6']} amplitude={0.7} frequency={3}>\n * ~~ wavy text ~~\n * </Wave>\n * ```\n */\nexport function Wave({\n children,\n colors = DEFAULT_COLORS,\n amplitude = DEFAULT_AMPLITUDE,\n frequency = DEFAULT_FREQUENCY,\n type = DEFAULT_TYPE,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: WaveProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const normalizedTime = elapsedTime / WAVE_PERIOD_MS\n\n const waveText = useMemo(() => {\n if (type === 'brightness') {\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const [darkColor, brightColor] = colors\n const characterColor = interpolateColor(darkColor, brightColor, waveValue)\n return colorize(character, characterColor)\n })\n }\n\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const shouldShift = waveValue > VERTICAL_SHIFT_THRESHOLD\n return shouldShift ? ` ${character}` : character\n })\n }, [children, normalizedTime, colors, amplitude, frequency, type])\n\n return <Text>{waveText}</Text>\n}\n"]}
1
+ {"version":3,"sources":["../src/hooks/useAnimationFrame.ts","../src/hooks/useElapsedTime.ts","../src/utils/colors.ts","../src/utils/easing.ts","../src/components/Fade.tsx","../src/components/Flash.tsx","../src/utils/text.ts","../src/components/Shimmer.tsx","../src/hooks/useCursorBlink.ts","../src/hooks/useTypewriterProgress.ts","../src/components/Typewriter.tsx","../src/components/Wave.tsx"],"names":["useRef","useEffect","useState","chalk","useMemo","jsx","Text","DEFAULT_DURATION_MS","DEFAULT_SPEED","MIN_INTENSITY","MAX_INTENSITY","FIRST_CHARACTER_INDEX","DEFAULT_COLORS","FULL_CIRCLE_RADIANS","SINE_WAVE_OFFSET","SINE_WAVE_NORMALIZE"],"mappings":"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","file":"index.cjs","sourcesContent":["import { useEffect, useRef } from 'react'\n\nconst TARGET_FPS = 60\nconst FRAME_INTERVAL_MS = 1000 / TARGET_FPS\n\n/**\n * Runs a callback on every animation frame using setInterval\n *\n * @param callback - Function called each frame with delta time in ms\n * @param enabled - Whether animation is active\n */\nexport function useAnimationFrame(\n callback: (deltaTime: number) => void,\n enabled: boolean = true,\n): void {\n const intervalRef = useRef<Timer>()\n const previousTimeRef = useRef<number>()\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n previousTimeRef.current = undefined\n return\n }\n\n intervalRef.current = setInterval(() => {\n const currentTime = Date.now()\n if (previousTimeRef.current !== undefined) {\n const deltaTime = currentTime - previousTimeRef.current\n callbackRef.current(deltaTime)\n }\n previousTimeRef.current = currentTime\n }, FRAME_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [enabled])\n}\n","import { useState } from 'react'\nimport { useAnimationFrame } from './useAnimationFrame.js'\n\n/**\n * Hook that tracks elapsed time since mount or last reset\n *\n * @param enabled - Whether to track time\n * @param speed - Speed multiplier (default: 1)\n * @returns Elapsed time in milliseconds\n */\nexport function useElapsedTime(\n enabled: boolean = true,\n speed: number = 1,\n): number {\n const [elapsedTime, setElapsedTime] = useState(0)\n\n useAnimationFrame((deltaTime) => {\n setElapsedTime(prev => prev + deltaTime * speed)\n }, enabled)\n\n return elapsedTime\n}\n","import type { Color } from '../types/index.js'\nimport chalk from 'chalk'\n\nconst HEX_BASE = 16\nconst DECIMAL_BASE = 10\nconst HEX_BYTE_LENGTH = 2\nconst HEX_PAD_CHARACTER = '0'\nconst MIN_RGB_COMPONENTS = 3\nconst INTERPOLATION_MIDPOINT = 0.5\n\nconst HEX_COLOR_REGEX = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i\nconst RGB_NUMBERS_REGEX = /\\d+/g\n\nfunction rgbToHex(red: number, green: number, blue: number): string {\n const redHex = red.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const greenHex = green.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const blueHex = blue.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n return `#${redHex}${greenHex}${blueHex}`\n}\n\n/**\n * Converts a hex color string to RGB values\n *\n * @param hex - Hex color string (with or without #)\n * @returns Tuple of [red, green, blue] values (0-255) or null if invalid\n */\nexport function hexToRgb(hex: string): [number, number, number] | null {\n const result = HEX_COLOR_REGEX.exec(hex)\n if (!result)\n return null\n\n const [, redHex, greenHex, blueHex] = result\n if (!redHex || !greenHex || !blueHex)\n return null\n\n return [\n Number.parseInt(redHex, HEX_BASE),\n Number.parseInt(greenHex, HEX_BASE),\n Number.parseInt(blueHex, HEX_BASE),\n ]\n}\n\n/**\n * Applies color to text using chalk\n *\n * @param text - Text to colorize\n * @param color - Color as hex (#ff0000), rgb(255,0,0), or named color (red, blue, etc)\n * @returns Colorized text with ANSI escape codes\n */\nexport function colorize(text: string, color: Color): string {\n try {\n if (color.startsWith('#'))\n return chalk.hex(color)(text)\n\n if (color.startsWith('rgb')) {\n const match = color.match(RGB_NUMBERS_REGEX)\n if (!match || match.length < MIN_RGB_COMPONENTS)\n return text\n\n const [redStr, greenStr, blueStr] = match\n if (!redStr || !greenStr || !blueStr)\n return text\n\n const red = Number.parseInt(redStr, DECIMAL_BASE)\n const green = Number.parseInt(greenStr, DECIMAL_BASE)\n const blue = Number.parseInt(blueStr, DECIMAL_BASE)\n\n if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue))\n return text\n\n return chalk.rgb(red, green, blue)(text)\n }\n\n const chalkColor = (chalk as any)[color]\n if (typeof chalkColor === 'function')\n return chalkColor(text)\n\n return text\n }\n catch {\n return text\n }\n}\n\n/**\n * Applies opacity to a hex color by darkening it\n * Note: Terminal approximation - true opacity not possible in most terminals\n *\n * @param color - Hex color string\n * @param opacity - Opacity value from 0 (transparent/black) to 1 (fully opaque)\n * @returns Adjusted hex color or original color if not hex format\n */\nexport function applyOpacity(color: Color, opacity: number): Color {\n if (!color.startsWith('#'))\n return color\n\n const rgb = hexToRgb(color)\n if (!rgb)\n return color\n\n const [red, green, blue] = rgb\n const adjustedRed = Math.round(red * opacity)\n const adjustedGreen = Math.round(green * opacity)\n const adjustedBlue = Math.round(blue * opacity)\n\n return rgbToHex(adjustedRed, adjustedGreen, adjustedBlue)\n}\n\n/**\n * Interpolates between two colors\n *\n * @param color1 - Starting color\n * @param color2 - Ending color\n * @param progress - Interpolation progress from 0 to 1\n * @returns Interpolated color (hex if both inputs are hex, otherwise snaps to nearest)\n */\nexport function interpolateColor(\n color1: Color,\n color2: Color,\n progress: number,\n): Color {\n const isColor1Hex = color1.startsWith('#')\n const isColor2Hex = color2.startsWith('#')\n\n if (!isColor1Hex || !isColor2Hex)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const rgb1 = hexToRgb(color1)\n const rgb2 = hexToRgb(color2)\n\n if (!rgb1 || !rgb2)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const [red1, green1, blue1] = rgb1\n const [red2, green2, blue2] = rgb2\n\n const red = Math.round(red1 + (red2 - red1) * progress)\n const green = Math.round(green1 + (green2 - green1) * progress)\n const blue = Math.round(blue1 + (blue2 - blue1) * progress)\n\n return rgbToHex(red, green, blue)\n}\n","import type { EasingFunction, EasingName } from '../types/index.js'\n\nexport const linear: EasingFunction = time => time\n\nexport const easeIn: EasingFunction = time => time * time\n\nexport const easeOut: EasingFunction = time => time * (2 - time)\n\nexport const easeInOut: EasingFunction = (time) => {\n return time < 0.5\n ? 2 * time * time\n : -1 + (4 - 2 * time) * time\n}\n\nexport const sineIn: EasingFunction = time => 1 - Math.cos((time * Math.PI) / 2)\n\nexport const sineOut: EasingFunction = time => Math.sin((time * Math.PI) / 2)\n\nexport const sineInOut: EasingFunction = time => -(Math.cos(Math.PI * time) - 1) / 2\n\nexport const easingFunctions: Record<EasingName, EasingFunction> = {\n 'linear': linear,\n 'ease-in': easeIn,\n 'ease-out': easeOut,\n 'ease-in-out': easeInOut,\n 'sine-in': sineIn,\n 'sine-out': sineOut,\n 'sine-in-out': sineInOut,\n}\n\nexport function getEasingFunction(name: EasingName = 'linear'): EasingFunction {\n return easingFunctions[name]\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n return clamp((value - min) / (max - min), 0, 1)\n}\n\nexport function lerp(start: number, end: number, progress: number): number {\n return start + (end - start) * progress\n}\n","import type { BaseEffectProps, Color, EasingName } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { getEasingFunction } from '../utils/easing.js'\n\ninterface FadeProps extends BaseEffectProps {\n /**\n * Text color\n * @default '#ffffff'\n * @example 'yellow'\n */\n color?: Color\n\n /**\n * Starting opacity (0-1)\n * @default 0\n */\n from?: number\n\n /**\n * Ending opacity (0-1)\n * @default 1\n */\n to?: number\n\n /**\n * Duration in milliseconds\n * @default 1000\n */\n duration?: number\n\n /**\n * Easing function\n * @default 'ease-out'\n */\n easing?: EasingName\n\n /**\n * Loop animation continuously\n * @default false\n */\n loop?: boolean\n}\n\nconst DEFAULT_FROM = 0\nconst DEFAULT_TO = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_EASING: EasingName = 'sine-in-out'\nconst DEFAULT_LOOP = false\nconst DEFAULT_SPEED = 1\n\nfunction calculateOpacity(\n elapsedTime: number,\n duration: number,\n from: number,\n to: number,\n easing: EasingName,\n): number {\n const progress = Math.min(elapsedTime / duration, 1)\n const easedProgress = getEasingFunction(easing)(progress)\n return from + (to - from) * easedProgress\n}\n\n/**\n * Fade effect component that smoothly transitions text opacity\n *\n * Animates text from one opacity to another using configurable easing functions.\n * Can loop continuously or run once.\n *\n * Note: Optimized for dark terminals. Fades to/from black which appears as true\n * transparency on dark backgrounds. On light terminals, low opacity text may appear\n * visible as dark text. For best results on all terminals, use bright colors.\n *\n * @example\n * ```tsx\n * <Fade color=\"yellow\" from={0} to={1} duration={500} easing=\"ease-in\">\n * Success!\n * </Fade>\n * ```\n */\nexport function Fade({\n children,\n color,\n from = DEFAULT_FROM,\n to = DEFAULT_TO,\n duration = DEFAULT_DURATION_MS,\n easing = DEFAULT_EASING,\n loop = DEFAULT_LOOP,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: FadeProps) {\n const [hasCompleted, setHasCompleted] = useState(false)\n const elapsedTime = useElapsedTime(enabled && !hasCompleted, speed)\n\n useEffect(() => {\n if (!enabled)\n return\n\n const isComplete = elapsedTime >= duration\n\n if (isComplete && !loop && !hasCompleted) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: prevents calling onComplete multiple times by setting completion flag once\n setHasCompleted(true)\n onComplete?.()\n }\n }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete])\n\n const fadedText = useMemo(() => {\n let effectiveTime = elapsedTime\n if (loop) {\n const cycleTime = elapsedTime % (duration * 2)\n effectiveTime = cycleTime > duration ? (duration * 2) - cycleTime : cycleTime\n }\n else {\n effectiveTime = Math.min(elapsedTime, duration)\n }\n\n const opacity = calculateOpacity(effectiveTime, duration, from, to, easing)\n\n if (opacity < 0.01) {\n return ''\n }\n\n const baseColor = color ?? '#ffffff'\n const elegantOpacity = opacity ** 1.5\n const fadedColor = interpolateColor('#000000', baseColor, elegantOpacity)\n\n return colorize(children, fadedColor)\n }, [children, elapsedTime, duration, from, to, easing, color, loop])\n\n return <Text>{fadedText}</Text>\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\n\ninterface FlashProps extends BaseEffectProps {\n /**\n * Base color\n * @default '#ffffff'\n * @example 'cyan'\n */\n color?: Color\n\n /**\n * Minimum brightness (0-1)\n * @default 0.3\n */\n minIntensity?: number\n\n /**\n * Maximum brightness (0-1)\n * @default 1\n */\n maxIntensity?: number\n\n /**\n * Flash cycle duration in milliseconds\n * @default 1000\n */\n duration?: number\n}\n\nconst DEFAULT_COLOR = '#ffffff'\nconst DEFAULT_MIN_INTENSITY = 0.3\nconst DEFAULT_MAX_INTENSITY = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\nfunction calculateFlashIntensity(\n time: number,\n duration: number,\n minIntensity: number,\n maxIntensity: number,\n): number {\n const clampedMin = clamp(minIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const clampedMax = clamp(maxIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const normalizedTime = time / duration\n const phase = normalizedTime * FULL_CIRCLE_RADIANS\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const intensityRange = clampedMax - clampedMin\n return clampedMin + normalizedSine * intensityRange\n}\n\n/**\n * Flash effect component that creates a pulsing neon-like glow\n *\n * Animates text with a continuous brightness pulse that oscillates\n * between minimum and maximum intensity levels, creating a flashing\n * or glowing neon effect.\n *\n * @example\n * ```tsx\n * <Flash color=\"cyan\" minIntensity={0.3} maxIntensity={1} duration={800}>\n * ⚡ NEON GLOW ⚡\n * </Flash>\n * ```\n */\nexport function Flash({\n children,\n color = DEFAULT_COLOR,\n minIntensity = DEFAULT_MIN_INTENSITY,\n maxIntensity = DEFAULT_MAX_INTENSITY,\n duration = DEFAULT_DURATION_MS,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: FlashProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const cycleTime = elapsedTime % duration\n\n const flashText = useMemo(() => {\n const intensity = calculateFlashIntensity(cycleTime, duration, minIntensity, maxIntensity)\n const adjustedColor = applyOpacity(color, intensity)\n return colorize(children, adjustedColor)\n }, [children, cycleTime, duration, minIntensity, maxIntensity, color])\n\n return <Text>{flashText}</Text>\n}\n","export function splitChars(text: string): string[] {\n return [...text]\n}\n\nexport function getTextLength(text: string): number {\n return [...text].length\n}\n\nexport function mapChars(\n text: string,\n fn: (char: string, index: number) => string,\n): string {\n return splitChars(text).map(fn).join('')\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo, useState } from 'react'\nimport { useAnimationFrame } from '../hooks/useAnimationFrame.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { getTextLength, mapChars } from '../utils/text.js'\n\ntype ShimmerDirection = 'left' | 'right'\n\ninterface ShimmerProps extends BaseEffectProps {\n /**\n * Gradient colours for the shimmer effect [start, peak, end]\n * @default ['#666666', '#ffffff', '#666666']\n * @example ['#60a5fa', '#3b82f6', '#60a5fa']\n */\n colors?: [Color, Color, Color]\n\n /**\n * Width of the shimmer band in characters\n * @default 4\n */\n width?: number\n\n /**\n * Brightness multiplier (0-1)\n * @default 1\n */\n intensity?: number\n\n /**\n * Direction of shimmer movement\n * @default 'right'\n */\n direction?: ShimmerDirection\n}\n\nconst DEFAULT_COLORS: [Color, Color, Color] = ['#666666', '#ffffff', '#666666']\nconst DEFAULT_WIDTH = 4\nconst DEFAULT_INTENSITY = 1\nconst DEFAULT_DIRECTION: ShimmerDirection = 'right'\nconst DEFAULT_SPEED = 1\nconst ANIMATION_CYCLE_MS = 2000\nconst COLOUR_TRANSITION_MIDPOINT = 0.5\nconst COLOUR_PROGRESS_MULTIPLIER = 2\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\n/**\n * Shimmer effect component that creates a moving highlight across text\n *\n * Creates a shimmering animation by interpolating through a gradient of colours\n * that sweeps across the text from left to right or right to left.\n *\n * @example\n * ```tsx\n * <Shimmer colors={['#60a5fa', '#3b82f6', '#60a5fa']} intensity={0.8}>\n * Loading...\n * </Shimmer>\n * ```\n */\nexport function Shimmer({\n children,\n colors = DEFAULT_COLORS,\n width = DEFAULT_WIDTH,\n intensity = DEFAULT_INTENSITY,\n direction = DEFAULT_DIRECTION,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: ShimmerProps) {\n const [offset, setOffset] = useState(0)\n const textLength = getTextLength(children)\n const totalWidth = textLength + width\n\n useAnimationFrame((deltaTime) => {\n setOffset((previousOffset) => {\n const movement = (deltaTime / ANIMATION_CYCLE_MS) * speed * totalWidth\n const newOffset = direction === 'right'\n ? previousOffset + movement\n : previousOffset - movement\n\n const hasCompletedCycle = Math.abs(newOffset) >= totalWidth\n if (hasCompletedCycle) {\n onComplete?.()\n return 0\n }\n\n return newOffset\n })\n }, enabled)\n\n const shimmerText = useMemo(() => {\n return mapChars(children, (char, index) => {\n const normalizedOffset = direction === 'right' ? offset : totalWidth - offset\n const distance = Math.abs(index - normalizedOffset)\n\n const isWithinShimmerWidth = distance < width\n const colorProgress = isWithinShimmerWidth\n ? distance / width\n : 1\n\n const [startColor, peakColor, endColor] = colors\n const adjustedIntensity = clamp(intensity, MIN_INTENSITY, MAX_INTENSITY)\n\n const isFirstHalf = colorProgress < COLOUR_TRANSITION_MIDPOINT\n const currentColor = isFirstHalf\n ? interpolateColor(\n startColor,\n peakColor,\n colorProgress * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n : interpolateColor(\n peakColor,\n endColor,\n (colorProgress - COLOUR_TRANSITION_MIDPOINT) * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n\n return colorize(char, currentColor)\n })\n }, [children, offset, colors, width, intensity, direction, totalWidth])\n\n return <Text>{shimmerText}</Text>\n}\n","import { useEffect, useRef, useState } from 'react'\n\nconst CURSOR_BLINK_INTERVAL_MS = 500\n\ninterface UseCursorBlinkOptions {\n enabled: boolean\n isComplete: boolean\n}\n\n/**\n * Hook that manages cursor blinking state\n *\n * @param options - Configuration for cursor blink\n * @param options.enabled - Whether cursor blinking is enabled\n * @param options.isComplete - Whether typing is complete\n * @returns Whether cursor should be visible\n */\nexport function useCursorBlink({\n enabled,\n isComplete,\n}: UseCursorBlinkOptions): boolean {\n const [showCursor, setShowCursor] = useState(true)\n const intervalRef = useRef<Timer>()\n\n useEffect(() => {\n if (!enabled || isComplete) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: synchronizing cursor visibility with prop changes\n setShowCursor(false)\n return\n }\n\n intervalRef.current = setInterval(() => {\n setShowCursor(previous => !previous)\n }, CURSOR_BLINK_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current)\n clearInterval(intervalRef.current)\n }\n }, [enabled, isComplete])\n\n return showCursor\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { clamp } from '../utils/easing.js'\n\nconst BASE_CHARACTER_DELAY_MS = 80\nconst MIN_VARIANCE = 0\nconst MAX_VARIANCE = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction calculateCharacterDelay(\n speed: number,\n variance: number,\n): number {\n const clampedVariance = clamp(variance, MIN_VARIANCE, MAX_VARIANCE)\n const randomVariance = (Math.random() - 0.5) * clampedVariance\n return (BASE_CHARACTER_DELAY_MS / speed) * (1 + randomVariance)\n}\n\ninterface UseTypewriterProgressOptions {\n totalCharacters: number\n speed: number\n variance: number\n initialDelay: number\n enabled: boolean\n onComplete?: () => void\n}\n\n/**\n * Hook that manages typewriter character reveal timing\n *\n * @param options - Configuration for typewriter progress\n * @param options.totalCharacters - Total number of characters to reveal\n * @param options.speed - Animation speed multiplier\n * @param options.variance - Typing variance for human-like timing (0-1)\n * @param options.initialDelay - Delay before typing starts in milliseconds\n * @param options.enabled - Whether the animation is enabled\n * @param options.onComplete - Callback when typing completes\n * @returns Number of characters to display\n */\nexport function useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay,\n enabled,\n onComplete,\n}: UseTypewriterProgressOptions): number {\n const [visibleCharacters, setVisibleCharacters] = useState(0)\n const timeoutRef = useRef<Timer>()\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n\n useEffect(() => {\n if (!enabled)\n return\n\n if (hasCompletedTyping) {\n onComplete?.()\n return\n }\n\n const characterDelay = calculateCharacterDelay(speed, variance)\n const isFirstCharacter = visibleCharacters === FIRST_CHARACTER_INDEX\n const totalDelay = isFirstCharacter ? initialDelay + characterDelay : characterDelay\n\n timeoutRef.current = setTimeout(() => {\n setVisibleCharacters(previous => previous + 1)\n }, totalDelay)\n\n return () => {\n if (timeoutRef.current)\n clearTimeout(timeoutRef.current)\n }\n }, [visibleCharacters, enabled, speed, variance, initialDelay, hasCompletedTyping, onComplete])\n\n return visibleCharacters\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useCursorBlink } from '../hooks/useCursorBlink.js'\nimport { useTypewriterProgress } from '../hooks/useTypewriterProgress.js'\nimport { colorize } from '../utils/colors.js'\nimport { getTextLength, splitChars } from '../utils/text.js'\n\ninterface TypewriterProps extends BaseEffectProps {\n /**\n * Text color\n * @default undefined (inherits)\n * @example 'green'\n */\n color?: Color\n\n /**\n * Cursor character or false to disable\n * @default '▋'\n * @example '█'\n */\n cursor?: string | boolean\n\n /**\n * Cursor color (defaults to text color)\n * @default undefined\n * @example 'cyan'\n */\n cursorColor?: Color\n\n /**\n * Typing speed randomness (0-1) for more human-like typing\n * @default 0.3\n */\n variance?: number\n\n /**\n * Initial delay before typing starts (ms)\n * @default 0\n */\n delay?: number\n}\n\nconst DEFAULT_CURSOR = '▋'\nconst DEFAULT_VARIANCE = 0.3\nconst DEFAULT_DELAY = 0\nconst DEFAULT_SPEED = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction getCursorCharacter(cursor: string | boolean): string {\n return typeof cursor === 'string' ? cursor : DEFAULT_CURSOR\n}\n\nfunction formatCursor(\n cursorCharacter: string,\n cursorColor: Color | undefined,\n textColor: Color | undefined,\n): string {\n if (cursorColor)\n return colorize(cursorCharacter, cursorColor)\n\n if (textColor)\n return colorize(cursorCharacter, textColor)\n\n return cursorCharacter\n}\n\n/**\n * Typewriter effect component that reveals text character by character\n *\n * Simulates typing text with configurable speed, variance for realistic timing,\n * and an optional cursor. The cursor blinks while typing is in progress.\n *\n * @example\n * ```tsx\n * <Typewriter color=\"green\" cursor=\"█\" variance={0.5} speed={2}>\n * npm install ink-motion\n * </Typewriter>\n * ```\n */\nexport function Typewriter({\n children,\n color,\n cursor = DEFAULT_CURSOR,\n cursorColor,\n variance = DEFAULT_VARIANCE,\n delay = DEFAULT_DELAY,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: TypewriterProps) {\n const characters = splitChars(children)\n const totalCharacters = getTextLength(children)\n\n const visibleCharacters = useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay: delay,\n enabled,\n onComplete,\n })\n\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n const isCursorEnabled = cursor !== false\n\n const showCursor = useCursorBlink({\n enabled: enabled && isCursorEnabled,\n isComplete: hasCompletedTyping,\n })\n\n const displayText = useMemo(() => {\n const visibleText = characters.slice(FIRST_CHARACTER_INDEX, visibleCharacters).join('')\n const coloredText = color ? colorize(visibleText, color) : visibleText\n\n const shouldShowCursor = isCursorEnabled && showCursor && !hasCompletedTyping\n if (!shouldShowCursor)\n return coloredText\n\n const cursorCharacter = getCursorCharacter(cursor)\n const cursorText = formatCursor(cursorCharacter, cursorColor, color)\n\n return coloredText + cursorText\n }, [characters, visibleCharacters, color, cursor, cursorColor, showCursor, hasCompletedTyping, isCursorEnabled])\n\n return <Text>{displayText}</Text>\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { mapChars } from '../utils/text.js'\n\ntype WaveType = 'brightness' | 'vertical'\n\ninterface WaveProps extends BaseEffectProps {\n /**\n * Gradient colors for the wave [dark, bright]\n * @default ['#888888', '#ffffff']\n * @example ['#ec4899', '#8b5cf6']\n */\n colors?: [Color, Color]\n\n /**\n * Wave height (0-1)\n * @default 0.5\n */\n amplitude?: number\n\n /**\n * Number of wave cycles across text\n * @default 2\n */\n frequency?: number\n\n /**\n * Wave effect type\n * @default 'brightness'\n */\n type?: WaveType\n}\n\nconst DEFAULT_COLORS: [Color, Color] = ['#888888', '#ffffff']\nconst DEFAULT_AMPLITUDE = 0.5\nconst DEFAULT_FREQUENCY = 2\nconst DEFAULT_TYPE: WaveType = 'brightness'\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst WAVE_PERIOD_MS = 2000\nconst MIN_AMPLITUDE = 0\nconst MAX_AMPLITUDE = 1\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst VERTICAL_SHIFT_THRESHOLD = 0.5\n\nfunction calculateWaveValue(\n characterIndex: number,\n time: number,\n frequency: number,\n amplitude: number,\n): number {\n const clampedAmplitude = clamp(amplitude, MIN_AMPLITUDE, MAX_AMPLITUDE)\n const safeFrequency = frequency || DEFAULT_FREQUENCY\n const waveLength = FULL_CIRCLE_RADIANS / safeFrequency\n const spatialComponent = (characterIndex / waveLength) * FULL_CIRCLE_RADIANS\n const temporalComponent = time * FULL_CIRCLE_RADIANS\n const phase = spatialComponent - temporalComponent\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const amplitudeComplement = MAX_AMPLITUDE - clampedAmplitude\n return normalizedSine * clampedAmplitude + amplitudeComplement\n}\n\n/**\n * Wave effect component that creates a wave motion through text\n *\n * Animates text with a sine wave pattern that can affect brightness or vertical position.\n * The wave continuously flows through the text.\n *\n * @example\n * ```tsx\n * <Wave colors={['#ec4899', '#8b5cf6']} amplitude={0.7} frequency={3}>\n * ~~ wavy text ~~\n * </Wave>\n * ```\n */\nexport function Wave({\n children,\n colors = DEFAULT_COLORS,\n amplitude = DEFAULT_AMPLITUDE,\n frequency = DEFAULT_FREQUENCY,\n type = DEFAULT_TYPE,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: WaveProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const normalizedTime = elapsedTime / WAVE_PERIOD_MS\n\n const waveText = useMemo(() => {\n if (type === 'brightness') {\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const [darkColor, brightColor] = colors\n const characterColor = interpolateColor(darkColor, brightColor, waveValue)\n return colorize(character, characterColor)\n })\n }\n\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const shouldShift = waveValue > VERTICAL_SHIFT_THRESHOLD\n return shouldShift ? ` ${character}` : character\n })\n }, [children, normalizedTime, colors, amplitude, frequency, type])\n\n return <Text>{waveText}</Text>\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,14 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
3
  /**
4
- * Colour value as hex (#ff0000), rgb (rgb(255,0,0)), or named (red, blue, etc.)
5
- * Note: Props use 'color' (US spelling) for React convention, but type uses UK spelling
4
+ * Color value as hex (#ff0000), rgb (rgb(255,0,0)), or named (red, blue, etc.)
6
5
  */
7
- type Colour = string;
8
- /**
9
- * @deprecated Use Colour instead
10
- */
11
- type Color = Colour;
6
+ type Color = string;
12
7
  /**
13
8
  * Easing function that takes normalised time (0-1) and returns eased value (0-1)
14
9
  */
@@ -16,7 +11,7 @@ type EasingFunction = (time: number) => number;
16
11
  /**
17
12
  * Named easing functions
18
13
  */
19
- type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
14
+ type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'sine-in' | 'sine-out' | 'sine-in-out';
20
15
  /**
21
16
  * Base props shared by all effect components
22
17
  */
@@ -45,11 +40,11 @@ interface BaseEffectProps {
45
40
 
46
41
  interface FadeProps extends BaseEffectProps {
47
42
  /**
48
- * Text colour
43
+ * Text color
49
44
  * @default '#ffffff'
50
45
  * @example 'yellow'
51
46
  */
52
- color?: Colour;
47
+ color?: Color;
53
48
  /**
54
49
  * Starting opacity (0-1)
55
50
  * @default 0
@@ -82,6 +77,10 @@ interface FadeProps extends BaseEffectProps {
82
77
  * Animates text from one opacity to another using configurable easing functions.
83
78
  * Can loop continuously or run once.
84
79
  *
80
+ * Note: Optimized for dark terminals. Fades to/from black which appears as true
81
+ * transparency on dark backgrounds. On light terminals, low opacity text may appear
82
+ * visible as dark text. For best results on all terminals, use bright colors.
83
+ *
85
84
  * @example
86
85
  * ```tsx
87
86
  * <Fade color="yellow" from={0} to={1} duration={500} easing="ease-in">
@@ -93,11 +92,11 @@ declare function Fade({ children, color, from, to, duration, easing, loop, speed
93
92
 
94
93
  interface FlashProps extends BaseEffectProps {
95
94
  /**
96
- * Text colour
95
+ * Base color
97
96
  * @default '#ffffff'
98
97
  * @example 'cyan'
99
98
  */
100
- color?: Colour;
99
+ color?: Color;
101
100
  /**
102
101
  * Minimum brightness (0-1)
103
102
  * @default 0.3
@@ -137,7 +136,7 @@ interface ShimmerProps extends BaseEffectProps {
137
136
  * @default ['#666666', '#ffffff', '#666666']
138
137
  * @example ['#60a5fa', '#3b82f6', '#60a5fa']
139
138
  */
140
- colors?: [Colour, Colour, Colour];
139
+ colors?: [Color, Color, Color];
141
140
  /**
142
141
  * Width of the shimmer band in characters
143
142
  * @default 4
@@ -171,11 +170,11 @@ declare function Shimmer({ children, colors, width, intensity, direction, speed,
171
170
 
172
171
  interface TypewriterProps extends BaseEffectProps {
173
172
  /**
174
- * Text colour
173
+ * Text color
175
174
  * @default undefined (inherits)
176
175
  * @example 'green'
177
176
  */
178
- color?: Colour;
177
+ color?: Color;
179
178
  /**
180
179
  * Cursor character or false to disable
181
180
  * @default '▋'
@@ -183,11 +182,11 @@ interface TypewriterProps extends BaseEffectProps {
183
182
  */
184
183
  cursor?: string | boolean;
185
184
  /**
186
- * Cursor colour (defaults to text colour)
185
+ * Cursor color (defaults to text color)
187
186
  * @default undefined
188
187
  * @example 'cyan'
189
188
  */
190
- cursorColor?: Colour;
189
+ cursorColor?: Color;
191
190
  /**
192
191
  * Typing speed randomness (0-1) for more human-like typing
193
192
  * @default 0.3
@@ -217,11 +216,11 @@ declare function Typewriter({ children, color, cursor, cursorColor, variance, de
217
216
  type WaveType = 'brightness' | 'vertical';
218
217
  interface WaveProps extends BaseEffectProps {
219
218
  /**
220
- * Gradient colours for the wave [dark, bright]
219
+ * Gradient colors for the wave [dark, bright]
221
220
  * @default ['#888888', '#ffffff']
222
221
  * @example ['#ec4899', '#8b5cf6']
223
222
  */
224
- colors?: [Colour, Colour];
223
+ colors?: [Color, Color];
225
224
  /**
226
225
  * Wave height (0-1)
227
226
  * @default 0.5
@@ -306,4 +305,4 @@ interface UseTypewriterProgressOptions {
306
305
  */
307
306
  declare function useTypewriterProgress({ totalCharacters, speed, variance, initialDelay, enabled, onComplete, }: UseTypewriterProgressOptions): number;
308
307
 
309
- export { type BaseEffectProps, type Color, type Colour, type EasingFunction, type EasingName, Fade, Flash, Shimmer, Typewriter, Wave, useAnimationFrame, useCursorBlink, useElapsedTime, useTypewriterProgress };
308
+ export { type BaseEffectProps, type Color, type EasingFunction, type EasingName, Fade, Flash, Shimmer, Typewriter, Wave, useAnimationFrame, useCursorBlink, useElapsedTime, useTypewriterProgress };
package/dist/index.d.ts CHANGED
@@ -1,14 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
3
  /**
4
- * Colour value as hex (#ff0000), rgb (rgb(255,0,0)), or named (red, blue, etc.)
5
- * Note: Props use 'color' (US spelling) for React convention, but type uses UK spelling
4
+ * Color value as hex (#ff0000), rgb (rgb(255,0,0)), or named (red, blue, etc.)
6
5
  */
7
- type Colour = string;
8
- /**
9
- * @deprecated Use Colour instead
10
- */
11
- type Color = Colour;
6
+ type Color = string;
12
7
  /**
13
8
  * Easing function that takes normalised time (0-1) and returns eased value (0-1)
14
9
  */
@@ -16,7 +11,7 @@ type EasingFunction = (time: number) => number;
16
11
  /**
17
12
  * Named easing functions
18
13
  */
19
- type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
14
+ type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'sine-in' | 'sine-out' | 'sine-in-out';
20
15
  /**
21
16
  * Base props shared by all effect components
22
17
  */
@@ -45,11 +40,11 @@ interface BaseEffectProps {
45
40
 
46
41
  interface FadeProps extends BaseEffectProps {
47
42
  /**
48
- * Text colour
43
+ * Text color
49
44
  * @default '#ffffff'
50
45
  * @example 'yellow'
51
46
  */
52
- color?: Colour;
47
+ color?: Color;
53
48
  /**
54
49
  * Starting opacity (0-1)
55
50
  * @default 0
@@ -82,6 +77,10 @@ interface FadeProps extends BaseEffectProps {
82
77
  * Animates text from one opacity to another using configurable easing functions.
83
78
  * Can loop continuously or run once.
84
79
  *
80
+ * Note: Optimized for dark terminals. Fades to/from black which appears as true
81
+ * transparency on dark backgrounds. On light terminals, low opacity text may appear
82
+ * visible as dark text. For best results on all terminals, use bright colors.
83
+ *
85
84
  * @example
86
85
  * ```tsx
87
86
  * <Fade color="yellow" from={0} to={1} duration={500} easing="ease-in">
@@ -93,11 +92,11 @@ declare function Fade({ children, color, from, to, duration, easing, loop, speed
93
92
 
94
93
  interface FlashProps extends BaseEffectProps {
95
94
  /**
96
- * Text colour
95
+ * Base color
97
96
  * @default '#ffffff'
98
97
  * @example 'cyan'
99
98
  */
100
- color?: Colour;
99
+ color?: Color;
101
100
  /**
102
101
  * Minimum brightness (0-1)
103
102
  * @default 0.3
@@ -137,7 +136,7 @@ interface ShimmerProps extends BaseEffectProps {
137
136
  * @default ['#666666', '#ffffff', '#666666']
138
137
  * @example ['#60a5fa', '#3b82f6', '#60a5fa']
139
138
  */
140
- colors?: [Colour, Colour, Colour];
139
+ colors?: [Color, Color, Color];
141
140
  /**
142
141
  * Width of the shimmer band in characters
143
142
  * @default 4
@@ -171,11 +170,11 @@ declare function Shimmer({ children, colors, width, intensity, direction, speed,
171
170
 
172
171
  interface TypewriterProps extends BaseEffectProps {
173
172
  /**
174
- * Text colour
173
+ * Text color
175
174
  * @default undefined (inherits)
176
175
  * @example 'green'
177
176
  */
178
- color?: Colour;
177
+ color?: Color;
179
178
  /**
180
179
  * Cursor character or false to disable
181
180
  * @default '▋'
@@ -183,11 +182,11 @@ interface TypewriterProps extends BaseEffectProps {
183
182
  */
184
183
  cursor?: string | boolean;
185
184
  /**
186
- * Cursor colour (defaults to text colour)
185
+ * Cursor color (defaults to text color)
187
186
  * @default undefined
188
187
  * @example 'cyan'
189
188
  */
190
- cursorColor?: Colour;
189
+ cursorColor?: Color;
191
190
  /**
192
191
  * Typing speed randomness (0-1) for more human-like typing
193
192
  * @default 0.3
@@ -217,11 +216,11 @@ declare function Typewriter({ children, color, cursor, cursorColor, variance, de
217
216
  type WaveType = 'brightness' | 'vertical';
218
217
  interface WaveProps extends BaseEffectProps {
219
218
  /**
220
- * Gradient colours for the wave [dark, bright]
219
+ * Gradient colors for the wave [dark, bright]
221
220
  * @default ['#888888', '#ffffff']
222
221
  * @example ['#ec4899', '#8b5cf6']
223
222
  */
224
- colors?: [Colour, Colour];
223
+ colors?: [Color, Color];
225
224
  /**
226
225
  * Wave height (0-1)
227
226
  * @default 0.5
@@ -306,4 +305,4 @@ interface UseTypewriterProgressOptions {
306
305
  */
307
306
  declare function useTypewriterProgress({ totalCharacters, speed, variance, initialDelay, enabled, onComplete, }: UseTypewriterProgressOptions): number;
308
307
 
309
- export { type BaseEffectProps, type Color, type Colour, type EasingFunction, type EasingName, Fade, Flash, Shimmer, Typewriter, Wave, useAnimationFrame, useCursorBlink, useElapsedTime, useTypewriterProgress };
308
+ export { type BaseEffectProps, type Color, type EasingFunction, type EasingName, Fade, Flash, Shimmer, Typewriter, Wave, useAnimationFrame, useCursorBlink, useElapsedTime, useTypewriterProgress };
package/dist/index.js CHANGED
@@ -64,6 +64,8 @@ function hexToRgb(hex) {
64
64
  if (!result)
65
65
  return null;
66
66
  const [, redHex, greenHex, blueHex] = result;
67
+ if (!redHex || !greenHex || !blueHex)
68
+ return null;
67
69
  return [
68
70
  Number.parseInt(redHex, HEX_BASE),
69
71
  Number.parseInt(greenHex, HEX_BASE),
@@ -79,6 +81,8 @@ function colorize(text, color) {
79
81
  if (!match || match.length < MIN_RGB_COMPONENTS)
80
82
  return text;
81
83
  const [redStr, greenStr, blueStr] = match;
84
+ if (!redStr || !greenStr || !blueStr)
85
+ return text;
82
86
  const red = Number.parseInt(redStr, DECIMAL_BASE);
83
87
  const green = Number.parseInt(greenStr, DECIMAL_BASE);
84
88
  const blue = Number.parseInt(blueStr, DECIMAL_BASE);
@@ -130,11 +134,17 @@ var easeOut = (time) => time * (2 - time);
130
134
  var easeInOut = (time) => {
131
135
  return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time;
132
136
  };
137
+ var sineIn = (time) => 1 - Math.cos(time * Math.PI / 2);
138
+ var sineOut = (time) => Math.sin(time * Math.PI / 2);
139
+ var sineInOut = (time) => -(Math.cos(Math.PI * time) - 1) / 2;
133
140
  var easingFunctions = {
134
141
  "linear": linear,
135
142
  "ease-in": easeIn,
136
143
  "ease-out": easeOut,
137
- "ease-in-out": easeInOut
144
+ "ease-in-out": easeInOut,
145
+ "sine-in": sineIn,
146
+ "sine-out": sineOut,
147
+ "sine-in-out": sineInOut
138
148
  };
139
149
  function getEasingFunction(name = "linear") {
140
150
  return easingFunctions[name];
@@ -145,7 +155,7 @@ function clamp(value, min, max) {
145
155
  var DEFAULT_FROM = 0;
146
156
  var DEFAULT_TO = 1;
147
157
  var DEFAULT_DURATION_MS = 1e3;
148
- var DEFAULT_EASING = "ease-out";
158
+ var DEFAULT_EASING = "sine-in-out";
149
159
  var DEFAULT_LOOP = false;
150
160
  var DEFAULT_SPEED = 1;
151
161
  function calculateOpacity(elapsedTime, duration, from, to, easing) {
@@ -177,10 +187,20 @@ function Fade({
177
187
  }
178
188
  }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete]);
179
189
  const fadedText = useMemo(() => {
180
- const effectiveTime = loop ? elapsedTime % duration : Math.min(elapsedTime, duration);
190
+ let effectiveTime = elapsedTime;
191
+ if (loop) {
192
+ const cycleTime = elapsedTime % (duration * 2);
193
+ effectiveTime = cycleTime > duration ? duration * 2 - cycleTime : cycleTime;
194
+ } else {
195
+ effectiveTime = Math.min(elapsedTime, duration);
196
+ }
181
197
  const opacity = calculateOpacity(effectiveTime, duration, from, to, easing);
198
+ if (opacity < 0.01) {
199
+ return "";
200
+ }
182
201
  const baseColor = color ?? "#ffffff";
183
- const fadedColor = applyOpacity(baseColor, opacity);
202
+ const elegantOpacity = opacity ** 1.5;
203
+ const fadedColor = interpolateColor("#000000", baseColor, elegantOpacity);
184
204
  return colorize(children, fadedColor);
185
205
  }, [children, elapsedTime, duration, from, to, easing, color, loop]);
186
206
  return /* @__PURE__ */ jsx(Text, { children: fadedText });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useAnimationFrame.ts","../src/hooks/useElapsedTime.ts","../src/utils/colors.ts","../src/utils/easing.ts","../src/components/Fade.tsx","../src/components/Flash.tsx","../src/utils/text.ts","../src/components/Shimmer.tsx","../src/hooks/useCursorBlink.ts","../src/hooks/useTypewriterProgress.ts","../src/components/Typewriter.tsx","../src/components/Wave.tsx"],"names":["useState","useEffect","DEFAULT_DURATION_MS","DEFAULT_SPEED","useMemo","jsx","Text","MIN_INTENSITY","MAX_INTENSITY","useRef","FIRST_CHARACTER_INDEX","DEFAULT_COLORS","FULL_CIRCLE_RADIANS","SINE_WAVE_OFFSET","SINE_WAVE_NORMALIZE"],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, useRef } from 'react'\n\nconst TARGET_FPS = 60\nconst FRAME_INTERVAL_MS = 1000 / TARGET_FPS\n\n/**\n * Runs a callback on every animation frame using setInterval\n *\n * @param callback - Function called each frame with delta time in ms\n * @param enabled - Whether animation is active\n */\nexport function useAnimationFrame(\n callback: (deltaTime: number) => void,\n enabled: boolean = true,\n): void {\n const intervalRef = useRef<Timer>()\n const previousTimeRef = useRef<number>()\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n previousTimeRef.current = undefined\n return\n }\n\n intervalRef.current = setInterval(() => {\n const currentTime = Date.now()\n if (previousTimeRef.current !== undefined) {\n const deltaTime = currentTime - previousTimeRef.current\n callbackRef.current(deltaTime)\n }\n previousTimeRef.current = currentTime\n }, FRAME_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [enabled])\n}\n","import { useState } from 'react'\nimport { useAnimationFrame } from './useAnimationFrame.js'\n\n/**\n * Hook that tracks elapsed time since mount or last reset\n *\n * @param enabled - Whether to track time\n * @param speed - Speed multiplier (default: 1)\n * @returns Elapsed time in milliseconds\n */\nexport function useElapsedTime(\n enabled: boolean = true,\n speed: number = 1,\n): number {\n const [elapsedTime, setElapsedTime] = useState(0)\n\n useAnimationFrame((deltaTime) => {\n setElapsedTime(prev => prev + deltaTime * speed)\n }, enabled)\n\n return elapsedTime\n}\n","import type { Colour } from '../types/index.js'\nimport chalk from 'chalk'\n\nconst HEX_BASE = 16\nconst DECIMAL_BASE = 10\nconst HEX_BYTE_LENGTH = 2\nconst HEX_PAD_CHARACTER = '0'\nconst MIN_RGB_COMPONENTS = 3\nconst INTERPOLATION_MIDPOINT = 0.5\n\nconst HEX_COLOR_REGEX = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i\nconst RGB_NUMBERS_REGEX = /\\d+/g\n\nfunction rgbToHex(red: number, green: number, blue: number): string {\n const redHex = red.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const greenHex = green.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const blueHex = blue.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n return `#${redHex}${greenHex}${blueHex}`\n}\n\n/**\n * Converts a hex color string to RGB values\n *\n * @param hex - Hex color string (with or without #)\n * @returns Tuple of [red, green, blue] values (0-255) or null if invalid\n */\nexport function hexToRgb(hex: string): [number, number, number] | null {\n const result = HEX_COLOR_REGEX.exec(hex)\n if (!result)\n return null\n\n const [, redHex, greenHex, blueHex] = result\n return [\n Number.parseInt(redHex, HEX_BASE),\n Number.parseInt(greenHex, HEX_BASE),\n Number.parseInt(blueHex, HEX_BASE),\n ]\n}\n\n/**\n * Applies color to text using chalk\n *\n * @param text - Text to colorize\n * @param color - Color as hex (#ff0000), rgb(255,0,0), or named color (red, blue, etc)\n * @returns Colorized text with ANSI escape codes\n */\nexport function colorize(text: string, color: Colour): string {\n try {\n if (color.startsWith('#'))\n return chalk.hex(color)(text)\n\n if (color.startsWith('rgb')) {\n const match = color.match(RGB_NUMBERS_REGEX)\n if (!match || match.length < MIN_RGB_COMPONENTS)\n return text\n\n const [redStr, greenStr, blueStr] = match\n const red = Number.parseInt(redStr, DECIMAL_BASE)\n const green = Number.parseInt(greenStr, DECIMAL_BASE)\n const blue = Number.parseInt(blueStr, DECIMAL_BASE)\n\n if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue))\n return text\n\n return chalk.rgb(red, green, blue)(text)\n }\n\n const chalkColor = chalk[color as keyof typeof chalk]\n if (typeof chalkColor === 'function')\n return chalkColor(text)\n\n return text\n }\n catch {\n return text\n }\n}\n\n/**\n * Applies opacity to a hex color by darkening it\n * Note: Terminal approximation - true opacity not possible in most terminals\n *\n * @param color - Hex color string\n * @param opacity - Opacity value from 0 (transparent/black) to 1 (fully opaque)\n * @returns Adjusted hex color or original color if not hex format\n */\nexport function applyOpacity(color: Colour, opacity: number): Colour {\n if (!color.startsWith('#'))\n return color\n\n const rgb = hexToRgb(color)\n if (!rgb)\n return color\n\n const [red, green, blue] = rgb\n const adjustedRed = Math.round(red * opacity)\n const adjustedGreen = Math.round(green * opacity)\n const adjustedBlue = Math.round(blue * opacity)\n\n return rgbToHex(adjustedRed, adjustedGreen, adjustedBlue)\n}\n\n/**\n * Interpolates between two colors\n *\n * @param color1 - Starting color\n * @param color2 - Ending color\n * @param progress - Interpolation progress from 0 to 1\n * @returns Interpolated color (hex if both inputs are hex, otherwise snaps to nearest)\n */\nexport function interpolateColor(\n color1: Colour,\n color2: Colour,\n progress: number,\n): Colour {\n const isColor1Hex = color1.startsWith('#')\n const isColor2Hex = color2.startsWith('#')\n\n if (!isColor1Hex || !isColor2Hex)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const rgb1 = hexToRgb(color1)\n const rgb2 = hexToRgb(color2)\n\n if (!rgb1 || !rgb2)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const [red1, green1, blue1] = rgb1\n const [red2, green2, blue2] = rgb2\n\n const red = Math.round(red1 + (red2 - red1) * progress)\n const green = Math.round(green1 + (green2 - green1) * progress)\n const blue = Math.round(blue1 + (blue2 - blue1) * progress)\n\n return rgbToHex(red, green, blue)\n}\n","import type { EasingFunction, EasingName } from '../types/index.js'\n\nexport const linear: EasingFunction = time => time\n\nexport const easeIn: EasingFunction = time => time * time\n\nexport const easeOut: EasingFunction = time => time * (2 - time)\n\nexport const easeInOut: EasingFunction = (time) => {\n return time < 0.5\n ? 2 * time * time\n : -1 + (4 - 2 * time) * time\n}\n\nexport const easingFunctions: Record<EasingName, EasingFunction> = {\n 'linear': linear,\n 'ease-in': easeIn,\n 'ease-out': easeOut,\n 'ease-in-out': easeInOut,\n}\n\nexport function getEasingFunction(name: EasingName = 'linear'): EasingFunction {\n return easingFunctions[name]\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n return clamp((value - min) / (max - min), 0, 1)\n}\n\nexport function lerp(start: number, end: number, progress: number): number {\n return start + (end - start) * progress\n}\n","import type { BaseEffectProps, Colour, EasingName } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { getEasingFunction } from '../utils/easing.js'\n\ninterface FadeProps extends BaseEffectProps {\n /**\n * Text colour\n * @default '#ffffff'\n * @example 'yellow'\n */\n color?: Colour\n\n /**\n * Starting opacity (0-1)\n * @default 0\n */\n from?: number\n\n /**\n * Ending opacity (0-1)\n * @default 1\n */\n to?: number\n\n /**\n * Duration in milliseconds\n * @default 1000\n */\n duration?: number\n\n /**\n * Easing function\n * @default 'ease-out'\n */\n easing?: EasingName\n\n /**\n * Loop animation continuously\n * @default false\n */\n loop?: boolean\n}\n\nconst DEFAULT_FROM = 0\nconst DEFAULT_TO = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_EASING: EasingName = 'ease-out'\nconst DEFAULT_LOOP = false\nconst DEFAULT_SPEED = 1\n\nfunction calculateOpacity(\n elapsedTime: number,\n duration: number,\n from: number,\n to: number,\n easing: EasingName,\n): number {\n const progress = Math.min(elapsedTime / duration, 1)\n const easedProgress = getEasingFunction(easing)(progress)\n return from + (to - from) * easedProgress\n}\n\n/**\n * Fade effect component that smoothly transitions text opacity\n *\n * Animates text from one opacity to another using configurable easing functions.\n * Can loop continuously or run once.\n *\n * @example\n * ```tsx\n * <Fade color=\"yellow\" from={0} to={1} duration={500} easing=\"ease-in\">\n * Success!\n * </Fade>\n * ```\n */\nexport function Fade({\n children,\n color,\n from = DEFAULT_FROM,\n to = DEFAULT_TO,\n duration = DEFAULT_DURATION_MS,\n easing = DEFAULT_EASING,\n loop = DEFAULT_LOOP,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: FadeProps) {\n const [hasCompleted, setHasCompleted] = useState(false)\n const elapsedTime = useElapsedTime(enabled && !hasCompleted, speed)\n\n useEffect(() => {\n if (!enabled)\n return\n\n const isComplete = elapsedTime >= duration\n\n if (isComplete && !loop && !hasCompleted) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: prevents calling onComplete multiple times by setting completion flag once\n setHasCompleted(true)\n onComplete?.()\n }\n }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete])\n\n const fadedText = useMemo(() => {\n const effectiveTime = loop ? elapsedTime % duration : Math.min(elapsedTime, duration)\n const opacity = calculateOpacity(effectiveTime, duration, from, to, easing)\n\n const baseColor = color ?? '#ffffff'\n const fadedColor = applyOpacity(baseColor, opacity)\n\n return colorize(children, fadedColor)\n }, [children, elapsedTime, duration, from, to, easing, color, loop])\n\n return <Text>{fadedText}</Text>\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\n\ninterface FlashProps extends BaseEffectProps {\n /**\n * Text colour\n * @default '#ffffff'\n * @example 'cyan'\n */\n color?: Colour\n\n /**\n * Minimum brightness (0-1)\n * @default 0.3\n */\n minIntensity?: number\n\n /**\n * Maximum brightness (0-1)\n * @default 1\n */\n maxIntensity?: number\n\n /**\n * Flash cycle duration in milliseconds\n * @default 1000\n */\n duration?: number\n}\n\nconst DEFAULT_COLOR = '#ffffff'\nconst DEFAULT_MIN_INTENSITY = 0.3\nconst DEFAULT_MAX_INTENSITY = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\nfunction calculateFlashIntensity(\n time: number,\n duration: number,\n minIntensity: number,\n maxIntensity: number,\n): number {\n const clampedMin = clamp(minIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const clampedMax = clamp(maxIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const normalizedTime = time / duration\n const phase = normalizedTime * FULL_CIRCLE_RADIANS\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const intensityRange = clampedMax - clampedMin\n return clampedMin + normalizedSine * intensityRange\n}\n\n/**\n * Flash effect component that creates a pulsing neon-like glow\n *\n * Animates text with a continuous brightness pulse that oscillates\n * between minimum and maximum intensity levels, creating a flashing\n * or glowing neon effect.\n *\n * @example\n * ```tsx\n * <Flash color=\"cyan\" minIntensity={0.3} maxIntensity={1} duration={800}>\n * ⚡ NEON GLOW ⚡\n * </Flash>\n * ```\n */\nexport function Flash({\n children,\n color = DEFAULT_COLOR,\n minIntensity = DEFAULT_MIN_INTENSITY,\n maxIntensity = DEFAULT_MAX_INTENSITY,\n duration = DEFAULT_DURATION_MS,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: FlashProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const cycleTime = elapsedTime % duration\n\n const flashText = useMemo(() => {\n const intensity = calculateFlashIntensity(cycleTime, duration, minIntensity, maxIntensity)\n const adjustedColor = applyOpacity(color, intensity)\n return colorize(children, adjustedColor)\n }, [children, cycleTime, duration, minIntensity, maxIntensity, color])\n\n return <Text>{flashText}</Text>\n}\n","export function splitChars(text: string): string[] {\n return [...text]\n}\n\nexport function getTextLength(text: string): number {\n return [...text].length\n}\n\nexport function mapChars(\n text: string,\n fn: (char: string, index: number) => string,\n): string {\n return splitChars(text).map(fn).join('')\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo, useState } from 'react'\nimport { useAnimationFrame } from '../hooks/useAnimationFrame.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { getTextLength, mapChars } from '../utils/text.js'\n\ntype ShimmerDirection = 'left' | 'right'\n\ninterface ShimmerProps extends BaseEffectProps {\n /**\n * Gradient colours for the shimmer effect [start, peak, end]\n * @default ['#666666', '#ffffff', '#666666']\n * @example ['#60a5fa', '#3b82f6', '#60a5fa']\n */\n colors?: [Colour, Colour, Colour]\n\n /**\n * Width of the shimmer band in characters\n * @default 4\n */\n width?: number\n\n /**\n * Brightness multiplier (0-1)\n * @default 1\n */\n intensity?: number\n\n /**\n * Direction of shimmer movement\n * @default 'right'\n */\n direction?: ShimmerDirection\n}\n\nconst DEFAULT_COLORS: [Colour, Colour, Colour] = ['#666666', '#ffffff', '#666666']\nconst DEFAULT_WIDTH = 4\nconst DEFAULT_INTENSITY = 1\nconst DEFAULT_DIRECTION: ShimmerDirection = 'right'\nconst DEFAULT_SPEED = 1\nconst ANIMATION_CYCLE_MS = 2000\nconst COLOUR_TRANSITION_MIDPOINT = 0.5\nconst COLOUR_PROGRESS_MULTIPLIER = 2\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\n/**\n * Shimmer effect component that creates a moving highlight across text\n *\n * Creates a shimmering animation by interpolating through a gradient of colours\n * that sweeps across the text from left to right or right to left.\n *\n * @example\n * ```tsx\n * <Shimmer colors={['#60a5fa', '#3b82f6', '#60a5fa']} intensity={0.8}>\n * Loading...\n * </Shimmer>\n * ```\n */\nexport function Shimmer({\n children,\n colors = DEFAULT_COLORS,\n width = DEFAULT_WIDTH,\n intensity = DEFAULT_INTENSITY,\n direction = DEFAULT_DIRECTION,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: ShimmerProps) {\n const [offset, setOffset] = useState(0)\n const textLength = getTextLength(children)\n const totalWidth = textLength + width\n\n useAnimationFrame((deltaTime) => {\n setOffset((previousOffset) => {\n const movement = (deltaTime / ANIMATION_CYCLE_MS) * speed * totalWidth\n const newOffset = direction === 'right'\n ? previousOffset + movement\n : previousOffset - movement\n\n const hasCompletedCycle = Math.abs(newOffset) >= totalWidth\n if (hasCompletedCycle) {\n onComplete?.()\n return 0\n }\n\n return newOffset\n })\n }, enabled)\n\n const shimmerText = useMemo(() => {\n return mapChars(children, (char, index) => {\n const normalizedOffset = direction === 'right' ? offset : totalWidth - offset\n const distance = Math.abs(index - normalizedOffset)\n\n const isWithinShimmerWidth = distance < width\n const colorProgress = isWithinShimmerWidth\n ? distance / width\n : 1\n\n const [startColor, peakColor, endColor] = colors\n const adjustedIntensity = clamp(intensity, MIN_INTENSITY, MAX_INTENSITY)\n\n const isFirstHalf = colorProgress < COLOUR_TRANSITION_MIDPOINT\n const currentColor = isFirstHalf\n ? interpolateColor(\n startColor,\n peakColor,\n colorProgress * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n : interpolateColor(\n peakColor,\n endColor,\n (colorProgress - COLOUR_TRANSITION_MIDPOINT) * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n\n return colorize(char, currentColor)\n })\n }, [children, offset, colors, width, intensity, direction, totalWidth])\n\n return <Text>{shimmerText}</Text>\n}\n","import { useEffect, useRef, useState } from 'react'\n\nconst CURSOR_BLINK_INTERVAL_MS = 500\n\ninterface UseCursorBlinkOptions {\n enabled: boolean\n isComplete: boolean\n}\n\n/**\n * Hook that manages cursor blinking state\n *\n * @param options - Configuration for cursor blink\n * @param options.enabled - Whether cursor blinking is enabled\n * @param options.isComplete - Whether typing is complete\n * @returns Whether cursor should be visible\n */\nexport function useCursorBlink({\n enabled,\n isComplete,\n}: UseCursorBlinkOptions): boolean {\n const [showCursor, setShowCursor] = useState(true)\n const intervalRef = useRef<Timer>()\n\n useEffect(() => {\n if (!enabled || isComplete) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: synchronizing cursor visibility with prop changes\n setShowCursor(false)\n return\n }\n\n intervalRef.current = setInterval(() => {\n setShowCursor(previous => !previous)\n }, CURSOR_BLINK_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current)\n clearInterval(intervalRef.current)\n }\n }, [enabled, isComplete])\n\n return showCursor\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { clamp } from '../utils/easing.js'\n\nconst BASE_CHARACTER_DELAY_MS = 80\nconst MIN_VARIANCE = 0\nconst MAX_VARIANCE = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction calculateCharacterDelay(\n speed: number,\n variance: number,\n): number {\n const clampedVariance = clamp(variance, MIN_VARIANCE, MAX_VARIANCE)\n const randomVariance = (Math.random() - 0.5) * clampedVariance\n return (BASE_CHARACTER_DELAY_MS / speed) * (1 + randomVariance)\n}\n\ninterface UseTypewriterProgressOptions {\n totalCharacters: number\n speed: number\n variance: number\n initialDelay: number\n enabled: boolean\n onComplete?: () => void\n}\n\n/**\n * Hook that manages typewriter character reveal timing\n *\n * @param options - Configuration for typewriter progress\n * @param options.totalCharacters - Total number of characters to reveal\n * @param options.speed - Animation speed multiplier\n * @param options.variance - Typing variance for human-like timing (0-1)\n * @param options.initialDelay - Delay before typing starts in milliseconds\n * @param options.enabled - Whether the animation is enabled\n * @param options.onComplete - Callback when typing completes\n * @returns Number of characters to display\n */\nexport function useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay,\n enabled,\n onComplete,\n}: UseTypewriterProgressOptions): number {\n const [visibleCharacters, setVisibleCharacters] = useState(0)\n const timeoutRef = useRef<Timer>()\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n\n useEffect(() => {\n if (!enabled)\n return\n\n if (hasCompletedTyping) {\n onComplete?.()\n return\n }\n\n const characterDelay = calculateCharacterDelay(speed, variance)\n const isFirstCharacter = visibleCharacters === FIRST_CHARACTER_INDEX\n const totalDelay = isFirstCharacter ? initialDelay + characterDelay : characterDelay\n\n timeoutRef.current = setTimeout(() => {\n setVisibleCharacters(previous => previous + 1)\n }, totalDelay)\n\n return () => {\n if (timeoutRef.current)\n clearTimeout(timeoutRef.current)\n }\n }, [visibleCharacters, enabled, speed, variance, initialDelay, hasCompletedTyping, onComplete])\n\n return visibleCharacters\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useCursorBlink } from '../hooks/useCursorBlink.js'\nimport { useTypewriterProgress } from '../hooks/useTypewriterProgress.js'\nimport { colorize } from '../utils/colors.js'\nimport { getTextLength, splitChars } from '../utils/text.js'\n\ninterface TypewriterProps extends BaseEffectProps {\n /**\n * Text colour\n * @default undefined (inherits)\n * @example 'green'\n */\n color?: Colour\n\n /**\n * Cursor character or false to disable\n * @default '▋'\n * @example '█'\n */\n cursor?: string | boolean\n\n /**\n * Cursor colour (defaults to text colour)\n * @default undefined\n * @example 'cyan'\n */\n cursorColor?: Colour\n\n /**\n * Typing speed randomness (0-1) for more human-like typing\n * @default 0.3\n */\n variance?: number\n\n /**\n * Initial delay before typing starts (ms)\n * @default 0\n */\n delay?: number\n}\n\nconst DEFAULT_CURSOR = '▋'\nconst DEFAULT_VARIANCE = 0.3\nconst DEFAULT_DELAY = 0\nconst DEFAULT_SPEED = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction getCursorCharacter(cursor: string | boolean): string {\n return typeof cursor === 'string' ? cursor : DEFAULT_CURSOR\n}\n\nfunction formatCursor(\n cursorCharacter: string,\n cursorColor: Colour | undefined,\n textColor: Colour | undefined,\n): string {\n if (cursorColor)\n return colorize(cursorCharacter, cursorColor)\n\n if (textColor)\n return colorize(cursorCharacter, textColor)\n\n return cursorCharacter\n}\n\n/**\n * Typewriter effect component that reveals text character by character\n *\n * Simulates typing text with configurable speed, variance for realistic timing,\n * and an optional cursor. The cursor blinks while typing is in progress.\n *\n * @example\n * ```tsx\n * <Typewriter color=\"green\" cursor=\"█\" variance={0.5} speed={2}>\n * npm install ink-motion\n * </Typewriter>\n * ```\n */\nexport function Typewriter({\n children,\n color,\n cursor = DEFAULT_CURSOR,\n cursorColor,\n variance = DEFAULT_VARIANCE,\n delay = DEFAULT_DELAY,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: TypewriterProps) {\n const characters = splitChars(children)\n const totalCharacters = getTextLength(children)\n\n const visibleCharacters = useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay: delay,\n enabled,\n onComplete,\n })\n\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n const isCursorEnabled = cursor !== false\n\n const showCursor = useCursorBlink({\n enabled: enabled && isCursorEnabled,\n isComplete: hasCompletedTyping,\n })\n\n const displayText = useMemo(() => {\n const visibleText = characters.slice(FIRST_CHARACTER_INDEX, visibleCharacters).join('')\n const coloredText = color ? colorize(visibleText, color) : visibleText\n\n const shouldShowCursor = isCursorEnabled && showCursor && !hasCompletedTyping\n if (!shouldShowCursor)\n return coloredText\n\n const cursorCharacter = getCursorCharacter(cursor)\n const cursorText = formatCursor(cursorCharacter, cursorColor, color)\n\n return coloredText + cursorText\n }, [characters, visibleCharacters, color, cursor, cursorColor, showCursor, hasCompletedTyping, isCursorEnabled])\n\n return <Text>{displayText}</Text>\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { mapChars } from '../utils/text.js'\n\ntype WaveType = 'brightness' | 'vertical'\n\ninterface WaveProps extends BaseEffectProps {\n /**\n * Gradient colours for the wave [dark, bright]\n * @default ['#888888', '#ffffff']\n * @example ['#ec4899', '#8b5cf6']\n */\n colors?: [Colour, Colour]\n\n /**\n * Wave height (0-1)\n * @default 0.5\n */\n amplitude?: number\n\n /**\n * Number of wave cycles across text\n * @default 2\n */\n frequency?: number\n\n /**\n * Wave effect type\n * @default 'brightness'\n */\n type?: WaveType\n}\n\nconst DEFAULT_COLORS: [Colour, Colour] = ['#888888', '#ffffff']\nconst DEFAULT_AMPLITUDE = 0.5\nconst DEFAULT_FREQUENCY = 2\nconst DEFAULT_TYPE: WaveType = 'brightness'\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst WAVE_PERIOD_MS = 2000\nconst MIN_AMPLITUDE = 0\nconst MAX_AMPLITUDE = 1\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst VERTICAL_SHIFT_THRESHOLD = 0.5\n\nfunction calculateWaveValue(\n characterIndex: number,\n time: number,\n frequency: number,\n amplitude: number,\n): number {\n const clampedAmplitude = clamp(amplitude, MIN_AMPLITUDE, MAX_AMPLITUDE)\n const safeFrequency = frequency || DEFAULT_FREQUENCY\n const waveLength = FULL_CIRCLE_RADIANS / safeFrequency\n const spatialComponent = (characterIndex / waveLength) * FULL_CIRCLE_RADIANS\n const temporalComponent = time * FULL_CIRCLE_RADIANS\n const phase = spatialComponent - temporalComponent\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const amplitudeComplement = MAX_AMPLITUDE - clampedAmplitude\n return normalizedSine * clampedAmplitude + amplitudeComplement\n}\n\n/**\n * Wave effect component that creates a wave motion through text\n *\n * Animates text with a sine wave pattern that can affect brightness or vertical position.\n * The wave continuously flows through the text.\n *\n * @example\n * ```tsx\n * <Wave colors={['#ec4899', '#8b5cf6']} amplitude={0.7} frequency={3}>\n * ~~ wavy text ~~\n * </Wave>\n * ```\n */\nexport function Wave({\n children,\n colors = DEFAULT_COLORS,\n amplitude = DEFAULT_AMPLITUDE,\n frequency = DEFAULT_FREQUENCY,\n type = DEFAULT_TYPE,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: WaveProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const normalizedTime = elapsedTime / WAVE_PERIOD_MS\n\n const waveText = useMemo(() => {\n if (type === 'brightness') {\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const [darkColor, brightColor] = colors\n const characterColor = interpolateColor(darkColor, brightColor, waveValue)\n return colorize(character, characterColor)\n })\n }\n\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const shouldShift = waveValue > VERTICAL_SHIFT_THRESHOLD\n return shouldShift ? ` ${character}` : character\n })\n }, [children, normalizedTime, colors, amplitude, frequency, type])\n\n return <Text>{waveText}</Text>\n}\n"]}
1
+ {"version":3,"sources":["../src/hooks/useAnimationFrame.ts","../src/hooks/useElapsedTime.ts","../src/utils/colors.ts","../src/utils/easing.ts","../src/components/Fade.tsx","../src/components/Flash.tsx","../src/utils/text.ts","../src/components/Shimmer.tsx","../src/hooks/useCursorBlink.ts","../src/hooks/useTypewriterProgress.ts","../src/components/Typewriter.tsx","../src/components/Wave.tsx"],"names":["useState","useEffect","DEFAULT_DURATION_MS","DEFAULT_SPEED","useMemo","jsx","Text","MIN_INTENSITY","MAX_INTENSITY","useRef","FIRST_CHARACTER_INDEX","DEFAULT_COLORS","FULL_CIRCLE_RADIANS","SINE_WAVE_OFFSET","SINE_WAVE_NORMALIZE"],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, useRef } from 'react'\n\nconst TARGET_FPS = 60\nconst FRAME_INTERVAL_MS = 1000 / TARGET_FPS\n\n/**\n * Runs a callback on every animation frame using setInterval\n *\n * @param callback - Function called each frame with delta time in ms\n * @param enabled - Whether animation is active\n */\nexport function useAnimationFrame(\n callback: (deltaTime: number) => void,\n enabled: boolean = true,\n): void {\n const intervalRef = useRef<Timer>()\n const previousTimeRef = useRef<number>()\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n previousTimeRef.current = undefined\n return\n }\n\n intervalRef.current = setInterval(() => {\n const currentTime = Date.now()\n if (previousTimeRef.current !== undefined) {\n const deltaTime = currentTime - previousTimeRef.current\n callbackRef.current(deltaTime)\n }\n previousTimeRef.current = currentTime\n }, FRAME_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [enabled])\n}\n","import { useState } from 'react'\nimport { useAnimationFrame } from './useAnimationFrame.js'\n\n/**\n * Hook that tracks elapsed time since mount or last reset\n *\n * @param enabled - Whether to track time\n * @param speed - Speed multiplier (default: 1)\n * @returns Elapsed time in milliseconds\n */\nexport function useElapsedTime(\n enabled: boolean = true,\n speed: number = 1,\n): number {\n const [elapsedTime, setElapsedTime] = useState(0)\n\n useAnimationFrame((deltaTime) => {\n setElapsedTime(prev => prev + deltaTime * speed)\n }, enabled)\n\n return elapsedTime\n}\n","import type { Color } from '../types/index.js'\nimport chalk from 'chalk'\n\nconst HEX_BASE = 16\nconst DECIMAL_BASE = 10\nconst HEX_BYTE_LENGTH = 2\nconst HEX_PAD_CHARACTER = '0'\nconst MIN_RGB_COMPONENTS = 3\nconst INTERPOLATION_MIDPOINT = 0.5\n\nconst HEX_COLOR_REGEX = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i\nconst RGB_NUMBERS_REGEX = /\\d+/g\n\nfunction rgbToHex(red: number, green: number, blue: number): string {\n const redHex = red.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const greenHex = green.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const blueHex = blue.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n return `#${redHex}${greenHex}${blueHex}`\n}\n\n/**\n * Converts a hex color string to RGB values\n *\n * @param hex - Hex color string (with or without #)\n * @returns Tuple of [red, green, blue] values (0-255) or null if invalid\n */\nexport function hexToRgb(hex: string): [number, number, number] | null {\n const result = HEX_COLOR_REGEX.exec(hex)\n if (!result)\n return null\n\n const [, redHex, greenHex, blueHex] = result\n if (!redHex || !greenHex || !blueHex)\n return null\n\n return [\n Number.parseInt(redHex, HEX_BASE),\n Number.parseInt(greenHex, HEX_BASE),\n Number.parseInt(blueHex, HEX_BASE),\n ]\n}\n\n/**\n * Applies color to text using chalk\n *\n * @param text - Text to colorize\n * @param color - Color as hex (#ff0000), rgb(255,0,0), or named color (red, blue, etc)\n * @returns Colorized text with ANSI escape codes\n */\nexport function colorize(text: string, color: Color): string {\n try {\n if (color.startsWith('#'))\n return chalk.hex(color)(text)\n\n if (color.startsWith('rgb')) {\n const match = color.match(RGB_NUMBERS_REGEX)\n if (!match || match.length < MIN_RGB_COMPONENTS)\n return text\n\n const [redStr, greenStr, blueStr] = match\n if (!redStr || !greenStr || !blueStr)\n return text\n\n const red = Number.parseInt(redStr, DECIMAL_BASE)\n const green = Number.parseInt(greenStr, DECIMAL_BASE)\n const blue = Number.parseInt(blueStr, DECIMAL_BASE)\n\n if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue))\n return text\n\n return chalk.rgb(red, green, blue)(text)\n }\n\n const chalkColor = (chalk as any)[color]\n if (typeof chalkColor === 'function')\n return chalkColor(text)\n\n return text\n }\n catch {\n return text\n }\n}\n\n/**\n * Applies opacity to a hex color by darkening it\n * Note: Terminal approximation - true opacity not possible in most terminals\n *\n * @param color - Hex color string\n * @param opacity - Opacity value from 0 (transparent/black) to 1 (fully opaque)\n * @returns Adjusted hex color or original color if not hex format\n */\nexport function applyOpacity(color: Color, opacity: number): Color {\n if (!color.startsWith('#'))\n return color\n\n const rgb = hexToRgb(color)\n if (!rgb)\n return color\n\n const [red, green, blue] = rgb\n const adjustedRed = Math.round(red * opacity)\n const adjustedGreen = Math.round(green * opacity)\n const adjustedBlue = Math.round(blue * opacity)\n\n return rgbToHex(adjustedRed, adjustedGreen, adjustedBlue)\n}\n\n/**\n * Interpolates between two colors\n *\n * @param color1 - Starting color\n * @param color2 - Ending color\n * @param progress - Interpolation progress from 0 to 1\n * @returns Interpolated color (hex if both inputs are hex, otherwise snaps to nearest)\n */\nexport function interpolateColor(\n color1: Color,\n color2: Color,\n progress: number,\n): Color {\n const isColor1Hex = color1.startsWith('#')\n const isColor2Hex = color2.startsWith('#')\n\n if (!isColor1Hex || !isColor2Hex)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const rgb1 = hexToRgb(color1)\n const rgb2 = hexToRgb(color2)\n\n if (!rgb1 || !rgb2)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const [red1, green1, blue1] = rgb1\n const [red2, green2, blue2] = rgb2\n\n const red = Math.round(red1 + (red2 - red1) * progress)\n const green = Math.round(green1 + (green2 - green1) * progress)\n const blue = Math.round(blue1 + (blue2 - blue1) * progress)\n\n return rgbToHex(red, green, blue)\n}\n","import type { EasingFunction, EasingName } from '../types/index.js'\n\nexport const linear: EasingFunction = time => time\n\nexport const easeIn: EasingFunction = time => time * time\n\nexport const easeOut: EasingFunction = time => time * (2 - time)\n\nexport const easeInOut: EasingFunction = (time) => {\n return time < 0.5\n ? 2 * time * time\n : -1 + (4 - 2 * time) * time\n}\n\nexport const sineIn: EasingFunction = time => 1 - Math.cos((time * Math.PI) / 2)\n\nexport const sineOut: EasingFunction = time => Math.sin((time * Math.PI) / 2)\n\nexport const sineInOut: EasingFunction = time => -(Math.cos(Math.PI * time) - 1) / 2\n\nexport const easingFunctions: Record<EasingName, EasingFunction> = {\n 'linear': linear,\n 'ease-in': easeIn,\n 'ease-out': easeOut,\n 'ease-in-out': easeInOut,\n 'sine-in': sineIn,\n 'sine-out': sineOut,\n 'sine-in-out': sineInOut,\n}\n\nexport function getEasingFunction(name: EasingName = 'linear'): EasingFunction {\n return easingFunctions[name]\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n return clamp((value - min) / (max - min), 0, 1)\n}\n\nexport function lerp(start: number, end: number, progress: number): number {\n return start + (end - start) * progress\n}\n","import type { BaseEffectProps, Color, EasingName } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { getEasingFunction } from '../utils/easing.js'\n\ninterface FadeProps extends BaseEffectProps {\n /**\n * Text color\n * @default '#ffffff'\n * @example 'yellow'\n */\n color?: Color\n\n /**\n * Starting opacity (0-1)\n * @default 0\n */\n from?: number\n\n /**\n * Ending opacity (0-1)\n * @default 1\n */\n to?: number\n\n /**\n * Duration in milliseconds\n * @default 1000\n */\n duration?: number\n\n /**\n * Easing function\n * @default 'ease-out'\n */\n easing?: EasingName\n\n /**\n * Loop animation continuously\n * @default false\n */\n loop?: boolean\n}\n\nconst DEFAULT_FROM = 0\nconst DEFAULT_TO = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_EASING: EasingName = 'sine-in-out'\nconst DEFAULT_LOOP = false\nconst DEFAULT_SPEED = 1\n\nfunction calculateOpacity(\n elapsedTime: number,\n duration: number,\n from: number,\n to: number,\n easing: EasingName,\n): number {\n const progress = Math.min(elapsedTime / duration, 1)\n const easedProgress = getEasingFunction(easing)(progress)\n return from + (to - from) * easedProgress\n}\n\n/**\n * Fade effect component that smoothly transitions text opacity\n *\n * Animates text from one opacity to another using configurable easing functions.\n * Can loop continuously or run once.\n *\n * Note: Optimized for dark terminals. Fades to/from black which appears as true\n * transparency on dark backgrounds. On light terminals, low opacity text may appear\n * visible as dark text. For best results on all terminals, use bright colors.\n *\n * @example\n * ```tsx\n * <Fade color=\"yellow\" from={0} to={1} duration={500} easing=\"ease-in\">\n * Success!\n * </Fade>\n * ```\n */\nexport function Fade({\n children,\n color,\n from = DEFAULT_FROM,\n to = DEFAULT_TO,\n duration = DEFAULT_DURATION_MS,\n easing = DEFAULT_EASING,\n loop = DEFAULT_LOOP,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: FadeProps) {\n const [hasCompleted, setHasCompleted] = useState(false)\n const elapsedTime = useElapsedTime(enabled && !hasCompleted, speed)\n\n useEffect(() => {\n if (!enabled)\n return\n\n const isComplete = elapsedTime >= duration\n\n if (isComplete && !loop && !hasCompleted) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: prevents calling onComplete multiple times by setting completion flag once\n setHasCompleted(true)\n onComplete?.()\n }\n }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete])\n\n const fadedText = useMemo(() => {\n let effectiveTime = elapsedTime\n if (loop) {\n const cycleTime = elapsedTime % (duration * 2)\n effectiveTime = cycleTime > duration ? (duration * 2) - cycleTime : cycleTime\n }\n else {\n effectiveTime = Math.min(elapsedTime, duration)\n }\n\n const opacity = calculateOpacity(effectiveTime, duration, from, to, easing)\n\n if (opacity < 0.01) {\n return ''\n }\n\n const baseColor = color ?? '#ffffff'\n const elegantOpacity = opacity ** 1.5\n const fadedColor = interpolateColor('#000000', baseColor, elegantOpacity)\n\n return colorize(children, fadedColor)\n }, [children, elapsedTime, duration, from, to, easing, color, loop])\n\n return <Text>{fadedText}</Text>\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\n\ninterface FlashProps extends BaseEffectProps {\n /**\n * Base color\n * @default '#ffffff'\n * @example 'cyan'\n */\n color?: Color\n\n /**\n * Minimum brightness (0-1)\n * @default 0.3\n */\n minIntensity?: number\n\n /**\n * Maximum brightness (0-1)\n * @default 1\n */\n maxIntensity?: number\n\n /**\n * Flash cycle duration in milliseconds\n * @default 1000\n */\n duration?: number\n}\n\nconst DEFAULT_COLOR = '#ffffff'\nconst DEFAULT_MIN_INTENSITY = 0.3\nconst DEFAULT_MAX_INTENSITY = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\nfunction calculateFlashIntensity(\n time: number,\n duration: number,\n minIntensity: number,\n maxIntensity: number,\n): number {\n const clampedMin = clamp(minIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const clampedMax = clamp(maxIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const normalizedTime = time / duration\n const phase = normalizedTime * FULL_CIRCLE_RADIANS\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const intensityRange = clampedMax - clampedMin\n return clampedMin + normalizedSine * intensityRange\n}\n\n/**\n * Flash effect component that creates a pulsing neon-like glow\n *\n * Animates text with a continuous brightness pulse that oscillates\n * between minimum and maximum intensity levels, creating a flashing\n * or glowing neon effect.\n *\n * @example\n * ```tsx\n * <Flash color=\"cyan\" minIntensity={0.3} maxIntensity={1} duration={800}>\n * ⚡ NEON GLOW ⚡\n * </Flash>\n * ```\n */\nexport function Flash({\n children,\n color = DEFAULT_COLOR,\n minIntensity = DEFAULT_MIN_INTENSITY,\n maxIntensity = DEFAULT_MAX_INTENSITY,\n duration = DEFAULT_DURATION_MS,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: FlashProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const cycleTime = elapsedTime % duration\n\n const flashText = useMemo(() => {\n const intensity = calculateFlashIntensity(cycleTime, duration, minIntensity, maxIntensity)\n const adjustedColor = applyOpacity(color, intensity)\n return colorize(children, adjustedColor)\n }, [children, cycleTime, duration, minIntensity, maxIntensity, color])\n\n return <Text>{flashText}</Text>\n}\n","export function splitChars(text: string): string[] {\n return [...text]\n}\n\nexport function getTextLength(text: string): number {\n return [...text].length\n}\n\nexport function mapChars(\n text: string,\n fn: (char: string, index: number) => string,\n): string {\n return splitChars(text).map(fn).join('')\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo, useState } from 'react'\nimport { useAnimationFrame } from '../hooks/useAnimationFrame.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { getTextLength, mapChars } from '../utils/text.js'\n\ntype ShimmerDirection = 'left' | 'right'\n\ninterface ShimmerProps extends BaseEffectProps {\n /**\n * Gradient colours for the shimmer effect [start, peak, end]\n * @default ['#666666', '#ffffff', '#666666']\n * @example ['#60a5fa', '#3b82f6', '#60a5fa']\n */\n colors?: [Color, Color, Color]\n\n /**\n * Width of the shimmer band in characters\n * @default 4\n */\n width?: number\n\n /**\n * Brightness multiplier (0-1)\n * @default 1\n */\n intensity?: number\n\n /**\n * Direction of shimmer movement\n * @default 'right'\n */\n direction?: ShimmerDirection\n}\n\nconst DEFAULT_COLORS: [Color, Color, Color] = ['#666666', '#ffffff', '#666666']\nconst DEFAULT_WIDTH = 4\nconst DEFAULT_INTENSITY = 1\nconst DEFAULT_DIRECTION: ShimmerDirection = 'right'\nconst DEFAULT_SPEED = 1\nconst ANIMATION_CYCLE_MS = 2000\nconst COLOUR_TRANSITION_MIDPOINT = 0.5\nconst COLOUR_PROGRESS_MULTIPLIER = 2\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\n/**\n * Shimmer effect component that creates a moving highlight across text\n *\n * Creates a shimmering animation by interpolating through a gradient of colours\n * that sweeps across the text from left to right or right to left.\n *\n * @example\n * ```tsx\n * <Shimmer colors={['#60a5fa', '#3b82f6', '#60a5fa']} intensity={0.8}>\n * Loading...\n * </Shimmer>\n * ```\n */\nexport function Shimmer({\n children,\n colors = DEFAULT_COLORS,\n width = DEFAULT_WIDTH,\n intensity = DEFAULT_INTENSITY,\n direction = DEFAULT_DIRECTION,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: ShimmerProps) {\n const [offset, setOffset] = useState(0)\n const textLength = getTextLength(children)\n const totalWidth = textLength + width\n\n useAnimationFrame((deltaTime) => {\n setOffset((previousOffset) => {\n const movement = (deltaTime / ANIMATION_CYCLE_MS) * speed * totalWidth\n const newOffset = direction === 'right'\n ? previousOffset + movement\n : previousOffset - movement\n\n const hasCompletedCycle = Math.abs(newOffset) >= totalWidth\n if (hasCompletedCycle) {\n onComplete?.()\n return 0\n }\n\n return newOffset\n })\n }, enabled)\n\n const shimmerText = useMemo(() => {\n return mapChars(children, (char, index) => {\n const normalizedOffset = direction === 'right' ? offset : totalWidth - offset\n const distance = Math.abs(index - normalizedOffset)\n\n const isWithinShimmerWidth = distance < width\n const colorProgress = isWithinShimmerWidth\n ? distance / width\n : 1\n\n const [startColor, peakColor, endColor] = colors\n const adjustedIntensity = clamp(intensity, MIN_INTENSITY, MAX_INTENSITY)\n\n const isFirstHalf = colorProgress < COLOUR_TRANSITION_MIDPOINT\n const currentColor = isFirstHalf\n ? interpolateColor(\n startColor,\n peakColor,\n colorProgress * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n : interpolateColor(\n peakColor,\n endColor,\n (colorProgress - COLOUR_TRANSITION_MIDPOINT) * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n\n return colorize(char, currentColor)\n })\n }, [children, offset, colors, width, intensity, direction, totalWidth])\n\n return <Text>{shimmerText}</Text>\n}\n","import { useEffect, useRef, useState } from 'react'\n\nconst CURSOR_BLINK_INTERVAL_MS = 500\n\ninterface UseCursorBlinkOptions {\n enabled: boolean\n isComplete: boolean\n}\n\n/**\n * Hook that manages cursor blinking state\n *\n * @param options - Configuration for cursor blink\n * @param options.enabled - Whether cursor blinking is enabled\n * @param options.isComplete - Whether typing is complete\n * @returns Whether cursor should be visible\n */\nexport function useCursorBlink({\n enabled,\n isComplete,\n}: UseCursorBlinkOptions): boolean {\n const [showCursor, setShowCursor] = useState(true)\n const intervalRef = useRef<Timer>()\n\n useEffect(() => {\n if (!enabled || isComplete) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: synchronizing cursor visibility with prop changes\n setShowCursor(false)\n return\n }\n\n intervalRef.current = setInterval(() => {\n setShowCursor(previous => !previous)\n }, CURSOR_BLINK_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current)\n clearInterval(intervalRef.current)\n }\n }, [enabled, isComplete])\n\n return showCursor\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { clamp } from '../utils/easing.js'\n\nconst BASE_CHARACTER_DELAY_MS = 80\nconst MIN_VARIANCE = 0\nconst MAX_VARIANCE = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction calculateCharacterDelay(\n speed: number,\n variance: number,\n): number {\n const clampedVariance = clamp(variance, MIN_VARIANCE, MAX_VARIANCE)\n const randomVariance = (Math.random() - 0.5) * clampedVariance\n return (BASE_CHARACTER_DELAY_MS / speed) * (1 + randomVariance)\n}\n\ninterface UseTypewriterProgressOptions {\n totalCharacters: number\n speed: number\n variance: number\n initialDelay: number\n enabled: boolean\n onComplete?: () => void\n}\n\n/**\n * Hook that manages typewriter character reveal timing\n *\n * @param options - Configuration for typewriter progress\n * @param options.totalCharacters - Total number of characters to reveal\n * @param options.speed - Animation speed multiplier\n * @param options.variance - Typing variance for human-like timing (0-1)\n * @param options.initialDelay - Delay before typing starts in milliseconds\n * @param options.enabled - Whether the animation is enabled\n * @param options.onComplete - Callback when typing completes\n * @returns Number of characters to display\n */\nexport function useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay,\n enabled,\n onComplete,\n}: UseTypewriterProgressOptions): number {\n const [visibleCharacters, setVisibleCharacters] = useState(0)\n const timeoutRef = useRef<Timer>()\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n\n useEffect(() => {\n if (!enabled)\n return\n\n if (hasCompletedTyping) {\n onComplete?.()\n return\n }\n\n const characterDelay = calculateCharacterDelay(speed, variance)\n const isFirstCharacter = visibleCharacters === FIRST_CHARACTER_INDEX\n const totalDelay = isFirstCharacter ? initialDelay + characterDelay : characterDelay\n\n timeoutRef.current = setTimeout(() => {\n setVisibleCharacters(previous => previous + 1)\n }, totalDelay)\n\n return () => {\n if (timeoutRef.current)\n clearTimeout(timeoutRef.current)\n }\n }, [visibleCharacters, enabled, speed, variance, initialDelay, hasCompletedTyping, onComplete])\n\n return visibleCharacters\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useCursorBlink } from '../hooks/useCursorBlink.js'\nimport { useTypewriterProgress } from '../hooks/useTypewriterProgress.js'\nimport { colorize } from '../utils/colors.js'\nimport { getTextLength, splitChars } from '../utils/text.js'\n\ninterface TypewriterProps extends BaseEffectProps {\n /**\n * Text color\n * @default undefined (inherits)\n * @example 'green'\n */\n color?: Color\n\n /**\n * Cursor character or false to disable\n * @default '▋'\n * @example '█'\n */\n cursor?: string | boolean\n\n /**\n * Cursor color (defaults to text color)\n * @default undefined\n * @example 'cyan'\n */\n cursorColor?: Color\n\n /**\n * Typing speed randomness (0-1) for more human-like typing\n * @default 0.3\n */\n variance?: number\n\n /**\n * Initial delay before typing starts (ms)\n * @default 0\n */\n delay?: number\n}\n\nconst DEFAULT_CURSOR = '▋'\nconst DEFAULT_VARIANCE = 0.3\nconst DEFAULT_DELAY = 0\nconst DEFAULT_SPEED = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction getCursorCharacter(cursor: string | boolean): string {\n return typeof cursor === 'string' ? cursor : DEFAULT_CURSOR\n}\n\nfunction formatCursor(\n cursorCharacter: string,\n cursorColor: Color | undefined,\n textColor: Color | undefined,\n): string {\n if (cursorColor)\n return colorize(cursorCharacter, cursorColor)\n\n if (textColor)\n return colorize(cursorCharacter, textColor)\n\n return cursorCharacter\n}\n\n/**\n * Typewriter effect component that reveals text character by character\n *\n * Simulates typing text with configurable speed, variance for realistic timing,\n * and an optional cursor. The cursor blinks while typing is in progress.\n *\n * @example\n * ```tsx\n * <Typewriter color=\"green\" cursor=\"█\" variance={0.5} speed={2}>\n * npm install ink-motion\n * </Typewriter>\n * ```\n */\nexport function Typewriter({\n children,\n color,\n cursor = DEFAULT_CURSOR,\n cursorColor,\n variance = DEFAULT_VARIANCE,\n delay = DEFAULT_DELAY,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: TypewriterProps) {\n const characters = splitChars(children)\n const totalCharacters = getTextLength(children)\n\n const visibleCharacters = useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay: delay,\n enabled,\n onComplete,\n })\n\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n const isCursorEnabled = cursor !== false\n\n const showCursor = useCursorBlink({\n enabled: enabled && isCursorEnabled,\n isComplete: hasCompletedTyping,\n })\n\n const displayText = useMemo(() => {\n const visibleText = characters.slice(FIRST_CHARACTER_INDEX, visibleCharacters).join('')\n const coloredText = color ? colorize(visibleText, color) : visibleText\n\n const shouldShowCursor = isCursorEnabled && showCursor && !hasCompletedTyping\n if (!shouldShowCursor)\n return coloredText\n\n const cursorCharacter = getCursorCharacter(cursor)\n const cursorText = formatCursor(cursorCharacter, cursorColor, color)\n\n return coloredText + cursorText\n }, [characters, visibleCharacters, color, cursor, cursorColor, showCursor, hasCompletedTyping, isCursorEnabled])\n\n return <Text>{displayText}</Text>\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { mapChars } from '../utils/text.js'\n\ntype WaveType = 'brightness' | 'vertical'\n\ninterface WaveProps extends BaseEffectProps {\n /**\n * Gradient colors for the wave [dark, bright]\n * @default ['#888888', '#ffffff']\n * @example ['#ec4899', '#8b5cf6']\n */\n colors?: [Color, Color]\n\n /**\n * Wave height (0-1)\n * @default 0.5\n */\n amplitude?: number\n\n /**\n * Number of wave cycles across text\n * @default 2\n */\n frequency?: number\n\n /**\n * Wave effect type\n * @default 'brightness'\n */\n type?: WaveType\n}\n\nconst DEFAULT_COLORS: [Color, Color] = ['#888888', '#ffffff']\nconst DEFAULT_AMPLITUDE = 0.5\nconst DEFAULT_FREQUENCY = 2\nconst DEFAULT_TYPE: WaveType = 'brightness'\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst WAVE_PERIOD_MS = 2000\nconst MIN_AMPLITUDE = 0\nconst MAX_AMPLITUDE = 1\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst VERTICAL_SHIFT_THRESHOLD = 0.5\n\nfunction calculateWaveValue(\n characterIndex: number,\n time: number,\n frequency: number,\n amplitude: number,\n): number {\n const clampedAmplitude = clamp(amplitude, MIN_AMPLITUDE, MAX_AMPLITUDE)\n const safeFrequency = frequency || DEFAULT_FREQUENCY\n const waveLength = FULL_CIRCLE_RADIANS / safeFrequency\n const spatialComponent = (characterIndex / waveLength) * FULL_CIRCLE_RADIANS\n const temporalComponent = time * FULL_CIRCLE_RADIANS\n const phase = spatialComponent - temporalComponent\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const amplitudeComplement = MAX_AMPLITUDE - clampedAmplitude\n return normalizedSine * clampedAmplitude + amplitudeComplement\n}\n\n/**\n * Wave effect component that creates a wave motion through text\n *\n * Animates text with a sine wave pattern that can affect brightness or vertical position.\n * The wave continuously flows through the text.\n *\n * @example\n * ```tsx\n * <Wave colors={['#ec4899', '#8b5cf6']} amplitude={0.7} frequency={3}>\n * ~~ wavy text ~~\n * </Wave>\n * ```\n */\nexport function Wave({\n children,\n colors = DEFAULT_COLORS,\n amplitude = DEFAULT_AMPLITUDE,\n frequency = DEFAULT_FREQUENCY,\n type = DEFAULT_TYPE,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: WaveProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const normalizedTime = elapsedTime / WAVE_PERIOD_MS\n\n const waveText = useMemo(() => {\n if (type === 'brightness') {\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const [darkColor, brightColor] = colors\n const characterColor = interpolateColor(darkColor, brightColor, waveValue)\n return colorize(character, characterColor)\n })\n }\n\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const shouldShift = waveValue > VERTICAL_SHIFT_THRESHOLD\n return shouldShift ? ` ${character}` : character\n })\n }, [children, normalizedTime, colors, amplitude, frequency, type])\n\n return <Text>{waveText}</Text>\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ink-motion",
3
3
  "type": "module",
4
- "version": "1.0.0",
4
+ "version": "1.0.2",
5
5
  "description": "Motion and animation components for Ink - beautiful text effects for your CLI",
6
6
  "author": "James Glenn",
7
7
  "license": "MIT",
@@ -51,6 +51,7 @@
51
51
  "dev": "tsup --watch",
52
52
  "demo": "bun examples/demo.tsx",
53
53
  "test": "bun test",
54
+ "test:file": "f() { bun test tests/${1:-*}.test.tsx; }; f",
54
55
  "type-check": "tsc --noEmit",
55
56
  "lint": "eslint .",
56
57
  "prepublishOnly": "bun run build && publint"