robot-heads-solid 0.0.0-stage → 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fayaz Ahmed
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,93 @@
1
- # Temporary Holding Version
1
+ # robot-heads-solid
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Animated robot heads for Solid. Four shapes, nine states, and the same Canvas 2D rendering engine as [Fayaz Ahmed's robot-heads](https://github.com/fayazara/robot-heads).
4
+
5
+ This is an independent Solid port of the MIT-licensed React project. The rendering, geometry, lighting, faces, and motion come from upstream. The component, playground, and build setup use Solid.
6
+
7
+ ## Install
8
+
9
+ ~~~sh
10
+ bun add robot-heads-solid@beta
11
+ ~~~
12
+
13
+ The next release is `0.1.0-beta.1`; the published `beta` tag remains on `0.1.0-beta.0` until this version is released. Use `@beta` explicitly while there is no stable `latest` release. Tested with Solid 1.9.17. Solid 2 prerelease compatibility has not been verified; its current release candidate does not provide the Solid 1 `solid-js/web` and `solid-js/jsx-runtime` entry points used by the tested consumer toolchain. React, Three.js, and WebGL are not required.
14
+
15
+ ## Usage
16
+
17
+ ~~~tsx
18
+ import { createSignal } from 'solid-js';
19
+ import { RobotHead } from 'robot-heads-solid';
20
+
21
+ function Example() {
22
+ const [state, setState] = createSignal<'idle' | 'thinking' | 'working'>('idle');
23
+
24
+ return (
25
+ <>
26
+ <RobotHead
27
+ state={state()}
28
+ shape="rectangle"
29
+ size={160}
30
+ color="#2b49a3"
31
+ trimColor="#93a6c8"
32
+ screenColor="#e8f2ff"
33
+ speed={1}
34
+ interactive
35
+ floorShadow
36
+ />
37
+ <button onClick={() => setState('thinking')}>Think</button>
38
+ </>
39
+ );
40
+ }
41
+ ~~~
42
+
43
+ The component forwards ordinary Solid canvas attributes, event handlers, styling, accessibility attributes, and a canvas ref. State and appearance props react to Solid signals.
44
+
45
+ ### Shapes
46
+
47
+ 'rectangle' (default), 'square', 'circle', 'hexagon'. Exported as `robotHeadShapes`.
48
+
49
+ ### States
50
+
51
+ 'idle', 'thinking', 'searching', 'listening', 'speaking', 'working', 'happy', 'error', 'sleeping'. Exported as `robotHeadStates`.
52
+
53
+ ### Props
54
+
55
+ | Prop | Type | Default |
56
+ | --- | --- | --- |
57
+ | 'model' | 'tv' | 'tv' |
58
+ | 'shape' | 'RobotHeadShape' | 'rectangle' |
59
+ | 'state' | 'RobotHeadState' | 'idle' |
60
+ | 'size' | 'number' (px) | 160 |
61
+ | 'color' | 'string' | '#2b49a3' |
62
+ | 'trimColor' | 'string' | '#93a6c8' |
63
+ | 'screenColor' | 'string' | '#e8f2ff' |
64
+ | 'speed' | 'number' | 1 |
65
+ | 'paused' | 'boolean' | false |
66
+ | 'interactive' | 'boolean' | true |
67
+ | 'floorShadow' | 'boolean' | true |
68
+ | 'seed' | 'number' (0–1) | generated per instance |
69
+
70
+ Animations use one shared requestAnimationFrame loop and stop when the page is hidden or the canvas leaves the viewport. Disabled or reduced motion draws the resting pose. Invalid sizes and speeds fall back to defaults; positive sizes are clamped to 32–1024px and speeds to 8× to keep rendering and simulation work bounded. Interactive heads follow the pointer and respond to clicks. The canvas defaults to 'role="img"' and an accessible state label. Node SSR imports resolve to server-compiled ESM/CJS builds; the canvas is rendered as markup and drawn once mounted on the client.
71
+
72
+ ## Development
73
+
74
+ ~~~sh
75
+ bun install
76
+ bun run dev # Solid playground
77
+ bun run lint # Oxlint: anti-slop rules and classic complexity (max 20)
78
+ bun run typecheck
79
+ bun run build # browser and SSR ES/CJS bundles and declarations
80
+ bun run check # lint, library and playground checks
81
+ bun run e2e # playground browser regressions, including all 36 shape/state combinations
82
+ bun run e2e:consumer # packed Solid 1 consumer: typecheck, browser and Node ESM/CJS SSR
83
+ ~~~
84
+
85
+ The playground lives in 'site/'. The library is in 'src/'. To build the Cloudflare Worker playground, run 'bun run deploy' after configuring your Cloudflare account.
86
+
87
+ Lint uses the vendored rules in 'tools/oxlint/anti-slop/' plus Oxlint's native accumulating-spread and ESLint classic cyclomatic-complexity rules. Geometric shape names are explicitly allowed by the shape-name rule because shape is a real domain concept here; unrelated `*Shape` names remain forbidden. Legitimate TypeScript type predicates may use `typeof` to distinguish Solid's callback and style unions. Browser screenshots and pixel observations are saved under 'test-results/'.
88
+
89
+ For now, the playground loads Open Runde fonts from the upstream repository because the source font binaries could not be transferred through the available GitHub connection. The library itself does not require fonts or external assets.
90
+
91
+ ## Attribution and licensing
92
+
93
+ Original design and Canvas renderer by [Fayaz Ahmed](https://github.com/fayazara/robot-heads), copyright © 2026 Fayaz Ahmed, licensed MIT. The original MIT license is preserved in [LICENSE](./LICENSE). Open Runde by Laurids Kern, licensed SIL OFL 1.1; see 'site/public/fonts/OFL.txt'. The Solid port is also distributed under MIT.
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("solid-js/web"),t=require("solid-js");var n=[`idle`,`thinking`,`searching`,`listening`,`speaking`,`working`,`happy`,`error`,`sleeping`],r=[`rectangle`,`square`,`circle`,`hexagon`],i={bevel:.075,margin:.045,gasket:.022,recess:.03,earY:.03,stem:.2,ball:.052},a={plate:i.bevel,hole:i.bevel+i.margin,glass:i.bevel+i.margin+i.gasket};function o(e,t,n){let r=Math.cos(e),i=Math.sin(e),a=Math.cos(t),o=Math.sin(t),s=Math.cos(n),c=Math.sin(n),l=[r,i*o,i*a,0,a,-o,-i,r*o,r*a];return[s*l[0]-c*l[3],s*l[1]-c*l[4],s*l[2]-c*l[5],c*l[0]+s*l[3],c*l[1]+s*l[4],c*l[2]+s*l[5],l[6],l[7],l[8]]}function s(e,t,n,r){return[e[0]*t+e[1]*n+e[2]*r,e[3]*t+e[4]*n+e[5]*r,e[6]*t+e[7]*n+e[8]*r]}var c=(e,t,n)=>{let r=Math.hypot(e,t,n)||1;return[e/r,t/r,n/r]},l=Math.PI*2;function u(e,t,n,r,o,s){let c=t.map(([e,t])=>({x:e,y:t,t:Math.atan2(t,e)})).sort((e,t)=>e.t-t.t),u=c.length,d=[];for(let e=0;e<u;e++){let t=c[e],n=c[(e+1)%u];d.push(Math.atan2(-(n.x-t.x),n.y-t.y))}let p=c.map((e,t)=>{if(u===1)return{x:e.x,y:e.y,a0:-Math.PI,a1:Math.PI};let n=d[(t-1+u)%u],r=d[t];for(;r<n;)r+=l;return{x:e.x,y:e.y,a0:n,a1:r}}),m=(e,t)=>{if(u===1)return Math.hypot(e-c[0].x,t-c[0].y);let n=1/0,r=!0;for(let i=0;i<u;i++){let a=c[i],o=c[(i+1)%u],s=o.x-a.x,l=o.y-a.y,d=e-a.x,f=t-a.y,p=Math.max(0,Math.min(1,(d*s+f*l)/(s*s+l*l)));n=Math.min(n,Math.hypot(d-s*p,f-l*p)),s*f-l*d<0&&(r=!1)}return r?-n:n},h=(e,t,r)=>m(e,t)-(n-r),g=(e,t)=>{let r=Math.max(5e-4,n-t);p.forEach((t,n)=>{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)}),e.closePath()},_=0,v=0;for(let e of c)_=Math.max(_,Math.abs(e.x)+n),v=Math.max(v,Math.abs(e.y)+n);let y=0,b=_+.1;for(let e=0;e<40;e++){let e=(y+b)/2;h(e,i.earY,0)<0?y=e:b=e}let x=(e,t)=>e.map((e,r)=>{let i=e*Math.PI/180,a=p.find(e=>[i,i+l,i-l].some(t=>t>=e.a0-1e-6&&t<=e.a1+1e-6))??p[0];return[a.x+Math.cos(i)*(n-t),a.y+Math.sin(i)*(n-t),.5+r*.9]}),S=2*(_-a.glass),C=2*(v-a.glass),w=Math.min(f*S/14,.65*C/10);return{name:e,r:n,depth:r,corners:p,hx:_,hy:v,pitch:w,earX:y-.008,screws:x(o,(a.hole-.018+a.plate)/2),backScrews:x(s,a.plate+.07),sd:h,path:g}}var d=e=>[0,60,120,180,240,300].map(t=>[e*Math.cos(t*Math.PI/180),e*Math.sin(t*Math.PI/180)]),f=.6,p=[45,135],m=[-135,-45,45,135],h={rectangle:()=>u(`rectangle`,[[-.29,-.17],[.29,-.17],[.29,.17],[-.29,.17]],.21,.6,p,m),square:()=>u(`square`,[[-.22,-.22],[.22,-.22],[.22,.22],[-.22,.22]],.2,.6,p,m),circle:()=>u(`circle`,[[0,0]],.46,.56,p,m),hexagon:()=>u(`hexagon`,d(.35),.16,.58,[60,120],[-120,-60,60,120])},g=new Map;function _(e){let t=g.get(e);return t||(t=(h[e]??h.rectangle)(),g.set(e,t)),t}function v(e,t,n){let r=new Float32Array(t.length/4*3);for(let e=0;e<t.length/4;e++){let i=0,a=0,o=0;for(let r=0;r<4;r++){let s=t[e*4+r]*3;i+=n[s],a+=n[s+1],o+=n[s+2]}r.set(c(i,a,o),e*3)}return{pos:new Float32Array(e),quads:new Uint16Array(t),normals:r}}function y(e,t,n=!0){let r=[],i=n?t:t-1;for(let n=0;n<e-1;n++)for(let e=0;e<i;e++){let i=(e+1)%t;r.push(n*t+e,n*t+i,(n+1)*t+i,(n+1)*t+e)}return r}function b(e,t=10){let n=e.r,r=i.bevel,a=e.depth/2,o=[];for(let t of e.corners){let e=t.a1-t.a0,n=Math.max(2,Math.ceil(e/(Math.PI/2)*14)),r=e>=l-1e-6?n-1:n;for(let i=0;i<=r;i++){let r=t.a0+i/n*e;o.push([t.x,t.y,Math.cos(r),Math.sin(r)])}}let s=[];for(let e=t;e>=0;e--){let n=e/t*(Math.PI/2);s.push([-a+r-r*Math.sin(n),r*(1-Math.cos(n)),-n])}for(let e=0;e<=t;e++){let n=e/t*(Math.PI/2);s.push([a-r+r*Math.sin(n),r*(1-Math.cos(n)),n])}let c=[],u=[];for(let[e,t,r]of s)for(let[i,a,s,l]of o)c.push(i+(n-t)*s,a+(n-t)*l,e),u.push(s*Math.cos(r),l*Math.cos(r),Math.sin(r));return v(c,y(s.length,o.length),u)}function x(e,t,n,r=36){let i=Math.abs(n[1])>.9?[1,0,0]:[0,1,0],a=c(n[1]*i[2]-n[2]*i[1],n[2]*i[0]-n[0]*i[2],n[0]*i[1]-n[1]*i[0]),o=[],s=[];for(let c=0;c<e.length;c++){let[u,d]=e[c],f=e[Math.max(0,c-1)],p=e[Math.min(e.length-1,c+1)],m=p[0]-f[0],h=p[1]-f[1],g=Math.hypot(m,h)||1,_=h/g,v=-m/g;for(let e=0;e<r;e++){let c=e/r*l,f=Math.cos(c)*i[0]+Math.sin(c)*a[0],p=Math.cos(c)*i[1]+Math.sin(c)*a[1],m=Math.cos(c)*i[2]+Math.sin(c)*a[2];o.push(t[0]+n[0]*d+u*f,t[1]+n[1]*d+u*p,t[2]+n[2]*d+u*m),s.push(f*_+n[0]*v,p*_+n[1]*v,m*_+n[2]*v)}}return v(o,y(e.length,r),s)}var S=[[.06,-.012],[.068,0],[.074,.006],[.08,.018],[.084,.032],[.084,.048],[.079,.06],[.068,.07],[.052,.077],[.032,.081],[.014,.083],[0,.0835]],C=[[.05,-.012],[.052,.006],[.05,.016],[.042,.024],[.026,.029],[.014,.031],[0,.032]],w=new Map;function T(e){let t=w.get(e.name);return t||(t={body:b(e),earL:x(S,[-e.earX,i.earY,0],[-1,0,0]),earR:x(S,[e.earX,i.earY,0],[1,0,0]),collar:x(C,[0,-e.hy,0],[0,-1,0],16)},w.set(e.name,t)),t}var E=class{x=0;v=0;constructor(e=0){this.x=e}step(e,t,n,r){let i=n*Math.PI*2;this.v+=(i*i*(e-this.x)-2*r*i*this.v)*t,this.x+=this.v*t}};function D(e){let t=Math.floor(e*4294967295)>>>0||1;return()=>{t=t+1831565813>>>0;let e=t;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}}var O=(e,t,n)=>Math.min(n,Math.max(t,e)),k=e=>e<.5?4*e*e*e:1-(-2*e+2)**3/2,A=.11,j=class{state;shown;previous;switched=10;age=0;time=0;since=0;pose={yaw:0,pitch:0,roll:0,x:0,lift:0,sx:1,sy:1,antennaX:0,antennaZ:0};face;pointer=null;yaw=new E;pitch=new E;roll=new E;sway=new E;squash=new E;antX=new E;antZ=new E;lastV={roll:0,pitch:0,sway:0};jump=null;random;lookAt={yaw:0,pitch:0,x:0,y:0};nextLook=.6;nextBlink=1.5;blinkAge=-1;nextHop=8;nextSide=4;reactUntil=-1;nextNod=2.5;constructor(e,t){this.random=D(e),this.state=this.shown=this.previous=t,this.face={lookX:0,lookY:0,blink:0,time:0,side:1,seed:e},this.nextBlink=1+this.random()*3,this.nextHop=6+this.random()*6}setState(e){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))}poke(){this.hop(.24,this.random()<.5?1:-1),this.reactUntil=this.time+1.6}hop(e,t){this.jump||={age:0,height:e,spin:t,lean:(this.random()-.5)*.3,air:.42+e*.45,landed:!1}}update(e){if(!Number.isFinite(e)||!(e>0))return;let t=Math.min(e,.8),n=Math.max(1,Math.ceil(t/(1/120)));for(let e=0;e<n;e++)this.step(t/n)}stepJump(e){let t=0,n=0,r=0,i=0,a=this.jump,o=this.random;if(a){if(a.age+=e,a.age<A)i=.14;else{let e=(a.age-A)/a.air;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*k(O(e*1.08,0,1)),r=a.lean*Math.sin(e*Math.PI),i=e<.5?-.05:0):a.landed?a.age-A-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)}}return this.squash.step(i,e,3.2,.32),{lift:t,spin:n,lean:r}}hopWithChance(e,t){this.hop(e,this.random()<t?this.random()<.5?1:-1:0)}updateLookAt(e){if(e>this.nextLook){let t=this.random;this.lookAt={yaw:(t()-.5)*.75,pitch:(t()-.5)*.24,x:0,y:0},this.lookAt.x=O(Math.round(this.lookAt.yaw*5),-2,2),this.lookAt.y=t()<.3?-1:+(t()<.2),this.nextLook=e+1.4+t()*2.6}}stateTargets(e){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;switch(this.state){case`idle`: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);break;case`thinking`:{e>this.nextSide&&(this.face.side=-this.face.side,this.nextSide=e+3+t()*2);let a=this.face.side;n=.24*a+Math.sin(e*.9)*.05,r=.17+Math.sin(e*1.3)*.03,i=-.13*a,c=.9;break}case`searching`:{let t=e*1.6;n=Math.sin(t)*.55,r=-.04+Math.sin(t*2)*.04,i=Math.sin(t)*-.06,o=O(Math.sin(t+.4)*3,-3,3),c=2.2,l=.8;break}case`listening`:n=-.14,r=.02,i=.17,e>this.nextNod&&(this.pitch.v-=.9,this.nextNod=e+2+t()*2.5);break;case`speaking`: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;break;case`working`: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);break;case`happy`: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);break;case`error`:{let t=e%2.4/.7;u=t<1?Math.sin(t*Math.PI*7)*.22*(1-t):0,r=-.06,i=-.05,c=1.6;break}case`sleeping`: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);break;default:this.state}return{yaw:n,pitch:r,roll:i,bob:a,lookX:o,lookY:s,freq:c,damping:l,shake:u}}step(e){this.time+=e,this.since+=e,this.age+=e,this.switched+=e;let t=this.time,n=this.random,r=t<this.reactUntil?`happy`:this.state;r!==this.shown&&(this.previous=this.shown,this.shown=r,this.switched=0),this.updateLookAt(t);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;p&&(this.state===`idle`||this.state===`listening`||this.state===`happy`||this.state===`speaking`)&&p&&(i=O(p.x/260,-1,1)*.55,a=-O(p.y/260,-1,1)*.32,o=-i*.12+(this.state===`listening`?.12:0),c=O(p.x/120,-2.4,2.4),l=O(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);let{lift:m,spin:h,lean:g}=this.stepJump(e);t>this.nextBlink&&(this.blinkAge=0,this.nextBlink=t+2.2+n()*3.5,n()<.2&&(this.nextBlink=t+.35));let _=0;this.blinkAge>=0&&(this.blinkAge+=e,_=Math.sin(O(this.blinkAge/.17,0,1)*Math.PI),this.blinkAge>.17&&(this.blinkAge=-1));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;this.lastV={roll:this.roll.v,pitch:this.pitch.v,sway:this.sway.v};let x=2.3;this.antX.v-=(v*.05+b*.3)*e*6,this.antZ.v-=y*.05*e*6,this.antX.step(0,e,x,.09),this.antZ.step(0,e,x,.09),this.antX.x=O(this.antX.x,-.7,.7),this.antZ.x=O(this.antZ.x,-.7,.7);let S=this.squash.x;this.pose={yaw:this.yaw.x+h+f,pitch:this.pitch.x,roll:this.roll.x+g,x:this.sway.x,lift:m+s,sx:1+S*.55,sy:1-S,antennaX:this.antX.x,antennaZ:this.antZ.x},this.face.lookX=c,this.face.lookY=l,this.face.blink=this.state===`sleeping`?0:_,this.face.time=this.since}};function ee(e){let t={yaw:0,pitch:0,roll:0,x:0,lift:0,sx:1,sy:1,antennaX:0,antennaZ:0};switch(e){case`thinking`:return{...t,yaw:.24,pitch:.17,roll:-.13};case`searching`:return{...t,yaw:.3,roll:-.04};case`listening`:return{...t,yaw:-.14,pitch:.02,roll:.17};case`working`:return{...t,pitch:-.16};case`happy`:return{...t,pitch:.08,roll:.06};case`error`:return{...t,pitch:-.06,roll:-.05};case`sleeping`:return{...t,pitch:-.34,roll:.13,yaw:.06};case`idle`:return{...t,yaw:-.18,pitch:.04,roll:.03};case`speaking`:return{...t,yaw:-.18,pitch:.04,roll:.03};default:return t}}function M(e,t){let n=22+2*Math.max(0,Math.ceil((e-22)/2)),r=14+2*Math.max(0,Math.ceil((t-14)/2));return{v:new Float32Array(n*r),cols:n,rows:r,ox:(n-22)/2,oy:(r-14)/2}}var N=(e,t,n,r)=>{let i=t+e.ox,a=n+e.oy;if(i<0||a<0||i>=e.cols||a>=e.rows)return;let o=a*e.cols+i;r>e.v[o]&&(e.v[o]=r)},P=(e,t,n,r,i,a)=>{for(let o=n;o<n+i;o++)for(let n=t;n<t+r;n++)N(e,n,o,a)},F=(e,t,n,r,i)=>{r.forEach((r,a)=>{for(let o=0;o<r.length;o++)r[o]===`#`?N(e,t+o,n+a,i):r[o]===`+`&&N(e,t+o,n+a,i*.5)})},I=6,L=13,R=5;function z(e,t,n=4,r=1,i=0,a=0){let o=Math.round(t.lookX),s=Math.round(t.lookY)+i,c=Math.max(1,Math.round(n-(n-1)*t.blink)),l=R+Math.floor((4-n)/2)+s+Math.floor((n-c)/2);for(let t of[I,L])a>0&&c>1?(P(e,t+o,l,3,1,r*(1-a)),P(e,t+o,l+1,3,c-1,r)):P(e,t+o,l,3,c,r)}var te=e=>.5+.25*Math.sin(e*1.7)+.15*Math.sin(e*3.1+1.3)+.1*Math.sin(e*5.3+4.1),ne=[`..#..`,`.#.#.`,`#...#`],re=[`#...#`,`.#.#.`,`..#..`,`.#.#.`,`#...#`],ie=[`####`,`..#.`,`.#..`,`####`],ae=[`###`,`.#.`,`###`],oe={idle(e,t){z(e,t)},thinking(e,t){z(e,{...t,lookX:t.lookX+t.side*1.4,lookY:t.lookY-1.2},3,1,0,.45);for(let n=0;n<3;n++){let r=(t.time*1.6-n*.22)%1,i=r<.35?Math.sin(r/.35*Math.PI):0;P(e,6+n*4,11-(i>.5),2,2,.28+.72*i)}},searching(e,t){z(e,t);let n=-e.ox,r=21+e.ox,i=n+(Math.sin(t.time*1.6+.4)*.5+.5)*(r-n),a=Math.cos(t.time*1.6+.4)>0?-1:1;for(let t=0;t<5;t++){let n=Math.round(i+a*t),r=.32*(1-t/5);for(let t=-e.oy;t<14+e.oy;t++)N(e,n,t,r)}},listening(e,t){z(e,t,4,1,-1);for(let n=0;n<12;n++){let r=1-Math.abs(n-5.5)/7,i=te(t.time*7+n*1.9+t.seed*10)*r,a=Math.max(1,Math.round(i*4));for(let t=0;t<a;t++)N(e,5+n,12-t,.75-t*.12)}},speaking(e,t){z(e,t,4,1,-1);let n=Math.max(0,Math.sin(t.time*2.1)*.5+Math.sin(t.time*3.7+1)*.5);for(let r=0;r<8;r++){let i=1-Math.abs(r-3.5)/5,a=te(t.time*11+r*.9)*i*(.35+n),o=a>.55?3:a>.28?2:1,s=o===3?10:11,c=o===3?3:o===2?2:1;P(e,7+r,s,1,c,1)}},working(e,t){z(e,{...t,lookY:t.lookY+1},2,1,0);let n=t.time/2.6%1,r=Math.round(n*12);for(let t=0;t<12;t++)N(e,5+t,11,t<r?.95:.16);N(e,4,11,.4),N(e,17,11,.4)},happy(e,t){let n=Math.round(Math.max(0,Math.sin(t.time*5.6))*-1);F(e,5,R+n,ne,1),F(e,12,R+n,ne,1),F(e,7,10+n,[`#......#`,`.######.`],.9)},error(e,t){let n=Math.sin(t.time*7)>-.6?1:.55;F(e,5,4,re,n),F(e,12,4,re,n);for(let t=0;t<8;t++)N(e,7+t,t%2?11:12,.8)},sleeping(e,t){for(let t of[I,L])N(e,t-1,7,.32),P(e,t,8,3,1,.42),N(e,t+3,7,.32);for(let[n,r]of[[0,!0],[1.1,!1]]){let i=(t.time+n)/2.2%1,a=Math.sin(i*Math.PI)*.6,o=Math.round(5-i*5);F(e,16+Math.round(i*2),o,r?ie:ae,a)}}},se=e=>()=>e,ce={idle:{screen:null,ball:[255,250,240],pulse:e=>.75+.1*Math.sin(e*1.4)},thinking:{screen:null,ball:[255,184,64],pulse:e=>.45+.55*(.5+.5*Math.sin(e*4.2))},searching:{screen:null,ball:[90,220,255],pulse:e=>e*2.4%1<.18?1:.25},listening:{screen:null,ball:[96,255,150],pulse:se(.95)},speaking:{screen:null,ball:[255,250,240],pulse:e=>.55+.45*te(e*11)},working:{screen:null,ball:[110,160,255],pulse:e=>e*1.7%1<.5?1:.35},happy:{screen:null,ball:[255,130,200],pulse:e=>.8+.2*Math.sin(e*8)},error:{screen:[255,70,64],ball:[255,60,50],pulse:e=>e*3%1<.5?1:.15},sleeping:{screen:null,ball:[255,250,240],pulse:se(0)}},B=(e,t,n)=>{let r=Math.hypot(e,t,n);return[e/r,t/r,n/r]},V=B(-.5,-.78,.62),le=B(.85,.15,.5),ue=B(.55,-.55,-.62),de=B(V[0],V[1],V[2]+1),H=(e,t,n)=>{let r=Math.min(1,Math.max(0,(n-e)/(t-e)));return r*r*(3-2*r)};function fe(e,t,n){let r=-t,i=.05+.12*H(-.25,.3,r),a=1.1*H(.42,.78,r)*H(-.9,-.2,n-.6*Math.abs(e)),o=2.6*H(.86,.97,e*V[0]+t*V[1]+n*V[2]),s=.5*H(.6,.85,-e)*H(-.35,.05,r)*(1-H(.2,.5,r));return i+a+o+s}var pe=e=>(e/255)**2.2;function me(e){return[pe(e[0]),pe(e[1]),pe(e[2])]}function U(e){let t=e*(2.51*e+.03)/(e*(2.43*e+.59)+.14);return Math.round(255*Math.min(1,Math.max(0,t))**(1/2.2))}function he(e,t,n,r,i=[0,0,0]){let a=t*V[0]+n*V[1]+r*V[2],o=Math.max(0,(a+.12)/1.12),s=Math.max(0,t*le[0]+n*le[1]+r*le[2]),c=.5-.5*n,l=Math.max(0,r),u=e.f0+(1-e.f0)*(1-l)**5,d=fe(2*l*t,2*l*n,2*l*r-1)*u,f=e.spec*Math.max(0,t*de[0]+n*de[1]+r*de[2])**+e.shininess,p=Math.max(0,t*ue[0]+n*ue[1]+r*ue[2]),m=e.rim*p*p*(1-l)**1.6,h=.05+.1*c+1.25*o+.16*s;for(let t=0;t<3;t++){let n=e.albedo[t],r=1-e.metal+e.metal*n*2.2,a=t===0?.62:t===1?.78:1;i[t]=n*h*(1-u*.6)+(d+f)*r+m*a*(.35+n)}return i}function ge(e,t=1){return t>=1?`rgb(${U(e[0])},${U(e[1])},${U(e[2])})`:`rgba(${U(e[0])},${U(e[1])},${U(e[2])},${t})`}function _e(e,t,n,r){return ge(he(e,t,n,r))}var W=(e,t)=>{let n=document.createElement(`canvas`);return n.width=Math.max(1,Math.ceil(e)),n.height=Math.max(1,Math.ceil(t)),n},G=(e,t,n)=>{let r=Math.min(1,Math.max(0,(n-e)/(t-e)));return r*r*(3-2*r)},ve=(e,t)=>{let n=Math.imul(e,374761393)+Math.imul(t,668265263);return n=Math.imul(n^n>>>13,1274126177),((n^n>>>16)>>>0)/4294967296},ye=(()=>{let e=Math.hypot(V[0],V[1],V[2]+1);return[V[0]/e,V[1]/e,(V[2]+1)/e]})(),K={antenna:.028+i.stem+i.ball*1.8,glow:.18,hop:.3,shadow:.22,margin:.02},be=.035,xe=e=>({hx:e.hx-a.glass,hy:e.hy-a.glass});function Se(e){let t=xe(e);return{hx:Math.max(t.hx,11*e.pitch)+be,hy:Math.max(t.hy,7*e.pitch)+be}}var Ce=e=>({hx:e.hx-a.plate,hy:e.hy-a.plate});function we(e,t,n){let r=Ce(e),i=W(Math.ceil(r.hx*2*t),Math.ceil(r.hy*2*t)),o=i.getContext(`2d`),s=o.createImageData(i.width,i.height),c=s.data,l=r.hx*2/i.width;for(let t=0;t<i.height;t++){let o=-r.hy+(t+.5)*l;for(let s=0;s<i.width;s++){let u=-r.hx+(s+.5)*l,d=e.sd(u,o,a.plate),f=Math.min(1,Math.max(0,.5-d/l));if(f<=0)continue;let p=n(u,o,l,s,t),m=(t*i.width+s)*4,h=Math.min(1,Math.abs(p))*f,g=p>0?255:0;c[m]=c[m+1]=c[m+2]=g,c[m+3]=Math.round(h*255)}}return o.putImageData(s,0,0),i}function q(e,t,n,r=.55,i=36){let a=Math.hypot(e,t,n);return e/=a,t/=a,n/=a,(e*V[0]+t*V[1]+n*V[2]-V[2])*.95+r*Math.max(0,e*ye[0]+t*ye[1]+n*ye[2])**+i-r*ye[2]**+i}function Te(e,t,n){let r=.0015,i=e(t+r,n)-e(t-r,n),a=e(t,n+r)-e(t,n-r),o=Math.hypot(i,a)||1;return[i/o,a/o]}function Ee(e,t,n,r,i){let a=.013,o=e-n,s=t-r,c=Math.hypot(o,s);if(c>.019)return null;if(c>a)return-.5*(1-(c-a)/.006);let l=Math.sqrt(Math.max(0,1-(c/a)**2))+.6,u=q(o/a,s/a,l,.9,30)*1.3+.08,d=Math.cos(i);return Math.abs(o*-Math.sin(i)+s*d)<.0026&&c<a*.8&&(u=-.65),u}function De(e,t){let n=.018,r=(t,n)=>e.sd(t,n,a.hole),o=(t,n)=>e.sd(t,n,a.glass),s=e.screws;return we(e,t,(e,t,a,c,l)=>{let u=(ve(c,l)-.5)*.07;for(let[n,r,i]of s){let a=Ee(e,t,n,r,i);if(a!==null)return a}let d=r(e,t);if(d>=0){if(d<n){let[i,a]=Te(r,e,t),o=1-d/n,s=o*o*1.25;return q(-i*Math.sin(s),-a*Math.sin(s),Math.cos(s))+u}return u}let f=o(e,t);if(f>=0){let n=f/i.gasket,[r,a]=Te(o,e,t),s=(n-.45)*2.2;return q(r*Math.sin(s),a*Math.sin(s),Math.cos(s),.22,14)*.7+u*.4}let p=.05;return-(.5*G(-.012,.012,o(e-V[0]*p,t-V[1]*p))+.32*Math.exp(f/.014))})}function Oe(e,t){let n=[-.12,-.065,-.01,.045,.1],r=(t,n)=>e.sd(t,n,a.plate+.04),i=e.backScrews;return we(e,t,(e,t,a,o,s)=>{let c=(ve(o,s)-.5)*.07;for(let[n,r,a]of i){let i=Ee(e,t,n,r,a);if(i!==null)return i}let l=r(e,t);if(Math.abs(l)<.006){let[n,i]=Te(r,e,t),a=l/.006*1.1;return q(-n*Math.sin(a),-i*Math.sin(a),Math.cos(a))*.9-.18}for(let r of n){let n=(e,t)=>Math.hypot(Math.max(0,Math.abs(e)-.196),t-r)-.014,i=n(e,t);if(i<0)return-.72-.15*G(-.014,0,-(t-r));if(i<.01){let[r,a]=Te(n,e,t),o=(1-i/.01)**2*1.2;return q(-r*Math.sin(o),-a*Math.sin(o),Math.cos(o))+c}}return c})}function ke(e,t,n,r,i,a){let o=W(e,t),s=o.getContext(`2d`),c=s.createRadialGradient(e*.5,t*.45,0,e*.5,t*.5,Math.max(e,t)*.65);c.addColorStop(0,`#111417`),c.addColorStop(1,`#050607`),s.fillStyle=c,s.fillRect(0,0,e,t);let l=n*.8,u=(n-l)/2,d=`rgba(${Math.round(60+a[0]*.12)},${Math.round(64+a[1]*.12)},${Math.round(70+a[2]*.12)},0.34)`,f=-Math.ceil(r/n),p=Math.ceil((e-r)/n),m=-Math.ceil(i/n),h=Math.ceil((t-i)/n);s.fillStyle=d;for(let e=m;e<h;e++)for(let t=f;t<p;t++)s.fillRect(r+t*n+u,i+e*n+u,l,l);s.fillStyle=`rgba(255,255,255,0.05)`;for(let e=m;e<h;e++)for(let t=f;t<p;t++)s.fillRect(r+t*n+u,i+e*n+u,l,Math.max(1,l*.16));return o}function Ae(e,t){let n=W(e,t),r=n.getContext(`2d`),i=r.createRadialGradient(e/2,t/2,Math.min(e,t)*.3,e/2,t/2,Math.hypot(e,t)*.55);i.addColorStop(0,`rgba(0,0,0,0)`),i.addColorStop(1,`rgba(0,0,0,0.5)`),r.fillStyle=i,r.fillRect(0,0,e,t);let a=r.createLinearGradient(0,0,0,t);a.addColorStop(0,`rgba(190,210,255,0.09)`),a.addColorStop(.42,`rgba(190,210,255,0.015)`),a.addColorStop(.43,`rgba(190,210,255,0)`),r.fillStyle=a,r.fillRect(0,0,e,t),r.save(),r.translate(e*.3,t*.2),r.scale(1,.45);let o=r.createRadialGradient(0,0,0,0,0,e*.35);return o.addColorStop(0,`rgba(255,255,255,0.07)`),o.addColorStop(1,`rgba(255,255,255,0)`),r.fillStyle=o,r.fillRect(-e,-t*3,e*2,t*6),r.restore(),n}function je(e){let t=W(128,128),n=t.getContext(`2d`),r=n.createImageData(128,128);for(let e=0;e<16384;e++){let t=ve(e,7)>.5?255:0;r.data[e*4]=r.data[e*4+1]=r.data[e*4+2]=t,r.data[e*4+3]=Math.round(ve(e,13)*9)}return n.putImageData(r,0,0),e.createPattern(t,`repeat`)}var J=new Map,Me=25165824,Ne=12,Pe=0;function Fe(e){return 4*(e.front.width*e.front.height+e.back.width*e.back.height+e.glass.width*e.glass.height)}function Ie(e,t){let n=`${e.name}:${Math.round(t)}`,r=J.get(n);if(r)return J.delete(n),J.set(n,r),r;let i=Se(e);r={front:De(e,t),back:Oe(e,t),glass:Ae(i.hx*2*t,i.hy*2*t)};let a=Fe(r);for(;J.size&&(J.size>=Ne||Pe+a>Me);){let e=J.keys().next().value;Pe-=Fe(J.get(e)),J.delete(e)}return a<=Me&&(J.set(n,r),Pe+=a),r}var Y=(e,t,n)=>[e[0]+(t[0]-e[0])*n,e[1]+(t[1]-e[1])*n,e[2]+(t[2]-e[2])*n],Le=class{shape=null;meshes=null;unit=0;ledKey=``;front=null;back=null;screen=null;screenBase=null;glass=null;layer=null;tiny=W(22,14);tinyHalf=W(11,7);tinyImg=null;grain=null;grid=M(22,14);gridPrev=M(22,14);proj=new Float32Array(6144);screenGeo={pitch:0,x0:0,y0:0};prepare(e,t,n){if(Math.abs(t-this.unit)>.5||e!==this.shape){this.unit=t,this.shape=e,this.meshes=T(e);let n=Ie(e,t);this.front=n.front,this.back=n.back,this.glass=n.glass;let r=Se(e);this.screen=W(r.hx*2*t,r.hy*2*t),this.ledKey=``;let i=xe(e);this.grid=M(Math.ceil(i.hx*2/e.pitch),Math.ceil(i.hy*2/e.pitch)),this.gridPrev=M(this.grid.cols,this.grid.rows),this.tiny=W(this.grid.cols,this.grid.rows),this.tinyHalf=W(Math.ceil(this.grid.cols/2),Math.ceil(this.grid.rows/2)),this.tinyImg=null;let a=e.pitch*t;this.screenGeo={pitch:a,x0:(this.screen.width-a*this.grid.cols)/2,y0:(this.screen.height-a*this.grid.rows)/2}}let r=n.join(`,`);if(r!==this.ledKey&&this.screen){this.ledKey=r;let{pitch:e,x0:t,y0:i}=this.screenGeo;this.screenBase=ke(this.screen.width,this.screen.height,e,t,i,n)}}compose(e,t){let n=this.grid,r=n.v,{cols:i,rows:a}=n;if(r.fill(0),!e)return oe[t](n,{lookX:0,lookY:0,blink:0,time:.4,side:1,seed:0}),n;if(oe[e.shown](n,e.face),e.switched<.3){let t=this.gridPrev;t.v.fill(0),oe[e.previous](t,{...e.face,time:e.face.time+10});let n=e.switched/.3;for(let e=0;e<r.length;e++)r[e]=r[e]*n+t.v[e]*(1-n);if(e.switched<.13){let t=Math.floor(e.time*30);for(let e=0;e<a;e++){let n=Math.floor((Math.sin(t*12.9+e*78.2)*.5+.5)*3)-1;if(!n)continue;let a=r.slice(e*i,(e+1)*i);for(let t=0;t<i;t++)r[e*i+t]=a[(t-n+i)%i]}for(let e=0;e<r.length;e++)Math.sin(e*91.7+t*3.1)>.93&&(r[e]=Math.max(r[e],.3))}}if(e.age<.55){let t=G(.08,.5,e.age)*(a/2+.5);for(let n=0;n<a;n++){let o=Math.abs(n-(a-1)/2);for(let a=0;a<i;a++){let s=n*i+a;o>t?r[s]=0:o>t-1.2&&(r[s]=Math.max(r[s],.85*(1-e.age/.55)))}}}return n}drawScreen(e,t){let n=this.screen.getContext(`2d`),{cols:r,rows:i,v:a}=e;n.globalCompositeOperation=`source-over`,n.globalAlpha=1,n.drawImage(this.screenBase,0,0);let{pitch:o,x0:s,y0:c}=this.screenGeo,l=`rgb(${Y(t,[255,255,255],.6).map(Math.round).join(`,`)})`,u=`rgb(${t.map(Math.round).join(`,`)})`,d=o*.8,f=(o-d)/2;for(let e=0;e<i;e++)for(let t=0;t<r;t++){let i=a[e*r+t];i<.01||(n.globalAlpha=Math.min(1,i*.4),n.fillStyle=u,n.fillRect(s+t*o+f*.4,c+e*o+f*.4,o-f*.8,o-f*.8),n.globalAlpha=Math.min(1,i),n.fillStyle=l,n.fillRect(s+t*o+f,c+e*o+f,d,d))}let p=this.tiny.getContext(`2d`);this.tinyImg||=p.createImageData(r,i);let m=this.tinyImg.data;for(let e=0;e<r*i;e++)m[e*4]=t[0],m[e*4+1]=t[1],m[e*4+2]=t[2],m[e*4+3]=Math.round(Math.min(1,a[e])*255);p.putImageData(this.tinyImg,0,0);let h=this.tinyHalf.getContext(`2d`);h.clearRect(0,0,this.tinyHalf.width,this.tinyHalf.height),h.imageSmoothingEnabled=!0,h.drawImage(this.tiny,0,0,this.tinyHalf.width,this.tinyHalf.height),n.imageSmoothingEnabled=!0,n.globalCompositeOperation=`lighter`,n.globalAlpha=.7,n.drawImage(this.tiny,s,c,r*o,i*o),n.globalAlpha=.65,n.drawImage(this.tinyHalf,s-o,c-o,(r+2)*o,(i+2)*o),n.globalCompositeOperation=`source-over`,n.globalAlpha=1,n.drawImage(this.glass,0,0)}drawFloorShadow(e,t,n,r,i,a,o){if(o){let o=Math.max(0,n.lift),s=r+(i.hy+.11)*a,c=a*i.hx*(1-o*.9)*n.sx;e.save(),e.translate(t/2+n.x*a,s),e.scale(1,.16);let l=e.createRadialGradient(0,0,0,0,0,c),u=.55*Math.max(0,1-o*1.6);l.addColorStop(0,`rgba(0,0,0,${u})`),l.addColorStop(.55,`rgba(0,0,0,${u*.45})`),l.addColorStop(1,`rgba(0,0,0,0)`),e.fillStyle=l,e.beginPath(),e.arc(0,0,c,0,Math.PI*2),e.fill(),e.restore()}}drawGrain(e,t,n){if(this.grain){e.setTransform(1,0,0,1,0,0),e.globalCompositeOperation=`source-atop`;let r=typeof DOMMatrix>`u`?null:new DOMMatrix().translate(t,n);r&&`setTransform`in this.grain&&this.grain.setTransform(r),e.fillStyle=this.grain,e.fillRect(0,0,e.canvas.width,e.canvas.height),e.globalCompositeOperation=`source-over`}}draw(e,t,n,r,c,l,u,d){let f=K.antenna+K.glow+K.hop,p=K.shadow,m=Math.min(t*.6,t*(1-2*K.margin)/(2*l.hy+f+p)),h=Ce(l),g=xe(l),_=Se(l),v=r?r.shown:c,y=ce[v],b=y.screen??u.led;r&&r.switched<.3&&(b=Y(ce[r.previous].screen??u.led,b,r.switched/.3).map(Math.round)),this.prepare(l,m,b),(!this.layer||this.layer.width!==e.canvas.width||this.layer.height!==e.canvas.height)&&(this.layer=W(e.canvas.width,e.canvas.height),this.grain=je(e));let x=this.layer.getContext(`2d`),S=o(n.yaw,n.pitch,n.roll),C=t/2+n.x*m,w=t*K.margin+(l.hy+f)*m,T=w-n.lift*m,E=T+l.hy*m,D=(e,t,r)=>{let i=s(S,e,t,r);return[C+i[0]*m*n.sx,E+(T+i[1]*m-E)*n.sy,i[2]]},O=(e,t,n)=>{let r=D(0,0,t),i=D(n?-1:1,0,t),a=D(0,1,t);e.setTransform(i[0]-r[0],i[1]-r[1],a[0]-r[0],a[1]-r[1],r[0],r[1])};e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,e.canvas.width,e.canvas.height),this.drawFloorShadow(e,t,n,w,l,m,d.floorShadow);let{body:k,earL:A,earR:j,collar:ee}=this.meshes,M=s(S,-l.earX-.05,i.earY,0)[2],N=s(S,l.earX+.05,i.earY,0)[2],P=s(S,0,-l.hy,0)[2]<-.012,F=(e,t,n)=>{let r=t.pos.length/3,i=this.proj;for(let e=0;e<r;e++){let n=D(t.pos[e*3],t.pos[e*3+1],t.pos[e*3+2]);i[e*3]=n[0],i[e*3+1]=n[1],i[e*3+2]=n[2]}let a=[],o=t.quads,c=t.normals;for(let e=0;e<o.length/4;e++){if(S[6]*c[e*3]+S[7]*c[e*3+1]+S[8]*c[e*3+2]<-.03)continue;let t=i[o[e*4]*3+2]+i[o[e*4+1]*3+2]+i[o[e*4+2]*3+2]+i[o[e*4+3]*3+2];a.push([t,e])}a.sort((e,t)=>e[0]-t[0]),e.lineWidth=Math.max(.6,m/260),e.lineJoin=`round`;for(let[,t]of a){let r=c[t*3],a=c[t*3+1],l=c[t*3+2],u=s(S,r,a,l),d=_e(n,u[0],u[1],u[2]);e.beginPath();for(let n=0;n<4;n++){let r=o[t*4+n]*3;n?e.lineTo(i[r],i[r+1]):e.moveTo(i[r],i[r+1])}e.closePath(),e.fillStyle=d,e.strokeStyle=d,e.fill(),e.stroke()}},I=()=>this.drawAntenna(e,D,m,n,u,r,v,y,ee);P&&I(),M<0&&F(e,A,u.trim),N<0&&F(e,j,u.trim),x.setTransform(1,0,0,1,0,0),x.globalCompositeOperation=`source-over`,x.clearRect(0,0,this.layer.width,this.layer.height),F(x,k,u.shell);let L=S[8],R=l.depth/2,z=Math.abs(L)>.005?L>0?1:-1:0;if(z){let e=.17;O(x,z*R,z<0);let t=(e,t)=>{let n=s(S,e*(z<0?-1:1),t,z),r=Math.hypot(n[0],n[1],n[2]);return ge(he(u.shell,n[0]/r,n[1]/r,n[2]/r))};x.beginPath(),l.path(x,a.plate-.002);let n=x.createLinearGradient(0,-h.hy,0,h.hy);n.addColorStop(0,t(0,-.17)),n.addColorStop(.5,t(0,0)),n.addColorStop(1,t(0,e)),x.fillStyle=n,x.fill();let r=x.createLinearGradient(-h.hx,0,h.hx,0);r.addColorStop(0,t(-.17,0)),r.addColorStop(.5,t(0,0)),r.addColorStop(1,t(e,0)),x.globalAlpha=.5,x.fillStyle=r,x.fill(),x.globalAlpha=1}if(this.drawGrain(x,C,T),e.drawImage(this.layer,0,0),z>0){e.save(),O(e,R,!1),e.beginPath(),l.path(e,a.hole),e.fillStyle=`#060709`,e.fill(),e.save(),e.beginPath(),l.path(e,a.glass),e.clip(),this.drawScreen(this.compose(r,c),b),O(e,R-i.recess,!1),e.drawImage(this.screen,-_.hx,-_.hy,_.hx*2,_.hy*2),O(e,R,!1);let t=-.05-n.yaw*.9+n.pitch*.5,o=e.createLinearGradient(-.55+t,-.35,.15+t,.35);o.addColorStop(0,`rgba(255,255,255,0)`),o.addColorStop(.36,`rgba(255,255,255,0)`),o.addColorStop(.43,`rgba(220,232,255,0.075)`),o.addColorStop(.5,`rgba(255,255,255,0)`),o.addColorStop(.58,`rgba(255,255,255,0)`),o.addColorStop(.61,`rgba(220,232,255,0.04)`),o.addColorStop(.65,`rgba(255,255,255,0)`),e.fillStyle=o,e.fillRect(-g.hx,-g.hy,g.hx*2,g.hy*2),e.restore(),e.drawImage(this.front,-h.hx,-h.hy,h.hx*2,h.hy*2),e.restore()}else z<0&&(e.save(),O(e,-R,!0),e.drawImage(this.back,-h.hx,-h.hy,h.hx*2,h.hy*2),e.restore());M>=0&&F(e,A,u.trim),N>=0&&F(e,j,u.trim),P||I(),e.setTransform(1,0,0,1,0,0)}drawAntenna(e,t,n,r,a,c,l,u,d){let f=o(r.yaw,r.pitch,r.roll),p=this.proj,m=d.pos.length/3;for(let e=0;e<m;e++){let n=t(d.pos[e*3],d.pos[e*3+1],d.pos[e*3+2]);p[e*3]=n[0],p[e*3+1]=n[1],p[e*3+2]=n[2]}let h=d.quads,g=d.normals;e.lineWidth=Math.max(.6,n/260);for(let t=0;t<h.length/4;t++){let n=s(f,g[t*3],g[t*3+1],g[t*3+2]);if(n[2]<-.03)continue;let r=_e(a.trim,n[0],n[1],n[2]);e.beginPath();for(let n=0;n<4;n++){let r=h[t*4+n]*3;n?e.lineTo(p[r],p[r+1]):e.moveTo(p[r],p[r+1])}e.closePath(),e.fillStyle=r,e.strokeStyle=r,e.fill(),e.stroke()}let _=-this.shape.hy-.028,v=i.stem,y=r.antennaX,b=r.antennaZ,x=[Math.sin(y),-Math.cos(y)*Math.cos(b),Math.sin(b)],S=t(0,_,0),C=t(0,_-v*.55,0),w=t(x[0]*v,_+x[1]*v,x[2]*v),T=t(x[0]*(v+i.ball*.8),_+x[1]*(v+i.ball*.8),x[2]*(v+i.ball*.8));e.lineCap=`round`,e.beginPath(),e.moveTo(S[0],S[1]),e.quadraticCurveTo(C[0],C[1],w[0],w[1]),e.lineWidth=n*.02,e.strokeStyle=`#4a5260`,e.stroke(),e.lineWidth=n*.009,e.strokeStyle=`#9aa3b1`,e.stroke(),e.save(),e.translate(-n*.004,0),e.lineWidth=n*.004,e.strokeStyle=`rgba(255,255,255,0.75)`,e.stroke(),e.restore();let E=u.ball,D=u.pulse(c?c.face.time:.3);if(c&&c.switched<.3){let e=ce[c.previous],t=c.switched/.3;E=Y(e.ball,E,t),D=e.pulse(c.face.time+10)*(1-t)+D*t}c&&c.age<.55&&(D*=G(.1,.5,c.age));let O=i.ball*n*r.sx,[k,A]=T,j=Y([168,174,186],Y(E,[255,255,255],.35),D),ee=Y(j,Y([150,158,172],E,.5),.48),M=Y([70,76,88],Y(E,[90,96,108],.5),D*.55),N=e.createRadialGradient(k-O*.18,A-O*.22,O*.05,k,A,O);if(N.addColorStop(0,`rgb(${Y(j,[255,255,255],.6+D*.3).map(Math.round).join(`,`)})`),N.addColorStop(.38,`rgb(${j.map(Math.round).join(`,`)})`),N.addColorStop(.78,`rgb(${ee.map(Math.round).join(`,`)})`),N.addColorStop(1,`rgb(${M.map(Math.round).join(`,`)})`),D>.01){e.globalCompositeOperation=`lighter`;let t=e.createRadialGradient(k,A,O*.6,k,A,O*4.2),n=E.map(Math.round).join(`,`);t.addColorStop(0,`rgba(${n},${.5*D})`),t.addColorStop(.35,`rgba(${n},${.14*D})`),t.addColorStop(1,`rgba(${n},0)`),e.fillStyle=t,e.beginPath(),e.arc(k,A,O*4.2,0,Math.PI*2),e.fill(),e.globalCompositeOperation=`source-over`}let P=e.createRadialGradient(k,A+O*.9,0,k,A+O*.9,O*.7);P.addColorStop(0,`rgba(20,24,32,0.28)`),P.addColorStop(1,`rgba(20,24,32,0)`),e.fillStyle=P,e.beginPath(),e.arc(k,A+O*.9,O*.7,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(k,A,O,0,Math.PI*2),e.fillStyle=N,e.fill(),e.lineWidth=Math.max(.75,O*.07),e.strokeStyle=`rgba(28,32,42,0.28)`,e.stroke();let F=e.createRadialGradient(k-O*.38,A-O*.42,0,k-O*.38,A-O*.42,O*.38);F.addColorStop(0,`rgba(255,255,255,0.95)`),F.addColorStop(1,`rgba(255,255,255,0)`),e.fillStyle=F,e.fill()}};function Re(e){let t=e.trim(),n=t.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);if(n){let e=n[1].length===3?n[1].replace(/./g,e=>e+e):n[1],t=parseInt(e,16);return[t>>16&255,t>>8&255,t&255]}let r=t.match(/^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)/i);return r?[Number(r[1]),Number(r[2]),Number(r[3])]:null}var X={x:NaN,y:NaN},Z=new Set,Q=0,ze=0,Be=!1;function $(){X.x=NaN,X.y=NaN}function Ve(e){X.x=e.clientX,X.y=e.clientY}function He(){document.hidden?Ge():Z.size&&We()}function Ue(e){Q=0;let t=ze?Math.min(.1,(e-ze)/1e3):0;ze=e,Z.forEach(e=>e(t)),Z.size&&(Q=requestAnimationFrame(Ue))}function We(){Q||typeof document>`u`||document.hidden||(ze=0,Q=requestAnimationFrame(Ue))}function Ge(){Q&&cancelAnimationFrame(Q),Q=0}function Ke(){Be||typeof document>`u`||(Be=!0,document.addEventListener(`pointermove`,Ve,{passive:!0}),document.addEventListener(`pointerleave`,$),window.addEventListener(`blur`,$),document.addEventListener(`visibilitychange`,He))}function qe(){Be&&(Be=!1,$(),document.removeEventListener(`pointermove`,Ve),document.removeEventListener(`pointerleave`,$),window.removeEventListener(`blur`,$),document.removeEventListener(`visibilitychange`,He))}function Je(e){return Ke(),Z.add(e),We(),()=>{Z.delete(e),Z.size||(Ge(),qe())}}var Ye=(0,e.template)(`<canvas role=img>`);function Xe(e){let t=2166136261;for(let n=0;n<e.length;n++)t=Math.imul(t^e.charCodeAt(n),16777619);return(t>>>0)%1e3/1e3}function Ze(e,t,n){let r=Re(e)??[48,80,172],i=Re(t)??[150,168,200],a=Re(n)??[232,242,255];return{shell:{albedo:me(r),f0:.05,metal:.15,spec:.55,shininess:70,rim:.9},trim:{albedo:me(i),f0:.2,metal:.65,spec:.8,shininess:45,rim:.7},led:a}}var Qe=e=>e&&n.includes(e)?e:`idle`,$e=e=>e&&r.includes(e)?e:`rectangle`;function et(e){return typeof e==`function`}function tt(e){return typeof e==`function`}function nt(e){return typeof e==`object`&&!!e&&`current`in e}function rt(e){return typeof e==`string`}function it(n){let r=(0,t.createUniqueId)(),[i,a]=(0,t.splitProps)(n,[`model`,`shape`,`state`,`size`,`color`,`trimColor`,`screenColor`,`speed`,`paused`,`interactive`,`floorShadow`,`seed`,`class`,`className`,`style`,`onClick`,`aria-label`,`ref`]),o,s,c=()=>Number.isFinite(i.size)&&(i.size??0)>0?Math.max(32,Math.min(i.size,1024)):160,l=()=>Number.isFinite(i.speed)&&(i.speed??-1)>=0?Math.min(i.speed,8):1,u=new j(Number.isFinite(i.seed)?Math.min(1,Math.max(0,i.seed)):Xe(r),Qe(i.state)),[d,f]=(0,t.createSignal)(!1),[p,m]=(0,t.createSignal)(!0);(0,t.onMount)(()=>{let e=new IntersectionObserver(([e])=>m(e.isIntersecting));e.observe(o),(0,t.onCleanup)(()=>e.disconnect());let n=window.matchMedia(`(prefers-reduced-motion: reduce)`);f(n.matches);let r=()=>f(n.matches);n.addEventListener(`change`,r),(0,t.onCleanup)(()=>n.removeEventListener(`change`,r))}),(0,t.createEffect)(()=>{let e=Qe(i.state),n=_($e(i.shape)),r=c(),a=Ze(i.color??`#2b49a3`,i.trimColor??`#93a6c8`,i.screenColor??`#e8f2ff`),f=l(),m=i.interactive??!0,h=i.floorShadow??!0,g=(i.paused??!1)||!(f>0)||d();u.setState(e);let v=t=>{if(!o)return;let i=Math.min(2,window.devicePixelRatio||1),c=Math.round(r*i);(o.width!==c||o.height!==c)&&(o.width=c,o.height=c);let l=o.getContext(`2d`);l&&(s??=new Le,s.draw(l,c,t?u.pose:ee(e),t?u:null,e,n,a,{floorShadow:h}))};if(g||!p()){p()&&v(!1);return}let y=Je(e=>{if(m&&Number.isFinite(X.x)){let e=o.getBoundingClientRect(),t=X.x-(e.left+e.width/2),n=X.y-(e.top+e.height*.56);u.pointer=Math.hypot(t,n)<700?{x:t,y:n}:null}else u.pointer=null;u.update(e*f),v(!0)});(0,t.onCleanup)(y)});let h=e=>{(i.interactive??!0)&&!(i.paused??!1)&&l()>0&&!d()&&u.poke();let t=i.onClick;et(t)?t(e):Array.isArray(t)&&t[0](t[1],e)},g=e=>{o=e;let t=i.ref;tt(t)?t(e):nt(t)&&(t.current=e)};return(()=>{var t=(0,e.getNextElement)(Ye);return t.$$click=h,(0,e.use)(g,t),(0,e.spread)(t,(0,e.mergeProps)({get"aria-label"(){return i[`aria-label`]??`Robot, ${Qe(i.state)}`},get class(){return i.class??i.className},get style(){return(0,e.memo)(()=>!!rt(i.style))()?`width:${c()}px;height:${c()}px;display:block;cursor:${i.interactive===!1?`auto`:`pointer`};${i.style}`:{width:`${c()}px`,height:`${c()}px`,display:`block`,cursor:i.interactive===!1?void 0:`pointer`,...i.style}}},a),!1,!1),(0,e.runHydrationEvents)(),t})()}(0,e.delegateEvents)([`click`]),exports.RobotHead=it,exports.robotHeadShapes=r,exports.robotHeadStates=n;
@@ -0,0 +1,39 @@
1
+ import { JSX } from 'solid-js';
2
+
3
+ declare const geometries: readonly ["rectangle", "square", "circle", "hexagon"];
4
+
5
+ /** An animated TV-headed robot, rendered on a 2D canvas. */
6
+ export declare function RobotHead(props: RobotHeadProps): JSX.Element;
7
+
8
+ export declare type RobotHeadModel = 'tv';
9
+
10
+ /** Canvas attributes are forwarded to the underlying canvas. */
11
+ export declare interface RobotHeadProps extends Omit<JSX.CanvasHTMLAttributes<HTMLCanvasElement>, 'color'> {
12
+ model?: RobotHeadModel;
13
+ shape?: RobotHeadShape;
14
+ state?: RobotHeadState;
15
+ size?: number;
16
+ color?: string;
17
+ trimColor?: string;
18
+ screenColor?: string;
19
+ speed?: number;
20
+ paused?: boolean;
21
+ interactive?: boolean;
22
+ floorShadow?: boolean;
23
+ /** 0–1. Offsets blinks and glances across a row of heads. */
24
+ seed?: number;
25
+ /** React-compatible className alias; Solid's class prop also works. */
26
+ className?: string;
27
+ }
28
+
29
+ export declare type RobotHeadShape = typeof geometries[number];
30
+
31
+ export declare const robotHeadShapes: RobotHeadShape[];
32
+
33
+ export declare type RobotHeadState = typeof states[number];
34
+
35
+ export declare const robotHeadStates: RobotHeadState[];
36
+
37
+ declare const states: readonly ["idle", "thinking", "searching", "listening", "speaking", "working", "happy", "error", "sleeping"];
38
+
39
+ export { }