/** * Terminal animation helpers derived from the web design language: * thinking uses Codex's slow shimmer sweep, the busy composer marker uses the * original braille chase, and the streaming caret blink is the Claude-Code * convention. * * The DeepSeek model-switch easter egg ports Codex's effort-ignition "Wave" * style (`codex-rs/tui/src/bottom_pane/effort_ignition_styles.rs`): switching * INTO an official DeepSeek route sweeps a blue wave across the composer's * input row — one column per cell, `backgroundColor` = the sampled wave * color — then, on the deepseek (Ultra-equivalent) tier, drops the `· ✦ ✧` * sparkle sequence into the rightmost blank cell before fading. The prompt * marker keeps the tier accent afterwards (persistent, like Codex's prompt * charge). Pure functions only — the Ink layer owns timers and colors. * * Wave and Pulse deliberately extend the Codex port after in-terminal * testing: the per-row phase cascade was removed (Codex tints each column * across the whole band), Wave became a WATER SURFACE — one continuous sine * swell spanning the band, mirror-symmetric about the center column, its * crests flowing outward from the center with a symmetric fade envelope * (the deepseek tier adds one faster harmonic crossing it), painted with * Aurora's recipe: wide soft gradients, mirrored second-hue mixing, and a * low alpha cap — no hard core line — while Pulse became true * two-dimensional, cell-aspect-corrected detonations: soft wide rings whose * color grades across their width, expanding outward through a symmetric * fade envelope and each trailing an echo ripple in the next blue. Aurora * keeps Codex's geometry verbatim. * * @module @deepseek-ai/dsh-code/render/animations */ import type { RgbTriple } from '../theme.ts'; /** Cadence for the original busy braille chase (8 frames × 125ms = 1s). */ export declare const BUSY_CHASE_TICK_MS = 125; /** Original terminal StateDot chase frames. */ export declare const BUSY_CHASE_FRAMES: readonly ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"]; /** Chase frame for a monotonic tick. */ export declare function busyChaseFrame(tick: number): string; /** Clock cadence for the Codex-style Deep diving shimmer. */ export declare const DEEP_DIVING_SHIMMER_TICK_MS = 33; /** Codex shimmer timing and geometry. */ export declare const DEEP_DIVING_SHIMMER_DURATION_MS = 2000; export declare const DEEP_DIVING_SHIMMER_PADDING = 10; export declare const DEEP_DIVING_SHIMMER_HALF_WIDTH = 5; export declare const DEEP_DIVING_SPARK_BREATH_DURATION_MS = 2000; /** * Codex's 2-second shimmer sweep, expressed in terminal ticks. The sweep has * ten virtual columns of padding on either side and a five-column cosine * highlight band, so the text changes gently rather than cycling rapidly. */ export declare function deepDivingShimmerIntensity(index: number, tick: number, graphemeCount: number): number; /** Blue RGB color for one grapheme in the Codex-style shimmer. */ export declare function deepDivingGradientColor(index: number, tick: number, graphemeCount: number, base: RgbTriple, highlight: RgbTriple): RgbTriple; /** Smooth breathing intensity for the always-visible Deep diving sparkle. */ export declare function deepDivingSparkIntensity(tick: number): number; /** Blue RGB color for the breathing Deep diving sparkle. */ export declare function deepDivingSparkColor(tick: number, base: RgbTriple, highlight: RgbTriple): RgbTriple; /** One full prismatic flow lap — lively: violet → fuchsia → cyan → violet in 2.4s. */ export declare const FLOW_PERIOD_MS = 2400; /** * The prismatic flow color at one elapsed-time sample: a smoothstep walk * around the anchor triangle, one full lap per {@link FLOW_PERIOD_MS}. Pure — * the Ink layer owns the timer and passes its tick scaled by its own cadence * (tick × tickMs). Callers gate on the animations preference and fall back to * a static palette color when animation is off. * @param elapsedMs - milliseconds since the flow started (any sign or size). * @param anchors - the colors to walk, in order (theme.ts FLOW_ANCHORS). * @returns the interpolated anchor color at this instant. */ export declare function flowColor(elapsedMs: number, anchors: readonly RgbTriple[]): RgbTriple; /** Caret blink cadence: one blink step (on or off) per tick. */ export declare const CARET_BLINK_TICK_MS = 530; /** Caret visibility: half the ticks on, half off (530ms blink). */ export declare function caretVisible(tick: number): boolean; /** * The one-shot DeepSeek model-switch easter egg: when the status bar model * label switches to an official DeepSeek route, the composer's input row * plays Codex's effort-ignition "Wave" — a blue crest sweeping the content * row column by column (background tint ≤ 0.55 under the draft), plus the * Ultra-style `· ✦ ✧` sparkles on the deepseek tier — and the prompt marker * keeps the tier accent afterwards. The Ink layer owns the timer and reads * the ACTIVE palette anchors (`getPalette`); everything below is pure * interpolation over the colors it is given. */ /** Frame cadence of the DeepSeek wave: Codex's IGNITION_FRAME_TICK (33ms ≈ 30fps). */ export declare const DEEPSEEK_WAVE_TICK_MS = 33; /** * The DeepSeek wave tiers. The concept maps Codex's reasoning tiers to * model ids: `flash` runs the Max parameters, `deepseek` (pro models) runs * the Ultra parameters (dual band + tail sparkles on the Wave style). * `unknown` is the "Into the Unknown" variant: it reuses the deepseek tier's * exact parameters (dual band, durations, sparkles) for NON-DeepSeek models * running a reasoning effort above high — the wordmark renders differently * but the motion is identical. */ export type DeepseekWaveTier = 'flash' | 'deepseek' | 'unknown'; /** * The three ignition styles — Codex `IgnitionStyle`: a traveling crest * (Wave), a drifting multi-hue band (Aurora), and an expanding ring (Pulse). * One style is picked at random per trigger and never repeats the previous. */ export type DeepseekWaveStyle = 'wave' | 'aurora' | 'pulse'; /** * The water surface: ONE continuous sine line spanning the whole band, * mirror-symmetric about the center column, its crests flowing OUTWARD from * the center (phase k·|x − center| − ω·t). No sweep window, no return trip — * the surface fades in, flows, and fades out, symmetric in both space and * time. The deepseek tier adds one faster, finer HARMONIC line whose crests * cross the fundamental's: interleaved richness with both lines still * symmetric and still only ever flowing outward. */ export declare const WAVE_SURFACE_AMPLITUDE = 0.8; export declare const WAVE_SURFACE_HARMONIC = 0.45; export declare const WAVE_SURFACE_WAVELENGTH = 40; export declare const WAVE_SURFACE_OMEGA = 9; /** Vertical thickness in lane units — Aurora-wide: soft gradients, no hard edges. */ export declare const WAVE_SURFACE_THICKNESS = 1.2; /** * The mirrored second-hue profile: the space BELOW the surface carries a * second blue at this strength, so color (not just brightness) varies * continuously across the wave — Aurora-style hue mixing instead of a * single flat tint. */ export declare const WAVE_SURFACE_MIRROR = 0.6; /** Aurora-style soft alpha: low gain, capped well under the pulse ring's. */ export declare const WAVE_SURFACE_ALPHA_GAIN = 0.45; export declare const WAVE_SURFACE_ALPHA_CAP = 0.68; /** Aurora-grade soft alpha for the detonation — a notch above the swell. */ export declare const PULSE_ALPHA_GAIN = 0.45; export declare const PULSE_ALPHA_CAP = 0.72; /** Sparkle glyphs in frame order — Codex SPARK_GLYPHS (`· ✦ ✧`). */ export declare const SPARK_GLYPHS: readonly ["·", "✦", "✧"]; /** * Band tables — Codex `bands(style, tier)`. Each entry is a triple whose * meaning depends on the style: Wave/Pulse use `(launch, travel, strength)`; * Aurora uses `(speed, phase, hueIndex)`. */ export type DeepseekWaveBand = readonly [number, number, number]; export declare const DEEPSEEK_WAVE_BANDS: Readonly>>>; /** * Total visible duration: the Codex ignition duration plus 200ms so its motion * remains readable in a busy terminal. * @param tier - the active wave tier. * @param style - the active ignition style. * @returns the duration in milliseconds. */ export declare function deepseekWaveDuration(tier: DeepseekWaveTier, style?: DeepseekWaveStyle): number; /** * Pick one ignition style at random, never repeating the previous one — * Codex `IgnitionStyle::random`. Falls back to the remaining styles. * @param previous - the style of the last trigger, if any. * @returns a style different from `previous`. */ export declare function deepseekWaveStyleRandom(previous: DeepseekWaveStyle | undefined): DeepseekWaveStyle; /** * Tier for a `provider/model` label: a MODEL ID containing `flash` runs the * single-band flash tier; everything else (pro/reasoner/chat) runs the * dual-band deepseek tier. Mirrors Codex's Max→Ultra mapping. Only the model * segment (after the `/`) is matched, so a provider whose name contains * `flash` cannot flip an unrelated model onto the flash tier. * @param model - the `provider/model` label of the applied model. * @returns the wave tier for that model. */ export declare function deepseekWaveTier(model: string): DeepseekWaveTier; /** * Cosine window — Codex `crest`: 1 exactly under the wave center, 0 from * one half-width away. * @param distance - distance from the crest center in half-widths. * @returns the crest strength in 0..1. */ export declare function crest(distance: number): number; /** * Cubic ease-in-out — Codex `ease_in_out`: flat at both ends, steepest in * the middle, so the crest accelerates and eases instead of sliding linearly. * @param progress - raw progress (clamped to 0..1). * @returns the eased progress in 0..1. */ export declare function easeInOut(progress: number): number; /** * Fade-in/fade-out envelope — Codex `envelope`: linear ramp over `fadeIn` * at the start and `fadeOut` at the end, plateau at 1 between, 0 outside the * total. The Wave style keeps the envelope at 1 (Codex paints Wave without * an envelope); exported for the Aurora-style fades and for tests. * @param elapsed - seconds since the animation started. * @param total - total duration in seconds. * @param fadeIn - seconds of fade-in. * @param fadeOut - seconds of fade-out. * @returns the envelope value in 0..1. */ export declare function envelope(elapsed: number, total: number, fadeIn: number, fadeOut: number): number; /** * The /rainbow celebration on the three-row composer band: a FIXED * seven-color spectrum (not the rolled palette) that slides across every * row as one ribbon. Triggered when switching to rainbow or rerolling the * seed; independent of RAINBOW_SEED so the burst always reads as a prism. */ export declare const RAINBOW_BURST_TICK_MS = 33; export declare const RAINBOW_BURST_DURATION_MS = 1800; export declare const RAINBOW_BURST_HUES: readonly RgbTriple[]; /** * Smoothstep in 0..1, then wrap-lerp around the seven burst hues. * Position 0 is red, wrapping back toward red at 1. Shared by the * composer burst and the static rainbow whale header. */ export declare function rainbowSpectrumHue(position: number): RgbTriple; /** * Background tint for one composer-band cell during the rainbow burst. * Every row of a column shares the same hue (a solid ribbon); edge rows * are slightly dimmer so the middle editor row reads as the crest. The * spectrum slides ~1.2 widths over the burst, then fades to the band base. * @param tick - frame index at {@link RAINBOW_BURST_TICK_MS}. * @param column - band column (0..width-1). * @param width - band width in columns. * @param base - the theme's composerBand color to blend toward. * @param row - band row (0..rows-1). * @param rows - band height (composer is three rows: pad, editor, pad). * @returns the blended RGB, or null after the burst (or at zero alpha). */ export declare function rainbowBurstColumnBg(tick: number, column: number, width: number, base: RgbTriple, row?: number, rows?: number): RgbTriple | null; /** * The background color for one composer-band column at a tick — Codex * `paint_bands` + `Canvas::tint` for all three styles. Bands overlap with a * max for Wave/Pulse and a SUM for Aurora (Codex differs by style), the * weighted hues mix per column (Wave/Pulse always end on hue 0), the tint * blends the mixed hue toward the blank-cell base at the style's alpha cap, * and Aurora applies its own fade envelope. Returns `null` when the column * should stay transparent, so the row returns to no `backgroundColor` on * both ends. With `rows > 1`: Wave is a water surface — every column * lights the row nearest the surface's current height, so the light reads * as ONE continuous wavy line spanning the band, symmetric about the center * column and flowing outward (a single-row band falls back to a flat glow); * Pulse rings in two dimensions around the band's center cell with trailing * echo ripples; only Aurora samples the timeline shifted by a per-row phase * offset. * @param tick - wave frame (0, 1, … at DEEPSEEK_WAVE_TICK_MS). * @param column - column index in the content row (0..width-1). * @param width - content-row width in columns. * @param tier - the wave tier (flash = Max, deepseek = Ultra parameters). * @param style - the ignition style. * @param hues - the tier's three hues. * @param base - the blank-cell base color the tint blends toward. * @param row - row index in the band (0..rows-1; default 0 = old single-row). * @param rows - band height in rows (default 1). * @returns the blended RGB background, or null for transparent. */ export declare function deepseekWaveColumnBg(tick: number, column: number, width: number, tier: DeepseekWaveTier, style: DeepseekWaveStyle, hues: readonly [RgbTriple, RgbTriple, RgbTriple], base: RgbTriple, row?: number, rows?: number): RgbTriple | null; /** * The sparkle glyph for a tick — Codex `spark_frame`, sampled on the same * proportionally slowed DeepSeek Wave timeline as the composer background. * The Ink layer still must skip occupied cells. * @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS. * @returns the sparkle glyph, or null outside the stretched tail window. */ export declare function deepseekWaveSpark(tick: number): string | null; /** * Whether the `deepseek` wordmark rides the wave at this tick: it fades in * shortly after the first crest launches and out before the wave settles, * so the brand name surfaces through the sweep's middle. The Ink layer * places it in the row's blank mid-section (never over real draft text). * @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS. * @param tier - the wave tier. * @returns true while the wordmark should be visible. */ export declare function deepseekWaveWordVisible(tick: number, tier: DeepseekWaveTier, style?: DeepseekWaveStyle): boolean; /** * The per-character color for the `deepseek` wordmark: the tier's hues * cycled per character (d→hue0, e→hue1, e→hue2, …), a brand-gradient text. * @param index - character index in the wordmark. * @param hues - the tier's three hues. * @returns the hue for that character. */ export declare function deepseekWaveWordHue(index: number, hues: readonly [RgbTriple, RgbTriple, RgbTriple]): RgbTriple; /** * True when a `provider/model` status label addresses the official DeepSeek * route: either segment contains `deepseek` (case-insensitive), covering the * `deepseek-official` provider route and its `deepseek-*` model ids. * @param label - the status bar model label (`provider/model`). * @returns whether the label names an official DeepSeek model. */ export declare function isOfficialDeepSeekLabel(label: string): boolean; /** * True when an effective reasoning effort is STRICTLY above `high` — the * trigger gate for the "Into the Unknown" wave on non-DeepSeek routes. * Absent efforts and unrecognized ids never qualify. * @param effort - the effective reasoning-effort id ('' or undefined when none). * @returns whether the effort ranks above high. */ export declare function effortAboveHigh(effort: string | undefined): boolean; /** * Parse a persisted animations preference (`animations.json`): timed * animations are on by default and only an explicit `false` disables them — * a missing key, corrupt value, or absent file all mean enabled, so the * /animation toggle degrades exactly like every other user preference. * @param value - the raw parsed JSON value (expected boolean). * @returns whether timed animations should run. */ export declare function parseAnimationsPref(value: unknown): boolean; /** * One parsed `/animation` argument: '' toggles, `on|true|1` enables, * `off|false|0` disables (case-insensitive, surrounding whitespace ignored), * and anything else is a usage error the caller surfaces. Kept pure so the * command's entire decision table is unit-testable. * @param argument - the raw text after `/animation`. * @returns `{ enabled }`, `'toggle'`, or `'usage'`. */ export declare function parseAnimationsArgument(argument: string): { enabled: boolean; } | 'toggle' | 'usage';