@spaced-out/ui-design-system 0.5.47 → 0.6.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 (34) hide show
  1. package/.cspell/custom-words.txt +2 -0
  2. package/CHANGELOG.md +4 -0
  3. package/lib/components/VoiceOrb/Microphone/Microphone.d.ts +13 -0
  4. package/lib/components/VoiceOrb/Microphone/Microphone.d.ts.map +1 -0
  5. package/lib/components/VoiceOrb/Microphone/Microphone.js +68 -0
  6. package/lib/components/VoiceOrb/Microphone/Microphone.module.css +21 -0
  7. package/lib/components/VoiceOrb/Microphone/index.d.ts +2 -0
  8. package/lib/components/VoiceOrb/Microphone/index.d.ts.map +1 -0
  9. package/lib/components/VoiceOrb/Microphone/index.js +16 -0
  10. package/lib/components/VoiceOrb/Microphone/mic.png +0 -0
  11. package/lib/components/VoiceOrb/VoiceOrb/VoiceOrb.d.ts +17 -0
  12. package/lib/components/VoiceOrb/VoiceOrb/VoiceOrb.d.ts.map +1 -0
  13. package/lib/components/VoiceOrb/VoiceOrb/VoiceOrb.js +44 -0
  14. package/lib/components/VoiceOrb/VoiceOrb/VoiceOrb.module.css +51 -0
  15. package/lib/components/VoiceOrb/VoiceOrb/index.d.ts +2 -0
  16. package/lib/components/VoiceOrb/VoiceOrb/index.d.ts.map +1 -0
  17. package/lib/components/VoiceOrb/VoiceOrb/index.js +16 -0
  18. package/lib/components/VoiceOrb/constants.d.ts +18 -0
  19. package/lib/components/VoiceOrb/constants.d.ts.map +1 -0
  20. package/lib/components/VoiceOrb/constants.js +62 -0
  21. package/lib/components/VoiceOrb/index.d.ts +3 -0
  22. package/lib/components/VoiceOrb/index.d.ts.map +1 -0
  23. package/lib/components/VoiceOrb/index.js +27 -0
  24. package/lib/components/index.d.ts +5 -2
  25. package/lib/components/index.d.ts.map +1 -1
  26. package/lib/components/index.js +49 -16
  27. package/lib/hooks/useAudioAnalyzer/index.d.ts +2 -0
  28. package/lib/hooks/useAudioAnalyzer/index.d.ts.map +1 -0
  29. package/lib/hooks/useAudioAnalyzer/index.js +16 -0
  30. package/lib/hooks/useAudioAnalyzer/useAudioAnalyzer.d.ts +27 -0
  31. package/lib/hooks/useAudioAnalyzer/useAudioAnalyzer.d.ts.map +1 -0
  32. package/lib/hooks/useAudioAnalyzer/useAudioAnalyzer.js +171 -0
  33. package/mcp/package.json +1 -1
  34. package/package.json +1 -1
@@ -161,3 +161,5 @@ xyflow
161
161
  yourcomponentname
162
162
  Yuzhno
163
163
  yxxx
