flawed-avatar 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +217 -0
  3. package/assets/icon.png +0 -0
  4. package/dist/chat-renderer-bundle/chat-index.html +1 -1
  5. package/dist/main/main/device-identity.d.ts +19 -0
  6. package/dist/main/main/device-identity.js +83 -0
  7. package/dist/main/main/gateway-client.d.ts +2 -1
  8. package/dist/main/main/gateway-client.js +50 -12
  9. package/dist/main/main/main.js +5 -7
  10. package/dist/main/main/persistence/types.d.ts +2 -2
  11. package/dist/renderer-bundle/renderer.js +35 -46
  12. package/dist/settings-preload.cjs +153 -0
  13. package/dist/settings-renderer-bundle/settings-index.html +16 -0
  14. package/dist/settings-renderer-bundle/settings-renderer.js +502 -0
  15. package/dist/settings-renderer-bundle/styles/base.css +106 -0
  16. package/dist/settings-renderer-bundle/styles/chat.css +516 -0
  17. package/dist/settings-renderer-bundle/styles/components/button.css +221 -0
  18. package/dist/settings-renderer-bundle/styles/components/indicator.css +216 -0
  19. package/dist/settings-renderer-bundle/styles/components/input.css +139 -0
  20. package/dist/settings-renderer-bundle/styles/components/toast.css +204 -0
  21. package/dist/settings-renderer-bundle/styles/controls.css +279 -0
  22. package/dist/settings-renderer-bundle/styles/settings.css +310 -0
  23. package/dist/settings-renderer-bundle/styles/tokens.css +220 -0
  24. package/dist/settings-renderer-bundle/styles/utilities.css +349 -0
  25. package/index.ts +2 -2
  26. package/package.json +6 -1
  27. package/src/main/device-identity.ts +103 -0
  28. package/src/main/gateway-client.ts +52 -11
  29. package/src/main/main.ts +5 -6
  30. package/src/renderer/audio/index.ts +0 -3
  31. package/src/renderer/audio/kokoro-model-loader.ts +0 -2
  32. package/src/renderer/audio/kokoro-tts-service.ts +0 -2
  33. package/src/renderer/audio/tts-controller.ts +0 -3
  34. package/src/renderer/avatar/ibl-enhancer.ts +1 -1
  35. package/src/renderer/chat-window/chat-index.html +1 -1
  36. package/src/renderer/renderer.ts +0 -1
  37. package/src/renderer/settings-window/settings-index.html +1 -1
  38. package/src/renderer/ui/chat-bubble.ts +0 -39
  39. package/src/service.ts +1 -1
  40. package/src/renderer/audio/tts-service.ts +0 -16
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Avatar Controls Styles
3
+ * Uses BEM naming convention and button component
4
+ */
5
+
6
+ @import "./tokens.css";
7
+ @import "./components/button.css";
8
+
9
+ /* Backdrop-filter fallback for unsupported browsers */
10
+ @supports not (backdrop-filter: blur(1px)) {
11
+ .controls__btn {
12
+ background: var(--glass-bg-solid) !important;
13
+ }
14
+
15
+ /* Legacy support */
16
+ #controls button {
17
+ background: var(--glass-bg-solid) !important;
18
+ }
19
+ }
20
+
21
+ /* === Controls Container === */
22
+ .controls {
23
+ position: absolute;
24
+ top: var(--space-1);
25
+ inset-inline-end: var(--space-2);
26
+ display: flex;
27
+ flex-direction: column;
28
+ gap: var(--space-1);
29
+ opacity: 0;
30
+ transition: opacity var(--transition-slow);
31
+ pointer-events: none;
32
+ z-index: var(--z-dropdown);
33
+ }
34
+
35
+ /* Legacy ID support */
36
+ #controls {
37
+ position: absolute;
38
+ top: var(--space-1);
39
+ inset-inline-end: var(--space-2);
40
+ display: flex;
41
+ flex-direction: column;
42
+ gap: var(--space-1);
43
+ opacity: 0;
44
+ transition: opacity var(--transition-slow);
45
+ pointer-events: none;
46
+ z-index: var(--z-dropdown);
47
+ }
48
+
49
+ /* Show on hover (pixel-sampled opaque hit) */
50
+ body.avatar-hovered .controls,
51
+ body:hover .controls,
52
+ .controls:focus-within {
53
+ opacity: 1;
54
+ }
55
+
56
+ /* Legacy support */
57
+ body.avatar-hovered #controls,
58
+ body:hover #controls,
59
+ #controls:focus-within {
60
+ opacity: 1;
61
+ }
62
+
63
+ /* === Control Button === */
64
+ .controls__btn {
65
+ width: 28px;
66
+ height: 28px;
67
+ border: none;
68
+ border-radius: var(--radius-md);
69
+ background: var(--surface-button);
70
+ backdrop-filter: blur(8px);
71
+ -webkit-backdrop-filter: blur(8px);
72
+ color: rgba(255, 255, 255, 0.7);
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ cursor: pointer;
77
+ pointer-events: auto;
78
+ padding: 0;
79
+ transition:
80
+ background var(--transition-normal),
81
+ color var(--transition-normal),
82
+ transform var(--transition-fast),
83
+ box-shadow var(--transition-fast);
84
+ }
85
+
86
+ .controls__btn:hover {
87
+ background: var(--surface-button-hover);
88
+ color: var(--text-primary);
89
+ transform: scale(1.05);
90
+ }
91
+
92
+ .controls__btn:active {
93
+ transform: scale(0.95);
94
+ }
95
+
96
+ .controls__btn:focus-visible {
97
+ outline: 2px solid var(--accent-blue);
98
+ outline-offset: 2px;
99
+ }
100
+
101
+ .controls__btn svg {
102
+ width: 14px;
103
+ height: 14px;
104
+ }
105
+
106
+ /* Legacy support */
107
+ #controls button {
108
+ width: 28px;
109
+ height: 28px;
110
+ border: none;
111
+ border-radius: var(--radius-md);
112
+ background: var(--surface-button);
113
+ backdrop-filter: blur(8px);
114
+ -webkit-backdrop-filter: blur(8px);
115
+ color: rgba(255, 255, 255, 0.7);
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ cursor: pointer;
120
+ pointer-events: auto;
121
+ padding: 0;
122
+ transition:
123
+ background var(--transition-normal),
124
+ color var(--transition-normal),
125
+ transform var(--transition-fast),
126
+ box-shadow var(--transition-fast);
127
+ }
128
+
129
+ #controls button:hover {
130
+ background: var(--surface-button-hover);
131
+ color: var(--text-primary);
132
+ transform: scale(1.05);
133
+ }
134
+
135
+ #controls button:active {
136
+ transform: scale(0.95);
137
+ }
138
+
139
+ #controls button:focus-visible {
140
+ outline: 2px solid var(--accent-blue);
141
+ outline-offset: 2px;
142
+ }
143
+
144
+ #controls button svg {
145
+ width: 14px;
146
+ height: 14px;
147
+ }
148
+
149
+ /* === Drag Handle === */
150
+ .controls__drag-handle {
151
+ cursor: grab;
152
+ }
153
+
154
+ .controls__drag-handle:active {
155
+ cursor: grabbing;
156
+ }
157
+
158
+ /* Legacy support */
159
+ #drag-handle {
160
+ cursor: grab;
161
+ }
162
+
163
+ #drag-handle:active {
164
+ cursor: grabbing;
165
+ }
166
+
167
+ /* === Active State === */
168
+ .controls__btn.is-active {
169
+ background: var(--accent-blue-soft);
170
+ color: var(--accent-blue);
171
+ box-shadow: var(--shadow-glow);
172
+ }
173
+
174
+ /* Chat toggle */
175
+ .controls__chat-toggle.is-active {
176
+ background: var(--accent-blue-soft);
177
+ color: var(--accent-blue);
178
+ box-shadow: var(--shadow-glow);
179
+ }
180
+
181
+ /* Legacy support */
182
+ #chat-toggle-btn.active {
183
+ background: var(--accent-blue-soft);
184
+ color: var(--accent-blue);
185
+ box-shadow: var(--shadow-glow);
186
+ }
187
+
188
+ /* === TTS Toggle === */
189
+ .controls__tts-toggle .icon-on {
190
+ display: none;
191
+ }
192
+
193
+ .controls__tts-toggle .icon-off {
194
+ display: block;
195
+ }
196
+
197
+ .controls__tts-toggle.is-active .icon-on {
198
+ display: block;
199
+ }
200
+
201
+ .controls__tts-toggle.is-active .icon-off {
202
+ display: none;
203
+ }
204
+
205
+ .controls__tts-toggle.is-active {
206
+ background: var(--accent-blue-soft);
207
+ color: var(--accent-blue);
208
+ box-shadow: var(--shadow-glow);
209
+ }
210
+
211
+ .controls__tts-toggle.is-speaking {
212
+ animation: tts-pulse 1.5s ease-in-out infinite;
213
+ }
214
+
215
+ /* Legacy support */
216
+ #tts-toggle-btn .icon-on {
217
+ display: none;
218
+ }
219
+
220
+ #tts-toggle-btn .icon-off {
221
+ display: block;
222
+ }
223
+
224
+ #tts-toggle-btn.active .icon-on {
225
+ display: block;
226
+ }
227
+
228
+ #tts-toggle-btn.active .icon-off {
229
+ display: none;
230
+ }
231
+
232
+ #tts-toggle-btn.active {
233
+ background: var(--accent-blue-soft);
234
+ color: var(--accent-blue);
235
+ box-shadow: var(--shadow-glow);
236
+ }
237
+
238
+ #tts-toggle-btn.speaking {
239
+ animation: tts-pulse 1.5s ease-in-out infinite;
240
+ }
241
+
242
+ @keyframes tts-pulse {
243
+ 0%,
244
+ 100% {
245
+ box-shadow: var(--shadow-glow);
246
+ }
247
+ 50% {
248
+ box-shadow: var(--glow-blue-md);
249
+ }
250
+ }
251
+
252
+ /* === Responsive Design === */
253
+ @media (max-width: 480px) {
254
+ .controls,
255
+ #controls {
256
+ top: var(--space-2);
257
+ inset-inline-end: var(--space-2);
258
+ }
259
+
260
+ .controls__btn,
261
+ #controls button {
262
+ width: 32px;
263
+ height: 32px;
264
+ }
265
+
266
+ .controls__btn svg,
267
+ #controls button svg {
268
+ width: 16px;
269
+ height: 16px;
270
+ }
271
+ }
272
+
273
+ /* === Forced Colors Mode === */
274
+ @media (forced-colors: active) {
275
+ .controls__btn,
276
+ #controls button {
277
+ border: 2px solid currentColor;
278
+ }
279
+ }
@@ -0,0 +1,310 @@
1
+ @import "./tokens.css";
2
+ @import "./base.css";
3
+ @import "./components/button.css";
4
+ @import "./components/input.css";
5
+
6
+ /* === Settings Root === */
7
+ .settings {
8
+ display: flex;
9
+ flex-direction: column;
10
+ width: 100%;
11
+ height: 100vh;
12
+ background: var(--glass-bg-solid);
13
+ color: var(--text-primary);
14
+ overflow: hidden;
15
+ }
16
+
17
+ /* === Title Bar === */
18
+ .settings__titlebar {
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: space-between;
22
+ padding: var(--space-2) var(--space-3);
23
+ -webkit-app-region: drag;
24
+ border-bottom: 1px solid var(--glass-border);
25
+ flex-shrink: 0;
26
+ }
27
+
28
+ .settings__titlebar-text {
29
+ font-size: var(--font-size-lg);
30
+ font-weight: var(--font-weight-semibold);
31
+ color: var(--text-primary);
32
+ }
33
+
34
+ .settings__titlebar-close {
35
+ -webkit-app-region: no-drag;
36
+ width: 24px;
37
+ height: 24px;
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ border-radius: var(--radius-sm);
42
+ color: var(--text-secondary);
43
+ transition: background var(--duration-fast), color var(--duration-fast);
44
+ }
45
+
46
+ .settings__titlebar-close:hover {
47
+ background: var(--color-error-soft);
48
+ color: var(--color-error);
49
+ }
50
+
51
+ /* === Tab Bar === */
52
+ .settings__tabs {
53
+ display: flex;
54
+ gap: 0;
55
+ padding: 0 var(--space-3);
56
+ border-bottom: 1px solid var(--glass-border);
57
+ flex-shrink: 0;
58
+ overflow-x: auto;
59
+ }
60
+
61
+ .settings__tab {
62
+ padding: var(--space-2) var(--space-3);
63
+ font-size: var(--font-size-sm);
64
+ font-weight: var(--font-weight-medium);
65
+ color: var(--text-secondary);
66
+ border-bottom: 2px solid transparent;
67
+ transition: color var(--duration-fast), border-color var(--duration-fast);
68
+ white-space: nowrap;
69
+ -webkit-app-region: no-drag;
70
+ }
71
+
72
+ .settings__tab:hover {
73
+ color: var(--text-primary);
74
+ }
75
+
76
+ .settings__tab.is-active {
77
+ color: var(--accent-blue);
78
+ border-bottom-color: var(--accent-blue);
79
+ }
80
+
81
+ /* === Panel === */
82
+ .settings__panel {
83
+ flex: 1;
84
+ overflow-y: auto;
85
+ padding: var(--space-4) var(--space-3);
86
+ }
87
+
88
+ .settings__panel[hidden] {
89
+ display: none;
90
+ }
91
+
92
+ /* === Section === */
93
+ .settings__section {
94
+ margin-bottom: var(--space-4);
95
+ }
96
+
97
+ .settings__section-title {
98
+ font-size: var(--font-size-xs);
99
+ font-weight: var(--font-weight-semibold);
100
+ color: var(--text-secondary);
101
+ text-transform: uppercase;
102
+ letter-spacing: 0.05em;
103
+ margin-bottom: var(--space-2);
104
+ }
105
+
106
+ /* === Row === */
107
+ .settings__row {
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: space-between;
111
+ padding: var(--space-1) 0;
112
+ min-height: 32px;
113
+ }
114
+
115
+ .settings__label {
116
+ font-size: var(--font-size-md);
117
+ color: var(--text-primary);
118
+ flex-shrink: 0;
119
+ }
120
+
121
+ .settings__value {
122
+ font-size: var(--font-size-sm);
123
+ color: var(--text-secondary);
124
+ margin-left: var(--space-2);
125
+ text-align: right;
126
+ overflow: hidden;
127
+ text-overflow: ellipsis;
128
+ white-space: nowrap;
129
+ max-width: 180px;
130
+ }
131
+
132
+ /* === Range Slider === */
133
+ .settings__range {
134
+ -webkit-appearance: none;
135
+ appearance: none;
136
+ width: 100%;
137
+ height: 4px;
138
+ background: var(--surface-sunken);
139
+ border-radius: 2px;
140
+ outline: none;
141
+ transition: background var(--duration-fast);
142
+ }
143
+
144
+ .settings__range::-webkit-slider-thumb {
145
+ -webkit-appearance: none;
146
+ appearance: none;
147
+ width: 14px;
148
+ height: 14px;
149
+ border-radius: 50%;
150
+ background: var(--accent-blue);
151
+ cursor: pointer;
152
+ transition: box-shadow var(--duration-fast);
153
+ }
154
+
155
+ .settings__range::-webkit-slider-thumb:hover {
156
+ box-shadow: var(--glow-blue-sm);
157
+ }
158
+
159
+ .settings__range:focus-visible::-webkit-slider-thumb {
160
+ box-shadow: 0 0 0 3px var(--surface-focus);
161
+ }
162
+
163
+ /* === Toggle Switch === */
164
+ .settings__toggle {
165
+ position: relative;
166
+ width: 36px;
167
+ height: 20px;
168
+ border-radius: 10px;
169
+ background: var(--surface-sunken);
170
+ cursor: pointer;
171
+ transition: background var(--duration-fast);
172
+ flex-shrink: 0;
173
+ }
174
+
175
+ .settings__toggle::after {
176
+ content: "";
177
+ position: absolute;
178
+ top: 2px;
179
+ left: 2px;
180
+ width: 16px;
181
+ height: 16px;
182
+ border-radius: 50%;
183
+ background: var(--text-secondary);
184
+ transition: transform var(--duration-fast), background var(--duration-fast);
185
+ }
186
+
187
+ .settings__toggle.is-on {
188
+ background: var(--accent-blue-soft);
189
+ }
190
+
191
+ .settings__toggle.is-on::after {
192
+ transform: translateX(16px);
193
+ background: var(--accent-blue);
194
+ }
195
+
196
+ /* === Select === */
197
+ .settings__select {
198
+ background: var(--surface-input);
199
+ border: 1px solid var(--glass-border);
200
+ border-radius: var(--radius-sm);
201
+ padding: var(--space-1) var(--space-2);
202
+ color: var(--text-primary);
203
+ font-size: var(--font-size-sm);
204
+ font-family: var(--font-sans);
205
+ cursor: pointer;
206
+ min-width: 120px;
207
+ }
208
+
209
+ .settings__select:hover {
210
+ border-color: var(--glass-border-hover);
211
+ }
212
+
213
+ .settings__select:focus-visible {
214
+ outline: 2px solid var(--accent-blue);
215
+ outline-offset: 1px;
216
+ }
217
+
218
+ .settings__select option {
219
+ background: var(--glass-bg-solid);
220
+ color: var(--text-primary);
221
+ }
222
+
223
+ /* === Radio Group === */
224
+ .settings__radio-group {
225
+ display: flex;
226
+ gap: var(--space-1);
227
+ flex-wrap: wrap;
228
+ }
229
+
230
+ .settings__radio {
231
+ padding: var(--space-1) var(--space-3);
232
+ border-radius: var(--radius-full);
233
+ font-size: var(--font-size-sm);
234
+ background: var(--surface-button);
235
+ border: 1px solid var(--glass-border);
236
+ color: var(--text-secondary);
237
+ cursor: pointer;
238
+ transition: all var(--duration-fast);
239
+ }
240
+
241
+ .settings__radio:hover {
242
+ background: var(--surface-hover);
243
+ color: var(--text-primary);
244
+ }
245
+
246
+ .settings__radio.is-selected {
247
+ background: var(--accent-blue-soft);
248
+ border-color: var(--accent-blue);
249
+ color: var(--accent-blue);
250
+ }
251
+
252
+ /* === Text Input (for settings) === */
253
+ .settings__text-input {
254
+ background: var(--surface-input);
255
+ border: 1px solid var(--glass-border);
256
+ border-radius: var(--radius-sm);
257
+ padding: var(--space-1) var(--space-2);
258
+ color: var(--text-primary);
259
+ font-size: var(--font-size-sm);
260
+ font-family: var(--font-sans);
261
+ width: 100%;
262
+ }
263
+
264
+ .settings__text-input:focus-visible {
265
+ outline: none;
266
+ border-color: var(--accent-blue);
267
+ box-shadow: 0 0 0 2px var(--surface-focus);
268
+ }
269
+
270
+ /* === Color Input === */
271
+ .settings__color-input {
272
+ width: 32px;
273
+ height: 24px;
274
+ border: 1px solid var(--glass-border);
275
+ border-radius: var(--radius-sm);
276
+ cursor: pointer;
277
+ padding: 0;
278
+ background: none;
279
+ }
280
+
281
+ .settings__color-input::-webkit-color-swatch-wrapper {
282
+ padding: 1px;
283
+ }
284
+
285
+ .settings__color-input::-webkit-color-swatch {
286
+ border: none;
287
+ border-radius: 2px;
288
+ }
289
+
290
+ /* === Utility: Full-width row stacking === */
291
+ .settings__row--stacked {
292
+ flex-direction: column;
293
+ align-items: flex-start;
294
+ gap: var(--space-1);
295
+ }
296
+
297
+ .settings__row--stacked > * {
298
+ width: 100%;
299
+ }
300
+
301
+ /* === Model path display === */
302
+ .settings__model-path {
303
+ font-size: var(--font-size-xs);
304
+ color: var(--text-secondary);
305
+ overflow: hidden;
306
+ text-overflow: ellipsis;
307
+ white-space: nowrap;
308
+ max-width: 100%;
309
+ padding: var(--space-1) 0;
310
+ }