@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.
- package/.cspell/custom-words.txt +2 -0
- package/CHANGELOG.md +4 -0
- package/lib/components/VoiceOrb/Microphone/Microphone.d.ts +13 -0
- package/lib/components/VoiceOrb/Microphone/Microphone.d.ts.map +1 -0
- package/lib/components/VoiceOrb/Microphone/Microphone.js +68 -0
- package/lib/components/VoiceOrb/Microphone/Microphone.module.css +21 -0
- package/lib/components/VoiceOrb/Microphone/index.d.ts +2 -0
- package/lib/components/VoiceOrb/Microphone/index.d.ts.map +1 -0
- package/lib/components/VoiceOrb/Microphone/index.js +16 -0
- package/lib/components/VoiceOrb/Microphone/mic.png +0 -0
- package/lib/components/VoiceOrb/VoiceOrb/VoiceOrb.d.ts +17 -0
- package/lib/components/VoiceOrb/VoiceOrb/VoiceOrb.d.ts.map +1 -0
- package/lib/components/VoiceOrb/VoiceOrb/VoiceOrb.js +44 -0
- package/lib/components/VoiceOrb/VoiceOrb/VoiceOrb.module.css +51 -0
- package/lib/components/VoiceOrb/VoiceOrb/index.d.ts +2 -0
- package/lib/components/VoiceOrb/VoiceOrb/index.d.ts.map +1 -0
- package/lib/components/VoiceOrb/VoiceOrb/index.js +16 -0
- package/lib/components/VoiceOrb/constants.d.ts +18 -0
- package/lib/components/VoiceOrb/constants.d.ts.map +1 -0
- package/lib/components/VoiceOrb/constants.js +62 -0
- package/lib/components/VoiceOrb/index.d.ts +3 -0
- package/lib/components/VoiceOrb/index.d.ts.map +1 -0
- package/lib/components/VoiceOrb/index.js +27 -0
- package/lib/components/index.d.ts +5 -2
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/index.js +49 -16
- package/lib/hooks/useAudioAnalyzer/index.d.ts +2 -0
- package/lib/hooks/useAudioAnalyzer/index.d.ts.map +1 -0
- package/lib/hooks/useAudioAnalyzer/index.js +16 -0
- package/lib/hooks/useAudioAnalyzer/useAudioAnalyzer.d.ts +27 -0
- package/lib/hooks/useAudioAnalyzer/useAudioAnalyzer.d.ts.map +1 -0
- package/lib/hooks/useAudioAnalyzer/useAudioAnalyzer.js +171 -0
- package/mcp/package.json +1 -1
- package/package.json +1 -1
package/.cspell/custom-words.txt
CHANGED
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 @@
|
|
|
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
|
+
});
|
|
Binary file
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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,
|
|
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"}
|
package/lib/components/index.js
CHANGED
|
@@ -520,25 +520,25 @@ Object.keys(_Panel).forEach(function (key) {
|
|
|
520
520
|
}
|
|
521
521
|
});
|
|
522
522
|
});
|
|
523
|
-
var
|
|
524
|
-
Object.keys(
|
|
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] ===
|
|
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
|
|
530
|
+
return _PastChatCard[key];
|
|
531
531
|
}
|
|
532
532
|
});
|
|
533
533
|
});
|
|
534
|
-
var
|
|
535
|
-
Object.keys(
|
|
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] ===
|
|
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
|
|
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
|
|
634
|
-
Object.keys(
|
|
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] ===
|
|
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
|
|
640
|
+
return _ScrollingLoader[key];
|
|
641
641
|
}
|
|
642
642
|
});
|
|
643
643
|
});
|
|
644
|
-
var
|
|
645
|
-
Object.keys(
|
|
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] ===
|
|
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
|
|
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 @@
|
|
|
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