164
+ normalised
165
+ analyse
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [0.6.0](https://github.com/spaced-out/ui-design-system/compare/v0.5.48-beta.0...v0.6.0) (2026-02-27)
6
+
7
+ ### [0.5.48-beta.0](https://github.com/spaced-out/ui-design-system/compare/v0.5.47...v0.5.48-beta.0) (2026-02-26)
8
+
5
9
  ### [0.5.47](https://github.com/spaced-out/ui-design-system/compare/v0.5.46...v0.5.47) (2026-02-18)
6
10
 
7
11
 
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ type ClassNames = Readonly<{
3
+ barsContainer?: string;
4
+ bar?: string;
5
+ }>;
6
+ export interface MicrophoneProps {
7
+ classNames?: ClassNames;
8
+ enableMicrophone?: boolean;
9
+ testId?: string;
10
+ }
11
+ declare const Microphone: React.FC<MicrophoneProps>;
12
+ export { Microphone };
13
+ //# sourceMappingURL=Microphone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Microphone.d.ts","sourceRoot":"","sources":["../../../../src/components/VoiceOrb/Microphone/Microphone.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAiB/B,KAAK,UAAU,GAAG,QAAQ,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAC,CAAC,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAsDzC,CAAC;AAEF,OAAO,EAAC,UAAU,EAAC,CAAC"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Microphone = void 0;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ var _useAudioAnalyzer = require("../../../hooks/useAudioAnalyzer");
9
+ var _classify = _interopRequireDefault(require("../../../utils/classify"));
10
+ var _qa = require("../../../utils/qa/qa");
11
+ var _constants = require("../constants");
12
+ var _mic = _interopRequireDefault(require("./mic.png"));
13
+ var _MicrophoneModule = _interopRequireDefault(require("./Microphone.module.css"));
14
+ var _jsxRuntime = require("react/jsx-runtime");
15
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
17
+ const Microphone = _ref => {
18
+ let {
19
+ enableMicrophone = false,
20
+ classNames,
21
+ testId
22
+ } = _ref;
23
+ const {
24
+ barIntensities
25
+ } = (0, _useAudioAnalyzer.useAudioAnalyzer)({
26
+ isListening: enableMicrophone,
27
+ audioStream: null,
28
+ barCount: _constants.BAR_COUNT
29
+ });
30
+ const barKeys = React.useMemo(() => Array.from({
31
+ length: _constants.BAR_COUNT
32
+ }, () => (0, _constants.uuid)()), [_constants.BAR_COUNT]);
33
+ // Calculate dynamic styles for each bar based on audio intensity
34
+ const barStyles = barIntensities.map((intensity, index) => {
35
+ // Height from BASE_HEIGHT (no audio) to BASE_HEIGHT * MAX_MULTIPLIERS[index] (max audio)
36
+ const multiplier = 1 + intensity * (_constants.MAX_MULTIPLIERS[index] - 1);
37
+ const height = _constants.BASE_HEIGHT * multiplier;
38
+ return {
39
+ height: `${height}px`
40
+ };
41
+ });
42
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
43
+ "data-testid": (0, _qa.generateTestId)({
44
+ base: testId,
45
+ slot: 'container'
46
+ }),
47
+ className: (0, _classify.default)(_MicrophoneModule.default.barsContainer, classNames?.barsContainer),
48
+ children: enableMicrophone ? barStyles.map((style, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
49
+ "data-testid": (0, _qa.generateTestId)({
50
+ base: testId,
51
+ slot: 'bar',
52
+ index
53
+ }),
54
+ className: (0, _classify.default)(_MicrophoneModule.default.bar, classNames?.bar),
55
+ style: style
56
+ }, barKeys[index])) : /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
57
+ "data-testid": (0, _qa.generateTestId)({
58
+ base: testId,
59
+ slot: 'icon'
60
+ }),
61
+ src: _mic.default,
62
+ alt: "Microphone",
63
+ width: 58,
64
+ height: 58
65
+ })
66
+ });
67
+ };
68
+ exports.Microphone = Microphone;
@@ -0,0 +1,21 @@
1
+ @value (size4, size1280) from '../../../styles/variables/_size.css';
2
+ @value (colorBackgroundTertiary) from '../../../styles/variables/_color.css';
3
+ @value (borderRadiusCircle) from '../../../styles/variables/_border.css';
4
+
5
+ .barsContainer {
6
+ position: absolute;
7
+ top: 50%;
8
+ left: 50%;
9
+ transform: translate(-50%, -50%);
10
+ display: flex;
11
+ gap: size4;
12
+ align-items: center;
13
+ }
14
+
15
+ .bar {
16
+ width: size4;
17
+ min-height: size4;
18
+ background: colorBackgroundTertiary;
19
+ border-radius: size1280;
20
+ transition: height 50ms ease-out;
21
+ }
@@ -0,0 +1,2 @@
1
+ export * from '../../../components/VoiceOrb/Microphone/Microphone';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/VoiceOrb/Microphone/index.ts"],"names":[],"mappings":"AAAA,cAAc,+CAA+C,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _Microphone = require("./Microphone");
7
+ Object.keys(_Microphone).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _Microphone[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _Microphone[key];
14
+ }
15
+ });
16
+ });
@@ -0,0 +1,17 @@
1
+ import * as React from 'react';
2
+ type ClassNames = Readonly<{
3
+ container?: string;
4
+ orbContainer?: string;
5
+ orb?: string;
6
+ }>;
7
+ export interface VoiceOrbProps {
8
+ classNames?: ClassNames;
9
+ /** Enable listening to microphone audio input for bar animation */
10
+ enableMicrophone?: boolean;
11
+ /** Volume value from Retell (0-1) to animate agent speaking */
12
+ volume?: number;
13
+ testId?: string;
14
+ }
15
+ export declare const VoiceOrb: React.ForwardRefExoticComponent<VoiceOrbProps & React.RefAttributes<HTMLDivElement>>;
16
+ export {};
17
+ //# sourceMappingURL=VoiceOrb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VoiceOrb.d.ts","sourceRoot":"","sources":["../../../../src/components/VoiceOrb/VoiceOrb/VoiceOrb.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,KAAK,UAAU,GAAG,QAAQ,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC,CAAC;AAEH,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,QAAQ,sFAyBpB,CAAC"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.VoiceOrb = void 0;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ var _classify = _interopRequireDefault(require("../../../utils/classify"));
9
+ var _qa = require("../../../utils/qa/qa");
10
+ var _constants = require("../constants");
11
+ var _Microphone = require("../Microphone");
12
+ var _VoiceOrbModule = _interopRequireDefault(require("./VoiceOrb.module.css"));
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
16
+ const VoiceOrb = exports.VoiceOrb = /*#__PURE__*/React.forwardRef((_ref, ref) => {
17
+ let {
18
+ classNames,
19
+ volume = 0,
20
+ enableMicrophone = false,
21
+ testId
22
+ } = _ref;
23
+ // Calculate CSS custom property values for volume-based box-shadow animation
24
+ const orbShadowVars = (0, _constants.calculateOrbShadowVars)(volume);
25
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
26
+ ref: ref,
27
+ "data-testid": (0, _qa.generateTestId)({
28
+ base: testId,
29
+ slot: 'container'
30
+ }),
31
+ className: (0, _classify.default)(_VoiceOrbModule.default.container, classNames?.container),
32
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
33
+ className: (0, _classify.default)(_VoiceOrbModule.default.orbContainer, classNames?.orbContainer),
34
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
35
+ className: (0, _classify.default)(_VoiceOrbModule.default.orb, classNames?.orb),
36
+ style: orbShadowVars,
37
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Microphone.Microphone, {
38
+ enableMicrophone: enableMicrophone
39
+ })
40
+ })
41
+ })
42
+ });
43
+ });
44
+ VoiceOrb.displayName = 'VoiceOrb';
@@ -0,0 +1,51 @@
1
+ @value (sizeFluid) from '../../../styles/variables/_size.css';
2
+ @value (borderRadiusCircle) from '../../../styles/variables/_border.css';
3
+
4
+ .container {
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: center;
8
+ }
9
+
10
+ .orbContainer {
11
+ width: 130px;
12
+ height: 130px;
13
+ }
14
+
15
+ .orb {
16
+ width: sizeFluid;
17
+ height: sizeFluid;
18
+ border-radius: borderRadiusCircle;
19
+ background: linear-gradient(135deg, #56ccf2 0%, #2f80ed 50%, #7c3aed 100%);
20
+ position: relative;
21
+ /* Default values for CSS variables */
22
+ --shadow-blur-1: 0px;
23
+ --shadow-blur-2: 0px;
24
+ --shadow-blur-3: 0px;
25
+ --shadow-opacity-1: 0.3;
26
+ --shadow-opacity-2: 0.2;
27
+ --shadow-opacity-3: 0.15;
28
+ /* Use CSS variables for box-shadow with smooth transitions */
29
+ box-shadow: 0px 0px var(--shadow-blur-1)
30
+ rgba(86, 204, 242, var(--shadow-opacity-1)),
31
+ 0px 0px var(--shadow-blur-2) rgba(47, 128, 237, var(--shadow-opacity-2)),
32
+ 0px 0px var(--shadow-blur-3) rgba(124, 58, 237, var(--shadow-opacity-3));
33
+ transition: box-shadow 50ms ease-out;
34
+ }
35
+
36
+ /* Additional glow effect for depth */
37
+ .orb::before {
38
+ content: '';
39
+ position: absolute;
40
+ top: 10%;
41
+ left: 10%;
42
+ right: 10%;
43
+ bottom: 10%;
44
+ border-radius: borderRadiusCircle;
45
+ background: radial-gradient(
46
+ circle at 30% 30%,
47
+ rgba(255, 255, 255, 0.3),
48
+ transparent 50%
49
+ );
50
+ pointer-events: none;
51
+ }
@@ -0,0 +1,2 @@
1
+ export * from '../../../components/VoiceOrb/VoiceOrb/VoiceOrb';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/VoiceOrb/VoiceOrb/index.ts"],"names":[],"mappings":"AAAA,cAAc,2CAA2C,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _VoiceOrb = require("./VoiceOrb");
7
+ Object.keys(_VoiceOrb).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _VoiceOrb[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _VoiceOrb[key];
14
+ }
15
+ });
16
+ });
@@ -0,0 +1,18 @@
1
+ export declare const BAR_COUNT = 5;
2
+ export declare const BASE_HEIGHT = 4;
3
+ export declare const MAX_MULTIPLIERS: readonly [4, 8, 12, 8, 4];
4
+ export declare const MIN_SHADOW_BLUR = 0;
5
+ export declare const MAX_SHADOW_BLUR = 30;
6
+ export declare const MIN_SHADOW_BLUR_2 = 0;
7
+ export declare const MAX_SHADOW_BLUR_2 = 50;
8
+ export declare const MIN_SHADOW_BLUR_3 = 0;
9
+ export declare const MAX_SHADOW_BLUR_3 = 70;
10
+ export declare const MIN_OPACITY_1 = 0.3;
11
+ export declare const MAX_OPACITY_1 = 0.8;
12
+ export declare const MIN_OPACITY_2 = 0.2;
13
+ export declare const MAX_OPACITY_2 = 0.6;
14
+ export declare const MIN_OPACITY_3 = 0.15;
15
+ export declare const MAX_OPACITY_3 = 0.4;
16
+ export declare function calculateOrbShadowVars(volume: number): React.CSSProperties;
17
+ export declare function uuid(): string;
18
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceOrb/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,SAAS,IAAI,CAAC;AAG3B,eAAO,MAAM,WAAW,IAAI,CAAC;AAG7B,eAAO,MAAM,eAAe,2BAA4B,CAAC;AAKzD,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,aAAa,OAAO,CAAC;AAClC,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GA2B9C,KAAK,CAAC,aAAa,CACzB;AAGD,wBAAgB,IAAI,WAQnB"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MIN_SHADOW_BLUR_3 = exports.MIN_SHADOW_BLUR_2 = exports.MIN_SHADOW_BLUR = exports.MIN_OPACITY_3 = exports.MIN_OPACITY_2 = exports.MIN_OPACITY_1 = exports.MAX_SHADOW_BLUR_3 = exports.MAX_SHADOW_BLUR_2 = exports.MAX_SHADOW_BLUR = exports.MAX_OPACITY_3 = exports.MAX_OPACITY_2 = exports.MAX_OPACITY_1 = exports.MAX_MULTIPLIERS = exports.BASE_HEIGHT = exports.BAR_COUNT = void 0;
7
+ exports.calculateOrbShadowVars = calculateOrbShadowVars;
8
+ exports.uuid = uuid;
9
+ // Bar animation constants
10
+ const BAR_COUNT = exports.BAR_COUNT = 5;
11
+
12
+ // Base height of each bar in pixels
13
+ const BASE_HEIGHT = exports.BASE_HEIGHT = 4;
14
+
15
+ // Maximum height multipliers for each bar position (center has highest, edges have lowest)
16
+ const MAX_MULTIPLIERS = exports.MAX_MULTIPLIERS = [4, 8, 12, 8, 4];
17
+
18
+ // Box-shadow values for volume animation
19
+ // Base (no volume): 0 0 0
20
+ // Max (full volume): 0 0 30px rgba(86, 204, 242, 0.8), 0 0 50px rgba(47, 128, 237, 0.6), 0 0 70px rgba(124, 58, 237, 0.4)
21
+ const MIN_SHADOW_BLUR = exports.MIN_SHADOW_BLUR = 0;
22
+ const MAX_SHADOW_BLUR = exports.MAX_SHADOW_BLUR = 30;
23
+ const MIN_SHADOW_BLUR_2 = exports.MIN_SHADOW_BLUR_2 = 0;
24
+ const MAX_SHADOW_BLUR_2 = exports.MAX_SHADOW_BLUR_2 = 50;
25
+ const MIN_SHADOW_BLUR_3 = exports.MIN_SHADOW_BLUR_3 = 0;
26
+ const MAX_SHADOW_BLUR_3 = exports.MAX_SHADOW_BLUR_3 = 70;
27
+ const MIN_OPACITY_1 = exports.MIN_OPACITY_1 = 0.3;
28
+ const MAX_OPACITY_1 = exports.MAX_OPACITY_1 = 0.8;
29
+ const MIN_OPACITY_2 = exports.MIN_OPACITY_2 = 0.2;
30
+ const MAX_OPACITY_2 = exports.MAX_OPACITY_2 = 0.6;
31
+ const MIN_OPACITY_3 = exports.MIN_OPACITY_3 = 0.15;
32
+ const MAX_OPACITY_3 = exports.MAX_OPACITY_3 = 0.4;
33
+ function calculateOrbShadowVars(volume) {
34
+ // Clamp volume between 0 and 1
35
+ const clampedVolume = Math.max(0, Math.min(1, volume));
36
+
37
+ // Interpolate shadow blur values
38
+ const blur1 = MIN_SHADOW_BLUR + clampedVolume * (MAX_SHADOW_BLUR - MIN_SHADOW_BLUR);
39
+ const blur2 = MIN_SHADOW_BLUR_2 + clampedVolume * (MAX_SHADOW_BLUR_2 - MIN_SHADOW_BLUR_2);
40
+ const blur3 = MIN_SHADOW_BLUR_3 + clampedVolume * (MAX_SHADOW_BLUR_3 - MIN_SHADOW_BLUR_3);
41
+
42
+ // Interpolate opacity values
43
+ const opacity1 = MIN_OPACITY_1 + clampedVolume * (MAX_OPACITY_1 - MIN_OPACITY_1);
44
+ const opacity2 = MIN_OPACITY_2 + clampedVolume * (MAX_OPACITY_2 - MIN_OPACITY_2);
45
+ const opacity3 = MIN_OPACITY_3 + clampedVolume * (MAX_OPACITY_3 - MIN_OPACITY_3);
46
+ return {
47
+ '--shadow-blur-1': `${blur1}px`,
48
+ '--shadow-blur-2': `${blur2}px`,
49
+ '--shadow-blur-3': `${blur3}px`,
50
+ '--shadow-opacity-1': opacity1,
51
+ '--shadow-opacity-2': opacity2,
52
+ '--shadow-opacity-3': opacity3
53
+ };
54
+ }
55
+
56
+ // crypto.randomUUID() is not supported in non-secure contexts (storybook dev mode - http)
57
+ function uuid() {
58
+ return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, s => {
59
+ const c = Number(s);
60
+ return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16);
61
+ });
62
+ }
@@ -0,0 +1,3 @@
1
+ export * from '../../components/VoiceOrb/Microphone';
2
+ export * from '../../components/VoiceOrb/VoiceOrb';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceOrb/index.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _Microphone = require("./Microphone");
7
+ Object.keys(_Microphone).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _Microphone[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _Microphone[key];
14
+ }
15
+ });
16
+ });
17
+ var _VoiceOrb = require("./VoiceOrb");
18
+ Object.keys(_VoiceOrb).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _VoiceOrb[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _VoiceOrb[key];
25
+ }
26
+ });
27
+ });
@@ -45,8 +45,8 @@ export * from '../components/OptionButton';
45
45
  export * from '../components/PageTitle';
