react-ai-avatar 0.1.0

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.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +310 -0
  3. package/dist/lib/GlbArkitAvatar-CcPWCsQV.cjs +1 -0
  4. package/dist/lib/GlbArkitAvatar-Dm9STiyR.js +232 -0
  5. package/dist/lib/VrmAvatar-CehRzj0J.js +224 -0
  6. package/dist/lib/VrmAvatar-D_jr2TOG.cjs +1 -0
  7. package/dist/lib/components/AudioVisualizer.d.ts +17 -0
  8. package/dist/lib/components/ContractAvatar.d.ts +25 -0
  9. package/dist/lib/components/DefaultAvatar.d.ts +37 -0
  10. package/dist/lib/components/DiceBearAvatar.d.ts +48 -0
  11. package/dist/lib/components/DiceBearThumb.d.ts +15 -0
  12. package/dist/lib/components/DoodleAvatar.d.ts +21 -0
  13. package/dist/lib/components/GeometricAvatar.d.ts +22 -0
  14. package/dist/lib/components/GlbArkitAvatar.d.ts +7 -0
  15. package/dist/lib/components/MemojiAvatar.d.ts +19 -0
  16. package/dist/lib/components/PixelArtAvatar.d.ts +23 -0
  17. package/dist/lib/components/RealtimeAvatar.d.ts +74 -0
  18. package/dist/lib/components/SquirrelAvatar.d.ts +29 -0
  19. package/dist/lib/components/VrmAvatar.d.ts +6 -0
  20. package/dist/lib/index.cjs +6 -0
  21. package/dist/lib/index.js +1231 -0
  22. package/dist/lib/lib/color.d.ts +6 -0
  23. package/dist/lib/lib/dicebear.d.ts +110 -0
  24. package/dist/lib/lib/index.d.ts +34 -0
  25. package/dist/lib/lib/mouthEngine.d.ts +37 -0
  26. package/dist/lib/lib/speechActivity.d.ts +51 -0
  27. package/dist/lib/lib/types.d.ts +22 -0
  28. package/dist/lib/lib/useAudioMouth.d.ts +20 -0
  29. package/dist/lib/lib/useAvatarRuntime.d.ts +39 -0
  30. package/dist/lib/lib/useReducedMotion.d.ts +5 -0
  31. package/dist/lib/lib/useStreamingTextActivity.d.ts +46 -0
  32. package/dist/lib/lib/vrm.d.ts +9 -0
  33. package/dist/lib/react-ai-avatar.css +1 -0
  34. package/dist/lib/useReducedMotion-BDcEizfP.js +104 -0
  35. package/dist/lib/useReducedMotion-BRDEmRNI.cjs +1 -0
  36. package/dist/lib/vrm.cjs +1 -0
  37. package/dist/lib/vrm.js +4 -0
  38. package/package.json +127 -0
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Convert a hex color (`#rgb` or `#rrggbb`) to an `rgba()` string at the given
3
+ * opacity. Non-hex input is returned as-is (or `transparent` when empty), so it
4
+ * is safe to pass already-resolved CSS colors through it.
5
+ */
6
+ export declare function hexToRgba(color: string, opacity: number): string;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * DiceBear catalog — curated, CC0-only styles.
3
+ *
4
+ * DiceBear (https://www.dicebear.com) ships ~30 avatar styles under mixed
5
+ * licenses. To keep this library's "no attribution headaches" promise, we
6
+ * expose ONLY the styles licensed CC0 1.0 (public domain). Styles such as
7
+ * `bottts` ("free for personal and commercial use") or the many CC BY 4.0
8
+ * ones are intentionally left out — a host app can still use them via the
9
+ * raw `<DiceBearAvatar collection={...} />` escape hatch at its own
10
+ * licensing discretion, the same way `byos` SVGs keep their own license.
11
+ *
12
+ * Generation is done client-side with the `@dicebear/core` +
13
+ * `@dicebear/collection` packages (optional peer deps, lazy-loaded). No
14
+ * network call, deterministic per `seed`, works offline.
15
+ */
16
+ /** The curated set of CC0 1.0 DiceBear style ids (kebab-case = DiceBear id). */
17
+ export type DiceBearCollection = 'pixel-art' | 'pixel-art-neutral' | 'lorelei' | 'lorelei-neutral' | 'notionists' | 'notionists-neutral' | 'open-peeps' | 'thumbs';
18
+ export interface DiceBearStyleMeta {
19
+ /** Kebab-case id — both the DiceBear style id and the UI/value key. */
20
+ id: DiceBearCollection;
21
+ /** camelCase named export inside `@dicebear/collection`. */
22
+ exportName: string;
23
+ /** Human label for catalog UIs. */
24
+ label: string;
25
+ /** Always 'CC0 1.0' here — that's the whole point of the curation. */
26
+ license: 'CC0 1.0';
27
+ }
28
+ /**
29
+ * kebab-case style id -> camelCase `@dicebear/collection` export name.
30
+ * `pixel-art-neutral` -> `pixelArtNeutral`, `open-peeps` -> `openPeeps`.
31
+ */
32
+ export declare function collectionExportName(id: string): string;
33
+ /**
34
+ * Curated CC0 catalog, in display order. All entries have a face, so all
35
+ * articulate via viseme swapping (see DICEBEAR_RIGS). The abstract CC0 styles
36
+ * (shapes, rings, glass, identicon) are intentionally excluded — they have no
37
+ * mouth to drive.
38
+ */
39
+ export declare const DICEBEAR_STYLES: readonly DiceBearStyleMeta[];
40
+ /**
41
+ * Prefix every internal id in a DiceBear SVG (and every reference to it) so
42
+ * multiple SVGs from the same style can coexist in one document without their
43
+ * `clipPath` / `mask` / gradient ids colliding — which would otherwise blank
44
+ * out all but the first. Needed because we stack several frames of the same
45
+ * avatar (closed/open mouth, blink) on top of each other.
46
+ */
47
+ export declare function scopeSvgIds(svg: string, prefix: string): string;
48
+ /**
49
+ * Per-style "rig": how to articulate a given DiceBear style for talking.
50
+ *
51
+ * DiceBear SVGs are pre-baked with no `#rra-*` hooks, but the official option
52
+ * API lets us *pick* which mouth/lips/face/eyes variant to render. So instead
53
+ * of the bounce-only fallback we pre-generate a few frames of the SAME avatar
54
+ * (same seed → identical everything else) with different mouth/eye variants and
55
+ * swap between them per audio frame — real articulation via the supported API.
56
+ *
57
+ * Only styles that actually expose suitable variants are rigged; the rest
58
+ * (abstract styles with no face) fall back to the audio-reactive bounce. The
59
+ * variant ids below were chosen by eye from each style's variant set.
60
+ */
61
+ export interface DiceBearRig {
62
+ /** Option key that drives the mouth shape. */
63
+ part: 'mouth' | 'lips' | 'face';
64
+ /** Three variant names ordered [closed, mid, open]. */
65
+ visemes: [string, string, string];
66
+ /** Independent eye blink (for `mouth`/`lips` styles where eyes are separate). */
67
+ blink?: {
68
+ open: string;
69
+ closed: string;
70
+ };
71
+ /**
72
+ * For `face` styles, mouth + eyes are a single coupled value, so a blink is a
73
+ * whole-face variant that briefly replaces the current viseme.
74
+ */
75
+ faceBlink?: string;
76
+ }
77
+ export declare const DICEBEAR_RIGS: Partial<Record<DiceBearCollection, DiceBearRig>>;
78
+ /**
79
+ * Curated "featured faces": hand-picked {style, seed} pairs that look good out
80
+ * of the box, so a host (or the demo picker) can offer a gallery instead of
81
+ * asking users to guess a seed string. Seeds are deterministic — these exact
82
+ * faces render identically everywhere, offline, no network call.
83
+ */
84
+ export interface DiceBearFeaturedFace {
85
+ /** Curated CC0 style id. */
86
+ collection: DiceBearCollection;
87
+ /** Deterministic seed picked for a nice-looking result. */
88
+ seed: string;
89
+ }
90
+ export declare const DICEBEAR_FEATURED_FACES: readonly DiceBearFeaturedFace[];
91
+ /** Default face when none is provided — the first featured face. */
92
+ export declare const DEFAULT_DICEBEAR_COLLECTION: DiceBearCollection;
93
+ export declare const DEFAULT_DICEBEAR_SEED: string;
94
+ /** O(1) lookup by id. */
95
+ export declare const DICEBEAR_STYLE_BY_ID: Record<DiceBearCollection, DiceBearStyleMeta>;
96
+ type CreateAvatar = (style: unknown, options: Record<string, unknown>) => {
97
+ toString(): string;
98
+ };
99
+ export type DiceBearModules = {
100
+ createAvatar: CreateAvatar;
101
+ collection: Record<string, unknown>;
102
+ };
103
+ export declare function loadDiceBear(): Promise<DiceBearModules>;
104
+ /**
105
+ * Render a single static DiceBear SVG string for a given style + seed. Used for
106
+ * non-animated thumbnails (e.g. a face-picker gallery). Throws if the style id
107
+ * is unknown.
108
+ */
109
+ export declare function renderDiceBearSvg(collection: DiceBearCollection | string, seed: string, options?: Record<string, unknown>): Promise<string>;
110
+ export {};
@@ -0,0 +1,34 @@
1
+ import './lib.css';
2
+ export { RealtimeAvatar } from '../components/RealtimeAvatar';
3
+ export type { RealtimeAvatarProps } from '../components/RealtimeAvatar';
4
+ export { ContractAvatar } from '../components/ContractAvatar';
5
+ export type { ContractAvatarProps } from '../components/ContractAvatar';
6
+ export { GeometricAvatar } from '../components/GeometricAvatar';
7
+ export type { GeometricAvatarProps } from '../components/GeometricAvatar';
8
+ export { MemojiAvatar } from '../components/MemojiAvatar';
9
+ export type { MemojiAvatarProps } from '../components/MemojiAvatar';
10
+ export { PixelArtAvatar } from '../components/PixelArtAvatar';
11
+ export type { PixelArtAvatarProps } from '../components/PixelArtAvatar';
12
+ export { DoodleAvatar } from '../components/DoodleAvatar';
13
+ export type { DoodleAvatarProps } from '../components/DoodleAvatar';
14
+ export { SquirrelAvatar } from '../components/SquirrelAvatar';
15
+ export type { SquirrelAvatarProps } from '../components/SquirrelAvatar';
16
+ export { DiceBearAvatar } from '../components/DiceBearAvatar';
17
+ export type { DiceBearAvatarProps } from '../components/DiceBearAvatar';
18
+ export { DiceBearThumb } from '../components/DiceBearThumb';
19
+ export type { DiceBearThumbProps } from '../components/DiceBearThumb';
20
+ export { DICEBEAR_STYLES, DICEBEAR_STYLE_BY_ID, DICEBEAR_RIGS, DICEBEAR_FEATURED_FACES, DEFAULT_DICEBEAR_COLLECTION, DEFAULT_DICEBEAR_SEED, collectionExportName, scopeSvgIds, loadDiceBear, renderDiceBearSvg, } from './dicebear';
21
+ export type { DiceBearCollection, DiceBearStyleMeta, DiceBearRig, DiceBearFeaturedFace, DiceBearModules, } from './dicebear';
22
+ export { AudioVisualizer } from '../components/AudioVisualizer';
23
+ export type { AudioVisualizerProps } from '../components/AudioVisualizer';
24
+ export { useAvatarRuntime } from './useAvatarRuntime';
25
+ export type { AvatarRuntimeOptions } from './useAvatarRuntime';
26
+ export { useAudioMouth } from './useAudioMouth';
27
+ export { createMouthEngine } from './mouthEngine';
28
+ export type { MouthEngine, MouthFrame, MouthShape, MouthSource } from './mouthEngine';
29
+ export { createSpeechActivity, isSpeechActivity, SPEECH_ACTIVITY_BRAND } from './speechActivity';
30
+ export type { SpeechActivitySource, SpeechActivityOptions } from './speechActivity';
31
+ export { useStreamingTextActivity } from './useStreamingTextActivity';
32
+ export { useReducedMotion } from './useReducedMotion';
33
+ export type { AvatarState, StateColors, StateLabels } from './types';
34
+ export type { AvatarCustomization, AvatarProps } from '../components/DefaultAvatar';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Shared mouth-animation engine.
3
+ *
4
+ * One implementation for every avatar variant (SVG presets, VRM, byos):
5
+ * given an AnalyserNode it produces a per-frame amplitude level plus a
6
+ * coarse mouth shape (A/E/O) derived from frequency-band ratios. Given
7
+ * `null` it degrades gracefully to a synthetic, speech-like procedural
8
+ * pattern — the mouth never freezes shut while "speaking".
9
+ *
10
+ * This is intentionally amplitude-based ("audio-reactive mouth"), not
11
+ * phoneme-accurate lip-sync: an AnalyserNode gives energy, not phonemes.
12
+ */
13
+ import { SpeechActivitySource } from './speechActivity';
14
+ export type MouthShape = 'a' | 'e' | 'o' | 'closed';
15
+ /**
16
+ * Anything that can drive the mouth: a WebAudio AnalyserNode (audio), a
17
+ * token-rate SpeechActivitySource (text streams), or `null` (procedural
18
+ * fallback). Components thread this through unchanged — the engine picks
19
+ * the right driver.
20
+ */
21
+ export type MouthSource = AnalyserNode | SpeechActivitySource | null;
22
+ export interface MouthFrame {
23
+ /** Normalized mouth-opening level, 0 (closed) to 1 (max). */
24
+ level: number;
25
+ /** Coarse mouth shape suggestion for the current frame. */
26
+ shape: MouthShape;
27
+ }
28
+ export interface MouthEngine {
29
+ /** Read the next frame. Call once per animation frame. */
30
+ read(): MouthFrame;
31
+ }
32
+ /**
33
+ * Create a mouth engine for the given source: a WebAudio AnalyserNode
34
+ * (audio-reactive), a token-rate SpeechActivitySource (text streams), or
35
+ * `null` for the procedural (synthetic) fallback engine.
36
+ */
37
+ export declare function createMouthEngine(source: MouthSource): MouthEngine;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Token-rate mouth driver.
3
+ *
4
+ * A text-streaming LLM (OpenAI-style `/chat/completions` or `/responses`
5
+ * with `stream: true`) returns no audio — only tokens arriving over time.
6
+ * This source turns that *cadence* into the same 0..1 energy signal an
7
+ * AnalyserNode would give the mouth engine: the host feeds streamed text
8
+ * chunks via `push()`, energy rises with how fast tokens arrive and decays
9
+ * during pauses. The result is a mouth that visibly tracks the stream
10
+ * (busy while the model is producing, settling when it stalls or ends).
11
+ *
12
+ * The library stays presentational and provider-agnostic: it never fetches
13
+ * anything. You bring the stream; this turns it into a face.
14
+ */
15
+ /** Brand so the mouth engine can tell a SpeechActivitySource from an AnalyserNode. */
16
+ export declare const SPEECH_ACTIVITY_BRAND: "__rraSpeechActivity";
17
+ export interface SpeechActivitySource {
18
+ readonly [SPEECH_ACTIVITY_BRAND]: true;
19
+ /** Feed a streamed chunk of model text (one or more tokens). */
20
+ push(textChunk: string): void;
21
+ /** Mark the stream finished; energy decays to closed on its own. */
22
+ end(): void;
23
+ /** Drop all energy immediately (e.g. an interrupted turn). */
24
+ reset(): void;
25
+ /** Current decayed energy, 0 (closed) to 1 (wide). Read once per frame. */
26
+ sample(): number;
27
+ }
28
+ export interface SpeechActivityOptions {
29
+ /**
30
+ * Energy added per character pushed. Higher = the mouth opens wider for
31
+ * the same amount of text. Default tuned for typical token sizes.
32
+ */
33
+ chargePerChar?: number;
34
+ /**
35
+ * Decay time constant in ms: energy falls to ~37% of its value after this
36
+ * long without new tokens. Smaller = the mouth closes faster on pauses.
37
+ */
38
+ decayMs?: number;
39
+ /** Max energy a single `push()` can contribute, so a big chunk can't peg the mouth. */
40
+ maxChargePerPush?: number;
41
+ /** Clock source, injectable for tests. Defaults to performance.now / Date.now. */
42
+ now?: () => number;
43
+ }
44
+ /**
45
+ * Create a token-rate activity source. Pass the returned object as the
46
+ * `speechActivity` prop of `<RealtimeAvatar />` and call `push()` with each
47
+ * streamed chunk of model text.
48
+ */
49
+ export declare function createSpeechActivity(options?: SpeechActivityOptions): SpeechActivitySource;
50
+ /** Type guard: is this mouth source a token-rate SpeechActivitySource? */
51
+ export declare function isSpeechActivity(source: AnalyserNode | SpeechActivitySource | null | undefined): source is SpeechActivitySource;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Core public types for react-ai-avatar.
3
+ *
4
+ * The library is purely presentational: the host app resolves the
5
+ * conversation state and (optionally) provides a WebAudio AnalyserNode;
6
+ * the library renders the face.
7
+ */
8
+ export type AvatarState = 'idle' | 'listening' | 'thinking' | 'speaking' | 'working';
9
+ export interface StateColors {
10
+ idle?: string;
11
+ listening?: string;
12
+ thinking?: string;
13
+ speaking?: string;
14
+ working?: string;
15
+ }
16
+ export interface StateLabels {
17
+ idle?: string;
18
+ listening?: string;
19
+ thinking?: string;
20
+ speaking?: string;
21
+ working?: string;
22
+ }
@@ -0,0 +1,20 @@
1
+ import { MouthFrame, MouthSource } from './mouthEngine';
2
+ export interface UseAudioMouthOptions {
3
+ /**
4
+ * Mouth source: a WebAudio AnalyserNode (audio), a token-rate
5
+ * SpeechActivitySource (text streams), or `null` (procedural fallback).
6
+ */
7
+ analyser: MouthSource;
8
+ /** Run the loop only while true (typically `state === 'speaking'`). */
9
+ enabled: boolean;
10
+ /** Called once per animation frame with the current mouth frame. */
11
+ onFrame: (frame: MouthFrame) => void;
12
+ /** Called when the loop stops (close the mouth here). */
13
+ onStop?: () => void;
14
+ }
15
+ /**
16
+ * Drives a mouth animation from audio (or the procedural fallback) via
17
+ * requestAnimationFrame. Components map the emitted MouthFrame onto
18
+ * whatever they animate: an SVG path, an ellipse `ry`, VRM visemes, etc.
19
+ */
20
+ export declare function useAudioMouth({ analyser, enabled, onFrame, onStop }: UseAudioMouthOptions): void;
@@ -0,0 +1,39 @@
1
+ import { RefObject } from 'react';
2
+ import { AvatarState, StateColors } from './types';
3
+ import { MouthSource } from './mouthEngine';
4
+ /**
5
+ * The layer contract: any SVG that exposes these stable hooks can be
6
+ * animated by this runtime — both the built-in presets and byos
7
+ * (bring-your-own-SVG) avatars.
8
+ *
9
+ * | hook | part | the runtime drives |
10
+ * |-------------------|-----------------|------------------------------------------|
11
+ * | `#rra-ring` | state ring | `stroke` = stateColors[state] |
12
+ * | `#rra-mouth` | mouth | ellipse: `ry`/`rx`; rect: `height` |
13
+ * | `.rra-pupil` (x2) | pupils | circle: `cx`/`cy`; rect: `x`/`y` |
14
+ * | `.rra-lid` (x2) | eyelids | `height` = blink (0 = open) |
15
+ * | `#rra-think` | thought bubble | `opacity` + pulsing dots (thinking) |
16
+ *
17
+ * Optional data attributes on the SVG refine behavior:
18
+ * - `data-base-x` / `data-base-y` on `.rra-pupil`: rest position.
19
+ * - `data-max-height` on `.rra-lid`: fully-closed lid height (default 16).
20
+ * - `data-quantize` on `#rra-mouth` / `.rra-pupil`: snap movement to a grid
21
+ * (e.g. `1` for pixel-art presets so motion happens in whole pixels).
22
+ *
23
+ * Honors `prefers-reduced-motion`: blink, gaze tracking and bubble pulsing
24
+ * are disabled; the informative audio-reactive mouth stays on.
25
+ */
26
+ export interface AvatarRuntimeOptions {
27
+ state: AvatarState;
28
+ /** Mouth source: AnalyserNode (audio), SpeechActivitySource (text), or null. */
29
+ analyser: MouthSource;
30
+ stateColors?: StateColors;
31
+ /** Scales mouth opening; ~30 ≈ ellipse ry growing ~12 viewBox units. */
32
+ maxMouthOpening?: number;
33
+ /** 0 disables gaze tracking, 1 is default, up to 2. */
34
+ mouseTrackingIntensity?: number;
35
+ blinkIntervalMin?: number;
36
+ blinkIntervalMax?: number;
37
+ blinkDuration?: number;
38
+ }
39
+ export declare function useAvatarRuntime(containerRef: RefObject<HTMLElement | null>, options: AvatarRuntimeOptions): void;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tracks the user's `prefers-reduced-motion` accessibility setting.
3
+ * SSR-safe: defaults to `false` and only reads `matchMedia` after mount.
4
+ */
5
+ export declare function useReducedMotion(): boolean;
@@ -0,0 +1,46 @@
1
+ import { SpeechActivitySource } from './speechActivity';
2
+ /**
3
+ * Pure diff between the previously-seen accumulated text and the latest one.
4
+ * Streaming hooks (e.g. the Vercel AI SDK's `useChat`) expose the *growing*
5
+ * assistant message, not raw chunks — so we infer what's new:
6
+ *
7
+ * - `push` — `next` continues `prev` (the common case mid-stream): the new
8
+ * suffix is the token cadence to feed the mouth.
9
+ * - `reset` — `next` replaced or shrank `prev` (a new turn, or the field was
10
+ * cleared): drop energy and re-seed with `next` (empty seed = just clear).
11
+ * - `none` — unchanged.
12
+ *
13
+ * Exported for unit tests; the hook below is a thin stateful wrapper.
14
+ */
15
+ export type StreamingTextAction = {
16
+ type: 'push';
17
+ text: string;
18
+ } | {
19
+ type: 'reset';
20
+ seed: string;
21
+ } | {
22
+ type: 'none';
23
+ };
24
+ export declare function diffStreamingText(prev: string, next: string): StreamingTextAction;
25
+ /**
26
+ * Declarative bridge for the dominant chat pattern: hooks like `useChat` hand
27
+ * you the *accumulated* assistant text (it grows every render), not stream
28
+ * chunks. This hook diffs that growth and feeds the new suffix into an internal
29
+ * `SpeechActivitySource`, so the mouth tracks the stream without the host ever
30
+ * touching `createSpeechActivity` or a reader loop.
31
+ *
32
+ * Pass `<RealtimeAvatar streamingText={lastAssistantText} />` and you're done:
33
+ *
34
+ * const { messages, status } = useChat();
35
+ * const last = messages.at(-1);
36
+ * <RealtimeAvatar
37
+ * state={status === 'submitted' ? 'thinking'
38
+ * : status === 'streaming' ? 'speaking' : 'idle'}
39
+ * streamingText={last?.role === 'assistant' ? last.text : ''}
40
+ * />
41
+ *
42
+ * Returns `null` when `text` is `undefined` (the prop wasn't used), so the
43
+ * caller can fall through to the `analyser` mouth driver. The low-level
44
+ * `createSpeechActivity` push() API stays available for imperative streams.
45
+ */
46
+ export declare function useStreamingTextActivity(text: string | undefined): SpeechActivitySource | null;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Optional VRM entry point: `react-ai-avatar/vrm`.
3
+ *
4
+ * Importing this module pulls in three.js, @react-three/fiber, @react-three/drei
5
+ * and @pixiv/three-vrm (optional peer dependencies). The main entry never does:
6
+ * `<RealtimeAvatar variant="vrm" />` loads this chunk lazily on demand.
7
+ */
8
+ export { VrmAvatar } from '../components/VrmAvatar';
9
+ export type { VrmAvatarProps } from '../components/VrmAvatar';
@@ -0,0 +1 @@
1
+ /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-400:oklch(70.4% .191 22.216);--color-amber-400:oklch(82.8% .189 84.429);--color-emerald-500:oklch(69.6% .17 162.48);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-zinc-100:oklch(96.7% .001 286.375);--color-zinc-200:oklch(92% .004 286.32);--color-zinc-300:oklch(87.1% .006 286.286);--color-zinc-400:oklch(70.5% .015 286.067);--color-zinc-500:oklch(55.2% .016 285.938);--color-zinc-800:oklch(27.4% .006 286.033);--color-zinc-900:oklch(21% .006 285.885);--color-zinc-950:oklch(14.1% .005 285.823);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--tracking-widest:.1em;--leading-relaxed:1.625;--radius-md:.375rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--drop-shadow-2xl:0 25px 25px #00000026;--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-md:12px;--blur-xl:24px;--blur-2xl:40px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer base,components;@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.top-\[115\%\]{top:115%}.-bottom-3{bottom:calc(var(--spacing) * -3)}.-bottom-6{bottom:calc(var(--spacing) * -6)}.-bottom-8{bottom:calc(var(--spacing) * -8)}.bottom-\[108\%\]{bottom:108%}.left-1\/2{left:50%}.left-\[47\%\]{left:47%}.left-\[48\%\]{left:48%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-4{height:calc(var(--spacing) * 4)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-full{height:100%}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-4{width:calc(var(--spacing) * 4)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-\[90vw\]{width:90vw}.w-full{width:100%}.max-w-\[200px\]{max-width:200px}.max-w-\[220px\]{max-width:220px}.max-w-\[340px\]{max-width:340px}.max-w-\[500px\]{max-width:500px}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-\[1\.75rem\]{border-radius:1.75rem}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-4{border-style:var(--tw-border-style);border-width:4px}.border-emerald-500\/20{border-color:#00bb7f33}@supports (color:color-mix(in lab,red,red)){.border-emerald-500\/20{border-color:color-mix(in oklab,var(--color-emerald-500) 20%,transparent)}}.border-purple-500\/10{border-color:#ac4bff1a}@supports (color:color-mix(in lab,red,red)){.border-purple-500\/10{border-color:color-mix(in oklab,var(--color-purple-500) 10%,transparent)}}.border-purple-500\/15{border-color:#ac4bff26}@supports (color:color-mix(in lab,red,red)){.border-purple-500\/15{border-color:color-mix(in oklab,var(--color-purple-500) 15%,transparent)}}.border-purple-500\/20{border-color:#ac4bff33}@supports (color:color-mix(in lab,red,red)){.border-purple-500\/20{border-color:color-mix(in oklab,var(--color-purple-500) 20%,transparent)}}.border-purple-500\/25{border-color:#ac4bff40}@supports (color:color-mix(in lab,red,red)){.border-purple-500\/25{border-color:color-mix(in oklab,var(--color-purple-500) 25%,transparent)}}.border-white\/10{border-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.border-white\/10{border-color:color-mix(in oklab,var(--color-white) 10%,transparent)}}.border-zinc-800{border-color:var(--color-zinc-800)}.border-zinc-800\/40{border-color:#27272a66}@supports (color:color-mix(in lab,red,red)){.border-zinc-800\/40{border-color:color-mix(in oklab,var(--color-zinc-800) 40%,transparent)}}.border-t-emerald-500{border-top-color:var(--color-emerald-500)}.bg-purple-400{background-color:var(--color-purple-400)}.bg-white{background-color:var(--color-white)}.bg-zinc-800\/40{background-color:#27272a66}@supports (color:color-mix(in lab,red,red)){.bg-zinc-800\/40{background-color:color-mix(in oklab,var(--color-zinc-800) 40%,transparent)}}.bg-zinc-900{background-color:var(--color-zinc-900)}.bg-zinc-900\/90{background-color:#18181be6}@supports (color:color-mix(in lab,red,red)){.bg-zinc-900\/90{background-color:color-mix(in oklab,var(--color-zinc-900) 90%,transparent)}}.bg-zinc-950\/40{background-color:#09090b66}@supports (color:color-mix(in lab,red,red)){.bg-zinc-950\/40{background-color:color-mix(in oklab,var(--color-zinc-950) 40%,transparent)}}.bg-zinc-950\/80{background-color:#09090bcc}@supports (color:color-mix(in lab,red,red)){.bg-zinc-950\/80{background-color:color-mix(in oklab,var(--color-zinc-950) 80%,transparent)}}.bg-zinc-950\/90{background-color:#09090be6}@supports (color:color-mix(in lab,red,red)){.bg-zinc-950\/90{background-color:color-mix(in oklab,var(--color-zinc-950) 90%,transparent)}}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.text-amber-400{color:var(--color-amber-400)}.text-purple-400{color:var(--color-purple-400)}.text-red-400{color:var(--color-red-400)}.text-white{color:var(--color-white)}.text-zinc-100{color:var(--color-zinc-100)}.text-zinc-200{color:var(--color-zinc-200)}.text-zinc-300{color:var(--color-zinc-300)}.text-zinc-400{color:var(--color-zinc-400)}.text-zinc-500{color:var(--color-zinc-500)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_10px_30px_rgba\(139\,92\,246\,0\.15\)\]{--tw-shadow:0 10px 30px var(--tw-shadow-color,#8b5cf626);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur-2xl{--tw-blur:blur(var(--blur-2xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-2xl{--tw-drop-shadow-size:drop-shadow(0 25px 25px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--drop-shadow-2xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}@media(min-width:48rem){.md\:max-w-\[420px\]{max-width:420px}.md\:max-w-\[640px\]{max-width:640px}.md\:text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}.\[\&\>svg\]\:h-full>svg{height:100%}.\[\&\>svg\]\:w-full>svg{width:100%}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}
@@ -0,0 +1,104 @@
1
+ import { useState as A, useEffect as D } from "react";
2
+ const v = "__rraSpeechActivity", l = {
3
+ chargePerChar: 0.12,
4
+ decayMs: 140,
5
+ maxChargePerPush: 0.9
6
+ };
7
+ function R(e = {}) {
8
+ const t = e.chargePerChar ?? l.chargePerChar, n = e.decayMs ?? l.decayMs, r = e.maxChargePerPush ?? l.maxChargePerPush, a = e.now ?? (typeof performance < "u" ? () => performance.now() : () => Date.now());
9
+ let c = 0, o = a();
10
+ const h = (s) => {
11
+ const i = s - o;
12
+ o = s, i > 0 && (c *= Math.exp(-i / n));
13
+ };
14
+ return {
15
+ [v]: !0,
16
+ push(s) {
17
+ if (!s) return;
18
+ const i = a();
19
+ h(i), c = Math.min(1, c + Math.min(r, s.length * t));
20
+ },
21
+ end() {
22
+ },
23
+ reset() {
24
+ c = 0, o = a();
25
+ },
26
+ sample() {
27
+ return h(a()), c < 1e-3 ? 0 : Math.min(1, c);
28
+ }
29
+ };
30
+ }
31
+ function q(e) {
32
+ return !!e && e[v] === !0;
33
+ }
34
+ const M = 0.05;
35
+ function x(e) {
36
+ let t = new Uint8Array(e.frequencyBinCount), n = new Uint8Array(e.frequencyBinCount);
37
+ return {
38
+ read() {
39
+ t.length !== e.frequencyBinCount && (t = new Uint8Array(e.frequencyBinCount), n = new Uint8Array(e.frequencyBinCount)), e.getByteTimeDomainData(t);
40
+ let r = 0;
41
+ for (let u = 0; u < t.length; u++) {
42
+ const d = Math.abs(t[u] - 128);
43
+ d > r && (r = d);
44
+ }
45
+ const a = Math.min(1, r / 128);
46
+ if (a <= M)
47
+ return { level: 0, shape: "closed" };
48
+ e.getByteFrequencyData(n);
49
+ const o = (e.context.sampleRate || 24e3) / 2 / e.frequencyBinCount, h = (u, d) => {
50
+ let C = 0;
51
+ const E = Math.round(u / o), w = Math.min(Math.round(d / o), n.length - 1);
52
+ for (let f = E; f <= w; f++) C += n[f];
53
+ return C;
54
+ }, s = h(200, 800), i = h(800, 1800), g = h(1800, 3200), p = s + i + g + 1e-3, y = g / p, P = i / p;
55
+ let m = "a";
56
+ return y > 0.35 ? m = "e" : P > 0.4 && y < 0.2 && (m = "o"), { level: a, shape: m };
57
+ }
58
+ };
59
+ }
60
+ function B() {
61
+ let e = Math.random() * 100;
62
+ return {
63
+ read() {
64
+ e += 0.18;
65
+ const t = 0.35 + 0.3 * Math.sin(e) + 0.25 * Math.sin(e * 1.7 + 1.3) + 0.1 * Math.sin(e * 3.1), n = Math.min(1, Math.max(0, t));
66
+ if (n <= M + 0.03)
67
+ return { level: 0, shape: "closed" };
68
+ const r = Math.sin(e * 0.43), a = r > 0.55 ? "o" : r < -0.6 ? "e" : "a";
69
+ return { level: n, shape: a };
70
+ }
71
+ };
72
+ }
73
+ function S(e) {
74
+ let t = Math.random() * 100;
75
+ return {
76
+ read() {
77
+ const n = e.sample();
78
+ if (n <= M)
79
+ return { level: 0, shape: "closed" };
80
+ t += 0.3;
81
+ const r = 0.5 + 0.34 * Math.sin(t) + 0.16 * Math.sin(t * 1.7 + 1.3), a = Math.min(1, n * Math.max(0, r)), c = Math.sin(t * 0.41), o = c > 0.55 ? "o" : c < -0.6 ? "e" : "a";
82
+ return { level: a, shape: o };
83
+ }
84
+ };
85
+ }
86
+ function b(e) {
87
+ return q(e) ? S(e) : e ? x(e) : B();
88
+ }
89
+ function L() {
90
+ const [e, t] = A(!1);
91
+ return D(() => {
92
+ const n = window.matchMedia("(prefers-reduced-motion: reduce)");
93
+ t(n.matches);
94
+ const r = (a) => t(a.matches);
95
+ return n.addEventListener("change", r), () => n.removeEventListener("change", r);
96
+ }, []), e;
97
+ }
98
+ export {
99
+ v as S,
100
+ R as a,
101
+ b as c,
102
+ q as i,
103
+ L as u
104
+ };
@@ -0,0 +1 @@
1
+ "use strict";const E=require("react"),M="__rraSpeechActivity",l={chargePerChar:.12,decayMs:140,maxChargePerPush:.9};function S(e={}){const t=e.chargePerChar??l.chargePerChar,n=e.decayMs??l.decayMs,r=e.maxChargePerPush??l.maxChargePerPush,a=e.now??(typeof performance<"u"?()=>performance.now():()=>Date.now());let c=0,o=a();const h=i=>{const s=i-o;o=i,s>0&&(c*=Math.exp(-s/n))};return{[M]:!0,push(i){if(!i)return;const s=a();h(s),c=Math.min(1,c+Math.min(r,i.length*t))},end(){},reset(){c=0,o=a()},sample(){return h(a()),c<.001?0:Math.min(1,c)}}}function A(e){return!!e&&e[M]===!0}const g=.05;function q(e){let t=new Uint8Array(e.frequencyBinCount),n=new Uint8Array(e.frequencyBinCount);return{read(){t.length!==e.frequencyBinCount&&(t=new Uint8Array(e.frequencyBinCount),n=new Uint8Array(e.frequencyBinCount)),e.getByteTimeDomainData(t);let r=0;for(let u=0;u<t.length;u++){const d=Math.abs(t[u]-128);d>r&&(r=d)}const a=Math.min(1,r/128);if(a<=g)return{level:0,shape:"closed"};e.getByteFrequencyData(n);const o=(e.context.sampleRate||24e3)/2/e.frequencyBinCount,h=(u,d)=>{let v=0;const w=Math.round(u/o),D=Math.min(Math.round(d/o),n.length-1);for(let f=w;f<=D;f++)v+=n[f];return v},i=h(200,800),s=h(800,1800),p=h(1800,3200),y=i+s+p+.001,C=p/y,P=s/y;let m="a";return C>.35?m="e":P>.4&&C<.2&&(m="o"),{level:a,shape:m}}}}function B(){let e=Math.random()*100;return{read(){e+=.18;const t=.35+.3*Math.sin(e)+.25*Math.sin(e*1.7+1.3)+.1*Math.sin(e*3.1),n=Math.min(1,Math.max(0,t));if(n<=g+.03)return{level:0,shape:"closed"};const r=Math.sin(e*.43),a=r>.55?"o":r<-.6?"e":"a";return{level:n,shape:a}}}}function R(e){let t=Math.random()*100;return{read(){const n=e.sample();if(n<=g)return{level:0,shape:"closed"};t+=.3;const r=.5+.34*Math.sin(t)+.16*Math.sin(t*1.7+1.3),a=Math.min(1,n*Math.max(0,r)),c=Math.sin(t*.41),o=c>.55?"o":c<-.6?"e":"a";return{level:a,shape:o}}}}function T(e){return A(e)?R(e):e?q(e):B()}function x(){const[e,t]=E.useState(!1);return E.useEffect(()=>{const n=window.matchMedia("(prefers-reduced-motion: reduce)");t(n.matches);const r=a=>t(a.matches);return n.addEventListener("change",r),()=>n.removeEventListener("change",r)},[]),e}exports.SPEECH_ACTIVITY_BRAND=M;exports.createMouthEngine=T;exports.createSpeechActivity=S;exports.isSpeechActivity=A;exports.useReducedMotion=x;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./VrmAvatar-D_jr2TOG.cjs");exports.VrmAvatar=r.VrmAvatar;
@@ -0,0 +1,4 @@
1
+ import { VrmAvatar as m } from "./VrmAvatar-CehRzj0J.js";
2
+ export {
3
+ m as VrmAvatar
4
+ };