@ghchinoy/lit-audio-ui 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.
@@ -0,0 +1,1217 @@
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`lit`),require(`lit/decorators.js`),require(`@material/web/button/filled-button.js`),require(`@material/web/icon/icon.js`),require(`lit/directives/class-map.js`),require(`@material/web/button/outlined-button.js`),require(`@material/web/iconbutton/filled-icon-button.js`),require(`@material/web/progress/circular-progress.js`),require(`@material/web/slider/slider.js`),require(`@material/web/menu/menu.js`),require(`@material/web/menu/menu-item.js`),require(`@material/web/divider/divider.js`),require(`@material/web/button/text-button.js`),require(`@material/web/button/filled-tonal-button.js`),require(`@material/web/textfield/outlined-text-field.js`),require(`three`),require(`@material/web/iconbutton/icon-button.js`)):typeof define==`function`&&define.amd?define([`exports`,`lit`,`lit/decorators.js`,`@material/web/button/filled-button.js`,`@material/web/icon/icon.js`,`lit/directives/class-map.js`,`@material/web/button/outlined-button.js`,`@material/web/iconbutton/filled-icon-button.js`,`@material/web/progress/circular-progress.js`,`@material/web/slider/slider.js`,`@material/web/menu/menu.js`,`@material/web/menu/menu-item.js`,`@material/web/divider/divider.js`,`@material/web/button/text-button.js`,`@material/web/button/filled-tonal-button.js`,`@material/web/textfield/outlined-text-field.js`,`three`,`@material/web/iconbutton/icon-button.js`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ScreamAudioUI={},e.Lit,e.Lit,e.MaterialWeb,e.MaterialWeb,e.Lit,e.MaterialWeb,e.MaterialWeb,e.MaterialWeb,e.MaterialWeb,e.MaterialWeb,e.MaterialWeb,e.MaterialWeb,e.MaterialWeb,e.MaterialWeb,e.MaterialWeb,e.THREE,e.MaterialWeb))})(this,function(e,t,n,r,i,a,o,s,c,l,u,d,f,p,m,h,g,_){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var v=Object.create,y=Object.defineProperty,b=Object.getOwnPropertyDescriptor,x=Object.getOwnPropertyNames,S=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty,w=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=x(t),a=0,o=i.length,s;a<o;a++)s=i[a],!C.call(e,s)&&s!==n&&y(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=b(t,s))||r.enumerable});return e};g=((e,t,n)=>(n=e==null?{}:v(S(e)),w(t||!e||!e.__esModule?y(n,`default`,{value:e,enumerable:!0}):n,e)))(g);function T(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}var E=class extends t.LitElement{constructor(...e){super(...e),this.state=`idle`}static{this.styles=t.css`
2
+ :host {
3
+ display: inline-block;
4
+ }
5
+
6
+ md-filled-button {
7
+ --md-filled-button-container-shape: 999px;
8
+ }
9
+
10
+ md-filled-button.recording {
11
+ --md-filled-button-container-color: var(--md-sys-color-error, #ba1a1a);
12
+ --md-filled-button-label-text-color: var(
13
+ --md-sys-color-on-error,
14
+ #ffffff
15
+ );
16
+ }
17
+ `}render(){return t.html`
18
+ <md-filled-button class="${this.state}" @click="${this._handleClick}">
19
+ <md-icon slot="icon">
20
+ ${this.state===`recording`?`stop`:`mic`}
21
+ </md-icon>
22
+
23
+ ${this.state===`recording`?`Recording...`:`Speak`}
24
+ </md-filled-button>
25
+ `}_handleClick(){this.state=this.state===`idle`?`recording`:`idle`,this.dispatchEvent(new CustomEvent(`voice-toggle`,{bubbles:!0,composed:!0,detail:{state:this.state}}))}};T([(0,n.property)({type:String})],E.prototype,`state`,void 0),E=T([(0,n.customElement)(`scream-voice-button`)],E);function D(e,t){e.getByteFrequencyData(t);let n=[];for(let e=0;e<t.length;e++)n.push(t[e]/255);return n}function O(e,t,n,r){if(r<=0||t<=0)return;let i=e.createLinearGradient(0,0,t,0),a=Math.min(.2,r/t);i.addColorStop(0,`rgba(0,0,0,0)`),i.addColorStop(a,`rgba(0,0,0,1)`),i.addColorStop(1-a,`rgba(0,0,0,1)`),i.addColorStop(1,`rgba(0,0,0,0)`),e.globalCompositeOperation=`destination-in`,e.fillStyle=i,e.fillRect(0,0,t,n),e.globalCompositeOperation=`source-over`}var k=class extends t.LitElement{constructor(...e){super(...e),this.active=!1,this.processing=!1,this.barWidth=3,this.barHeight=4,this.barGap=1,this.barRadius=1.5,this.fadeEdges=!0,this.fadeWidth=24,this.height=64,this.sensitivity=1,this.updateRate=30,this._animationFrameId=0,this._lastUpdateTime=0,this._currentBars=[],this._processingTime=0,this._transitionProgress=0,this._lastActiveData=[]}static{this.styles=t.css`
26
+ :host {
27
+ display: block;
28
+ width: 100%;
29
+ }
30
+ .container {
31
+ position: relative;
32
+ width: 100%;
33
+ }
34
+ canvas {
35
+ position: absolute;
36
+ top: 0;
37
+ left: 0;
38
+ display: block;
39
+ height: 100%;
40
+ width: 100%;
41
+ }
42
+ `}render(){return t.html`
43
+ <div class="container" style="height: ${this.height}px;">
44
+ <canvas></canvas>
45
+ </div>
46
+ `}firstUpdated(){this._resizeObserver=new ResizeObserver(()=>{this._handleResize()}),this._resizeObserver.observe(this._container),this._startAnimationLoop()}updated(e){super.updated(e),e.has(`analyserNode`)&&this.analyserNode&&(this._dataArray=new Uint8Array(this.analyserNode.frequencyBinCount)),e.has(`processing`)&&this.processing&&!this.active&&(this._processingTime=0,this._transitionProgress=0)}disconnectedCallback(){super.disconnectedCallback(),this._resizeObserver&&this._resizeObserver.disconnect(),this._animationFrameId&&cancelAnimationFrame(this._animationFrameId)}_handleResize(){if(!this._canvas||!this._container)return;let e=this._container.getBoundingClientRect(),t=window.devicePixelRatio||1;this._canvas.width=e.width*t,this._canvas.height=e.height*t,this._canvas.style.width=`${e.width}px`,this._canvas.style.height=`${e.height}px`;let n=this._canvas.getContext(`2d`);n&&n.scale(t,t),this._renderFrame()}_startAnimationLoop(){let e=t=>{this._updateData(t),this._renderFrame(),this._animationFrameId=requestAnimationFrame(e)};this._animationFrameId=requestAnimationFrame(e)}_updateData(e){if(!this._canvas)return;let t=this._canvas.getBoundingClientRect(),n=Math.floor(t.width/(this.barWidth+this.barGap));if(this.active&&this.analyserNode&&this._dataArray){if(e-this._lastUpdateTime>this.updateRate){this._lastUpdateTime=e;let t=D(this.analyserNode,this._dataArray),r=Math.floor(t.length*.05),i=Math.floor(t.length*.4),a=t.slice(r,i),o=Math.floor(n/2),s=Array(n).fill(.05),c=a.length-1;for(let e=0;e<=o;e++){let t=e/o,r=a[Math.floor(t*c)]||0;t>.8&&(r*=1-(t-.8)*5);let i=Math.max(.05,Math.min(1,r*this.sensitivity)),l=o+e,u=o-e;l<n&&(s[l]=i),u>=0&&(s[u]=i)}this._currentBars=s,this._lastActiveData=[...s]}}else if(this.processing&&!this.active){this._processingTime+=.03,this._transitionProgress=Math.min(1,this._transitionProgress+.02);let e=Array(n).fill(.05),t=Math.floor(n/2);for(let r=0;r<n;r++){let n=(r-t)/t,i=1-Math.abs(n)*.4,a=Math.sin(this._processingTime*1.5+n*3)*.25,o=Math.sin(this._processingTime*.8-n*2)*.2,s=Math.cos(this._processingTime*2+n)*.15,c=(.2+(a+o+s))*i,l=c;if(this._lastActiveData.length>0&&this._transitionProgress<1){let e=Math.min(r,this._lastActiveData.length-1);l=(this._lastActiveData[e]||0)*(1-this._transitionProgress)+c*this._transitionProgress}e[r]=Math.max(.05,Math.min(1,l))}this._currentBars=e}else if(this._currentBars.length>0){let e=!0;for(let t=0;t<this._currentBars.length;t++)this._currentBars[t]=Math.max(.05,this._currentBars[t]*.85),this._currentBars[t]>.06&&(e=!1);e&&(this._currentBars=[])}}_renderFrame(){if(!this._canvas)return;let e=this._canvas.getContext(`2d`);if(!e)return;let t=this._canvas.getBoundingClientRect();e.clearRect(0,0,t.width,t.height);let n=getComputedStyle(this),r=this.barColor;if(!r){let e=n.getPropertyValue(`--md-sys-color-primary`).trim(),t=n.getPropertyValue(`color`).trim();r=e||t||`#0066cc`}let i=this.barWidth+this.barGap,a=Math.floor(t.width/i),o=t.height/2;for(let n=0;n<a&&n<this._currentBars.length;n++){let a=this._currentBars[n]||.05,s=n*i,c=Math.max(this.barHeight,a*t.height*.8),l=o-c/2;e.fillStyle=r,e.globalAlpha=.4+a*.6,this.barRadius>0?(e.beginPath(),e.roundRect(s,l,this.barWidth,c,this.barRadius),e.fill()):e.fillRect(s,l,this.barWidth,c)}this.fadeEdges&&O(e,t.width,t.height,this.fadeWidth),e.globalAlpha=1}};T([(0,n.property)({type:Boolean})],k.prototype,`active`,void 0),T([(0,n.property)({type:Boolean})],k.prototype,`processing`,void 0),T([(0,n.property)({attribute:!1})],k.prototype,`analyserNode`,void 0),T([(0,n.property)({type:Number})],k.prototype,`barWidth`,void 0),T([(0,n.property)({type:Number})],k.prototype,`barHeight`,void 0),T([(0,n.property)({type:Number})],k.prototype,`barGap`,void 0),T([(0,n.property)({type:Number})],k.prototype,`barRadius`,void 0),T([(0,n.property)({type:String})],k.prototype,`barColor`,void 0),T([(0,n.property)({type:Boolean})],k.prototype,`fadeEdges`,void 0),T([(0,n.property)({type:Number})],k.prototype,`fadeWidth`,void 0),T([(0,n.property)({type:Number})],k.prototype,`height`,void 0),T([(0,n.property)({type:Number})],k.prototype,`sensitivity`,void 0),T([(0,n.property)({type:Number})],k.prototype,`updateRate`,void 0),T([(0,n.query)(`canvas`)],k.prototype,`_canvas`,void 0),T([(0,n.query)(`.container`)],k.prototype,`_container`,void 0),k=T([(0,n.customElement)(`ui-live-waveform`)],k);var A=class extends t.LitElement{constructor(...e){super(...e),this.state=`idle`,this.disabled=!1,this._showFeedback=!1}static{this.styles=t.css`
47
+ :host {
48
+ display: inline-block;
49
+ --ui-waveform-height: 24px;
50
+ --ui-waveform-width: 96px;
51
+ }
52
+
53
+ .wrapper {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 12px;
57
+ }
58
+
59
+ md-filled-button,
60
+ md-outlined-button {
61
+ transition: all 0.2s ease-in-out;
62
+ }
63
+
64
+ /* Customize the button depending on the state */
65
+ md-filled-button.recording {
66
+ --md-filled-button-container-color: var(
67
+ --md-sys-color-error-container,
68
+ #ffdad6
69
+ );
70
+ --md-filled-button-label-text-color: var(
71
+ --md-sys-color-on-error-container,
72
+ #410002
73
+ );
74
+ }
75
+
76
+ md-filled-button.processing {
77
+ --md-filled-button-container-color: var(
78
+ --md-sys-color-secondary-container,
79
+ #cce5ff
80
+ );
81
+ --md-filled-button-label-text-color: var(
82
+ --md-sys-color-on-secondary-container,
83
+ #001d36
84
+ );
85
+ }
86
+
87
+ md-filled-button.success {
88
+ --md-filled-button-container-color: var(
89
+ --md-sys-color-primary-container,
90
+ #d1e4ff
91
+ );
92
+ --md-filled-button-label-text-color: var(
93
+ --md-sys-color-on-primary-container,
94
+ #001d36
95
+ );
96
+ }
97
+
98
+ .waveform-slot {
99
+ position: relative;
100
+ width: var(--ui-waveform-width);
101
+ height: var(--ui-waveform-height);
102
+ border-radius: 4px;
103
+ overflow: hidden;
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ background: var(--md-sys-color-surface-container-highest, #e3e3e3);
108
+ border: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);
109
+ transition: background-color 0.3s ease;
110
+ }
111
+
112
+ .waveform-slot.recording {
113
+ background: var(--md-sys-color-error-container, #ffdad6);
114
+ border-color: transparent;
115
+ }
116
+
117
+ .waveform-slot.processing {
118
+ background: var(--md-sys-color-secondary-container, #cce5ff);
119
+ border-color: transparent;
120
+ }
121
+
122
+ .trailing-text {
123
+ font-family: monospace;
124
+ font-size: 11px;
125
+ color: var(--md-sys-color-on-surface-variant, #444);
126
+ font-weight: 500;
127
+ user-select: none;
128
+ }
129
+
130
+ .feedback-overlay {
131
+ position: absolute;
132
+ inset: 0;
133
+ display: flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ background: var(--md-sys-color-surface, #fff);
137
+ animation: fadeIn 0.3s ease forwards;
138
+ }
139
+
140
+ .feedback-icon {
141
+ font-size: 16px;
142
+ }
143
+ .feedback-icon.success {
144
+ color: var(--md-sys-color-primary, #0066cc);
145
+ }
146
+ .feedback-icon.error {
147
+ color: var(--md-sys-color-error, #ba1a1a);
148
+ }
149
+
150
+ @keyframes fadeIn {
151
+ from {
152
+ opacity: 0;
153
+ }
154
+ to {
155
+ opacity: 0.9;
156
+ }
157
+ }
158
+ `}updated(e){super.updated(e),e.has(`state`)&&(this.state===`success`||this.state===`error`?(this._showFeedback=!0,this._feedbackTimeout&&clearTimeout(this._feedbackTimeout),this._feedbackTimeout=setTimeout(()=>{this._showFeedback=!1,(this.state===`success`||this.state===`error`)&&(this.state=`idle`)},1500)):this._showFeedback=!1)}render(){let e=this.state===`recording`,n=this.state===`processing`,r=this.state===`success`,i=this.state===`error`,o=this.disabled||n,s=e||n,c=!s&&!this._showFeedback&&this.trailing,l={recording:e,processing:n,success:r&&this._showFeedback,error:i&&this._showFeedback},u={"waveform-slot":!0,recording:e,processing:n};return t.html`
159
+ <md-filled-button
160
+ class=${(0,a.classMap)(l)}
161
+ ?disabled=${o}
162
+ @click=${this._handleClick}
163
+ >
164
+ <div class="wrapper">
165
+ ${this.label?t.html`<span>${this.label}</span>`:``}
166
+
167
+ <div class=${(0,a.classMap)(u)}>
168
+ ${s?t.html`
169
+ <ui-live-waveform
170
+ .active=${e}
171
+ .processing=${n}
172
+ .analyserNode=${this.analyserNode}
173
+ .barWidth=${2}
174
+ .barGap=${1}
175
+ .barRadius=${4}
176
+ .fadeEdges=${!1}
177
+ .sensitivity=${1.8}
178
+ height="20"
179
+ style="position: absolute; inset: 0;"
180
+ ></ui-live-waveform>
181
+ `:``}
182
+ ${c?t.html` <span class="trailing-text">${this.trailing}</span> `:``}
183
+ ${this._showFeedback&&r?t.html`
184
+ <div class="feedback-overlay">
185
+ <md-icon class="feedback-icon success">check</md-icon>
186
+ </div>
187
+ `:``}
188
+ ${this._showFeedback&&i?t.html`
189
+ <div class="feedback-overlay">
190
+ <md-icon class="feedback-icon error">close</md-icon>
191
+ </div>
192
+ `:``}
193
+ </div>
194
+ </div>
195
+ </md-filled-button>
196
+ `}_handleClick(e){this.dispatchEvent(new CustomEvent(`voice-button-click`,{bubbles:!0,composed:!0,detail:{state:this.state}}))}};T([(0,n.property)({type:String})],A.prototype,`state`,void 0),T([(0,n.property)({type:String})],A.prototype,`label`,void 0),T([(0,n.property)({type:String})],A.prototype,`trailing`,void 0),T([(0,n.property)({type:Boolean})],A.prototype,`disabled`,void 0),T([(0,n.property)({attribute:!1})],A.prototype,`analyserNode`,void 0),T([(0,n.state)()],A.prototype,`_showFeedback`,void 0),A=T([(0,n.customElement)(`ui-voice-button`)],A);var j=class extends t.LitElement{constructor(...e){super(...e),this.data=[],this.barWidth=4,this.barHeight=4,this.barGap=2,this.barRadius=2,this.fadeEdges=!0,this.fadeWidth=24,this.height=128}static{this.styles=t.css`
197
+ :host {
198
+ display: block;
199
+ width: 100%;
200
+ }
201
+ .container {
202
+ position: relative;
203
+ width: 100%;
204
+ }
205
+ canvas {
206
+ position: absolute;
207
+ top: 0;
208
+ left: 0;
209
+ display: block;
210
+ height: 100%;
211
+ width: 100%;
212
+ }
213
+ `}render(){return t.html`
214
+ <div class="container" style="height: ${this.height}px;">
215
+ <canvas></canvas>
216
+ </div>
217
+ `}firstUpdated(){this._resizeObserver=new ResizeObserver(()=>{this._handleResize()}),this._resizeObserver.observe(this._container)}updated(e){super.updated(e),(e.has(`data`)||e.has(`barColor`))&&this._renderWaveform()}disconnectedCallback(){super.disconnectedCallback(),this._resizeObserver&&this._resizeObserver.disconnect()}_handleResize(){if(!this._canvas||!this._container)return;let e=this._container.getBoundingClientRect(),t=window.devicePixelRatio||1;this._canvas.width=e.width*t,this._canvas.height=e.height*t,this._canvas.style.width=`${e.width}px`,this._canvas.style.height=`${e.height}px`;let n=this._canvas.getContext(`2d`);n&&(n.scale(t,t),this._renderWaveform())}_renderWaveform(){if(!this._canvas)return;let e=this._canvas.getContext(`2d`);if(!e)return;let t=this._canvas.getBoundingClientRect();e.clearRect(0,0,t.width,t.height);let n=getComputedStyle(this),r=this.barColor;if(!r){let e=n.getPropertyValue(`--md-sys-color-primary`).trim(),t=n.getPropertyValue(`color`).trim();r=e||t||`#0066cc`}let i=Math.floor(t.width/(this.barWidth+this.barGap)),a=t.height/2;for(let n=0;n<i;n++){let o=Math.floor(n/i*this.data.length),s=this.data[o]||0,c=Math.max(this.barHeight,s*t.height*.8),l=n*(this.barWidth+this.barGap),u=a-c/2;e.fillStyle=r,e.globalAlpha=.3+s*.7,this.barRadius>0?(e.beginPath(),e.roundRect(l,u,this.barWidth,c,this.barRadius),e.fill()):e.fillRect(l,u,this.barWidth,c)}this.fadeEdges&&O(e,t.width,t.height,this.fadeWidth),e.globalAlpha=1}};T([(0,n.property)({type:Array})],j.prototype,`data`,void 0),T([(0,n.property)({type:Number})],j.prototype,`barWidth`,void 0),T([(0,n.property)({type:Number})],j.prototype,`barHeight`,void 0),T([(0,n.property)({type:Number})],j.prototype,`barGap`,void 0),T([(0,n.property)({type:Number})],j.prototype,`barRadius`,void 0),T([(0,n.property)({type:String})],j.prototype,`barColor`,void 0),T([(0,n.property)({type:Boolean})],j.prototype,`fadeEdges`,void 0),T([(0,n.property)({type:Number})],j.prototype,`fadeWidth`,void 0),T([(0,n.property)({type:Number})],j.prototype,`height`,void 0),T([(0,n.query)(`canvas`)],j.prototype,`_canvas`,void 0),T([(0,n.query)(`.container`)],j.prototype,`_container`,void 0),j=T([(0,n.customElement)(`ui-waveform`)],j);var M=class extends Event{constructor(e,t,n,r){super(`context-request`,{bubbles:!0,composed:!0}),this.context=e,this.contextTarget=t,this.callback=n,this.subscribe=r??!1}};function N(e){return e}var P=class{constructor(e,t,n,r){if(this.subscribe=!1,this.provided=!1,this.value=void 0,this.t=(e,t)=>{this.unsubscribe&&(this.unsubscribe!==t&&(this.provided=!1,this.unsubscribe()),this.subscribe||this.unsubscribe()),this.value=e,this.host.requestUpdate(),this.provided&&!this.subscribe||(this.provided=!0,this.callback&&this.callback(e,t)),this.unsubscribe=t},this.host=e,t.context!==void 0){let e=t;this.context=e.context,this.callback=e.callback,this.subscribe=e.subscribe??!1}else this.context=t,this.callback=n,this.subscribe=r??!1;this.host.addController(this)}hostConnected(){this.dispatchRequest()}hostDisconnected(){this.unsubscribe&&=(this.unsubscribe(),void 0)}dispatchRequest(){this.host.dispatchEvent(new M(this.context,this.host,this.t,this.subscribe))}},F=class{get value(){return this.o}set value(e){this.setValue(e)}setValue(e,t=!1){let n=t||!Object.is(e,this.o);this.o=e,n&&this.updateObservers()}constructor(e){this.subscriptions=new Map,this.updateObservers=()=>{for(let[e,{disposer:t}]of this.subscriptions)e(this.o,t)},e!==void 0&&(this.value=e)}addCallback(e,t,n){if(!n)return void e(this.value);this.subscriptions.has(e)||this.subscriptions.set(e,{disposer:()=>{this.subscriptions.delete(e)},consumerHost:t});let{disposer:r}=this.subscriptions.get(e);e(this.value,r)}clearCallbacks(){this.subscriptions.clear()}},I=class extends Event{constructor(e,t){super(`context-provider`,{bubbles:!0,composed:!0}),this.context=e,this.contextTarget=t}},L=class extends F{constructor(e,t,n){super(t.context===void 0?n:t.initialValue),this.onContextRequest=e=>{if(e.context!==this.context)return;let t=e.contextTarget??e.composedPath()[0];t!==this.host&&(e.stopPropagation(),this.addCallback(e.callback,t,e.subscribe))},this.onProviderRequest=e=>{if(e.context!==this.context||(e.contextTarget??e.composedPath()[0])===this.host)return;let t=new Set;for(let[e,{consumerHost:n}]of this.subscriptions)t.has(e)||(t.add(e),n.dispatchEvent(new M(this.context,n,e,!0)));e.stopPropagation()},this.host=e,t.context===void 0?this.context=t:this.context=t.context,this.attachListeners(),this.host.addController?.(this)}attachListeners(){this.host.addEventListener(`context-request`,this.onContextRequest),this.host.addEventListener(`context-provider`,this.onProviderRequest)}hostConnected(){this.host.dispatchEvent(new I(this.context,this.host))}};function R({context:e}){return(t,n)=>{let r=new WeakMap;if(typeof n==`object`)return{get(){return t.get.call(this)},set(e){return r.get(this).setValue(e),t.set.call(this,e)},init(t){return r.set(this,new L(this,{context:e,initialValue:t})),t}};{t.constructor.addInitializer((t=>{r.set(t,new L(t,{context:e}))}));let i=Object.getOwnPropertyDescriptor(t,n),a;if(i===void 0){let e=new WeakMap;a={get(){return e.get(this)},set(t){r.get(this).setValue(t),e.set(this,t)},configurable:!0,enumerable:!0}}else{let e=i.set;a={...i,set(t){r.get(this).setValue(t),e?.call(this,t)}}}Object.defineProperty(t,n,a);return}}}function z({context:e,subscribe:t}){return(n,r)=>{typeof r==`object`?r.addInitializer((function(){new P(this,{context:e,callback:e=>{n.set.call(this,e)},subscribe:t})})):n.constructor.addInitializer((n=>{new P(n,{context:e,callback:e=>{n[r]=e},subscribe:t})}))}}let B=N(`ui-audio-player-context`);var V=class extends t.LitElement{constructor(...e){super(...e),this.src=``,this._animationFrameId=0,this.state={src:``,isPlaying:!1,isBuffering:!1,currentTime:0,duration:0,volume:1,muted:!1,analyserNode:void 0,play:()=>this.play(),pause:()=>this.pause(),togglePlay:()=>this._togglePlay(),seek:e=>this._seek(e),setVolume:e=>this._setVolume(e),toggleMute:()=>this._toggleMute()}}static{this.styles=t.css`
218
+ :host {
219
+ display: contents; /* We are completely invisible, just wrapping children */
220
+ }
221
+ audio {
222
+ display: none;
223
+ }
224
+ `}render(){return t.html`
225
+ <audio
226
+ crossorigin="anonymous"
227
+ src="${this.src}"
228
+ preload="metadata"
229
+ @loadedmetadata="${this._handleLoadedMetadata}"
230
+ @ended="${this._handleEnded}"
231
+ @playing="${this._handlePlaying}"
232
+ @pause="${this._handlePause}"
233
+ @waiting="${()=>this._updateState({isBuffering:!0})}"
234
+ @canplay="${()=>this._updateState({isBuffering:!1})}"
235
+ @error="${this._handleError}"
236
+ ></audio>
237
+ <slot></slot>
238
+ `}willUpdate(e){e.has(`src`)&&this._updateState({src:this.src,isPlaying:!1,currentTime:0,error:void 0})}updated(e){e.has(`src`)&&this._audioEl&&this._audioEl.load()}disconnectedCallback(){super.disconnectedCallback(),this._animationFrameId&&cancelAnimationFrame(this._animationFrameId),this._audioContext&&this._audioContext.state!==`closed`&&this._audioContext.close()}_updateState(e){this.state={...this.state,...e},this.dispatchEvent(new CustomEvent(`state-change`,{detail:this.state,bubbles:!0,composed:!0}))}_setupAudioContext(){if(!(this._audioContext||!this._audioEl))try{this._audioContext=new(window.AudioContext||window.webkitAudioContext),this._analyserNode=this._audioContext.createAnalyser(),this._analyserNode.fftSize=256,this._analyserNode.smoothingTimeConstant=.8,this._mediaSource=this._audioContext.createMediaElementSource(this._audioEl),this._mediaSource.connect(this._analyserNode),this._analyserNode.connect(this._audioContext.destination),this._updateState({analyserNode:this._analyserNode})}catch(e){console.warn(`Failed to set up AudioContext for visualizer:`,e)}}play(){this._audioEl.src&&(this._setupAudioContext(),this._audioContext?.state===`suspended`&&this._audioContext.resume(),this._audioEl.play().catch(e=>{console.error(`Error playing audio`,e),this._updateState({error:`Playback failed`})}))}pause(){this._audioEl&&this._audioEl.pause()}_togglePlay(){this.state.isPlaying?this.pause():this.play()}_seek(e){this._audioEl&&(this._audioEl.currentTime=e,this._updateState({currentTime:e}))}_setVolume(e){this._audioEl&&(this._audioEl.volume=e,this._updateState({volume:e,muted:e===0}))}_toggleMute(){this._audioEl&&(this._audioEl.muted=!this._audioEl.muted,this._updateState({muted:this._audioEl.muted}))}_handleLoadedMetadata(){this._updateState({duration:this._audioEl.duration})}_handleEnded(){this._updateState({isPlaying:!1,currentTime:0}),this._audioEl.currentTime=0}_handlePlaying(){this._updateState({isPlaying:!0,isBuffering:!1,error:void 0}),this._startTrackingTime()}_handlePause(){this._updateState({isPlaying:!1}),this._animationFrameId&&cancelAnimationFrame(this._animationFrameId)}_handleError(){this._updateState({error:`Error loading audio`,isPlaying:!1,isBuffering:!1})}_startTrackingTime(){let e=()=>{this._audioEl&&this.state.isPlaying&&(Math.abs(this.state.currentTime-this._audioEl.currentTime)>.05&&this._updateState({currentTime:this._audioEl.currentTime}),this._animationFrameId=requestAnimationFrame(e))};this._animationFrameId=requestAnimationFrame(e)}};T([(0,n.property)({type:String})],V.prototype,`src`,void 0),T([(0,n.query)(`audio`)],V.prototype,`_audioEl`,void 0),T([R({context:B}),(0,n.state)()],V.prototype,`state`,void 0),V=T([(0,n.customElement)(`ui-audio-provider`)],V);var H=class extends t.LitElement{static{this.styles=t.css`
239
+ :host {
240
+ display: inline-flex;
241
+ position: relative;
242
+ align-items: center;
243
+ justify-content: center;
244
+ font-family: inherit;
245
+ }
246
+
247
+ md-filled-icon-button {
248
+ --md-filled-icon-button-container-color: var(
249
+ --md-sys-color-primary,
250
+ #0066cc
251
+ );
252
+ --md-filled-icon-button-icon-color: var(
253
+ --md-sys-color-on-primary,
254
+ #ffffff
255
+ );
256
+ --md-filled-icon-button-hover-icon-color: var(
257
+ --md-sys-color-on-primary,
258
+ #ffffff
259
+ );
260
+ --md-filled-icon-button-focus-icon-color: var(
261
+ --md-sys-color-on-primary,
262
+ #ffffff
263
+ );
264
+ --md-filled-icon-button-pressed-icon-color: var(
265
+ --md-sys-color-on-primary,
266
+ #ffffff
267
+ );
268
+
269
+ --md-filled-icon-button-toggle-icon-color: var(
270
+ --md-sys-color-on-primary,
271
+ #ffffff
272
+ );
273
+ --md-filled-icon-button-selected-container-color: var(
274
+ --md-sys-color-primary,
275
+ #0066cc
276
+ );
277
+ --md-filled-icon-button-selected-icon-color: var(
278
+ --md-sys-color-on-primary,
279
+ #ffffff
280
+ );
281
+ color: var(--md-sys-color-on-primary, #ffffff);
282
+ }
283
+
284
+ md-circular-progress {
285
+ position: absolute;
286
+ --md-circular-progress-size: 48px;
287
+ }
288
+ `}render(){let e=this.playerState?.isPlaying??!1,n=this.playerState?.isBuffering??!1;return t.html`
289
+ <md-filled-icon-button
290
+ part="button"
291
+ @click="${this._handleClick}"
292
+ ?disabled="${!this.playerState?.src}"
293
+ >
294
+ <md-icon>${e?`pause`:`play_arrow`}</md-icon>
295
+ </md-filled-icon-button>
296
+ ${n&&e?t.html`<md-circular-progress indeterminate></md-circular-progress>`:``}
297
+ `}_handleClick(){this.playerState&&this.playerState.togglePlay()}};T([z({context:B,subscribe:!0}),(0,n.property)({attribute:!1})],H.prototype,`playerState`,void 0),H=T([(0,n.customElement)(`ui-audio-play-button`)],H);var U=class extends t.LitElement{constructor(...e){super(...e),this._isDragging=!1,this._dragValue=0}static{this.styles=t.css`
298
+ :host {
299
+ display: flex;
300
+ width: 100%;
301
+ align-items: center;
302
+ min-width: 100px;
303
+ }
304
+
305
+ md-slider {
306
+ width: 100%;
307
+ /* Give the slider track better contrast against backgrounds */
308
+ --md-slider-inactive-track-color: var(--md-sys-color-outline, #79747e);
309
+ }
310
+ `}render(){let e=this.playerState?.duration||0,n=e===0||!this.playerState?.src,r=this._isDragging?this._dragValue:this.playerState?.currentTime||0;return t.html`
311
+ <md-slider
312
+ min="0"
313
+ max="${e||100}"
314
+ value="${r}"
315
+ step="0.1"
316
+ ?disabled="${n}"
317
+ @input="${this._handleInput}"
318
+ @change="${this._handleChange}"
319
+ ></md-slider>
320
+ `}_handleInput(e){this._isDragging=!0,this._dragValue=e.target.value}_handleChange(e){this._dragValue=e.target.value,this.playerState&&this.playerState.seek(this._dragValue),this._isDragging=!1}};T([z({context:B,subscribe:!0}),(0,n.property)({attribute:!1})],U.prototype,`playerState`,void 0),U=T([(0,n.customElement)(`ui-audio-progress-slider`)],U);var W=class extends t.LitElement{constructor(...e){super(...e),this.format=`full`}static{this.styles=t.css`
321
+ :host {
322
+ display: inline-block;
323
+ font-variant-numeric: tabular-nums;
324
+ font-size: 14px;
325
+ color: var(--md-sys-color-on-surface-variant, #444);
326
+ font-family: inherit;
327
+ }
328
+ `}render(){let e=this.playerState?.currentTime||0,n=this.playerState?.duration||0;if(this.format===`elapsed`)return t.html`${this._formatTime(e)}`;if(this.format===`remaining`){let r=Math.max(0,n-e);return t.html`-${this._formatTime(r)}`}else return t.html`${this._formatTime(e)} /
329
+ ${n?this._formatTime(n):`--:--`}`}_formatTime(e){if(!e||isNaN(e))return`0:00`;let t=Math.floor(e/3600),n=Math.floor(e%3600/60),r=Math.floor(e%60),i=``;return t>0&&(i+=``+t+`:`+(n<10?`0`:``)),i+=``+n+`:`+(r<10?`0`:``),i+=``+r,i}};T([z({context:B,subscribe:!0}),(0,n.property)({attribute:!1})],W.prototype,`playerState`,void 0),T([(0,n.property)({type:String})],W.prototype,`format`,void 0),W=T([(0,n.customElement)(`ui-audio-time-display`)],W);var G=class extends t.LitElement{static{this.styles=t.css`
330
+ :host {
331
+ display: inline-block;
332
+ width: 100%;
333
+ max-width: 400px;
334
+ }
335
+
336
+ .player-pill {
337
+ display: flex;
338
+ align-items: center;
339
+ gap: 16px;
340
+ padding: 12px 24px;
341
+ background: var(--md-sys-color-surface-container-high, #e2e2e2);
342
+ border-radius: 999px; /* Pill shape */
343
+ width: fit-content;
344
+ font-family: inherit;
345
+ }
346
+
347
+ .time-container {
348
+ min-width: 85px; /* prevent jitter when times change */
349
+ }
350
+
351
+ .slider-container {
352
+ width: 200px;
353
+ display: flex;
354
+ align-items: center;
355
+ }
356
+ `}render(){return t.html`
357
+ <ui-audio-provider .src="${this.item?.src||``}">
358
+ <div class="player-pill" part="container">
359
+ <!-- Atomic Play/Pause Button -->
360
+ <ui-audio-play-button></ui-audio-play-button>
361
+
362
+ <!-- Atomic Time Display (Full format: 0:00 / 0:00) -->
363
+ <div class="time-container">
364
+ <ui-audio-time-display format="full"></ui-audio-time-display>
365
+ </div>
366
+
367
+ <!-- Atomic Slider -->
368
+ <div class="slider-container">
369
+ <ui-audio-progress-slider></ui-audio-progress-slider>
370
+ </div>
371
+ </div>
372
+ </ui-audio-provider>
373
+ `}};T([(0,n.property)({type:Object})],G.prototype,`item`,void 0),G=T([(0,n.customElement)(`ui-audio-player`)],G);var K=class extends t.LitElement{constructor(...e){super(...e),this.muted=!1,this.disabled=!1,this._devices=[],this._loading=!0,this._error=null,this._hasPermission=!1,this._isMenuOpen=!1,this._handleDeviceChange=()=>{this._hasPermission?this._loadDevicesWithPermission():this._loadDevicesWithoutPermission()}}static{this.styles=t.css`
374
+ :host {
375
+ display: inline-block;
376
+ position: relative;
377
+ font-family: inherit;
378
+ }
379
+
380
+ .anchor-button {
381
+ display: flex;
382
+ align-items: center;
383
+ gap: 8px;
384
+ padding: 8px 16px;
385
+ background: var(--md-sys-color-surface-container-high, #e2e2e2);
386
+ color: var(--md-sys-color-on-surface, #1e1e1e);
387
+ border-radius: 999px;
388
+ cursor: pointer;
389
+ border: none;
390
+ font-family: inherit;
391
+ font-size: 14px;
392
+ font-weight: 500;
393
+ transition: background-color 0.2s;
394
+ max-width: 250px;
395
+ }
396
+
397
+ .anchor-button:hover:not(:disabled) {
398
+ background: var(--md-sys-color-surface-container-highest, #e3e3e3);
399
+ }
400
+
401
+ .anchor-button:disabled {
402
+ opacity: 0.5;
403
+ cursor: not-allowed;
404
+ }
405
+
406
+ .label-text {
407
+ flex: 1;
408
+ white-space: nowrap;
409
+ overflow: hidden;
410
+ text-overflow: ellipsis;
411
+ text-align: left;
412
+ }
413
+
414
+ md-menu {
415
+ --md-menu-container-color: var(
416
+ --md-sys-color-surface-container,
417
+ var(--md-sys-color-surface, #ffffff)
418
+ );
419
+ --md-menu-container-shape: 12px;
420
+ min-width: 280px;
421
+ }
422
+
423
+ .menu-footer {
424
+ display: flex;
425
+ align-items: center;
426
+ justify-content: space-between;
427
+ padding: 8px 12px;
428
+ gap: 12px;
429
+ }
430
+
431
+ .preview-waveform {
432
+ flex: 1;
433
+ height: 24px;
434
+ background: var(
435
+ --md-sys-color-surface-variant,
436
+ var(--md-sys-color-surface-container-highest, #e1e2e1)
437
+ );
438
+ border-radius: 6px;
439
+ overflow: hidden;
440
+ display: flex;
441
+ align-items: center;
442
+ padding: 0 4px;
443
+ }
444
+ `}connectedCallback(){super.connectedCallback(),this._loadDevicesWithoutPermission(),navigator.mediaDevices.addEventListener(`devicechange`,this._handleDeviceChange)}disconnectedCallback(){super.disconnectedCallback(),navigator.mediaDevices.removeEventListener(`devicechange`,this._handleDeviceChange),this._stopPreview()}updated(e){super.updated(e),e.has(`_isMenuOpen`)&&this._isMenuOpen&&(!this._hasPermission&&!this._loading?this._loadDevicesWithPermission():this._hasPermission&&!this.muted&&this._startPreview()),(e.has(`_isMenuOpen`)&&!this._isMenuOpen||e.has(`muted`)&&this.muted)&&this._stopPreview(),e.has(`muted`)&&!this.muted&&this._isMenuOpen&&this._hasPermission&&this._startPreview()}render(){let e=this._devices.find(e=>e.deviceId===this.value)||this._devices[0]||{label:this._loading?`Loading...`:`No microphone`};return t.html`
445
+ <!-- Anchor Button -->
446
+ <button
447
+ id="anchor-button"
448
+ class="anchor-button"
449
+ ?disabled=${this._loading||this.disabled}
450
+ @click=${this._toggleMenu}
451
+ >
452
+ <md-icon>${this.muted?`mic_off`:`mic`}</md-icon>
453
+ <span class="label-text">${e.label}</span>
454
+ <md-icon style="font-size: 18px;">unfold_more</md-icon>
455
+ </button>
456
+
457
+ <!-- Dropdown Menu -->
458
+ <md-menu
459
+ id="device-menu"
460
+ anchor="anchor-button"
461
+ positioning="popover"
462
+ @closed=${()=>this._isMenuOpen=!1}
463
+ @opened=${()=>this._isMenuOpen=!0}
464
+ >
465
+ ${this._loading?t.html`<md-menu-item disabled
466
+ ><div slot="headline">Loading devices...</div></md-menu-item
467
+ >`:this._error?t.html`<md-menu-item disabled
468
+ ><div slot="headline" style="color: var(--md-sys-color-error)">
469
+ ${this._error}
470
+ </div></md-menu-item
471
+ >`:this._devices.map(e=>t.html`
472
+ <md-menu-item
473
+ @click=${()=>this._selectDevice(e.deviceId)}
474
+ ?selected=${this.value===e.deviceId||!this.value&&this._devices[0]?.deviceId===e.deviceId}
475
+ >
476
+ <div slot="headline">${e.label}</div>
477
+ ${this.value===e.deviceId||!this.value&&this._devices[0]?.deviceId===e.deviceId?t.html`<md-icon slot="end">check</md-icon>`:``}
478
+ </md-menu-item>
479
+ `)}
480
+ ${this._devices.length>0?t.html`
481
+ <md-divider></md-divider>
482
+ <div class="menu-footer">
483
+ <md-text-button @click=${this._toggleMute}>
484
+ <md-icon slot="icon"
485
+ >${this.muted?`mic_off`:`mic`}</md-icon
486
+ >
487
+ ${this.muted?`Unmute`:`Mute`}
488
+ </md-text-button>
489
+
490
+ <div class="preview-waveform">
491
+ <ui-live-waveform
492
+ .active=${this._isMenuOpen&&!this.muted&&this._hasPermission}
493
+ .processing=${!1}
494
+ .analyserNode=${this._previewAnalyser}
495
+ .barWidth=${3}
496
+ .barGap=${1}
497
+ .fadeEdges=${!1}
498
+ height="16"
499
+ ></ui-live-waveform>
500
+ </div>
501
+ </div>
502
+ `:``}
503
+ </md-menu>
504
+ `}_toggleMenu(){this._menuEl&&(this._menuEl.open=!this._menuEl.open,this._isMenuOpen=this._menuEl.open)}_selectDevice(e){this.value=e,this.dispatchEvent(new CustomEvent(`device-change`,{detail:{deviceId:e},bubbles:!0,composed:!0})),this._isMenuOpen&&!this.muted&&this._hasPermission&&this._startPreview()}_toggleMute(e){e.stopPropagation(),this.muted=!this.muted,this.dispatchEvent(new CustomEvent(`mute-change`,{detail:{muted:this.muted},bubbles:!0,composed:!0}))}async _loadDevicesWithoutPermission(){try{this._loading=!0,this._error=null;let e=await navigator.mediaDevices.enumerateDevices();this._parseDeviceList(e)}catch(e){this._error=e instanceof Error?e.message:`Failed to get audio devices`}finally{this._loading=!1}}async _loadDevicesWithPermission(){if(!this._loading)try{this._loading=!0,this._error=null,(await navigator.mediaDevices.getUserMedia({audio:!0})).getTracks().forEach(e=>e.stop());let e=await navigator.mediaDevices.enumerateDevices();this._parseDeviceList(e),this._hasPermission=!0,this._isMenuOpen&&!this.muted&&this._startPreview()}catch(e){this._error=e instanceof Error?e.message:`Permission denied`}finally{this._loading=!1}}_parseDeviceList(e){let t=e.filter(e=>e.kind===`audioinput`).map(e=>{let t=e.label||"Microphone ${device.deviceId.slice(0, 8)}";return t=t.replace(/\s*\([^)]*\)/g,``).trim(),{deviceId:e.deviceId,label:t,groupId:e.groupId}});this._devices=t,!this.value&&t.length>0&&(this.value=t[0].deviceId,this.dispatchEvent(new CustomEvent(`device-change`,{detail:{deviceId:this.value},bubbles:!0,composed:!0})))}async _startPreview(){if(this._stopPreview(),this.value)try{this._previewStream=await navigator.mediaDevices.getUserMedia({audio:{deviceId:{exact:this.value}}}),this._previewAudioContext=new(window.AudioContext||window.webkitAudioContext),this._previewAnalyser=this._previewAudioContext.createAnalyser(),this._previewAnalyser.fftSize=256,this._previewAnalyser.smoothingTimeConstant=.8,this._previewAudioContext.createMediaStreamSource(this._previewStream).connect(this._previewAnalyser)}catch(e){console.warn(`Failed to start preview stream`,e)}}_stopPreview(){this._previewStream&&=(this._previewStream.getTracks().forEach(e=>e.stop()),void 0),this._previewAudioContext&&this._previewAudioContext.state!==`closed`&&(this._previewAudioContext.close(),this._previewAudioContext=void 0),this._previewAnalyser=void 0}};T([(0,n.property)({type:String})],K.prototype,`value`,void 0),T([(0,n.property)({type:Boolean})],K.prototype,`muted`,void 0),T([(0,n.property)({type:Boolean})],K.prototype,`disabled`,void 0),T([(0,n.state)()],K.prototype,`_devices`,void 0),T([(0,n.state)()],K.prototype,`_loading`,void 0),T([(0,n.state)()],K.prototype,`_error`,void 0),T([(0,n.state)()],K.prototype,`_hasPermission`,void 0),T([(0,n.state)()],K.prototype,`_isMenuOpen`,void 0),T([(0,n.state)()],K.prototype,`_previewAnalyser`,void 0),T([(0,n.query)(`md-menu`)],K.prototype,`_menuEl`,void 0),K=T([(0,n.customElement)(`ui-mic-selector`)],K);var q=class extends t.LitElement{constructor(...e){super(...e),this.voices=[],this.placeholder=`Select a voice...`,this.idKey=`voiceId`,this.titleKey=`name`,this.subtitleKey=`category`,this.previewUrlKey=`previewUrl`,this.useOrbs=!1,this.colorKey=`colors`,this._searchQuery=``}static{this.styles=t.css`
505
+ :host {
506
+ display: inline-block;
507
+ width: 100%;
508
+ font-family: inherit;
509
+ }
510
+
511
+ .anchor-button {
512
+ display: flex;
513
+ align-items: center;
514
+ justify-content: space-between;
515
+ width: 100%;
516
+ padding: 8px 16px;
517
+ background: transparent;
518
+ border: 1px solid var(--md-sys-color-outline, #79747e);
519
+ border-radius: 8px;
520
+ color: var(--md-sys-color-on-surface, #1e1e1e);
521
+ cursor: pointer;
522
+ font-family: inherit;
523
+ font-size: 14px;
524
+ min-height: 48px;
525
+ transition:
526
+ background-color 0.2s,
527
+ border-color 0.2s;
528
+ }
529
+
530
+ .anchor-button:hover {
531
+ background: var(--md-sys-color-surface-container-highest, #e3e3e3);
532
+ }
533
+
534
+ .anchor-button:focus-visible {
535
+ outline: none;
536
+ border-color: var(--md-sys-color-primary, #0066cc);
537
+ box-shadow: 0 0 0 1px var(--md-sys-color-primary, #0066cc);
538
+ }
539
+
540
+ .trigger-content {
541
+ display: flex;
542
+ align-items: center;
543
+ justify-content: space-between;
544
+ width: 100%;
545
+ min-width: 100%;
546
+ padding: 4px 0;
547
+ }
548
+
549
+ .trigger-left {
550
+ display: flex;
551
+ align-items: center;
552
+ gap: 12px;
553
+ overflow: hidden;
554
+ }
555
+
556
+ .trigger-icon {
557
+ width: 24px;
558
+ height: 24px;
559
+ border-radius: 50%;
560
+ background: var(--md-sys-color-primary-container);
561
+ color: var(--md-sys-color-on-primary-container);
562
+ display: flex;
563
+ align-items: center;
564
+ justify-content: center;
565
+ flex-shrink: 0;
566
+ }
567
+
568
+ .trigger-text {
569
+ white-space: nowrap;
570
+ overflow: hidden;
571
+ text-overflow: ellipsis;
572
+ color: var(--md-sys-color-on-surface);
573
+ }
574
+
575
+ md-menu {
576
+ --md-menu-container-shape: 12px;
577
+ --md-menu-container-color: var(--md-sys-color-surface-container, #f3f3f3);
578
+ max-width: 400px;
579
+ }
580
+
581
+ .search-container {
582
+ padding: 8px 12px;
583
+ background: var(--md-sys-color-surface-container, #f3f3f3);
584
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
585
+ }
586
+
587
+ md-outlined-text-field {
588
+ width: 100%;
589
+ --md-outlined-text-field-container-shape: 8px;
590
+ }
591
+
592
+ md-menu-item {
593
+ --md-menu-item-hover-state-layer-color: var(
594
+ --md-sys-color-on-surface-variant
595
+ );
596
+ --md-menu-item-focus-state-layer-color: var(
597
+ --md-sys-color-on-surface-variant
598
+ );
599
+ }
600
+
601
+ .voice-item-content {
602
+ display: flex;
603
+ align-items: center;
604
+ gap: 16px;
605
+ width: 100%;
606
+ padding: 8px 0;
607
+ }
608
+
609
+ .voice-avatar {
610
+ position: relative;
611
+ width: 32px;
612
+ height: 32px;
613
+ border-radius: 50%;
614
+ background: var(--md-sys-color-surface-variant);
615
+ display: flex;
616
+ align-items: center;
617
+ justify-content: center;
618
+ flex-shrink: 0;
619
+ cursor: pointer;
620
+ overflow: hidden;
621
+ color: var(--md-sys-color-on-surface-variant);
622
+ z-index: 2; /* Keep above the menu item ripple */
623
+ }
624
+
625
+ .voice-avatar:hover .play-overlay {
626
+ opacity: 1;
627
+ }
628
+
629
+ .play-overlay {
630
+ position: absolute;
631
+ inset: 0;
632
+ background: rgba(0, 0, 0, 0.4);
633
+ display: flex;
634
+ align-items: center;
635
+ justify-content: center;
636
+ color: white;
637
+ opacity: 0;
638
+ transition: opacity 0.2s;
639
+ border-radius: 50%;
640
+ }
641
+
642
+ .play-overlay.active {
643
+ opacity: 1;
644
+ background: rgba(0, 0, 0, 0.6);
645
+ }
646
+
647
+ .voice-info {
648
+ display: flex;
649
+ flex-direction: column;
650
+ gap: 2px;
651
+ flex: 1;
652
+ overflow: hidden;
653
+ }
654
+
655
+ .voice-name {
656
+ font-weight: 500;
657
+ font-size: 14px;
658
+ white-space: nowrap;
659
+ overflow: hidden;
660
+ text-overflow: ellipsis;
661
+ color: var(--md-sys-color-on-surface);
662
+ }
663
+
664
+ .voice-labels {
665
+ display: flex;
666
+ align-items: center;
667
+ gap: 6px;
668
+ font-size: 12px;
669
+ color: var(--md-sys-color-on-surface-variant);
670
+ white-space: nowrap;
671
+ overflow: hidden;
672
+ text-overflow: ellipsis;
673
+ }
674
+
675
+ .label-dot {
676
+ font-size: 8px;
677
+ }
678
+
679
+ .empty-state {
680
+ padding: 24px;
681
+ text-align: center;
682
+ color: var(--md-sys-color-on-surface-variant);
683
+ font-size: 14px;
684
+ }
685
+ `}render(){let e=this.voices.find(e=>e[this.idKey]===this.value),n=this.voices.filter(e=>{if(!this._searchQuery)return!0;let t=this._searchQuery.toLowerCase();return e[this.titleKey].toLowerCase().includes(t)||e.labels?.accent?.toLowerCase().includes(t)||e.labels?.gender?.toLowerCase().includes(t)||e.labels?.age?.toLowerCase().includes(t)});return t.html`
686
+ <!-- Hidden audio player for previews -->
687
+ <audio
688
+ crossorigin="anonymous"
689
+ @ended=${()=>this._previewingVoiceId=void 0}
690
+ @pause=${()=>this._previewingVoiceId=void 0}
691
+ ></audio>
692
+
693
+ <!-- Anchor Button -->
694
+ <button
695
+ class="anchor-button"
696
+ part="button"
697
+ id="voice-anchor"
698
+ @click=${this._toggleMenu}
699
+ >
700
+ <div class="trigger-content">
701
+ <div class="trigger-left">
702
+ ${e?t.html`
703
+ <div
704
+ class="trigger-icon"
705
+ style="${this.useOrbs?`overflow: hidden;`:``}"
706
+ >
707
+ ${this.useOrbs?t.html`<ui-orb
708
+ agentState="listening"
709
+ .colors="${e[this.colorKey]||[`#CADCFC`,`#A0B9D1`]}"
710
+ ></ui-orb>`:t.html`<md-icon style="font-size: 16px;"
711
+ >record_voice_over</md-icon
712
+ >`}
713
+ </div>
714
+ <span class="trigger-text"
715
+ >${e[this.titleKey]||e.name}</span
716
+ >
717
+ `:t.html`
718
+ <span
719
+ class="trigger-text"
720
+ style="color: var(--md-sys-color-on-surface-variant)"
721
+ >${this.placeholder}</span
722
+ >
723
+ `}
724
+ </div>
725
+ <md-icon style="color: var(--md-sys-color-on-surface-variant);"
726
+ >unfold_more</md-icon
727
+ >
728
+ </div>
729
+ </button>
730
+
731
+ <!-- Dropdown Menu -->
732
+ <md-menu
733
+ id="voice-menu"
734
+ anchor="voice-anchor"
735
+ positioning="popover"
736
+ @closed=${this._handleMenuClosed}
737
+ >
738
+ <!-- The click.stop modifier stops the menu from closing when searching -->
739
+ <div
740
+ class="search-container"
741
+ @click=${e=>e.stopPropagation()}
742
+ >
743
+ <md-outlined-text-field
744
+ placeholder="Search voices..."
745
+ .value=${this._searchQuery}
746
+ @input=${e=>this._searchQuery=e.target.value}
747
+ >
748
+ <md-icon slot="leading-icon">search</md-icon>
749
+ </md-outlined-text-field>
750
+ </div>
751
+
752
+ ${n.length===0?t.html` <div class="empty-state">No voice found.</div> `:n.map(e=>t.html`
753
+ <md-menu-item
754
+ @click=${()=>this._selectVoice(e[this.idKey])}
755
+ ?selected=${this.value===e[this.idKey]}
756
+ >
757
+ <div slot="headline" class="voice-item-content">
758
+ <!-- Avatar / Preview Button -->
759
+ <div
760
+ class="voice-avatar"
761
+ @click=${t=>this._togglePreview(t,e)}
762
+ >
763
+ ${this.useOrbs?t.html`<ui-orb
764
+ agentState="${this._previewingVoiceId===e[this.idKey]?`talking`:`listening`}"
765
+ .colors="${e[this.colorKey]||[`#CADCFC`,`#A0B9D1`]}"
766
+ ></ui-orb>`:t.html`<md-icon style="font-size: 18px;"
767
+ >face</md-icon
768
+ >`}
769
+ ${e[this.previewUrlKey]?t.html`
770
+ <div
771
+ class="play-overlay ${this._previewingVoiceId===e[this.idKey]?`active`:``}"
772
+ >
773
+ <md-icon style="font-size: 16px;">
774
+ ${this._previewingVoiceId===e[this.idKey]?`pause`:`play_arrow`}
775
+ </md-icon>
776
+ </div>
777
+ `:``}
778
+ </div>
779
+
780
+ <!-- Voice Info -->
781
+ <div class="voice-info">
782
+ <span class="voice-name">${e[this.titleKey]}</span>
783
+ ${e[this.subtitleKey]||e.labels?t.html`
784
+ <div class="voice-labels">
785
+ ${e[this.subtitleKey]?t.html`<span class="voice-badge"
786
+ >${e[this.subtitleKey]}</span
787
+ >`:Object.values(e.labels||{}).filter(Boolean).map(e=>t.html`<span class="voice-badge"
788
+ >${e}</span
789
+ >`)}
790
+ </div>
791
+ `:``}
792
+ </div>
793
+ </div>
794
+
795
+ ${this.value===e[this.idKey]?t.html`<md-icon slot="end">check</md-icon>`:``}
796
+ </md-menu-item>
797
+ `)}
798
+ </md-menu>
799
+ `}_toggleMenu(){this._menuEl&&(this._menuEl.open=!this._menuEl.open)}_handleMenuClosed(){this._stopPreview()}_selectVoice(e){this.value=e,this.dispatchEvent(new CustomEvent(`voice-change`,{detail:{voiceId:e},bubbles:!0,composed:!0}))}_togglePreview(e,t){e.stopPropagation(),e.preventDefault(),!(!t[this.previewUrlKey]||!this._audioEl)&&(this._previewingVoiceId===t[this.idKey]?this._stopPreview():(this._audioEl.src=t[this.previewUrlKey],this._audioEl.play().catch(console.error),this._previewingVoiceId=t[this.idKey]))}_stopPreview(){this._audioEl&&(this._audioEl.pause(),this._audioEl.currentTime=0),this._previewingVoiceId=void 0}};T([(0,n.property)({type:Array})],q.prototype,`voices`,void 0),T([(0,n.property)({type:String})],q.prototype,`value`,void 0),T([(0,n.property)({type:String})],q.prototype,`placeholder`,void 0),T([(0,n.property)({type:String})],q.prototype,`idKey`,void 0),T([(0,n.property)({type:String})],q.prototype,`titleKey`,void 0),T([(0,n.property)({type:String})],q.prototype,`subtitleKey`,void 0),T([(0,n.property)({type:String})],q.prototype,`previewUrlKey`,void 0),T([(0,n.property)({type:Boolean})],q.prototype,`useOrbs`,void 0),T([(0,n.property)({type:String})],q.prototype,`colorKey`,void 0),T([(0,n.state)()],q.prototype,`_searchQuery`,void 0),T([(0,n.state)()],q.prototype,`_previewingVoiceId`,void 0),T([(0,n.query)(`md-menu`)],q.prototype,`_menuEl`,void 0),T([(0,n.query)(`audio`)],q.prototype,`_audioEl`,void 0),q=T([(0,n.customElement)(`ui-voice-picker`)],q);var J=class extends t.LitElement{constructor(...e){super(...e),this.speed=50,this.barCount=60,this.barWidth=4,this.barHeight=4,this.barGap=2,this.barRadius=2,this.fadeEdges=!0,this.fadeWidth=24,this.height=128,this.active=!0,this._animationFrameId=0,this._lastTime=0,this._bars=[],this._seed=Math.random(),this._dataIndex=0}static{this.styles=t.css`
800
+ :host {
801
+ display: block;
802
+ width: 100%;
803
+ }
804
+ .container {
805
+ position: relative;
806
+ width: 100%;
807
+ overflow: hidden;
808
+ }
809
+ canvas {
810
+ position: absolute;
811
+ top: 0;
812
+ left: 0;
813
+ display: block;
814
+ height: 100%;
815
+ width: 100%;
816
+ }
817
+ `}render(){return t.html`
818
+ <div class="container" style="height: ${this.height}px;">
819
+ <canvas></canvas>
820
+ </div>
821
+ `}firstUpdated(){this._resizeObserver=new ResizeObserver(()=>{this._handleResize()}),this._resizeObserver.observe(this._container),this._canvas&&this._container&&this._populateInitialBars(),this._startAnimation()}disconnectedCallback(){super.disconnectedCallback(),this._resizeObserver&&this._resizeObserver.disconnect(),this._animationFrameId&&cancelAnimationFrame(this._animationFrameId)}_handleResize(){if(!this._canvas||!this._container)return;let e=this._container.getBoundingClientRect(),t=window.devicePixelRatio||1;this._canvas.width=e.width*t,this._canvas.height=e.height*t,this._canvas.style.width=`${e.width}px`,this._canvas.style.height=`${e.height}px`;let n=this._canvas.getContext(`2d`);n&&n.scale(t,t)}_seededRandom(e){let t=Math.sin(this._seed*1e4+e*137.5)*1e4;return t-Math.floor(t)}_populateInitialBars(){let e=this._container.getBoundingClientRect(),t=this.barWidth+this.barGap,n=e.width,r=0;for(this._bars=[];n>-t;)this._bars.push({x:n,height:.2+this._seededRandom(r++)*.6}),n-=t;this._bars.reverse()}_startAnimation(){this._lastTime=performance.now();let e=t=>{if(!this._canvas)return;let n=this._canvas.getContext(`2d`);if(!n)return;let r=this._lastTime?(t-this._lastTime)/1e3:0;this._lastTime=t;let i=this._canvas.getBoundingClientRect();n.clearRect(0,0,i.width,i.height);let a=this.barColor;a||=getComputedStyle(this).getPropertyValue(`--md-sys-color-primary`).trim()||`#0066cc`;let o=this.barWidth+this.barGap,s=this.active?this.speed:0;for(let e=0;e<this._bars.length;e++)this._bars[e].x-=s*r,this.active||(this._bars[e].height+=(.05-this._bars[e].height)*.15);for(this._bars=this._bars.filter(e=>e.x+this.barWidth>-o);this._bars.length===0||this._bars[this._bars.length-1].x<i.width;){let e=this._bars[this._bars.length-1],t=e?e.x+o:i.width,n;if(this.data&&this.data.length>0)n=this.data[this._dataIndex%this.data.length]||.1,this._dataIndex=(this._dataIndex+1)%this.data.length;else if(this.analyserNode){(!this._dataArray||this._dataArray.length!==this.analyserNode.frequencyBinCount)&&(this._dataArray=new Uint8Array(this.analyserNode.frequencyBinCount)),this.analyserNode.getByteFrequencyData(this._dataArray);let e=0,t=Math.min(this._dataArray.length,50);for(let n=0;n<t;n++)e+=this._dataArray[n];let r=e/t/255;n=Math.max(.1,r**1.5*1.5)}else{let e=Date.now()/1e3,t=this._bars.length+e*.01,r=Math.sin(t*.1)*.2,i=Math.cos(t*.05)*.15,a=this._seededRandom(t)*.4;n=Math.max(.1,Math.min(.9,.3+r+i+a))}if(this._bars.push({x:t,height:n}),this._bars.length>this.barCount*2)break}let c=i.height/2;for(let e of this._bars)if(e.x<i.width&&e.x+this.barWidth>0){let t=Math.max(this.barHeight,e.height*i.height*.8),r=c-t/2;n.fillStyle=a,n.globalAlpha=.3+e.height*.7,this.barRadius>0?(n.beginPath(),n.roundRect(e.x,r,this.barWidth,t,this.barRadius),n.fill()):n.fillRect(e.x,r,this.barWidth,t)}n.globalAlpha=1,this.fadeEdges&&this.fadeWidth>0&&O(n,i.width,i.height,this.fadeWidth),this._animationFrameId=requestAnimationFrame(e)};this._animationFrameId=requestAnimationFrame(e)}};T([(0,n.property)({type:Number})],J.prototype,`speed`,void 0),T([(0,n.property)({type:Number})],J.prototype,`barCount`,void 0),T([(0,n.property)({type:Number})],J.prototype,`barWidth`,void 0),T([(0,n.property)({type:Number})],J.prototype,`barHeight`,void 0),T([(0,n.property)({type:Number})],J.prototype,`barGap`,void 0),T([(0,n.property)({type:Number})],J.prototype,`barRadius`,void 0),T([(0,n.property)({type:String})],J.prototype,`barColor`,void 0),T([(0,n.property)({type:Boolean})],J.prototype,`fadeEdges`,void 0),T([(0,n.property)({type:Number})],J.prototype,`fadeWidth`,void 0),T([(0,n.property)({type:Number})],J.prototype,`height`,void 0),T([(0,n.property)({type:Array})],J.prototype,`data`,void 0),T([(0,n.property)({attribute:!1})],J.prototype,`analyserNode`,void 0),T([(0,n.property)({type:Boolean})],J.prototype,`active`,void 0),T([(0,n.query)(`canvas`)],J.prototype,`_canvas`,void 0),T([(0,n.query)(`.container`)],J.prototype,`_container`,void 0),J=T([(0,n.customElement)(`ui-scrolling-waveform`)],J);var Y=class extends t.LitElement{constructor(...e){super(...e),this.title=`Component`,this.description=``,this.mode=`preview`}static{this.styles=t.css`
822
+ :host {
823
+ display: block;
824
+ background: var(--md-sys-color-surface, #ffffff);
825
+ color: var(--md-sys-color-on-surface, #1e1e1e);
826
+ border-radius: 12px;
827
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
828
+ transition:
829
+ background-color 0.3s,
830
+ color 0.3s;
831
+ overflow: hidden;
832
+ font-family: inherit;
833
+ border: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);
834
+ }
835
+
836
+ .header {
837
+ padding: 1.5rem 2rem 1rem 2rem;
838
+ }
839
+
840
+ .title {
841
+ margin-top: 0;
842
+ margin-bottom: 0.5rem;
843
+ font-size: 1.4rem;
844
+ font-weight: 600;
845
+ }
846
+
847
+ .description {
848
+ margin: 0;
849
+ font-size: 0.95rem;
850
+ color: var(--md-sys-color-on-surface-variant, #444444);
851
+ line-height: 1.5;
852
+ }
853
+
854
+ .tabs {
855
+ display: flex;
856
+ gap: 8px;
857
+ padding: 0 2rem;
858
+ border-bottom: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);
859
+ }
860
+
861
+ .tab-btn {
862
+ padding: 8px 16px;
863
+ background: transparent;
864
+ border: none;
865
+ border-bottom: 2px solid transparent;
866
+ color: var(--md-sys-color-on-surface-variant, #444444);
867
+ font-family: inherit;
868
+ font-weight: 600;
869
+ font-size: 0.9rem;
870
+ cursor: pointer;
871
+ transition: all 0.2s;
872
+ }
873
+
874
+ .tab-btn:hover {
875
+ color: var(--md-sys-color-primary, #0066cc);
876
+ background: var(--md-sys-color-surface-container-highest, #e3e3e3);
877
+ }
878
+
879
+ .tab-btn.active {
880
+ color: var(--md-sys-color-primary, #0066cc);
881
+ border-bottom-color: var(--md-sys-color-primary, #0066cc);
882
+ }
883
+
884
+ .content-area {
885
+ padding: 2rem;
886
+ position: relative;
887
+ background: var(--md-sys-color-surface, #ffffff);
888
+ }
889
+
890
+ .preview-panel {
891
+ display: none;
892
+ }
893
+
894
+ .preview-panel.active {
895
+ display: block;
896
+ }
897
+
898
+ .code-panel {
899
+ display: none;
900
+ background: #1e1e1e; /* Standard terminal color */
901
+ color: #e3e3e3;
902
+ padding: 1.5rem;
903
+ border-radius: 8px;
904
+ overflow-x: auto;
905
+ font-family: 'Courier New', Courier, monospace;
906
+ font-size: 0.85rem;
907
+ line-height: 1.5;
908
+ margin: 0;
909
+ }
910
+
911
+ .code-panel.active {
912
+ display: block;
913
+ }
914
+ `}render(){return t.html`
915
+ <div class="header">
916
+ <h2 class="title">${this.title}</h2>
917
+ ${this.description?t.html`<p class="description">${this.description}</p>`:``}
918
+ </div>
919
+
920
+ <div class="tabs">
921
+ <button
922
+ class="tab-btn ${this.mode===`preview`?`active`:``}"
923
+ @click="${()=>this.mode=`preview`}"
924
+ >
925
+ Preview
926
+ </button>
927
+ <button
928
+ class="tab-btn ${this.mode===`code`?`active`:``}"
929
+ @click="${()=>this.mode=`code`}"
930
+ >
931
+ Code
932
+ </button>
933
+ </div>
934
+
935
+ <div class="content-area">
936
+ <div class="preview-panel ${this.mode===`preview`?`active`:``}">
937
+ <slot></slot>
938
+ </div>
939
+
940
+ <pre
941
+ class="code-panel ${this.mode===`code`?`active`:``}"
942
+ ><code><slot name="code"></slot></code></pre>
943
+ </div>
944
+ `}};T([(0,n.property)({type:String})],Y.prototype,`title`,void 0),T([(0,n.property)({type:String})],Y.prototype,`description`,void 0),T([(0,n.property)({type:String})],Y.prototype,`mode`,void 0),Y=T([(0,n.customElement)(`ui-showcase-card`)],Y);var X=class extends t.LitElement{constructor(...e){super(...e),this.text=``,this.duration=2,this.delay=0,this.repeat=!0,this.repeatDelay=.5,this.startOnView=!0,this.once=!1,this.spread=2,this._isInView=!1}static{this.styles=t.css`
945
+ :host {
946
+ display: inline-block;
947
+ font-family: inherit;
948
+ }
949
+
950
+ span {
951
+ position: relative;
952
+ display: inline-block;
953
+
954
+ /* Default colors fallback to MD3 tokens if available */
955
+ /* Use a highly transparent base color for maximum contrast against the shimmer */
956
+ --base-color: color-mix(
957
+ in srgb,
958
+ var(--md-sys-color-on-surface, #1e1e1e) 20%,
959
+ transparent
960
+ );
961
+ --shimmer-color: var(--md-sys-color-on-surface, #1e1e1e);
962
+
963
+ --shimmer-bg: linear-gradient(
964
+ 90deg,
965
+ transparent calc(50% - var(--spread)),
966
+ var(--shimmer-color) 50%,
967
+ transparent calc(50% + var(--spread))
968
+ );
969
+
970
+ background-image:
971
+ var(--shimmer-bg), linear-gradient(var(--base-color), var(--base-color));
972
+ background-size:
973
+ 250% 100%,
974
+ auto; /* Important: this defines the size of the animated gradient */
975
+ background-position: 100% center;
976
+ background-repeat: no-repeat;
977
+ -webkit-background-clip: text;
978
+ background-clip: text;
979
+ color: transparent;
980
+ -webkit-text-fill-color: transparent;
981
+ opacity: 0;
982
+ transition: opacity 0.3s ease;
983
+ }
984
+
985
+ /* When active, trigger the keyframe animation */
986
+ span.active {
987
+ opacity: 1;
988
+ }
989
+
990
+ @keyframes shimmer {
991
+ 0% {
992
+ background-position: 100% center;
993
+ }
994
+ 100% {
995
+ background-position: 0% center;
996
+ }
997
+ }
998
+ `}firstUpdated(){this.startOnView?(this._intersectionObserver=new IntersectionObserver(e=>{e.forEach(e=>{e.isIntersecting?(this._isInView=!0,this.once&&this._intersectionObserver&&this._intersectionObserver.disconnect()):this.once||(this._isInView=!1)})}),this._intersectionObserver.observe(this)):this._isInView=!0}disconnectedCallback(){super.disconnectedCallback(),this._intersectionObserver&&this._intersectionObserver.disconnect()}render(){let e=!this.startOnView||this._isInView,n=`${this.text.length*this.spread}px`,r=this.duration+this.repeatDelay,i=this.repeat?`infinite`:`1`,a={"--spread":n,...this.color&&{"--base-color":this.color},...this.shimmerColor&&{"--shimmer-color":this.shimmerColor},"animation-name":e?`shimmer`:`none`,"animation-duration":`${r}s`,"animation-timing-function":`linear`,"animation-delay":`${this.delay}s`,"animation-iteration-count":i,"background-position":e&&!this.repeat?`0% center`:`100% center`},o=Object.entries(a).map(([e,t])=>`${e}: ${t}`).join(`; `);return t.html`
999
+ <span class="${e?`active`:``}" style="${o}">
1000
+ ${this.text}
1001
+ </span>
1002
+ `}};T([(0,n.property)({type:String})],X.prototype,`text`,void 0),T([(0,n.property)({type:Number})],X.prototype,`duration`,void 0),T([(0,n.property)({type:Number})],X.prototype,`delay`,void 0),T([(0,n.property)({type:Boolean})],X.prototype,`repeat`,void 0),T([(0,n.property)({type:Number})],X.prototype,`repeatDelay`,void 0),T([(0,n.property)({type:Boolean})],X.prototype,`startOnView`,void 0),T([(0,n.property)({type:Boolean})],X.prototype,`once`,void 0),T([(0,n.property)({type:Number})],X.prototype,`spread`,void 0),T([(0,n.property)({type:String})],X.prototype,`color`,void 0),T([(0,n.property)({type:String})],X.prototype,`shimmerColor`,void 0),T([(0,n.state)()],X.prototype,`_isInView`,void 0),X=T([(0,n.customElement)(`ui-shimmering-text`)],X);var Z=class extends t.LitElement{constructor(...e){super(...e),this.agentState=null,this.inputVolume=0,this.outputVolume=0,this.volumeMode=`auto`,this.seed=Math.floor(Math.random()*2**32),this._animationFrameId=0,this._animSpeed=.1,this._curIn=0,this._curOut=0,this._textureLoader=new g.TextureLoader,this._lastTime=0,this._vertexShader=`
1003
+ uniform float uTime;
1004
+ uniform sampler2D uPerlinTexture;
1005
+ varying vec2 vUv;
1006
+
1007
+ void main() {
1008
+ vUv = uv;
1009
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
1010
+ }
1011
+ `,this._fragmentShader=`
1012
+ uniform float uTime;
1013
+ uniform float uAnimation;
1014
+ uniform float uInverted;
1015
+ uniform float uOffsets[7];
1016
+ uniform vec3 uColor1;
1017
+ uniform vec3 uColor2;
1018
+ uniform float uInputVolume;
1019
+ uniform float uOutputVolume;
1020
+ uniform float uOpacity;
1021
+ uniform sampler2D uPerlinTexture;
1022
+ varying vec2 vUv;
1023
+
1024
+ const float PI = 3.14159265358979323846;
1025
+
1026
+ bool drawOval(vec2 polarUv, vec2 polarCenter, float a, float b, bool reverseGradient, float softness, out vec4 color) {
1027
+ vec2 p = polarUv - polarCenter;
1028
+ float oval = (p.x * p.x) / (a * a) + (p.y * p.y) / (b * b);
1029
+ float edge = smoothstep(1.0, 1.0 - softness, oval);
1030
+ if (edge > 0.0) {
1031
+ float gradient = reverseGradient ? (1.0 - (p.x / a + 1.0) / 2.0) : ((p.x / a + 1.0) / 2.0);
1032
+ gradient = mix(0.5, gradient, 0.1);
1033
+ color = vec4(vec3(gradient), 0.85 * edge);
1034
+ return true;
1035
+ }
1036
+ return false;
1037
+ }
1038
+
1039
+ vec3 colorRamp(float grayscale, vec3 color1, vec3 color2, vec3 color3, vec3 color4) {
1040
+ if (grayscale < 0.33) {
1041
+ return mix(color1, color2, grayscale * 3.0);
1042
+ } else if (grayscale < 0.66) {
1043
+ return mix(color2, color3, (grayscale - 0.33) * 3.0);
1044
+ } else {
1045
+ return mix(color3, color4, (grayscale - 0.66) * 3.0);
1046
+ }
1047
+ }
1048
+
1049
+ vec2 hash2(vec2 p) {
1050
+ return fract(sin(vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)))) * 43758.5453);
1051
+ }
1052
+
1053
+ float noise2D(vec2 p) {
1054
+ vec2 i = floor(p);
1055
+ vec2 f = fract(p);
1056
+ vec2 u = f * f * (3.0 - 2.0 * f);
1057
+ float n = mix(
1058
+ mix(dot(hash2(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)),
1059
+ dot(hash2(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x),
1060
+ mix(dot(hash2(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)),
1061
+ dot(hash2(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x),
1062
+ u.y
1063
+ );
1064
+ return 0.5 + 0.5 * n;
1065
+ }
1066
+
1067
+ float sharpRing(vec3 decomposed, float time) {
1068
+ float ringStart = 1.0;
1069
+ float ringWidth = 0.3;
1070
+ float noiseScale = 5.0;
1071
+ float noise = mix(
1072
+ noise2D(vec2(decomposed.x, time) * noiseScale),
1073
+ noise2D(vec2(decomposed.y, time) * noiseScale),
1074
+ decomposed.z
1075
+ );
1076
+ noise = (noise - 0.5) * 2.5;
1077
+ return ringStart + noise * ringWidth * 1.5;
1078
+ }
1079
+
1080
+ float smoothRing(vec3 decomposed, float time) {
1081
+ float ringStart = 0.9;
1082
+ float ringWidth = 0.2;
1083
+ float noiseScale = 6.0;
1084
+ float noise = mix(
1085
+ noise2D(vec2(decomposed.x, time) * noiseScale),
1086
+ noise2D(vec2(decomposed.y, time) * noiseScale),
1087
+ decomposed.z
1088
+ );
1089
+ noise = (noise - 0.5) * 5.0;
1090
+ return ringStart + noise * ringWidth;
1091
+ }
1092
+
1093
+ float flow(vec3 decomposed, float time) {
1094
+ return mix(
1095
+ texture(uPerlinTexture, vec2(time, decomposed.x / 2.0)).r,
1096
+ texture(uPerlinTexture, vec2(time, decomposed.y / 2.0)).r,
1097
+ decomposed.z
1098
+ );
1099
+ }
1100
+
1101
+ void main() {
1102
+ vec2 uv = vUv * 2.0 - 1.0;
1103
+ float radius = length(uv);
1104
+ float theta = atan(uv.y, uv.x);
1105
+ if (theta < 0.0) theta += 2.0 * PI;
1106
+
1107
+ vec3 decomposed = vec3(
1108
+ theta / (2.0 * PI),
1109
+ mod(theta / (2.0 * PI) + 0.5, 1.0) + 1.0,
1110
+ abs(theta / PI - 1.0)
1111
+ );
1112
+
1113
+ float noise = flow(decomposed, radius * 0.03 - uAnimation * 0.2) - 0.5;
1114
+ theta += noise * mix(0.08, 0.25, uOutputVolume);
1115
+
1116
+ vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
1117
+ float originalCenters[7] = float[7](0.0, 0.5 * PI, 1.0 * PI, 1.5 * PI, 2.0 * PI, 2.5 * PI, 3.0 * PI);
1118
+ float centers[7];
1119
+ for (int i = 0; i < 7; i++) {
1120
+ centers[i] = originalCenters[i] + 0.5 * sin(uTime / 20.0 + uOffsets[i]);
1121
+ }
1122
+
1123
+ float a, b;
1124
+ vec4 ovalColor;
1125
+
1126
+ for (int i = 0; i < 7; i++) {
1127
+ float noise = texture(uPerlinTexture, vec2(mod(centers[i] + uTime * 0.05, 1.0), 0.5)).r;
1128
+ a = 0.5 + noise * 0.3;
1129
+ b = noise * mix(3.5, 2.5, uInputVolume);
1130
+ bool reverseGradient = (i % 2 == 1);
1131
+ float distTheta = min(
1132
+ abs(theta - centers[i]),
1133
+ min(abs(theta + 2.0 * PI - centers[i]), abs(theta - 2.0 * PI - centers[i]))
1134
+ );
1135
+ if (drawOval(vec2(distTheta, radius), vec2(0.0, 0.0), a, b, reverseGradient, 0.6, ovalColor)) {
1136
+ color.rgb = mix(color.rgb, ovalColor.rgb, ovalColor.a);
1137
+ color.a = max(color.a, ovalColor.a);
1138
+ }
1139
+ }
1140
+
1141
+ float ringRadius1 = sharpRing(decomposed, uTime * 0.1);
1142
+ float ringRadius2 = smoothRing(decomposed, uTime * 0.1);
1143
+ float inputRadius1 = radius + uInputVolume * 0.2;
1144
+ float inputRadius2 = radius + uInputVolume * 0.15;
1145
+ float opacity1 = mix(0.2, 0.6, uInputVolume);
1146
+ float opacity2 = mix(0.15, 0.45, uInputVolume);
1147
+
1148
+ float ringAlpha1 = (inputRadius2 >= ringRadius1) ? opacity1 : 0.0;
1149
+ float ringAlpha2 = smoothstep(ringRadius2 - 0.05, ringRadius2 + 0.05, inputRadius1) * opacity2;
1150
+ float totalRingAlpha = max(ringAlpha1, ringAlpha2);
1151
+
1152
+ vec3 ringColor = vec3(1.0);
1153
+ color.rgb = 1.0 - (1.0 - color.rgb) * (1.0 - ringColor * totalRingAlpha);
1154
+
1155
+ vec3 color1 = vec3(0.0, 0.0, 0.0);
1156
+ vec3 color2 = uColor1;
1157
+ vec3 color3 = uColor2;
1158
+ vec3 color4 = vec3(1.0, 1.0, 1.0);
1159
+
1160
+ float luminance = mix(color.r, 1.0 - color.r, uInverted);
1161
+ color.rgb = colorRamp(luminance, color1, color2, color3, color4);
1162
+ color.a *= uOpacity;
1163
+
1164
+ gl_FragColor = color;
1165
+ }
1166
+ `}static{this.styles=t.css`
1167
+ :host {
1168
+ display: block;
1169
+ width: 100%;
1170
+ height: 100%;
1171
+ position: relative;
1172
+ }
1173
+ .container {
1174
+ width: 100%;
1175
+ height: 100%;
1176
+ }
1177
+ canvas {
1178
+ display: block;
1179
+ width: 100%;
1180
+ height: 100%;
1181
+ }
1182
+ `}render(){return t.html`<div class="container"></div>`}firstUpdated(){this._initThree()}updated(e){e.has(`colors`)&&this._updateColors()}_updateColors(){if(!(!this._targetColor1||!this._targetColor2))if(this.colors&&this.colors.length===2)this._targetColor1.set(this.colors[0]),this._targetColor2.set(this.colors[1]);else{let e=getComputedStyle(this),t=e.getPropertyValue(`--md-sys-color-primary`).trim()||`#CADCFC`,n=e.getPropertyValue(`--md-sys-color-secondary`).trim()||`#A0B9D1`;this._targetColor1.set(t),this._targetColor2.set(n)}}disconnectedCallback(){super.disconnectedCallback(),this._animationFrameId&&cancelAnimationFrame(this._animationFrameId),this._resizeObserver&&this._resizeObserver.disconnect(),this._renderer&&this._renderer.dispose(),this._mesh&&(this._mesh.geometry.dispose(),this._mesh.material.dispose())}async _initThree(){if(!this._container)return;this._targetColor1=new g.Color,this._targetColor2=new g.Color,this._updateColors();try{this._perlinNoiseTexture=await this._textureLoader.loadAsync(`https://storage.googleapis.com/eleven-public-cdn/images/perlin-noise.png`),this._perlinNoiseTexture.wrapS=g.RepeatWrapping,this._perlinNoiseTexture.wrapT=g.RepeatWrapping}catch(e){console.warn(`Failed to load perlin noise texture for orb.`,e);return}let e=this._container.clientWidth,t=this._container.clientHeight;this._scene=new g.Scene,this._camera=new g.OrthographicCamera(-5,5,5,-5,.1,10),this._camera.position.z=1,this._renderer=new g.WebGLRenderer({alpha:!0,antialias:!0,premultipliedAlpha:!0}),this._renderer.setSize(e,t),this._renderer.setPixelRatio(window.devicePixelRatio),this._container.appendChild(this._renderer.domElement);let n=this._splitmix32(this.seed),r=new Float32Array(Array.from({length:7},()=>n()*Math.PI*2)),i=document.documentElement.classList.contains(`dark`)||window.matchMedia(`(prefers-color-scheme: dark)`).matches,a={uColor1:new g.Uniform(this._targetColor1),uColor2:new g.Uniform(this._targetColor2),uOffsets:{value:r},uPerlinTexture:new g.Uniform(this._perlinNoiseTexture),uTime:new g.Uniform(0),uAnimation:new g.Uniform(.1),uInverted:new g.Uniform(i?1:0),uInputVolume:new g.Uniform(0),uOutputVolume:new g.Uniform(0),uOpacity:new g.Uniform(0)},o=new g.CircleGeometry(3.5,64),s=new g.ShaderMaterial({uniforms:a,vertexShader:this._vertexShader,fragmentShader:this._fragmentShader,transparent:!0});this._mesh=new g.Mesh(o,s),this._scene.add(this._mesh),this._resizeObserver=new ResizeObserver(()=>{this._container&&this._renderer&&this._renderer.setSize(this._container.clientWidth,this._container.clientHeight)}),this._resizeObserver.observe(this._container),new MutationObserver(()=>{if(!this._mesh)return;let e=document.documentElement.classList.contains(`dark`);this._mesh.material.uniforms.uInverted.value=e?1:0,this._updateColors()}).observe(document.documentElement,{attributes:!0,attributeFilter:[`class`]}),this._lastTime=performance.now(),this._animate()}_animate(){if(this._animationFrameId=requestAnimationFrame(()=>this._animate()),!this._mesh||!this._renderer||!this._scene||!this._camera)return;let e=performance.now(),t=(e-this._lastTime)/1e3;this._lastTime=e;let n=this._mesh.material.uniforms;n.uTime.value+=t*.5,n.uOpacity.value<1&&(n.uOpacity.value=Math.min(1,n.uOpacity.value+t*2));let r=0,i=.3;if(this.volumeMode===`manual`)r=this._clamp01(this.inputVolume),i=this._clamp01(this.outputVolume);else{let e=n.uTime.value*2;if(this.agentState===null)r=0,i=.3;else if(this.agentState===`listening`)r=this._clamp01(.55+Math.sin(e*3.2)*.35),i=.45;else if(this.agentState===`talking`)r=this._clamp01(.65+Math.sin(e*4.8)*.22),i=this._clamp01(.75+Math.sin(e*3.6)*.22);else{let t=.38+.07*Math.sin(e*.7),n=.05*Math.sin(e*2.1)*Math.sin(e*.37+1.2);r=this._clamp01(t+n),i=this._clamp01(.48+.12*Math.sin(e*1.05+.6))}}this._curIn+=(r-this._curIn)*.2,this._curOut+=(i-this._curOut)*.2;let a=.1+(1-(this._curOut-1)**2)*.9;this._animSpeed+=(a-this._animSpeed)*.12,n.uAnimation.value+=t*this._animSpeed,n.uInputVolume.value=this._curIn,n.uOutputVolume.value=this._curOut,n.uColor1.value.lerp(this._targetColor1,.08),n.uColor2.value.lerp(this._targetColor2,.08),this._renderer.render(this._scene,this._camera)}_splitmix32(e){return function(){e|=0,e=e+2654435769|0;let t=e^e>>>16;return t=Math.imul(t,569420461),t^=t>>>15,t=Math.imul(t,1935289751),((t^=t>>>15)>>>0)/4294967296}}_clamp01(e){return Number.isFinite(e)?Math.min(1,Math.max(0,e)):0}};T([(0,n.property)({type:Array})],Z.prototype,`colors`,void 0),T([(0,n.property)({type:String})],Z.prototype,`agentState`,void 0),T([(0,n.property)({type:Number})],Z.prototype,`inputVolume`,void 0),T([(0,n.property)({type:Number})],Z.prototype,`outputVolume`,void 0),T([(0,n.property)({type:String})],Z.prototype,`volumeMode`,void 0),T([(0,n.property)({type:Number})],Z.prototype,`seed`,void 0),T([(0,n.query)(`.container`)],Z.prototype,`_container`,void 0),Z=T([(0,n.customElement)(`ui-orb`)],Z);var Q=class extends t.LitElement{static{this.styles=t.css`
1183
+ :host {
1184
+ display: flex;
1185
+ align-items: center;
1186
+ gap: 8px;
1187
+ width: 100%;
1188
+ box-sizing: border-box;
1189
+ }
1190
+
1191
+ md-slider {
1192
+ flex: 1;
1193
+ min-width: 0; /* Prevent flex overflow */
1194
+ width: 100%;
1195
+ --md-slider-inactive-track-color: var(
1196
+ --md-sys-color-outline-variant,
1197
+ #c4c7c5
1198
+ );
1199
+ }
1200
+
1201
+ md-icon-button {
1202
+ color: var(--md-sys-color-on-surface-variant, #444);
1203
+ }
1204
+ `}render(){let e=this.playerState?.volume??1,n=this.playerState?.muted??!1,r=`volume_up`;return n||e===0?r=`volume_off`:e<.5&&(r=`volume_down`),t.html`
1205
+ <md-icon-button @click="${this._toggleMute}" part="button">
1206
+ <md-icon>${r}</md-icon>
1207
+ </md-icon-button>
1208
+ <md-slider
1209
+ part="slider"
1210
+ min="0"
1211
+ max="1"
1212
+ value="${n?0:e}"
1213
+ step="0.01"
1214
+ ?disabled="${!this.playerState?.src}"
1215
+ @input="${this._handleInput}"
1216
+ ></md-slider>
1217
+ `}_handleInput(e){let t=e.target;this.playerState&&this.playerState.setVolume(t.value)}_toggleMute(){this.playerState&&this.playerState.toggleMute()}};T([z({context:B,subscribe:!0}),(0,n.property)({attribute:!1})],Q.prototype,`playerState`,void 0),Q=T([(0,n.customElement)(`ui-audio-volume-slider`)],Q),Object.defineProperty(e,`ScreamVoiceButton`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(e,`UiAudioPlayButton`,{enumerable:!0,get:function(){return H}}),Object.defineProperty(e,`UiAudioPlayer`,{enumerable:!0,get:function(){return G}}),Object.defineProperty(e,`UiAudioProgressSlider`,{enumerable:!0,get:function(){return U}}),Object.defineProperty(e,`UiAudioProvider`,{enumerable:!0,get:function(){return V}}),Object.defineProperty(e,`UiAudioTimeDisplay`,{enumerable:!0,get:function(){return W}}),Object.defineProperty(e,`UiAudioVolumeSlider`,{enumerable:!0,get:function(){return Q}}),Object.defineProperty(e,`UiLiveWaveform`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(e,`UiMicSelector`,{enumerable:!0,get:function(){return K}}),Object.defineProperty(e,`UiOrb`,{enumerable:!0,get:function(){return Z}}),Object.defineProperty(e,`UiScrollingWaveform`,{enumerable:!0,get:function(){return J}}),Object.defineProperty(e,`UiShimmeringText`,{enumerable:!0,get:function(){return X}}),Object.defineProperty(e,`UiShowcaseCard`,{enumerable:!0,get:function(){return Y}}),Object.defineProperty(e,`UiVoiceButton`,{enumerable:!0,get:function(){return A}}),Object.defineProperty(e,`UiVoicePicker`,{enumerable:!0,get:function(){return q}}),Object.defineProperty(e,`UiWaveform`,{enumerable:!0,get:function(){return j}}),e.audioPlayerContext=B});