46
46
  export * from '../components/Pagination';
47
47
  export * from '../components/Panel';
48
- export * from '../components/PreviewCard';
49
48
  export * from '../components/PastChatCard';
49
+ export * from '../components/PreviewCard';
50
50
  export * from '../components/ProgressDonut';
51
51
  export * from '../components/PromptChip';
52
52
  export * from '../components/PromptInput';
@@ -55,8 +55,8 @@ export * from '../components/RadioTile';
55
55
  export * from '../components/RangeSlider';
56
56
  export * from '../components/Rating';
57
57
  export * from '../components/ScoreBar';
58
- export * from '../components/SearchInput';
59
58
  export * from '../components/ScrollingLoader';
59
+ export * from '../components/SearchInput';
60
60
  export * from '../components/Separator';
61
61
  export * from '../components/Shimmer';
62
62
  export * from '../components/SideMenuLink';
@@ -78,5 +78,8 @@ export * from '../components/Tooltip';
78
78
  export * from '../components/Truncate';
79
79
  export * from '../components/TruncatedTextWithTooltip';
80
80
  export * from '../components/Typeahead';
81
+ export * from '../hooks/useAudioAnalyzer';
82
+ export * from '../components/VoiceOrb/Microphone';
83
+ export * from '../components/VoiceOrb/VoiceOrb';
81
84
  export * from '../components/WeekdayPicker';
