pictoguys 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 C3B
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 ADDED
@@ -0,0 +1,397 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/logo.png" alt="picto" width="340" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/latte.gif" width="92" alt="Latte dancing" />
7
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/kiwi.gif" width="92" alt="Kiwi dancing" />
8
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/goose.gif" width="92" alt="Goose dancing" />
9
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/waffle.gif" width="92" alt="Waffle dancing" />
10
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/mango.gif" width="92" alt="Mango dancing" />
11
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/udon.gif" width="92" alt="Udon dancing" />
12
+ </p>
13
+
14
+ <p align="center">
15
+ <strong>Give it a name. Get a little guy.</strong><br/>
16
+ Tiny React library for procedural SVG characters (I call them <em>pictos</em>).
17
+ </p>
18
+
19
+ <p align="center">
20
+ <img src="https://img.shields.io/badge/version-0.1.0-ff69b4" alt="version" />
21
+ <img src="https://img.shields.io/badge/TypeScript-ready-3178c6?logo=typescript&logoColor=white" alt="typescript" />
22
+ <img src="https://img.shields.io/badge/React-%E2%89%A5%2017-61dafb?logo=react&logoColor=white" alt="react" />
23
+ <img src="https://img.shields.io/badge/runtime%20deps-0-22c55e" alt="zero deps" />
24
+ <img src="https://img.shields.io/badge/license-MIT-22c55e" alt="license" />
25
+ <img src="https://img.shields.io/badge/pictos-%E2%88%9E-8b5cf6" alt="infinite pictos" />
26
+ </p>
27
+
28
+ ---
29
+
30
+ ## What is this?
31
+
32
+ `pictoguys` makes cute little SVG characters out of thin air.
33
+
34
+ You hand it a number or a word. It hands you back a character: a colored body,
35
+ some eyes, eyebrows, and (if you want one) a background tile. The same word
36
+ always makes the exact same character, so "Bloop" is always Bloop, on every
37
+ device, forever.
38
+
39
+ Think of it like a profile-picture generator, except:
40
+
41
+ - the art is real vector SVG (crisp at any size, never blurry),
42
+ - there are no image files to download (the parts are baked into the library),
43
+ - and the little guys can blink, hop, breathe, and dance.
44
+
45
+ No design skills needed. You do not draw anything. You just pick a seed.
46
+
47
+ ## What is a "picto"?
48
+
49
+ A **picto** is one character. That is the whole vocabulary you need.
50
+
51
+ Every picto is built from a few parts that get mixed and recolored:
52
+
53
+ | Part | Choices |
54
+ | ----------- | ---------------------------------------- |
55
+ | body color | 10 hand-picked colors, plus blended ones |
56
+ | body shape | 4 shapes |
57
+ | eyes | single, double, or triple |
58
+ | eye coloring| plain, two-tone, or rainbow |
59
+ | background | 5 tiles |
60
+
61
+ Pick those yourself, or let a seed pick them for you. Either way you get a picto.
62
+
63
+ ## Install
64
+
65
+ ```bash
66
+ npm install pictoguys
67
+ ```
68
+
69
+ For React components, bring your own `react` (version 17 or newer). For SVG-only
70
+ usage, import from `pictoguys/core` and React is not loaded. There are zero
71
+ runtime dependencies.
72
+
73
+ | Import path | Use it for |
74
+ | ----------- | ---------- |
75
+ | `pictoguys` | React projects that want `<Picto />` plus the core helpers |
76
+ | `pictoguys/react` | Only the React component and its props |
77
+ | `pictoguys/core` | SVG strings, characters, presets, and catalog helpers without React |
78
+ | `pictoguys/rng` | The tiny deterministic RNG only |
79
+
80
+ ## Your first picto
81
+
82
+ Drop this into any React component:
83
+
84
+ ```tsx
85
+ import { Picto } from 'pictoguys'
86
+
87
+ export default function App() {
88
+ return <Picto seed="Bloop" size={120} />
89
+ }
90
+ ```
91
+
92
+ That is it. You just rendered Bloop.
93
+
94
+ `seed` can be a word (`"Bloop"`) or a number (`7`). Same seed, same picto, every
95
+ single time. Change the word, get a different friend.
96
+
97
+ ## Meet some pictos
98
+
99
+ Here is what a handful of names look like. Try your own.
100
+
101
+ | | | | | | |
102
+ |:-:|:-:|:-:|:-:|:-:|:-:|
103
+ | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/bloop.svg" width="76" alt="Bloop"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/mochi.svg" width="76" alt="Mochi"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/zorp.svg" width="76" alt="Zorp"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/waffle.svg" width="76" alt="Waffle"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/gizmo.svg" width="76" alt="Gizmo"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/noodle.svg" width="76" alt="Noodle"/> |
104
+ | `"Bloop"` | `"Mochi"` | `"Zorp"` | `"Waffle"` | `"Gizmo"` | `"Noodle"` |
105
+ | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/tofu.svg" width="76" alt="Tofu"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/bubbles.svg" width="76" alt="Bubbles"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/sprocket.svg" width="76" alt="Sprocket"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/pickle.svg" width="76" alt="Pickle"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/goose.svg" width="76" alt="Goose"/> | <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/wizard.svg" width="76" alt="Wizard"/> |
106
+ | `"Tofu"` | `"Bubbles"` | `"Sprocket"` | `"Pickle"` | `"Goose"` | `"Wizard"` |
107
+
108
+ Waffle and Bubbles got fancy multi-colored eyes. Lucky.
109
+
110
+ ## Three ways to make a picto
111
+
112
+ **1. By name (a word).** Great for usernames, emails, anything text.
113
+
114
+ ```tsx
115
+ <Picto seed="ada@example.com" />
116
+ ```
117
+
118
+ **2. By number.** Great when you just want "give me number 42".
119
+
120
+ ```tsx
121
+ <Picto seed={42} />
122
+ ```
123
+
124
+ **3. By hand.** Want an exact look? Spell it out. Anything you leave out gets
125
+ filled in for you.
126
+
127
+ ```tsx
128
+ <Picto
129
+ config={{
130
+ color: 'pink', // 'blue' 'cian' 'gray' 'green' 'lime'
131
+ // 'orange' 'pink' 'purple' 'red' 'yellow'
132
+ shape: 2, // 1, 2, 3, or 4
133
+ eyes: 'triple', // 'single' | 'double' | 'triple'
134
+ mode: 'triad', // 'mono' (plain) | 'hetero' (two-tone) | 'triad' (rainbow)
135
+ bg: 4, // 1 to 5
136
+ }}
137
+ />
138
+ ```
139
+
140
+ <p align="center">
141
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/custom.svg" width="120" alt="custom pink triple-eye picto" />
142
+ </p>
143
+
144
+ Using TypeScript? Import the config type for full autocomplete:
145
+
146
+ ```ts
147
+ import type { CharConfig } from 'pictoguys'
148
+
149
+ const cfg: CharConfig = { color: 'blue', eyes: 'double' }
150
+ ```
151
+
152
+ ## Constraints and branding (the fun part)
153
+
154
+ Here is the one rule that gives you total control. For **every** setting:
155
+
156
+ | You write | You get |
157
+ | ------------------ | -------------------------------- |
158
+ | nothing (omit it) | fully random (picked by the seed)|
159
+ | one value | locked to that value |
160
+ | an array of values | random, but only from that set |
161
+
162
+ Mix and match freely. Add a `seed` (like a user id) and the random parts become
163
+ stable per person.
164
+
165
+ ### "Use my brand color on every avatar"
166
+
167
+ Set your brand once with `picto.preset(...)`, then stamp out users. Each person
168
+ keeps your color but gets their own body and face. You can pass a brand **hex**
169
+ straight in, and a matching darker shade is generated for the gradient.
170
+
171
+ ```tsx
172
+ import { picto, Picto } from 'pictoguys'
173
+
174
+ const brand = picto.preset({ color: '#19c37d' }) // your green
175
+
176
+ function Avatar({ userId }) {
177
+ const me = React.useMemo(() => brand.character(userId), [userId])
178
+ return <Picto char={me} size={96} />
179
+ }
180
+ ```
181
+
182
+ <p align="center">
183
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/brand-1.svg" width="84" alt="" />
184
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/brand-2.svg" width="84" alt="" />
185
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/brand-3.svg" width="84" alt="" />
186
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/brand-4.svg" width="84" alt="" />
187
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/brand-5.svg" width="84" alt="" />
188
+ </p>
189
+
190
+ <p align="center"><em>Same brand green. Different bodies and faces. One per user.</em></p>
191
+
192
+ ### "Always this body, random colors, no random face"
193
+
194
+ Lock the shape and the face, let the color come from the seed:
195
+
196
+ ```tsx
197
+ <Picto
198
+ config={{
199
+ seed: userId,
200
+ shape: 2, // always this body
201
+ eyes: 'double', // always this face
202
+ brow: 'double_1', // "
203
+ mode: 'mono', // always plain eyes
204
+ // color is left out, so it is the only thing that changes per user
205
+ }}
206
+ />
207
+ ```
208
+
209
+ <p align="center">
210
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/shapelock-1.svg" width="84" alt="" />
211
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/shapelock-2.svg" width="84" alt="" />
212
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/shapelock-3.svg" width="84" alt="" />
213
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/shapelock-4.svg" width="84" alt="" />
214
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/shapelock-5.svg" width="84" alt="" />
215
+ </p>
216
+
217
+ <p align="center"><em>Same shape, same plain face. Only the color rolls.</em></p>
218
+
219
+ ### Random, but only from a set
220
+
221
+ Want variety, but inside guardrails? Pass arrays:
222
+
223
+ ```tsx
224
+ // only ever shapes 1 or 3, only double or triple eyes, only your two greens
225
+ <Picto
226
+ config={{
227
+ seed: userId,
228
+ shape: [1, 3],
229
+ eyes: ['double', 'triple'],
230
+ color: ['green', 'lime'],
231
+ }}
232
+ />
233
+ ```
234
+
235
+ ### Brand colors, spelled out
236
+
237
+ `color` accepts an anchor name (`'blue'`), a brand hex (`'#19c37d'`, auto-gradient),
238
+ or an array of either. For full manual control, set both gradient stops yourself
239
+ with `light` and `dark`. Want to preview the gradient a hex would make?
240
+
241
+ ```ts
242
+ import { picto } from 'pictoguys'
243
+
244
+ picto.gradient('#19c37d') // { light: '#19c37d', dark: '#003329' }
245
+ picto.gradient(140) // a gradient for hue 140 degrees
246
+ ```
247
+
248
+ > **Tip:** pass something stable as the `seed` (a user id, an email, a username)
249
+ > so the same person always lands on the same picto.
250
+
251
+ ## Make them move
252
+
253
+ Two ways, pick whichever feels easier.
254
+
255
+ **The easy way: just ask for an animation.**
256
+
257
+ ```tsx
258
+ <Picto seed="Gizmo" animate="breath" />
259
+ ```
260
+
261
+ Animations available: `"blink"`, `"jump"`, `"breath"`, `"dance"`.
262
+ `breath` and `dance` loop forever. `blink` and `jump` play once.
263
+
264
+ **The hands-on way: tell a specific picto to do something.**
265
+
266
+ First make a picto with `picto.character(...)`, then call methods on it:
267
+
268
+ ```tsx
269
+ import { picto, Picto } from 'pictoguys'
270
+
271
+ function Mascot() {
272
+ const guy = React.useMemo(() => picto.character('Gizmo'), [])
273
+
274
+ return (
275
+ <>
276
+ <Picto char={guy} size={140} />
277
+ <button onClick={() => guy.blink()}>blink</button>
278
+ <button onClick={() => guy.dance()}>dance</button>
279
+ <button onClick={() => guy.stop()}>chill</button>
280
+ </>
281
+ )
282
+ }
283
+ ```
284
+
285
+ ```ts
286
+ guy.blink() // one blink
287
+ guy.jump() // one hop
288
+ guy.breath() // breathe (loops)
289
+ guy.dance() // dance (loops)
290
+ guy.stop() // freeze
291
+ ```
292
+
293
+ > **Heads up for beginners:** `guy.blink()` works by poking the `<Picto char={guy} />`
294
+ > on screen. If that picto is not currently rendered, the call simply does
295
+ > nothing (no crash, no error, just a no-op). So render it first, then animate it.
296
+
297
+ ## All the props
298
+
299
+ `<Picto>` accepts these. Everything is optional.
300
+
301
+ | Prop | Type | Default | What it does |
302
+ | ------------ | -------------------------------------- | ------- | ----------------------------------------- |
303
+ | `seed` | `number \| string` | `0` | Build a picto from a number or a word. |
304
+ | `config` | `CharConfig` | none | Build a picto from exact settings. |
305
+ | `char` | `Character` | none | Use a picto you already made (wins). |
306
+ | `size` | `number` | `120` | Width and height, in pixels. |
307
+ | `background` | `boolean` | `false` | Set `true` to add a background tile. |
308
+ | `animate` | `"blink" \| "jump" \| "breath" \| "dance"` | none | Play an animation on loop or once. |
309
+
310
+ Any normal `<span>` prop works too (`className`, `style`, `onClick`, and so on),
311
+ because that is what `<Picto>` renders into.
312
+
313
+ Pictos are see-through by default, so they sit nicely on top of anything. Want a
314
+ colored tile behind one instead? Flip one switch:
315
+
316
+ ```tsx
317
+ <Picto seed="Bloop" /> {/* bare, the default */}
318
+ <Picto seed="Bloop" background /> {/* with a background tile */}
319
+ ```
320
+
321
+ <p align="center">
322
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/bloop.svg" width="120" alt="Bloop, bare" />
323
+ &nbsp;&nbsp;
324
+ <img src="https://raw.githubusercontent.com/ctresb/picto/main/assets/bloop-bg.svg" width="120" alt="Bloop with a background tile" />
325
+ </p>
326
+
327
+ ## Using it outside React
328
+
329
+ A picto is just an SVG string under the hood, so you can grab that string and do
330
+ whatever you want with it (emails, server rendering, saving to a file).
331
+
332
+ ```ts
333
+ import { picto } from 'pictoguys/core'
334
+
335
+ const svg = picto.character('Bloop').svg() // bare (default)
336
+ // -> "<svg viewBox=\"0 0 40 40\" ...>...</svg>"
337
+
338
+ const withTile = picto.character('Bloop').svg({ background: true }) // add a tile
339
+ const prefixed = picto.character('Bloop').svg({ uid: 'a_' }) // custom id prefix
340
+ ```
341
+
342
+ You can also read what a picto turned out to be:
343
+
344
+ ```ts
345
+ const guy = picto.character('Bloop')
346
+ guy.config
347
+ // { color: 'gen319', shape: '4', eyes: 'single', mode: 'mono', ... }
348
+ ```
349
+
350
+ The `svg()` output is deterministic, and every id inside is prefixed, so you can
351
+ drop many pictos into one page without their gradients or filters fighting.
352
+
353
+ ## Bonus: just the random number maker
354
+
355
+ The seeded randomness that powers picto lives on its own tiny path, with **none**
356
+ of the character art attached. Handy if you only want stable, repeatable random
357
+ numbers:
358
+
359
+ ```ts
360
+ import { mulberry32, hashSeed } from 'pictoguys/rng'
361
+
362
+ const random = mulberry32(hashSeed('any-string'))
363
+ random() // a number 0..1, the same every time for that string
364
+ ```
365
+
366
+ Importing `pictoguys/rng` pulls in well under 1 KB. Importing the full library
367
+ includes the character art (that art is the whole point, so it ships with it).
368
+
369
+ ## How it works (the 20 second version)
370
+
371
+ 1. Your seed goes through a small, predictable shuffler.
372
+ 2. The shuffle picks a color, a shape, eyes, eyebrows, and a background.
373
+ 3. Those SVG parts get recolored in OKLCH color space (so the colors always look
374
+ nice together, not muddy) and stitched into one SVG.
375
+ 4. React drops that SVG on the page. Animations are just smooth CSS transforms on
376
+ the body or the eyes.
377
+
378
+ Same seed in means same picto out. No randomness leaks, no surprises.
379
+
380
+ ## FAQ
381
+
382
+ **Is it really the same picto every time?**
383
+ Yes. "Bloop" is Bloop on your laptop, your phone, and your friend's machine.
384
+
385
+ **Do I need to download or host any images?**
386
+ No. The parts are inside the package. One `npm install` and you are done.
387
+
388
+ **Can I get a totally specific look?**
389
+ Yes, use `config={{ ... }}` and set exactly what you want.
390
+
391
+ **How big is it?**
392
+ The art data is around 120 KB before gzip. It compresses well, and it is the
393
+ actual content of the library, so there is nothing to fetch separately.
394
+
395
+ ## License
396
+
397
+ MIT. Go make a thousand little guys.
@@ -0,0 +1,141 @@
1
+ /** Artist body colors, e.g. "blue", "pink". */
2
+ declare const COLORS: string[];
3
+ /** Body shape variants, "1".."4". */
4
+ declare const SHAPES: string[];
5
+ /** Background keys, "1".."5". */
6
+ declare const BGS: string[];
7
+ /** Eye kinds that have both eyes and matching eyebrows: "single" | "double" | "triple". */
8
+ declare const PREFIXES: string[];
9
+ interface PalEntry {
10
+ name: string;
11
+ light: string;
12
+ dark: string;
13
+ gen: boolean;
14
+ }
15
+ declare function buildPalette(selColors: string[], extra: number): PalEntry[];
16
+ interface Tuning {
17
+ /** feature (outline) lightness, 10..45 */
18
+ featL: number;
19
+ /** feature tint chroma, 0..12 */
20
+ featC: number;
21
+ /** lit pupil lightness, 60..95 */
22
+ litL: number;
23
+ /** pupil chroma, 4..22 */
24
+ pupC: number;
25
+ }
26
+ declare const DEFAULT_TUNING: Tuning;
27
+ interface ComposeArgs {
28
+ light: string;
29
+ dark: string;
30
+ shape: string;
31
+ bg: string;
32
+ eye: string;
33
+ brow: string;
34
+ mode: string;
35
+ tuning: Tuning;
36
+ uid: string;
37
+ background: boolean;
38
+ }
39
+ declare function compose(a: ComposeArgs): string;
40
+ type Mode = 'mono' | 'hetero' | 'triad';
41
+ type EyeKind = 'single' | 'double' | 'triple';
42
+ /**
43
+ * A constraint value. Three ways to use any field:
44
+ * - omit it -> fully random (picked from the seed)
45
+ * - one value -> locked to that value
46
+ * - an array of values -> random, but only from that set (picked from the seed)
47
+ */
48
+ type OneOrMany<T> = T | readonly T[];
49
+ interface CharConfig {
50
+ /** Explicit seed. Omit to derive a stable seed from the other fields. */
51
+ seed?: number | string;
52
+ /**
53
+ * Body color. An anchor name ("blue"), OR a brand hex ("#19c37d") which gets a
54
+ * matching darker shade auto-generated. Array = pick one at random.
55
+ */
56
+ color?: OneOrMany<string>;
57
+ /** Body hue in degrees. Array = pick one. Used when `color` is absent. */
58
+ hue?: OneOrMany<number>;
59
+ /** Explicit gradient stops. Full manual lock, wins over color/hue. */
60
+ light?: string;
61
+ dark?: string;
62
+ /** Body shape, 1..4. Array = pick one. */
63
+ shape?: OneOrMany<number | string>;
64
+ /** Eye kind. Array = pick one. */
65
+ eyes?: OneOrMany<EyeKind>;
66
+ /** Exact eye file key, e.g. "double_2" (implies `eyes`). Array = pick one. */
67
+ eye?: OneOrMany<string>;
68
+ /** Exact eyebrow file key. Array = pick one. */
69
+ brow?: OneOrMany<string>;
70
+ /** Background, 1..5. Array = pick one. */
71
+ bg?: OneOrMany<number | string>;
72
+ /** Eye coloring mode. Array = pick one. Invalid combos fall back to "mono". */
73
+ mode?: OneOrMany<Mode>;
74
+ /** OKLCH fine-tuning overrides. */
75
+ tuning?: Partial<Tuning>;
76
+ /** Generated-hue variety for seeded picks (default 8). */
77
+ genHues?: number;
78
+ }
79
+ type CharInput = number | string | CharConfig;
80
+ /** A fully-resolved, concrete character spec. */
81
+ interface Resolved {
82
+ color: string;
83
+ light: string;
84
+ dark: string;
85
+ shape: string;
86
+ eyes: EyeKind;
87
+ eye: string;
88
+ brow: string;
89
+ bg: string;
90
+ mode: Mode;
91
+ hue: number;
92
+ tuning: Tuning;
93
+ }
94
+ /**
95
+ * Build a body gradient from a single brand color (hex) or a hue (degrees).
96
+ * Handy for inspecting or reusing what `color: '#hex'` would produce.
97
+ */
98
+ declare function gradient(input: string | number): {
99
+ light: string;
100
+ dark: string;
101
+ };
102
+ declare function resolve(input: CharInput): Resolved;
103
+
104
+ type AnimName = 'blink' | 'jump' | 'breath' | 'dance';
105
+ /** name = animation to play, or null to stop. */
106
+ interface AnimEvent {
107
+ name: AnimName | null;
108
+ }
109
+ type Listener = (e: AnimEvent) => void;
110
+ interface SvgOptions {
111
+ /** Add a background tile (default false). Omit/false -> transparent. */
112
+ background?: boolean;
113
+ /** Id prefix to keep filters/gradients unique across SVGs in one document. */
114
+ uid?: string;
115
+ }
116
+ declare class Character {
117
+ /** The fully-resolved, concrete spec. */
118
+ readonly config: Resolved;
119
+ /** Stable id prefix derived from the spec — keeps .svg() deterministic. */
120
+ private readonly _uid;
121
+ private _listeners;
122
+ constructor(input?: CharInput);
123
+ /** Render this character to a standalone SVG string. */
124
+ svg(opts?: SvgOptions): string;
125
+ toString(): string;
126
+ /** Blink once. */
127
+ blink(): this;
128
+ /** Hop once. */
129
+ jump(): this;
130
+ /** Breathe (loops until stop or another animation). */
131
+ breath(): this;
132
+ /** Dance (loops until stop or another animation). */
133
+ dance(): this;
134
+ /** Stop any running animation. */
135
+ stop(): this;
136
+ /** @internal — used by <Picto> to react to animation calls. */
137
+ _subscribe(fn: Listener): () => void;
138
+ private _emit;
139
+ }
140
+
141
+ export { type AnimEvent as A, BGS as B, COLORS as C, DEFAULT_TUNING as D, type EyeKind as E, type Mode as M, type OneOrMany as O, PREFIXES as P, type Resolved as R, SHAPES as S, type Tuning as T, type AnimName as a, type CharConfig as b, type CharInput as c, Character as d, type ComposeArgs as e, type PalEntry as f, type SvgOptions as g, buildPalette as h, compose as i, gradient as j, resolve as r };