brandbot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +42 -0
- package/README.md +137 -0
- package/dist/BrandBot.d.ts +40 -0
- package/dist/BrandBot.js +53 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/nexbot-model.d.ts +3 -0
- package/dist/nexbot-model.js +8692 -0
- package/dist/robot-core.d.ts +2 -0
- package/dist/robot-core.js +681 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.js +1 -0
- package/package.json +39 -0
- package/preview.png +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
MIT License (applies to all code in this package)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aidan Zarski
|
|
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.
|
|
22
|
+
|
|
23
|
+
--------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
3D Model provenance (src/nexbot-model.js)
|
|
26
|
+
|
|
27
|
+
The bundled robot model is "NEXBOT - robot character concept", a Spline
|
|
28
|
+
Community file created by the Spline team, exported to glTF.
|
|
29
|
+
|
|
30
|
+
Source: https://community.spline.design/file/87343305-102d-4670-bb8e-38252064de27
|
|
31
|
+
License: CC0 1.0 Universal (public domain dedication)
|
|
32
|
+
https://creativecommons.org/publicdomain/zero/1.0/
|
|
33
|
+
|
|
34
|
+
Spline's Community Platform documentation
|
|
35
|
+
(https://docs.spline.design/doc/community-platform/docSaqY7mlFz) states:
|
|
36
|
+
"All the community files are licensed under CC0 1.0 Universal Deed."
|
|
37
|
+
(Verified 2026-06-12. Archived evidence:
|
|
38
|
+
https://web.archive.org/web/20260612220813/https://docs.spline.design/basics/community-platform
|
|
39
|
+
https://web.archive.org/web/20260612220949/https://community.spline.design/file/87343305-102d-4670-bb8e-38252064de27 )
|
|
40
|
+
|
|
41
|
+
CC0 places the work in the public domain: it may be used, modified, and
|
|
42
|
+
redistributed for any purpose, including commercially, without attribution.
|
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# BrandBot ๐ค
|
|
2
|
+
|
|
3
|
+
**A 3D robot mascot you brand with your own logo and colors.** A drop-in React component that gestures, blinks, and follows the visitor's cursor. It renders with [Three.js](https://threejs.org), is written in TypeScript with full type declarations, and bundles the model โ so there's nothing to configure or host. Works in any React app (see the Next.js note below).
|
|
4
|
+
|
|
5
|
+
**[โถ Live demo](https://aidan945.github.io/brandbot/demo/)** ยท **[Configure & copy code](https://aidan945.github.io/brandbot/demo/configure.html)**
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install brandbot three react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Use
|
|
16
|
+
|
|
17
|
+
```jsx
|
|
18
|
+
import { BrandBot } from 'brandbot';
|
|
19
|
+
|
|
20
|
+
export function Hero() {
|
|
21
|
+
return (
|
|
22
|
+
<div style={{ height: 600 }}>
|
|
23
|
+
<BrandBot primary="#13294b" eyes="#7fd4ff" logoText="ACME" />
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
That's it. The component fills its parent, renders on a transparent background, and starts moving. **The default needs no extra CSS** โ drop it in a sized box and it looks right.
|
|
30
|
+
|
|
31
|
+
### Full-bleed hero (optional)
|
|
32
|
+
|
|
33
|
+
To have the robot rise from the bottom of a full-height hero with its legs fading into the page (like the [demo](https://aidan945.github.io/brandbot/demo/)), wrap it:
|
|
34
|
+
|
|
35
|
+
```jsx
|
|
36
|
+
<div style={{ height: '100vh', overflow: 'hidden',
|
|
37
|
+
WebkitMaskImage: 'linear-gradient(180deg,#000 88%,transparent 100%)' }}>
|
|
38
|
+
<div style={{ position: 'absolute', inset: 0,
|
|
39
|
+
transform: 'scale(1.1) translateY(8%)', transformOrigin: 'center top' }}>
|
|
40
|
+
<BrandBot />
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**By default it stays put** โ locked in its box, facing forward, following the cursor. It does *not* let visitors drag-rotate it (rarely what you want in a hero or card). Add `orbit` to enable drag-to-rotate for demos.
|
|
46
|
+
|
|
47
|
+
## Brand it
|
|
48
|
+
|
|
49
|
+
Every color and the chest logo is a prop. Drop in your logo as text, an uploaded image (inlined as base64), or a URL:
|
|
50
|
+
|
|
51
|
+
```jsx
|
|
52
|
+
<BrandBot
|
|
53
|
+
primary="#0e1a2b"
|
|
54
|
+
accent="#1d3350"
|
|
55
|
+
eyes="#7fd4ff"
|
|
56
|
+
logoImage="/logo.png" // or logoText="ACME"
|
|
57
|
+
/>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The **[configurator](https://aidan945.github.io/brandbot/demo/configure.html)** lets you tweak everything visually and copies the exact JSX for your setup.
|
|
61
|
+
|
|
62
|
+
## Props
|
|
63
|
+
|
|
64
|
+
| Prop | Type | Default | |
|
|
65
|
+
|---|---|---|---|
|
|
66
|
+
| `primary` | color | near-black | body shell + carbon parts |
|
|
67
|
+
| `accent` | color | dark metal | joints, mechanical internals |
|
|
68
|
+
| `visor` | color | chrome | face plate |
|
|
69
|
+
| `hands` | color | chrome | hands |
|
|
70
|
+
| `eyes` | color | white-blue | LED dot-matrix eyes |
|
|
71
|
+
| `logoText` | string | โ | text logo on the chest (1โ3 words) |
|
|
72
|
+
| `logoColor` | color | white | |
|
|
73
|
+
| `logoImage` | url | โ | image logo (transparent PNG/SVG best); overrides text |
|
|
74
|
+
| `legs` | boolean | `true` | `false` shows the upper body only |
|
|
75
|
+
| `orbit` | boolean | `false` | `true` lets visitors drag to rotate (for demos) |
|
|
76
|
+
| `intro` | boolean | `true` | one-time zoom-in when the model loads |
|
|
77
|
+
| `trackPointer` | `'window' \| 'element' \| false` | `'window'` | what the head watches |
|
|
78
|
+
| `shadow` | boolean | `true` | soft ground shadow |
|
|
79
|
+
| `modelUrl` | url | bundled | load a different glTF instead of the bundled model |
|
|
80
|
+
| `className`, `style` | | | passed to the wrapper div |
|
|
81
|
+
|
|
82
|
+
All color/logo/legs props are live โ update them in state and the robot changes instantly. (`orbit` and `intro` are set once at mount.)
|
|
83
|
+
|
|
84
|
+
Imperative handle via ref:
|
|
85
|
+
|
|
86
|
+
```jsx
|
|
87
|
+
const bot = useRef(null);
|
|
88
|
+
<BrandBot ref={bot} />
|
|
89
|
+
<button onClick={() => bot.current.spin()}>Spin</button> {/* one full turn */}
|
|
90
|
+
<button onClick={() => bot.current.replay()}>Replay</button> {/* the zoom-in intro */}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Next.js
|
|
94
|
+
|
|
95
|
+
WebGL can't server-render, so load it client-side:
|
|
96
|
+
|
|
97
|
+
```jsx
|
|
98
|
+
import dynamic from 'next/dynamic';
|
|
99
|
+
const BrandBot = dynamic(() => import('brandbot').then(m => m.BrandBot), { ssr: false });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Without React
|
|
103
|
+
|
|
104
|
+
The engine is framework-agnostic:
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
import { createBrandbot } from 'brandbot/core';
|
|
108
|
+
import model from 'brandbot/model';
|
|
109
|
+
|
|
110
|
+
const robot = createBrandbot(document.querySelector('#hero'), { gltf: model });
|
|
111
|
+
robot.set({ primary: '#13294b', logoText: 'ACME' });
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Demo
|
|
115
|
+
|
|
116
|
+
The `demo/` folder is a no-build static site (works on GitHub Pages):
|
|
117
|
+
|
|
118
|
+
- **`demo/index.html`** โ showcase: the robot rising from a light-grid hero with the zoom-in intro and cursor tracking.
|
|
119
|
+
- **`demo/configure.html`** โ live configurator with tabbed code, "copy code", and "copy prompt for agent".
|
|
120
|
+
|
|
121
|
+
Run `python3 -m http.server` in the package folder and open `demo/index.html`.
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm install # toolchain (typescript, @types/three, @types/react)
|
|
127
|
+
npm run build # compile src/*.ts โ dist/ (+ .d.ts) and copy the model
|
|
128
|
+
npm run typecheck
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Source lives in `src/` (TypeScript). The committed `dist/` is what the demo and
|
|
132
|
+
npm package consume; rebuild it after changing `src/`.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
- **Code:** MIT.
|
|
137
|
+
- **Model:** the bundled robot is the [NEXBOT character](https://community.spline.design/file/87343305-102d-4670-bb8e-38252064de27), a Spline Community file under [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/) (public domain). Per [Spline's docs](https://docs.spline.design/doc/community-platform/docSaqY7mlFz): "All the community files are licensed under CC0 1.0 Universal Deed." Free to use, modify, and redistribute โ including commercially โ with no attribution required. Credited anyway, because it's a great model.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
import type { BrandBotHandle, Color, TrackPointer } from './types.js';
|
|
3
|
+
export interface BrandBotProps {
|
|
4
|
+
primary?: Color;
|
|
5
|
+
accent?: Color;
|
|
6
|
+
visor?: Color;
|
|
7
|
+
hands?: Color;
|
|
8
|
+
eyes?: Color;
|
|
9
|
+
logoText?: string;
|
|
10
|
+
logoColor?: Color;
|
|
11
|
+
/** Image logo: URL, data URI, or object URL. Overrides `logoText`. */
|
|
12
|
+
logoImage?: string | null;
|
|
13
|
+
/** `false` shows the upper body only. */
|
|
14
|
+
legs?: boolean;
|
|
15
|
+
/** Let visitors drag to rotate (for demos). */
|
|
16
|
+
orbit?: boolean;
|
|
17
|
+
/** One-time zoom-in when the model loads. */
|
|
18
|
+
intro?: boolean;
|
|
19
|
+
/** What the head watches. */
|
|
20
|
+
trackPointer?: TrackPointer;
|
|
21
|
+
/** Soft ground shadow. */
|
|
22
|
+
shadow?: boolean;
|
|
23
|
+
/** Load a different glTF instead of the bundled model. */
|
|
24
|
+
modelUrl?: string;
|
|
25
|
+
className?: string;
|
|
26
|
+
style?: CSSProperties;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* <BrandBot primary="#13294b" eyes="#7fd4ff" logoText="ACME"
|
|
30
|
+
* style={{ height: 600 }} />
|
|
31
|
+
*
|
|
32
|
+
* A 3D robot mascot you brand with your own logo and colors. It sits locked in
|
|
33
|
+
* its box, faces forward, and follows the cursor. It does NOT let visitors
|
|
34
|
+
* drag-rotate unless you pass `orbit` (handy for demos).
|
|
35
|
+
*
|
|
36
|
+
* All color/logo props are live โ change them and the robot updates.
|
|
37
|
+
* Use a ref for the imperative bits: ref.current.spin() / ref.current.replay()
|
|
38
|
+
*/
|
|
39
|
+
export declare const BrandBot: import("react").ForwardRefExoticComponent<BrandBotProps & import("react").RefAttributes<BrandBotHandle>>;
|
|
40
|
+
export default BrandBot;
|
package/dist/BrandBot.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createElement, forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
|
|
2
|
+
import { createBrandbot } from './robot-core.js';
|
|
3
|
+
import model from './nexbot-model.js';
|
|
4
|
+
/**
|
|
5
|
+
* <BrandBot primary="#13294b" eyes="#7fd4ff" logoText="ACME"
|
|
6
|
+
* style={{ height: 600 }} />
|
|
7
|
+
*
|
|
8
|
+
* A 3D robot mascot you brand with your own logo and colors. It sits locked in
|
|
9
|
+
* its box, faces forward, and follows the cursor. It does NOT let visitors
|
|
10
|
+
* drag-rotate unless you pass `orbit` (handy for demos).
|
|
11
|
+
*
|
|
12
|
+
* All color/logo props are live โ change them and the robot updates.
|
|
13
|
+
* Use a ref for the imperative bits: ref.current.spin() / ref.current.replay()
|
|
14
|
+
*/
|
|
15
|
+
export const BrandBot = forwardRef(function BrandBot(props, ref) {
|
|
16
|
+
const { primary, accent, visor, hands, eyes, logoText, logoColor, logoImage, legs = true, trackPointer = 'window', shadow = true, modelUrl, orbit = false, intro = true, className, style, } = props;
|
|
17
|
+
const el = useRef(null);
|
|
18
|
+
const bot = useRef(null);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!el.current)
|
|
21
|
+
return;
|
|
22
|
+
bot.current = createBrandbot(el.current, {
|
|
23
|
+
gltf: modelUrl ? null : model,
|
|
24
|
+
modelUrl,
|
|
25
|
+
trackPointer,
|
|
26
|
+
shadow,
|
|
27
|
+
legs,
|
|
28
|
+
orbit,
|
|
29
|
+
intro,
|
|
30
|
+
...(primary && { primary }), ...(accent && { accent }),
|
|
31
|
+
...(visor && { visor }), ...(hands && { hands }), ...(eyes && { eyes }),
|
|
32
|
+
...(logoText !== undefined && { logoText }),
|
|
33
|
+
...(logoColor && { logoColor }), ...(logoImage && { logoImage }),
|
|
34
|
+
});
|
|
35
|
+
return () => bot.current?.dispose();
|
|
36
|
+
// structural options rebuild the scene; colors/logo flow through below
|
|
37
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
38
|
+
}, [modelUrl, trackPointer, shadow, orbit, intro]);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
bot.current?.set({ primary, accent, visor, hands, eyes, logoText, logoColor, logoImage, legs });
|
|
41
|
+
}, [primary, accent, visor, hands, eyes, logoText, logoColor, logoImage, legs]);
|
|
42
|
+
useImperativeHandle(ref, () => ({
|
|
43
|
+
spin: () => bot.current?.spin(),
|
|
44
|
+
replay: () => bot.current?.replay(),
|
|
45
|
+
set: (o) => bot.current?.set(o),
|
|
46
|
+
}), []);
|
|
47
|
+
return createElement('div', {
|
|
48
|
+
ref: el,
|
|
49
|
+
className,
|
|
50
|
+
style: { width: '100%', height: '100%', ...style },
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
export default BrandBot;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { BrandBot, default } from './BrandBot.js';
|
|
2
|
+
export { createBrandbot } from './robot-core.js';
|
|
3
|
+
export type { BrandbotOptions, BrandbotUpdate, BrandbotInstance, BrandBotHandle, TrackPointer, Color, } from './types.js';
|
|
4
|
+
export type { BrandBotProps } from './BrandBot.js';
|
package/dist/index.js
ADDED