82
85
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mDAAmD,CAAC;AAClE,cAAc,iCAAiC,CAAC;AAChD,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yCAAyC,CAAC;AACxD,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mDAAmD,CAAC;AAClE,cAAc,iCAAiC,CAAC;AAChD,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yCAAyC,CAAC;AACxD,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,8BAA8B,CAAC"}
@@ -520,25 +520,25 @@ Object.keys(_Panel).forEach(function (key) {
520
520
  }
521
521
  });
522
522
  });
523
- var _PreviewCard = require("./PreviewCard");
524
- Object.keys(_PreviewCard).forEach(function (key) {
523
+ var _PastChatCard = require("./PastChatCard");
524
+ Object.keys(_PastChatCard).forEach(function (key) {
525
525
  if (key === "default" || key === "__esModule") return;
526
- if (key in exports && exports[key] === _PreviewCard[key]) return;
526
+ if (key in exports && exports[key] === _PastChatCard[key]) return;
527
527
  Object.defineProperty(exports, key, {
528
528
  enumerable: true,
529
529
  get: function () {
530
- return _PreviewCard[key];
530
+ return _PastChatCard[key];
531
531
  }
532
532
  });
533
533
  });
534
- var _PastChatCard = require("./PastChatCard");
535
- Object.keys(_PastChatCard).forEach(function (key) {
534
+ var _PreviewCard = require("./PreviewCard");
535
+ Object.keys(_PreviewCard).forEach(function (key) {
536
536
  if (key === "default" || key === "__esModule") return;
537
- if (key in exports && exports[key] === _PastChatCard[key]) return;
537
+ if (key in exports && exports[key] === _PreviewCard[key]) return;
538
538
  Object.defineProperty(exports, key, {
539
539
  enumerable: true,
540
540
  get: function () {
541
- return _PastChatCard[key];
541
+ return _PreviewCard[key];
542
542
  }
543
543
  });
544
544
  });
@@ -630,25 +630,25 @@ Object.keys(_ScoreBar).forEach(function (key) {
630
630
  }
631
631
  });
632
632
  });
633
- var _SearchInput = require("./SearchInput");
634
- Object.keys(_SearchInput).forEach(function (key) {
633
+ var _ScrollingLoader = require("./ScrollingLoader");
634
+ Object.keys(_ScrollingLoader).forEach(function (key) {
635
635
  if (key === "default" || key === "__esModule") return;
636
- if (key in exports && exports[key] === _SearchInput[key]) return;
636
+ if (key in exports && exports[key] === _ScrollingLoader[key]) return;
637
637
  Object.defineProperty(exports, key, {
638
638
  enumerable: true,
639
639
  get: function () {
640
- return _SearchInput[key];
640
+ return _ScrollingLoader[key];
641
641
  }
642
642
  });
643
643
  });
644
- var _ScrollingLoader = require("./ScrollingLoader");
645
- Object.keys(_ScrollingLoader).forEach(function (key) {
644
+ var _SearchInput = require("./SearchInput");
645
+ Object.keys(_SearchInput).forEach(function (key) {
646
646
  if (key === "default" || key === "__esModule") return;
647
- if (key in exports && exports[key] === _ScrollingLoader[key]) return;
647
+ if (key in exports && exports[key] === _SearchInput[key]) return;
648
648
  Object.defineProperty(exports, key, {
649
649
  enumerable: true,
650
650
  get: function () {
651
- return _ScrollingLoader[key];
651
+ return _SearchInput[key];
652
652
  }
653
653
  });
654
654
  });
@@ -883,6 +883,39 @@ Object.keys(_Typeahead).forEach(function (key) {
883
883
  }
884
884
  });
885
885
  });
886
+ var _useAudioAnalyzer = require("../hooks/useAudioAnalyzer");
887
+ Object.keys(_useAudioAnalyzer).forEach(function (key) {
888
+ if (key === "default" || key === "__esModule") return;
889
+ if (key in exports && exports[key] === _useAudioAnalyzer[key]) return;
890
+ Object.defineProperty(exports, key, {
891
+ enumerable: true,
892
+ get: function () {
893
+ return _useAudioAnalyzer[key];
894
+ }
895
+ });
896
+ });
897
+ var _Microphone = require("./VoiceOrb/Microphone");
898
+ Object.keys(_Microphone).forEach(function (key) {
899
+ if (key === "default" || key === "__esModule") return;
900
+ if (key in exports && exports[key] === _Microphone[key]) return;
901
+ Object.defineProperty(exports, key, {
902
+ enumerable: true,
903
+ get: function () {
904
+ return _Microphone[key];
905
+ }
906
+ });
907
+ });
908
+ var _VoiceOrb = require("./VoiceOrb/VoiceOrb");
909
+ Object.keys(_VoiceOrb).forEach(function (key) {
910
+ if (key === "default" || key === "__esModule") return;
911
+ if (key in exports && exports[key] === _VoiceOrb[key]) return;
912
+ Object.defineProperty(exports, key, {
913
+ enumerable: true,
914
+ get: function () {
915
+ return _VoiceOrb[key];
916
+ }
917
+ });
918
+ });
886
919
  var _WeekdayPicker = require("./WeekdayPicker");
887
920
  Object.keys(_WeekdayPicker).forEach(function (key) {
888
921
  if (key === "default" || key === "__esModule") return;
@@ -0,0 +1,2 @@
1
+ export * from '../../hooks/useAudioAnalyzer/useAudioAnalyzer';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/useAudioAnalyzer/index.ts"],"names":[],"mappings":"AAAA,cAAc,6CAA6C,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _useAudioAnalyzer = require("./useAudioAnalyzer");
7
+ Object.keys(_useAudioAnalyzer).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _useAudioAnalyzer[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _useAudioAnalyzer[key];
14
+ }
15
+ });
16
+ });
@@ -0,0 +1,27 @@
1
+ export interface AudioAnalyzerOptions {
2
+ /** Enable/disable audio analysis */
3
+ isListening: boolean;
4
+ /** Optional external MediaStream to use */
5
+ audioStream?: MediaStream | null;
6
+ /** Number of bars to generate intensity values for */
7
+ barCount?: number;
8
+ /** Smoothing factor for the analyzer (0-1) */
9
+ smoothingTimeConstant?: number;
10
+ /** FFT size for frequency analysis */
11
+ fftSize?: number;
12
+ /** Minimum ms between state updates (throttle). Default 50 (~20fps). */
13
+ updateIntervalMs?: number;
14
+ }
15
+ export interface AudioAnalyzerResult {
16
+ /** Array of intensity values (0-1) for each bar */
17
+ barIntensities: number[];
18
+ /** Whether the audio stream is active */
19
+ isActive: boolean;
20
+ /** Any error that occurred */
21
+ error: Error | null;
22
+ }
23
+ export declare const useAudioAnalyzer: {
24
+ (options: AudioAnalyzerOptions): AudioAnalyzerResult;
25
+ displayName: string;
26
+ };
27
+ //# sourceMappingURL=useAudioAnalyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAudioAnalyzer.d.ts","sourceRoot":"","sources":["../../../src/hooks/useAudioAnalyzer/useAudioAnalyzer.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACnC,oCAAoC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,yCAAyC;IACzC,QAAQ,EAAE,OAAO,CAAC;IAClB,8BAA8B;IAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAcD,eAAO,MAAM,gBAAgB;cAClB,oBAAoB,GAC5B,mBAAmB;;CA+KrB,CAAC"}
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useAudioAnalyzer = void 0;
7
+ var _react = require("react");
8
+ const DEFAULT_BAR_COUNT = 5;
9
+ const DEFAULT_SMOOTHING = 0.8; // Lower smoothing for more responsive animation
10
+ const DEFAULT_FFT_SIZE = 256;
11
+ /** Throttle state updates to reduce re-renders (~20fps) */
12
+ const DEFAULT_UPDATE_INTERVAL_MS = 50;
13
+ /** Sample every Nth sample for RMS to reduce work */
14
+ const RMS_SAMPLE_STRIDE = 4;
15
+ // Sensitivity multiplier - higher values make the animation more responsive to quieter sounds
16
+ const SENSITIVITY = 3.5;
17
+ // Minimum threshold to filter out background noise
18
+ const NOISE_THRESHOLD = 0.1;
19
+ const useAudioAnalyzer = options => {
20
+ const {
21
+ isListening,
22
+ audioStream: externalStream,
23
+ barCount = DEFAULT_BAR_COUNT,
24
+ smoothingTimeConstant = DEFAULT_SMOOTHING,
25
+ fftSize = DEFAULT_FFT_SIZE,
26
+ updateIntervalMs = DEFAULT_UPDATE_INTERVAL_MS
27
+ } = options;
28
+ const [barIntensities, setBarIntensities] = (0, _react.useState)(() => Array(barCount).fill(0));
29
+ const [isActive, setIsActive] = (0, _react.useState)(false);
30
+ const [error, setError] = (0, _react.useState)(null);
31
+ const audioContextRef = (0, _react.useRef)(null);
32
+ const analyzerRef = (0, _react.useRef)(null);
33
+ const sourceRef = (0, _react.useRef)(null);
34
+ const streamRef = (0, _react.useRef)(null);
35
+ const animationFrameRef = (0, _react.useRef)(null);
36
+ const ownStreamRef = (0, _react.useRef)(false);
37
+ const lastUpdateTimeRef = (0, _react.useRef)(0);
38
+ const analyzeAudio = (0, _react.useCallback)(() => {
39
+ if (!analyzerRef.current) {
40
+ return;
41
+ }
42
+ const analyzer = analyzerRef.current;
43
+ const timeDomainData = new Uint8Array(analyzer.fftSize);
44
+ const frequencyData = new Uint8Array(analyzer.frequencyBinCount);
45
+ const freqBinCount = Math.floor(analyzer.frequencyBinCount * 0.3);
46
+ const middleIndex = Math.floor(barCount / 2) || 1;
47
+ const analyze = () => {
48
+ if (!analyzerRef.current) {
49
+ return;
50
+ }
51
+ analyzer.getByteTimeDomainData(timeDomainData);
52
+ analyzer.getByteFrequencyData(frequencyData);
53
+
54
+ // Sampled RMS: every Nth sample to reduce iterations
55
+ let sumSquares = 0;
56
+ let sampledCount = 0;
57
+ for (let i = 0; i < timeDomainData.length; i += RMS_SAMPLE_STRIDE) {
58
+ const normalized = (timeDomainData[i] - 128) / 128;
59
+ sumSquares += normalized * normalized;
60
+ sampledCount++;
61
+ }
62
+ const rms = Math.sqrt(sampledCount ? sumSquares / sampledCount : 0);
63
+ let intensity = Math.min(rms * SENSITIVITY, 1);
64
+ if (intensity < NOISE_THRESHOLD) {
65
+ intensity = 0;
66
+ }
67
+
68
+ // One pass over low frequencies to get per-bar band sums
69
+ const bandSums = new Array(barCount).fill(0);
70
+ const bandCounts = new Array(barCount).fill(0);
71
+ for (let j = 0; j < freqBinCount; j++) {
72
+ const barIdx = Math.min(Math.floor(j / freqBinCount * barCount), barCount - 1);
73
+ bandSums[barIdx] += frequencyData[j];
74
+ bandCounts[barIdx]++;
75
+ }
76
+ const intensities = [];
77
+ for (let i = 0; i < barCount; i++) {
78
+ const distanceFromCenter = Math.abs(i - middleIndex) / middleIndex;
79
+ const barMultiplier = 1 - distanceFromCenter * 0.4;
80
+ const freqAvg = bandCounts[i] ? bandSums[i] / bandCounts[i] / 255 : 0;
81
+ const combinedIntensity = (intensity * 0.7 + freqAvg * 0.3) * barMultiplier;
82
+ intensities.push(Math.min(Math.max(combinedIntensity, 0), 1));
83
+ }
84
+ const now = Date.now();
85
+ if (now - lastUpdateTimeRef.current >= updateIntervalMs) {
86
+ lastUpdateTimeRef.current = now;
87
+ setBarIntensities(intensities);
88
+ }
89
+ animationFrameRef.current = requestAnimationFrame(analyze);
90
+ };
91
+ analyze();
92
+ }, [barCount, updateIntervalMs]);
93
+ const cleanup = (0, _react.useCallback)(() => {
94
+ if (animationFrameRef.current) {
95
+ cancelAnimationFrame(animationFrameRef.current);
96
+ animationFrameRef.current = null;
97
+ }
98
+ if (sourceRef.current) {
99
+ sourceRef.current.disconnect();
100
+ sourceRef.current = null;
101
+ }
102
+ if (analyzerRef.current) {
103
+ analyzerRef.current.disconnect();
104
+ analyzerRef.current = null;
105
+ }
106
+
107
+ // Only stop the stream if we created it ourselves
108
+ if (streamRef.current && ownStreamRef.current) {
109
+ streamRef.current.getTracks().forEach(track => track.stop());
110
+ }
111
+ streamRef.current = null;
112
+ ownStreamRef.current = false;
113
+ if (audioContextRef.current) {
114
+ audioContextRef.current.close();
115
+ audioContextRef.current = null;
116
+ }
117
+ setIsActive(false);
118
+ setBarIntensities(Array(barCount).fill(0));
119
+ }, [barCount]);
120
+ (0, _react.useEffect)(() => {
121
+ if (!isListening) {
122
+ cleanup();
123
+ return;
124
+ }
125
+ const initAudio = async () => {
126
+ try {
127
+ setError(null);
128
+
129
+ // Use external stream or request microphone access
130
+ let stream;
131
+ if (externalStream) {
132
+ stream = externalStream;
133
+ ownStreamRef.current = false;
134
+ } else {
135
+ stream = await navigator.mediaDevices.getUserMedia({
136
+ audio: true
137
+ });
138
+ ownStreamRef.current = true;
139
+ }
140
+ streamRef.current = stream;
141
+
142
+ // Create audio context and analyzer
143
+ const audioContext = new AudioContext();
144
+ audioContextRef.current = audioContext;
145
+ const analyzer = audioContext.createAnalyser();
146
+ analyzer.fftSize = fftSize;
147
+ analyzer.smoothingTimeConstant = smoothingTimeConstant;
148
+ analyzerRef.current = analyzer;
149
+
150
+ // Connect stream to analyzer
151
+ const source = audioContext.createMediaStreamSource(stream);
152
+ source.connect(analyzer);
153
+ sourceRef.current = source;
154
+ setIsActive(true);
155
+ analyzeAudio();
156
+ } catch (err) {
157
+ setError(err instanceof Error ? err : new Error('Failed to access microphone'));
158
+ setIsActive(false);
159
+ }
160
+ };
161
+ initAudio();
162
+ return cleanup;
163
+ }, [isListening, externalStream, fftSize, smoothingTimeConstant, analyzeAudio, cleanup]);
164
+ return {
165
+ barIntensities,
166
+ isActive,
167
+ error
168
+ };
169
+ };
170
+ exports.useAudioAnalyzer = useAudioAnalyzer;
171
+ useAudioAnalyzer.displayName = 'useAudioAnalyzer';
package/mcp/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaced-out/genesis-mcp",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "MCP server for Genesis UI Design System - provides AI assistants with access to components, hooks, and design tokens",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaced-out/ui-design-system",
3
- "version": "0.5.47",
3
+ "version": "0.6.0",
4
4
  "description": "Sense UI components library",
5
5
  "author": {
6
6
  "name": "Spaced Out"