robot-heads-solid 0.1.0 → 0.2.0-beta.1

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,532 @@
1
+ import { ssrElement as e } from "@solidjs/web";
2
+ import { createSignal as t, createTrackedEffect as n, createUniqueId as r, omit as i, onSettled as a } from "solid-js";
3
+ var o = [
4
+ "idle",
5
+ "thinking",
6
+ "searching",
7
+ "listening",
8
+ "speaking",
9
+ "working",
10
+ "happy",
11
+ "error",
12
+ "sleeping"
13
+ ], s = [
14
+ "rectangle",
15
+ "square",
16
+ "circle",
17
+ "hexagon"
18
+ ], c = {
19
+ bevel: .075,
20
+ margin: .045,
21
+ gasket: .022,
22
+ recess: .03,
23
+ earY: .03,
24
+ stem: .2,
25
+ ball: .052
26
+ }, l = {
27
+ plate: c.bevel,
28
+ hole: c.bevel + c.margin,
29
+ glass: c.bevel + c.margin + c.gasket
30
+ }, u = Math.PI * 2;
31
+ function d(e, t, n, r, i, a) {
32
+ let o = t.map(([e, t]) => ({
33
+ x: e,
34
+ y: t,
35
+ t: Math.atan2(t, e)
36
+ })).sort((e, t) => e.t - t.t), s = o.length, d = [];
37
+ for (let e = 0; e < s; e++) {
38
+ let t = o[e], n = o[(e + 1) % s];
39
+ d.push(Math.atan2(-(n.x - t.x), n.y - t.y));
40
+ }
41
+ let f = o.map((e, t) => {
42
+ if (s === 1) return {
43
+ x: e.x,
44
+ y: e.y,
45
+ a0: -Math.PI,
46
+ a1: Math.PI
47
+ };
48
+ let n = d[(t - 1 + s) % s], r = d[t];
49
+ for (; r < n;) r += u;
50
+ return {
51
+ x: e.x,
52
+ y: e.y,
53
+ a0: n,
54
+ a1: r
55
+ };
56
+ }), m = (e, t) => {
57
+ if (s === 1) return Math.hypot(e - o[0].x, t - o[0].y);
58
+ let n = Infinity, r = !0;
59
+ for (let i = 0; i < s; i++) {
60
+ let a = o[i], c = o[(i + 1) % s], l = c.x - a.x, u = c.y - a.y, d = e - a.x, f = t - a.y, p = Math.max(0, Math.min(1, (d * l + f * u) / (l * l + u * u)));
61
+ n = Math.min(n, Math.hypot(d - l * p, f - u * p)), l * f - u * d < 0 && (r = !1);
62
+ }
63
+ return r ? -n : n;
64
+ }, h = (e, t, r) => m(e, t) - (n - r), g = (e, t) => {
65
+ let r = Math.max(5e-4, n - t);
66
+ f.forEach((t, n) => {
67
+ n === 0 && e.moveTo(t.x + r * Math.cos(t.a0), t.y + r * Math.sin(t.a0)), e.arc(t.x, t.y, r, t.a0, t.a1);
68
+ }), e.closePath();
69
+ }, _ = 0, v = 0;
70
+ for (let e of o) _ = Math.max(_, Math.abs(e.x) + n), v = Math.max(v, Math.abs(e.y) + n);
71
+ let y = 0, b = _ + .1;
72
+ for (let e = 0; e < 40; e++) {
73
+ let e = (y + b) / 2;
74
+ h(e, c.earY, 0) < 0 ? y = e : b = e;
75
+ }
76
+ let x = (e, t) => e.map((e, r) => {
77
+ let i = e * Math.PI / 180, a = f.find((e) => [
78
+ i,
79
+ i + u,
80
+ i - u
81
+ ].some((t) => t >= e.a0 - 1e-6 && t <= e.a1 + 1e-6)) ?? f[0];
82
+ return [
83
+ a.x + Math.cos(i) * (n - t),
84
+ a.y + Math.sin(i) * (n - t),
85
+ .5 + r * .9
86
+ ];
87
+ }), S = 2 * (_ - l.glass), C = 2 * (v - l.glass), w = Math.min(p * S / 14, .65 * C / 10);
88
+ return {
89
+ name: e,
90
+ r: n,
91
+ depth: r,
92
+ corners: f,
93
+ hx: _,
94
+ hy: v,
95
+ pitch: w,
96
+ earX: y - .008,
97
+ screws: x(i, (l.hole - .018 + l.plate) / 2),
98
+ backScrews: x(a, l.plate + .07),
99
+ sd: h,
100
+ path: g
101
+ };
102
+ }
103
+ var f = (e) => [
104
+ 0,
105
+ 60,
106
+ 120,
107
+ 180,
108
+ 240,
109
+ 300
110
+ ].map((t) => [e * Math.cos(t * Math.PI / 180), e * Math.sin(t * Math.PI / 180)]), p = .6, m = [45, 135], h = [
111
+ -135,
112
+ -45,
113
+ 45,
114
+ 135
115
+ ], g = {
116
+ rectangle: () => d("rectangle", [
117
+ [-.29, -.17],
118
+ [.29, -.17],
119
+ [.29, .17],
120
+ [-.29, .17]
121
+ ], .21, .6, m, h),
122
+ square: () => d("square", [
123
+ [-.22, -.22],
124
+ [.22, -.22],
125
+ [.22, .22],
126
+ [-.22, .22]
127
+ ], .2, .6, m, h),
128
+ circle: () => d("circle", [[0, 0]], .46, .56, m, h),
129
+ hexagon: () => d("hexagon", f(.35), .16, .58, [60, 120], [
130
+ -120,
131
+ -60,
132
+ 60,
133
+ 120
134
+ ])
135
+ }, _ = /* @__PURE__ */ new Map();
136
+ function v(e) {
137
+ let t = _.get(e);
138
+ return t || (t = (g[e] ?? g.rectangle)(), _.set(e, t)), t;
139
+ }
140
+ //#endregion
141
+ //#region ../src/tv/sim.ts
142
+ var y = class {
143
+ x = 0;
144
+ v = 0;
145
+ constructor(e = 0) {
146
+ this.x = e;
147
+ }
148
+ step(e, t, n, r) {
149
+ let i = n * Math.PI * 2;
150
+ this.v += (i * i * (e - this.x) - 2 * r * i * this.v) * t, this.x += this.v * t;
151
+ }
152
+ };
153
+ function b(e) {
154
+ let t = Math.floor(e * 4294967295) >>> 0 || 1;
155
+ return () => {
156
+ t = t + 1831565813 >>> 0;
157
+ let e = t;
158
+ return e = Math.imul(e ^ e >>> 15, e | 1), e ^= e + Math.imul(e ^ e >>> 7, e | 61), ((e ^ e >>> 14) >>> 0) / 4294967296;
159
+ };
160
+ }
161
+ var x = (e, t, n) => Math.min(n, Math.max(t, e)), S = (e) => e < .5 ? 4 * e * e * e : 1 - (-2 * e + 2) ** 3 / 2, C = .11, w = class {
162
+ state;
163
+ shown;
164
+ previous;
165
+ switched = 10;
166
+ age = 0;
167
+ time = 0;
168
+ since = 0;
169
+ pose = {
170
+ yaw: 0,
171
+ pitch: 0,
172
+ roll: 0,
173
+ x: 0,
174
+ lift: 0,
175
+ sx: 1,
176
+ sy: 1,
177
+ antennaX: 0,
178
+ antennaZ: 0
179
+ };
180
+ face;
181
+ pointer = null;
182
+ yaw = new y();
183
+ pitch = new y();
184
+ roll = new y();
185
+ sway = new y();
186
+ squash = new y();
187
+ antX = new y();
188
+ antZ = new y();
189
+ lastV = {
190
+ roll: 0,
191
+ pitch: 0,
192
+ sway: 0
193
+ };
194
+ jump = null;
195
+ random;
196
+ lookAt = {
197
+ yaw: 0,
198
+ pitch: 0,
199
+ x: 0,
200
+ y: 0
201
+ };
202
+ nextLook = .6;
203
+ nextBlink = 1.5;
204
+ blinkAge = -1;
205
+ nextHop = 8;
206
+ nextSide = 4;
207
+ reactUntil = -1;
208
+ nextNod = 2.5;
209
+ constructor(e, t) {
210
+ this.random = b(e), this.state = this.shown = this.previous = t, this.face = {
211
+ lookX: 0,
212
+ lookY: 0,
213
+ blink: 0,
214
+ time: 0,
215
+ side: 1,
216
+ seed: e
217
+ }, this.nextBlink = 1 + this.random() * 3, this.nextHop = 6 + this.random() * 6;
218
+ }
219
+ setState(e) {
220
+ e !== this.state && (this.state = e, this.since = 0, this.nextLook = 0, this.nextHop = this.time + (e === "happy" ? .2 : 3 + this.random() * 4), e === "happy" && this.hop(.22, 1));
221
+ }
222
+ poke() {
223
+ this.hop(.24, this.random() < .5 ? 1 : -1), this.reactUntil = this.time + 1.6;
224
+ }
225
+ hop(e, t) {
226
+ this.jump ||= {
227
+ age: 0,
228
+ height: e,
229
+ spin: t,
230
+ lean: (this.random() - .5) * .3,
231
+ air: .42 + e * .45,
232
+ landed: !1
233
+ };
234
+ }
235
+ update(e) {
236
+ if (!Number.isFinite(e) || !(e > 0)) return;
237
+ let t = Math.min(e, .8), n = Math.max(1, Math.ceil(t / (1 / 120)));
238
+ for (let e = 0; e < n; e++) this.step(t / n);
239
+ }
240
+ stepJump(e) {
241
+ let t = 0, n = 0, r = 0, i = 0, a = this.jump, o = this.random;
242
+ if (a) {
243
+ if (a.age += e, a.age < C) i = .14;
244
+ else {
245
+ let e = (a.age - C) / a.air;
246
+ e < 1 ? (e < .06 && this.squash.x > .05 && (this.squash.v = -2.6, this.antZ.v -= 3), t = 4 * a.height * e * (1 - e), n = a.spin * Math.PI * 2 * S(x(e * 1.08, 0, 1)), r = a.lean * Math.sin(e * Math.PI), i = e < .5 ? -.05 : 0) : a.landed ? a.age - C - a.air > .35 && (this.jump = null) : (a.landed = !0, this.squash.v += 3.2, this.antX.v += (o() < .5 ? -1 : 1) * (2.5 + o() * 2), this.antZ.v += 3.5);
247
+ }
248
+ }
249
+ return this.squash.step(i, e, 3.2, .32), {
250
+ lift: t,
251
+ spin: n,
252
+ lean: r
253
+ };
254
+ }
255
+ hopWithChance(e, t) {
256
+ this.hop(e, this.random() < t ? this.random() < .5 ? 1 : -1 : 0);
257
+ }
258
+ updateLookAt(e) {
259
+ if (e > this.nextLook) {
260
+ let t = this.random;
261
+ this.lookAt = {
262
+ yaw: (t() - .5) * .75,
263
+ pitch: (t() - .5) * .24,
264
+ x: 0,
265
+ y: 0
266
+ }, this.lookAt.x = x(Math.round(this.lookAt.yaw * 5), -2, 2), this.lookAt.y = t() < .3 ? -1 : +(t() < .2), this.nextLook = e + 1.4 + t() * 2.6;
267
+ }
268
+ }
269
+ stateTargets(e) {
270
+ let t = this.random, n = 0, r = 0, i = 0, a = Math.sin(e * 1.9) * .008, o = 0, s = 0, c = 1.3, l = .62, u = 0;
271
+ switch (this.state) {
272
+ case "idle":
273
+ n = this.lookAt.yaw, r = this.lookAt.pitch, i = -this.lookAt.yaw * .16, o = this.lookAt.x, s = this.lookAt.y, e > this.nextHop && (this.hopWithChance(.15 + t() * .07, .35), this.nextHop = e + 7 + t() * 7);
274
+ break;
275
+ case "thinking": {
276
+ e > this.nextSide && (this.face.side = -this.face.side, this.nextSide = e + 3 + t() * 2);
277
+ let a = this.face.side;
278
+ n = .24 * a + Math.sin(e * .9) * .05, r = .17 + Math.sin(e * 1.3) * .03, i = -.13 * a, c = .9;
279
+ break;
280
+ }
281
+ case "searching": {
282
+ let t = e * 1.6;
283
+ n = Math.sin(t) * .55, r = -.04 + Math.sin(t * 2) * .04, i = Math.sin(t) * -.06, o = x(Math.sin(t + .4) * 3, -3, 3), c = 2.2, l = .8;
284
+ break;
285
+ }
286
+ case "listening":
287
+ n = -.14, r = .02, i = .17, e > this.nextNod && (this.pitch.v -= .9, this.nextNod = e + 2 + t() * 2.5);
288
+ break;
289
+ case "speaking":
290
+ n = Math.sin(e * .7) * .12, r = .03 + Math.sin(e * 6.3) * .025 * (.5 + .5 * Math.sin(e * 2.1)), i = Math.sin(e * .9) * .05, a += Math.abs(Math.sin(e * 6.3)) * .01, c = 1.8;
291
+ break;
292
+ case "working":
293
+ n = Math.sin(e * .8) * .08, r = -.16, i = Math.sin(e * .5) * .04, a += Math.abs(Math.sin(e * 7)) * .012, e > this.nextHop && (this.hop(.2, t() < .5 ? 1 : -1), this.nextHop = e + 5 + t() * 3);
294
+ break;
295
+ case "happy":
296
+ n = Math.sin(e * 2.2) * .18, i = Math.sin(e * 4.4) * .12, r = .08, e > this.nextHop && (this.hopWithChance(.17, .34), this.nextHop = e + 1.05 + t() * .4);
297
+ break;
298
+ case "error": {
299
+ let t = e % 2.4 / .7;
300
+ u = t < 1 ? Math.sin(t * Math.PI * 7) * .22 * (1 - t) : 0, r = -.06, i = -.05, c = 1.6;
301
+ break;
302
+ }
303
+ case "sleeping":
304
+ r = -.34, i = .13, n = .06, a = Math.sin(e * 1.15) * .016, c = .55, l = .9, e > this.nextNod && (this.pitch.v -= .5, this.nextNod = e + 5 + t() * 4);
305
+ break;
306
+ default: this.state;
307
+ }
308
+ return {
309
+ yaw: n,
310
+ pitch: r,
311
+ roll: i,
312
+ bob: a,
313
+ lookX: o,
314
+ lookY: s,
315
+ freq: c,
316
+ damping: l,
317
+ shake: u
318
+ };
319
+ }
320
+ step(e) {
321
+ this.time += e, this.since += e, this.age += e, this.switched += e;
322
+ let t = this.time, n = this.random, r = t < this.reactUntil ? "happy" : this.state;
323
+ r !== this.shown && (this.previous = this.shown, this.shown = r, this.switched = 0), this.updateLookAt(t);
324
+ let { yaw: i, pitch: a, roll: o, bob: s, lookX: c, lookY: l, freq: u, damping: d, shake: f } = this.stateTargets(t), p = this.pointer;
325
+ p && (this.state === "idle" || this.state === "listening" || this.state === "happy" || this.state === "speaking") && p && (i = x(p.x / 260, -1, 1) * .55, a = -x(p.y / 260, -1, 1) * .32, o = -i * .12 + (this.state === "listening" ? .12 : 0), c = x(p.x / 120, -2.4, 2.4), l = x(p.y / 160, -1.4, 1.4)), this.yaw.step(i, e, u, d), this.pitch.step(a, e, u, d), this.roll.step(o, e, u, d), this.sway.step(0, e, 1.2, .7);
326
+ let { lift: m, spin: h, lean: g } = this.stepJump(e);
327
+ t > this.nextBlink && (this.blinkAge = 0, this.nextBlink = t + 2.2 + n() * 3.5, n() < .2 && (this.nextBlink = t + .35));
328
+ let _ = 0;
329
+ this.blinkAge >= 0 && (this.blinkAge += e, _ = Math.sin(x(this.blinkAge / .17, 0, 1) * Math.PI), this.blinkAge > .17 && (this.blinkAge = -1));
330
+ let v = (this.roll.v - this.lastV.roll) / e, y = (this.pitch.v - this.lastV.pitch) / e, b = (this.sway.v - this.lastV.sway) / e;
331
+ this.lastV = {
332
+ roll: this.roll.v,
333
+ pitch: this.pitch.v,
334
+ sway: this.sway.v
335
+ };
336
+ let S = 2.3;
337
+ this.antX.v -= (v * .05 + b * .3) * e * 6, this.antZ.v -= y * .05 * e * 6, this.antX.step(0, e, S, .09), this.antZ.step(0, e, S, .09), this.antX.x = x(this.antX.x, -.7, .7), this.antZ.x = x(this.antZ.x, -.7, .7);
338
+ let C = this.squash.x;
339
+ this.pose = {
340
+ yaw: this.yaw.x + h + f,
341
+ pitch: this.pitch.x,
342
+ roll: this.roll.x + g,
343
+ x: this.sway.x,
344
+ lift: m + s,
345
+ sx: 1 + C * .55,
346
+ sy: 1 - C,
347
+ antennaX: this.antX.x,
348
+ antennaZ: this.antZ.x
349
+ }, this.face.lookX = c, this.face.lookY = l, this.face.blink = this.state === "sleeping" ? 0 : _, this.face.time = this.since;
350
+ }
351
+ }, T = (e, t, n) => {
352
+ let r = Math.hypot(e, t, n);
353
+ return [
354
+ e / r,
355
+ t / r,
356
+ n / r
357
+ ];
358
+ }, E = T(-.5, -.78, .62);
359
+ T(.85, .15, .5), T(.55, -.55, -.62), T(E[0], E[1], E[2] + 1);
360
+ var D = (e) => (e / 255) ** 2.2;
361
+ function O(e) {
362
+ return [
363
+ D(e[0]),
364
+ D(e[1]),
365
+ D(e[2])
366
+ ];
367
+ }
368
+ //#endregion
369
+ //#region ../src/color.ts
370
+ function k(e) {
371
+ let t = e.trim(), n = t.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
372
+ if (n) {
373
+ let e = n[1].length === 3 ? n[1].replace(/./g, (e) => e + e) : n[1], t = parseInt(e, 16);
374
+ return [
375
+ t >> 16 & 255,
376
+ t >> 8 & 255,
377
+ t & 255
378
+ ];
379
+ }
380
+ let r = t.match(/^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)/i);
381
+ return r ? [
382
+ Number(r[1]),
383
+ Number(r[2]),
384
+ Number(r[3])
385
+ ] : null;
386
+ }
387
+ //#endregion
388
+ //#region ../src/ticker.ts
389
+ var A = {
390
+ x: NaN,
391
+ y: NaN
392
+ }, j = /* @__PURE__ */ new Set(), M = 0, N = 0, P = !1;
393
+ function F() {
394
+ A.x = NaN, A.y = NaN;
395
+ }
396
+ function I(e) {
397
+ A.x = e.clientX, A.y = e.clientY;
398
+ }
399
+ function L() {
400
+ document.hidden ? B() : j.size && z();
401
+ }
402
+ function R(e) {
403
+ M = 0;
404
+ let t = N ? Math.min(.1, (e - N) / 1e3) : 0;
405
+ N = e, j.forEach((e) => e(t)), j.size && (M = requestAnimationFrame(R));
406
+ }
407
+ function z() {
408
+ M || typeof document > "u" || document.hidden || (N = 0, M = requestAnimationFrame(R));
409
+ }
410
+ function B() {
411
+ M && cancelAnimationFrame(M), M = 0;
412
+ }
413
+ function V() {
414
+ P || typeof document > "u" || (P = !0, document.addEventListener("pointermove", I, { passive: !0 }), document.addEventListener("pointerleave", F), window.addEventListener("blur", F), document.addEventListener("visibilitychange", L));
415
+ }
416
+ function H() {
417
+ P && (P = !1, F(), document.removeEventListener("pointermove", I), document.removeEventListener("pointerleave", F), window.removeEventListener("blur", F), document.removeEventListener("visibilitychange", L));
418
+ }
419
+ function U(e) {
420
+ return V(), j.add(e), z(), () => {
421
+ j.delete(e), j.size || (B(), H());
422
+ };
423
+ }
424
+ //#endregion
425
+ //#region ../src/solid2/RobotHead.tsx
426
+ var W = Symbol(), G = Symbol(), K = {
427
+ get() {
428
+ let e = this[W];
429
+ return e["aria-label"] ?? `Robot, ${Q(e.state)}`;
430
+ },
431
+ enumerable: !0,
432
+ configurable: !0
433
+ }, q = {
434
+ get() {
435
+ let e = this[W];
436
+ return e.class ?? e.className;
437
+ },
438
+ enumerable: !0,
439
+ configurable: !0
440
+ }, J = {
441
+ get() {
442
+ let e = this[W], t = this[G];
443
+ return ee(e.style) ? `width:${t()}px;height:${t()}px;display:block;cursor:${e.interactive === !1 ? "auto" : "pointer"};${e.style}` : {
444
+ width: `${t()}px`,
445
+ height: `${t()}px`,
446
+ display: "block",
447
+ cursor: e.interactive === !1 ? void 0 : "pointer",
448
+ ...e.style
449
+ };
450
+ },
451
+ enumerable: !0,
452
+ configurable: !0
453
+ };
454
+ function Y(e, t, n) {
455
+ this[W] = e, this[G] = t, this.role = n, Object.defineProperty(this, "aria-label", K), Object.defineProperty(this, "class", q), Object.defineProperty(this, "style", J);
456
+ }
457
+ Y.prototype = Object.prototype;
458
+ function X(e) {
459
+ let t = 2166136261;
460
+ for (let n = 0; n < e.length; n++) t = Math.imul(t ^ e.charCodeAt(n), 16777619);
461
+ return (t >>> 0) % 1e3 / 1e3;
462
+ }
463
+ function Z(e, t, n) {
464
+ let r = k(e) ?? [
465
+ 48,
466
+ 80,
467
+ 172
468
+ ], i = k(t) ?? [
469
+ 150,
470
+ 168,
471
+ 200
472
+ ], a = k(n) ?? [
473
+ 232,
474
+ 242,
475
+ 255
476
+ ];
477
+ return {
478
+ shell: {
479
+ albedo: O(r),
480
+ f0: .05,
481
+ metal: .15,
482
+ spec: .55,
483
+ shininess: 70,
484
+ rim: .9
485
+ },
486
+ trim: {
487
+ albedo: O(i),
488
+ f0: .2,
489
+ metal: .65,
490
+ spec: .8,
491
+ shininess: 45,
492
+ rim: .7
493
+ },
494
+ led: a
495
+ };
496
+ }
497
+ var Q = (e) => e && o.includes(e) ? e : "idle", $ = (e) => e && s.includes(e) ? e : "rectangle";
498
+ function ee(e) {
499
+ return typeof e == "string";
500
+ }
501
+ function te(o) {
502
+ let s = r(), c = o, l = i(o, "model", "shape", "state", "size", "color", "trimColor", "screenColor", "speed", "paused", "interactive", "floorShadow", "seed", "class", "className", "style", "onClick", "aria-label", "ref"), u, d = () => Number.isFinite(c.size) && (c.size ?? 0) > 0 ? Math.max(32, Math.min(c.size, 1024)) : 160, f = () => Number.isFinite(c.speed) && (c.speed ?? -1) >= 0 ? Math.min(c.speed, 8) : 1, p = new w(Number.isFinite(c.seed) ? Math.min(1, Math.max(0, c.seed)) : X(s), Q(c.state)), [m, h] = t(!1), [g, _] = t(!0);
503
+ return a(() => {
504
+ let e = new IntersectionObserver(([e]) => _(e.isIntersecting));
505
+ e.observe(u);
506
+ let t = window.matchMedia("(prefers-reduced-motion: reduce)");
507
+ h(t.matches);
508
+ let n = () => h(t.matches);
509
+ return t.addEventListener("change", n), () => {
510
+ e.disconnect(), t.removeEventListener("change", n);
511
+ };
512
+ }), n(() => {
513
+ let e = Q(c.state);
514
+ v($(c.shape)), d(), Z(c.color ?? "#2b49a3", c.trimColor ?? "#93a6c8", c.screenColor ?? "#e8f2ff");
515
+ let t = f(), n = c.interactive ?? !0;
516
+ c.floorShadow;
517
+ let r = (c.paused ?? !1) || !(t > 0) || m();
518
+ if (p.setState(e), r || !g()) g();
519
+ else return U((e) => {
520
+ if (n && Number.isFinite(A.x)) {
521
+ let e = u.getBoundingClientRect(), t = A.x - (e.left + e.width / 2), n = A.y - (e.top + e.height * .56);
522
+ p.pointer = Math.hypot(t, n) < 700 ? {
523
+ x: t,
524
+ y: n
525
+ } : null;
526
+ } else p.pointer = null;
527
+ p.update(e * t);
528
+ });
529
+ }), e("canvas", [new Y(c, d, "img"), l], void 0, !0);
530
+ }
531
+ //#endregion
532
+ export { te as RobotHead, s as robotHeadShapes, o as robotHeadStates };
@@ -0,0 +1,4 @@
1
+ import type { JSX } from 'solid-js';
2
+ import type { RobotHeadProps } from './types';
3
+ /** An animated TV-headed robot, rendered on a 2D canvas. */
4
+ export declare function RobotHead(props: RobotHeadProps): JSX.Element;
@@ -0,0 +1,2 @@
1
+ /** Parse #rgb, #rrggbb or rgb() into 0–255 channels; null for anything else. */
2
+ export declare function parseColor(input: string): [number, number, number] | null;
@@ -0,0 +1,8 @@
1
+ declare const states: readonly ["idle", "thinking", "searching", "listening", "speaking", "working", "happy", "error", "sleeping"];
2
+ export type RobotHeadState = typeof states[number];
3
+ export declare const robotHeadStates: RobotHeadState[];
4
+ export type RobotHeadModel = 'tv';
5
+ declare const geometries: readonly ["rectangle", "square", "circle", "hexagon"];
6
+ export type RobotHeadShape = typeof geometries[number];
7
+ export declare const robotHeadShapes: RobotHeadShape[];
8
+ export {};
@@ -0,0 +1,3 @@
1
+ export { RobotHead } from './RobotHead';
2
+ export { robotHeadStates, robotHeadShapes } from './types';
3
+ export type { RobotHeadProps, RobotHeadState, RobotHeadModel, RobotHeadShape } from './types';
@@ -0,0 +1,8 @@
1
+ type Tick = (dt: number) => void;
2
+ /** Where the pointer last was on the page, NaN while it is away. */
3
+ export declare const pointer: {
4
+ x: number;
5
+ y: number;
6
+ };
7
+ export declare function subscribe(fn: Tick): () => void;
8
+ export {};
@@ -0,0 +1,28 @@
1
+ import type { RobotHeadState } from '../domain-types';
2
+ export declare const COLS = 22;
3
+ export declare const ROWS = 14;
4
+ export interface FaceParams {
5
+ lookX: number;
6
+ lookY: number;
7
+ blink: number;
8
+ time: number;
9
+ side: number;
10
+ seed: number;
11
+ }
12
+ export interface Grid {
13
+ v: Float32Array;
14
+ cols: number;
15
+ rows: number;
16
+ ox: number;
17
+ oy: number;
18
+ }
19
+ /** A matrix of `cols` × `rows` (each at least the face area, by even steps) with the face area centred. */
20
+ export declare function makeGrid(cols: number, rows: number): Grid;
21
+ export declare const FACES: Record<RobotHeadState, (g: Grid, f: FaceParams) => void>;
22
+ /** The light the screen and the antenna ball carry in a state. */
23
+ export interface StateLight {
24
+ screen: [number, number, number] | null;
25
+ ball: [number, number, number];
26
+ pulse: (t: number) => number;
27
+ }
28
+ export declare const LIGHTS: Record<RobotHeadState, StateLight>;
@@ -0,0 +1,62 @@
1
+ import type { RobotHeadShape } from '../domain-types';
2
+ export type V3 = [number, number, number];
3
+ export declare const HEAD: {
4
+ readonly bevel: 0.075;
5
+ readonly margin: 0.045;
6
+ readonly gasket: 0.022;
7
+ readonly recess: 0.03;
8
+ readonly earY: 0.03;
9
+ readonly stem: 0.2;
10
+ readonly ball: 0.052;
11
+ };
12
+ export declare const INSET: {
13
+ readonly plate: 0.075;
14
+ readonly hole: number;
15
+ readonly glass: number;
16
+ };
17
+ export interface Mesh {
18
+ pos: Float32Array;
19
+ quads: Uint16Array;
20
+ normals: Float32Array;
21
+ }
22
+ /** v' = Roll · Yaw · Pitch · v, row-major. */
23
+ export declare function rotation(yaw: number, pitch: number, roll: number): number[];
24
+ export declare function rotate(m: number[], x: number, y: number, z: number): V3;
25
+ interface Corner {
26
+ x: number;
27
+ y: number;
28
+ a0: number;
29
+ a1: number;
30
+ }
31
+ export interface Shape {
32
+ name: RobotHeadShape;
33
+ r: number;
34
+ depth: number;
35
+ corners: Corner[];
36
+ hx: number;
37
+ hy: number;
38
+ pitch: number;
39
+ earX: number;
40
+ screws: Array<[number, number, number]>;
41
+ backScrews: Array<[number, number, number]>;
42
+ /** Signed distance to the outline inset by `inset` (negative inside). */
43
+ sd: (x: number, y: number, inset: number) => number;
44
+ /** Trace the outline inset by `inset` as a closed path. */
45
+ path: (ctx: CanvasRenderingContext2D | Path2D, inset: number) => void;
46
+ }
47
+ export declare function getShape(name: RobotHeadShape): Shape;
48
+ /** The shell's sides and its rolled edges, front and back (the flat faces are drawn as plates). */
49
+ export declare function buildBody(shape: Shape, bevelSteps?: number): Mesh;
50
+ /**
51
+ * A solid of revolution: `profile` is [radius, distance along the axis]
52
+ * from `origin` outward, closing on the axis at its end.
53
+ */
54
+ export declare function buildLathe(profile: Array<[number, number]>, origin: V3, axis: V3, segments?: number): Mesh;
55
+ export interface HeadMeshes {
56
+ body: Mesh;
57
+ earL: Mesh;
58
+ earR: Mesh;
59
+ collar: Mesh;
60
+ }
61
+ export declare function headMeshes(shape: Shape): HeadMeshes;
62
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { V3 } from './geometry';
2
+ export interface Material {
3
+ albedo: V3;
4
+ f0: number;
5
+ metal: number;
6
+ spec: number;
7
+ shininess: number;
8
+ rim: number;
9
+ }
10
+ export declare const KEY: V3;
11
+ export declare function linear(rgb: [number, number, number]): V3;
12
+ /** The shell's colour at a world-space normal, as linear light. */
13
+ export declare function radiance(m: Material, nx: number, ny: number, nz: number, out?: V3): V3;
14
+ export declare function css(c: V3, alpha?: number): string;
15
+ export declare function shadeCss(m: Material, nx: number, ny: number, nz: number): string;
16
+ export declare function luma(c: V3): number;