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.
package/README.md CHANGED
@@ -1,113 +1,136 @@
1
1
  # robot-heads-solid
2
2
 
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).
3
+ Animated 3D robot heads for Solid. Glossy, TV-headed bots with an LED-matrix face that shows what your agent is doing: thinking, searching, listening, speaking and more. Choose from four shapes, with a springy antenna, knob ears and a light on top that changes with the state.
4
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.
5
+ Drawn on a 2D canvas: no WebGL or runtime dependencies.
6
+
7
+ **[Playground →](https://robot-heads-solid.jhonra121.workers.dev)**
6
8
 
7
9
  ## Install
8
10
 
9
- ~~~sh
11
+ ```sh
10
12
  bun add robot-heads-solid
11
- ~~~
13
+ ```
12
14
 
13
- The stable release is `0.1.0`. 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.
15
+ Solid 1.9+ is supported by the default entry point. Solid 2 is still a prerelease and has a separate, explicitly selected entry point: `robot-heads-solid/solid2`. Do not mix the two entry points in one application. Solid 2 apps need both `solid-js` and `@solidjs/web` at matching versions. Solid 2 support is verified against `2.0.0-rc.14`; it is opt-in prerelease support, not a claim of compatibility with a stable Solid 2 release.
14
16
 
15
- ## Releases
17
+ ## Quick start
16
18
 
17
- Releases publish from an annotated Git tag matching the version in the root `package.json` (for example, `vX.Y.Z-beta.N`). The tag must point to the `main` commit that introduced that package version. The release workflow runs anti-slop rule regression, lint, typecheck, build, browser E2E, and packed-consumer checks before publishing the exact verified tarball with npm provenance. Beta versions publish to the `beta` dist-tag; stable versions publish to `latest`. Versions are immutable and are never republished.
18
- All package releases share one concurrency group, and the workflow requires a release version to be strictly newer than the version already on its target npm dist-tag. If tags are pushed close together, an older queued release fails rather than moving the channel backward.
19
+ ```tsx
20
+ import { RobotHead } from 'robot-heads-solid';
19
21
 
20
- One-time maintainer setup:
22
+ function Agent(props: { status: 'idle' | 'thinking' | 'speaking' }) {
23
+ return <RobotHead state={props.status} size={160} />;
24
+ }
25
+ ```
21
26
 
22
- 1. In npm package settings for `robot-heads-solid`, configure **Trusted Publishers** for GitHub Actions with repository owner `jhomra21`, repository `robot-heads-solid`, workflow filename `release.yml`, and GitHub environment `npm-publish`. Do not create or store an npm token.
23
- 2. In GitHub repository settings, create the `npm-publish` environment. Optionally require a reviewer to approve publication; do not add environment secrets.
24
- 3. Ensure GitHub Actions is allowed to run and protect the `v*` tag namespace so only release maintainers can create release tags.
27
+ ### Solid 2 prerelease
25
28
 
26
- For each release, merge the versioned package change to `main`, then create and push its matching tag:
29
+ Install matching Solid 2 prerelease packages and use the separate entry point:
27
30
 
28
- ~~~sh
29
- git tag -a vX.Y.Z -m "vX.Y.Z"
30
- git push origin vX.Y.Z
31
- ~~~
31
+ ```sh
32
+ bun add solid-js@2.0.0-rc.14 @solidjs/web@2.0.0-rc.14 robot-heads-solid
33
+ ```
32
34
 
33
- Do not run `npm publish` locally. If npm Trusted Publishing is not configured or the workflow binding does not match, the publish job will fail without a token fallback.
35
+ ```tsx
36
+ import { render } from '@solidjs/web';
37
+ import { RobotHead } from 'robot-heads-solid/solid2';
34
38
 
35
- ## Usage
39
+ render(() => <RobotHead state="thinking" />, document.getElementById('root')!);
40
+ ```
36
41
 
37
- ~~~tsx
38
- import { createSignal } from 'solid-js';
39
- import { RobotHead } from 'robot-heads-solid';
42
+ The default `robot-heads-solid` entry remains the Solid 1.9 build. Configure the Solid 2 JSX runtime as `jsxImportSource: "@solidjs/web"` and use the Solid 2 Vite integration (`@solidjs/vite-plugin`); the Solid 1 `vite-plugin-solid` compiler does not target Solid 2. The library's Solid 2 entry has been checked for client rendering, server rendering, hydration and early-event replay.
40
43
 
41
- function Example() {
42
- const [state, setState] = createSignal<'idle' | 'thinking' | 'working'>('idle');
43
-
44
- return (
45
- <>
46
- <RobotHead
47
- state={state()}
48
- shape="rectangle"
49
- size={160}
50
- color="#2b49a3"
51
- trimColor="#93a6c8"
52
- screenColor="#e8f2ff"
53
- speed={1}
54
- interactive
55
- floorShadow
56
- />
57
- <button onClick={() => setState('thinking')}>Think</button>
58
- </>
59
- );
60
- }
61
- ~~~
44
+ ## Shapes
45
+
46
+ One head, four outlines. Every shape has the same screen, ears, antenna, screws and back panel, and moves the same way.
47
+
48
+ ```tsx
49
+ <RobotHead shape="rectangle" /> {/* the classic TV (default) */}
50
+ <RobotHead shape="square" />
51
+ <RobotHead shape="circle" /> {/* a porthole */}
52
+ <RobotHead shape="hexagon" /> {/* a nut, flat on top */}
53
+ ```
62
54
 
63
- The component forwards ordinary Solid canvas attributes, event handlers, styling, accessibility attributes, and a canvas ref. State and appearance props react to Solid signals.
55
+ The list is exported as `robotHeadShapes`.
64
56
 
65
- ### Shapes
57
+ ## States
66
58
 
67
- 'rectangle' (default), 'square', 'circle', 'hexagon'. Exported as `robotHeadShapes`.
59
+ Each state has its own face on the screen, its own motion and its own antenna light. Switching states plays a short glitch and cross-fade, and the head eases into its new pose.
68
60
 
69
- ### States
61
+ | State | Screen | Motion |
62
+ |---|---|---|
63
+ | `idle` | block eyes that blink and glance | looks around, hops now and then |
64
+ | `thinking` | heavy-lidded eyes looking up, three pulsing dots | head tilted up, switching sides; amber light pulses |
65
+ | `searching` | darting eyes, a beam sweeping the whole screen | head sweeps side to side; cyan beacon |
66
+ | `listening` | alert eyes over a live equaliser | head cocked, small nods; steady green light |
67
+ | `speaking` | a mouth that moves with the words | bobs as it talks |
68
+ | `working` | focused eyes looking down, a progress bar | busy bobbing, a hop with a spin now and then |
69
+ | `happy` | `^ ^` eyes and a smile | bouncy hops |
70
+ | `error` | red `X X` eyes | shakes its head; red light blinks |
71
+ | `sleeping` | closed eyes and rising z's | head drooped, slow breathing; light off |
70
72
 
71
- 'idle', 'thinking', 'searching', 'listening', 'speaking', 'working', 'happy', 'error', 'sleeping'. Exported as `robotHeadStates`.
73
+ The list is exported as `robotHeadStates`.
72
74
 
73
- ### Props
75
+ ## Props
74
76
 
75
- | Prop | Type | Default |
76
- | --- | --- | --- |
77
- | 'model' | 'tv' | 'tv' |
78
- | 'shape' | 'RobotHeadShape' | 'rectangle' |
79
- | 'state' | 'RobotHeadState' | 'idle' |
80
- | 'size' | 'number' (px) | 160 |
81
- | 'color' | 'string' | '#2b49a3' |
82
- | 'trimColor' | 'string' | '#93a6c8' |
83
- | 'screenColor' | 'string' | '#e8f2ff' |
84
- | 'speed' | 'number' | 1 |
85
- | 'paused' | 'boolean' | false |
86
- | 'interactive' | 'boolean' | true |
87
- | 'floorShadow' | 'boolean' | true |
88
- | 'seed' | 'number' (0–1) | generated per instance |
77
+ ```tsx
78
+ <RobotHead
79
+ model="tv" // only "tv" is supported
80
+ shape="rectangle" // rectangle, square, circle or hexagon
81
+ state="idle" // what it is doing (above)
82
+ size={160} // px
83
+ color="#2b49a3" // the shell
84
+ trimColor="#93a6c8" // the ears and the antenna's collar
85
+ screenColor="#e8f2ff" // the LEDs
86
+ speed={1} // multiplier on every animation
87
+ paused={false} // hold the state's still pose
88
+ interactive // follow the pointer, hop and spin on a click
89
+ floorShadow // the soft shadow under the head
90
+ seed={0.3} // 0–1, desyncs blinks and glances in a row of heads
91
+ />
92
+ ```
89
93
 
90
- 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.
94
+ Any other canvas attribute (`class`, `className`, `style`, `onClick`, `aria-label`, ...) is passed through to the `<canvas>`, and a `ref` reaches it too. State and appearance props update when Solid signals change. Invalid sizes and speeds fall back to their defaults. Positive sizes are clamped to 32–1024px and speeds to 8×.
95
+
96
+ ## Behaviour
97
+
98
+ - **Pointer play.** With `interactive` on (the default), the head and eyes follow a nearby pointer, and a click makes it hop with a full spin and a happy face.
99
+ - **Reduced motion.** With `prefers-reduced-motion: reduce`, `paused`, or a speed of `0`, the still pose of the state is drawn instead of the animation.
100
+ - **Accessible by default.** The canvas has `role="img"` and an `aria-label` naming the state ("Robot, thinking"); pass your own `aria-label` to override it.
101
+ - **Cheap to run many.** Every head on the page shares one animation loop, which sleeps while the tab is hidden, and heads of the same shape and size share their baked textures.
102
+
103
+ ## How it is drawn
104
+
105
+ The head is real geometry: a shell with a rolled edge, its outline a convex polygon of corner centres grown by a corner radius, so one builder makes every shape. Knob ears and the antenna collar are lathed and built once as quad meshes. Each frame, the head turns with the pose and is projected, back faces are culled, and every quad is lit by a small studio model: a key light, a fill, a sky dome, a softbox and the key's window caught as clear-coat reflections with Fresnel, a cool back light rimming the silhouette, and a filmic tone curve.
106
+
107
+ The flat front and back are plates drawn in their own plane with baked relief: the lip rolling into the screen hole, the rubber gasket, the shadow the lip casts onto the glass, screws, and vents on the back. The glass sits a little behind the bezel, so it slides against it as the head turns. The LED matrix covers the whole screen, with the face centred on it. The LEDs are drawn crisp, then bloomed from a one-pixel-per-LED image scaled up smooth. The antenna is a damped spring that whips when the head hops, lands or tilts, topped with a frosted bulb lit from inside.
91
108
 
92
109
  ## Development
93
110
 
94
- ~~~sh
111
+ The library is in `src/`; the Solid playground is in `site/` and runs against the library source.
112
+
113
+ ```sh
95
114
  bun install
96
- bun run dev # Solid playground
97
- bun run lint # Oxlint: anti-slop rules and classic complexity (max 20)
98
- bun run typecheck
99
- bun run build # browser and SSR ES/CJS bundles and declarations
100
- bun run check # lint, library and playground checks
101
- bun run e2e # playground browser regressions, including all 36 shape/state combinations
102
- bun run e2e:consumer # packed Solid 1 consumer: typecheck, browser and Node ESM/CJS SSR
103
- ~~~
115
+ bun run setup:solid2 # installs the isolated Solid 2 compiler/runtime toolchain
116
+ bun run dev # the playground
117
+ bun run build # the library, to dist/
118
+ bun run typecheck # installs the isolated Solid 2 toolchain if needed
119
+ bun run build:site # build the library and playground (including Solid 2)
120
+ bun run deploy # build everything and deploy the playground Worker
121
+ ```
104
122
 
105
- 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.
123
+ ```
124
+ src/ the library
125
+ RobotHead.tsx the component
126
+ tv/ geometry, lighting, faces, motion and renderer
127
+ site/ the playground (Vite + Cloudflare Worker)
128
+ ```
106
129
 
107
- 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/'.
130
+ Release and npm publishing instructions are in [docs/releases.md](docs/releases.md).
108
131
 
109
- 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.
132
+ ## License
110
133
 
111
- ## Attribution and licensing
134
+ [MIT](LICENSE) © [Fayaz Ahmed](https://x.com/fayazara). This is a Solid port by [jhomra21](https://github.com/jhomra21) of [Fayaz Ahmed's React library](https://github.com/fayazara/robot-heads).
112
135
 
113
- 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.
136
+ The playground uses Open Runde by Laurids Kern under the SIL Open Font License 1.1 (`site/public/fonts/OFL.txt`). The font is not part of the npm package.
@@ -0,0 +1,40 @@
1
+ import type { JSX } from '@solidjs/web';
2
+
3
+ export type RobotHeadState =
4
+ | 'idle'
5
+ | 'thinking'
6
+ | 'searching'
7
+ | 'listening'
8
+ | 'speaking'
9
+ | 'working'
10
+ | 'happy'
11
+ | 'error'
12
+ | 'sleeping';
13
+
14
+ export declare const robotHeadStates: RobotHeadState[];
15
+
16
+ export type RobotHeadModel = 'tv';
17
+
18
+ export type RobotHeadShape = 'rectangle' | 'square' | 'circle' | 'hexagon';
19
+
20
+ export declare const robotHeadShapes: RobotHeadShape[];
21
+
22
+ export interface RobotHeadProps extends Omit<JSX.CanvasHTMLAttributes<HTMLCanvasElement>, 'color'> {
23
+ model?: RobotHeadModel;
24
+ shape?: RobotHeadShape;
25
+ state?: RobotHeadState;
26
+ size?: number;
27
+ color?: string;
28
+ trimColor?: string;
29
+ screenColor?: string;
30
+ speed?: number;
31
+ paused?: boolean;
32
+ interactive?: boolean;
33
+ floorShadow?: boolean;
34
+ /** 0–1. Offsets blinks and glances across a row of heads. */
35
+ seed?: number;
36
+ /** React-compatible className alias; Solid's class prop also works. */
37
+ className?: string;
38
+ }
39
+
40
+ export declare function RobotHead(props: RobotHeadProps): JSX.Element;