@fungi.computer/sprite-zdog 0.0.0-stage → 0.0.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +125 -2
  3. package/dist/agent-proof/moth.d.ts +50 -0
  4. package/dist/agent-proof/moth.js +52 -0
  5. package/dist/author.d.ts +217 -0
  6. package/dist/author.js +372 -0
  7. package/dist/avatar.d.ts +69 -0
  8. package/dist/avatar.js +40 -0
  9. package/dist/builtins/base-face.d.ts +290 -0
  10. package/dist/builtins/base-face.js +615 -0
  11. package/dist/builtins/base.d.ts +331 -0
  12. package/dist/builtins/base.js +579 -0
  13. package/dist/builtins/burger-input.d.ts +310 -0
  14. package/dist/builtins/burger-input.js +517 -0
  15. package/dist/builtins/burger.d.ts +305 -0
  16. package/dist/builtins/burger.js +4 -0
  17. package/dist/builtins/cat-input.d.ts +316 -0
  18. package/dist/builtins/cat-input.js +255 -0
  19. package/dist/builtins/cat.d.ts +311 -0
  20. package/dist/builtins/cat.js +4 -0
  21. package/dist/builtins/index.d.ts +4 -0
  22. package/dist/builtins/index.js +4 -0
  23. package/dist/builtins/mushroom-input.d.ts +314 -0
  24. package/dist/builtins/mushroom-input.js +94 -0
  25. package/dist/builtins/mushroom.d.ts +310 -0
  26. package/dist/builtins/mushroom.js +4 -0
  27. package/dist/burger.d.ts +9 -0
  28. package/dist/burger.js +15 -0
  29. package/dist/cat.d.ts +9 -0
  30. package/dist/cat.js +15 -0
  31. package/dist/catalog.d.ts +3 -0
  32. package/dist/catalog.js +63 -0
  33. package/dist/document.d.ts +444 -0
  34. package/dist/document.js +204 -0
  35. package/dist/index.d.ts +10 -0
  36. package/dist/index.js +10 -0
  37. package/dist/internal.d.ts +41 -0
  38. package/dist/internal.js +21 -0
  39. package/dist/mushroom.character.json +1930 -0
  40. package/dist/mushroom.d.ts +4 -0
  41. package/dist/mushroom.js +9 -0
  42. package/dist/palette.d.ts +3 -0
  43. package/dist/palette.js +5 -0
  44. package/dist/portable.d.ts +4 -0
  45. package/dist/portable.js +61 -0
  46. package/dist/renderer.d.ts +4 -0
  47. package/dist/renderer.js +106 -0
  48. package/dist/zdog-runtime.d.ts +21 -0
  49. package/dist/zdog-runtime.js +622 -0
  50. package/package.json +112 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jamstack Consulting LLC
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,126 @@
1
- # Temporary Holding Version
1
+ # Sprite Zdog (`@fungi.computer/sprite-zdog`)
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
+ Sprite Zdog is an optional Canvas renderer for characters built with Zdog. It
4
+ also provides built-in characters and tools for authoring a portable character
5
+ document that [Sprite](../sprite/README.md) can load.
6
+
7
+ ## Install or set up
8
+
9
+ ```sh
10
+ npm install @fungi.computer/sprite-zdog
11
+ ```
12
+
13
+ The package ships ESM only and depends on Effect, Zod, `animejs`, `zdog`, and
14
+ [Sprite](../sprite/README.md) at runtime. Add it only to a host that already
15
+ uses Sprite and renders with Zdog. The parent Sprite host still owns the player
16
+ and asset policy. The root entrypoint exports the Zdog renderer. `./author` and
17
+ `./portable` support scene authoring. `./builtins` (and the individual
18
+ `./builtins/base`, `./builtins/mushroom`, `./builtins/cat`, and
19
+ `./builtins/burger` subpaths) expose the bundled authoring definitions.
20
+ `./mushroom`, `./cat` and `./burger` provide ready-to-load local characters,
21
+ each with its document and renderer. `./catalog` and `./avatar` provide pure
22
+ avatar validation and derivation without importing the Canvas renderer.
23
+
24
+ ## Quick start
25
+
26
+ This illustrative example installs the bundled mushroom as a local character and
27
+ renders it with the Sprite React component:
28
+
29
+ ```tsx
30
+ import { createSprite } from "@fungi.computer/sprite";
31
+ import { Sprite } from "@fungi.computer/sprite/react";
32
+ import { builtinCharacters } from "@fungi.computer/sprite-zdog";
33
+
34
+ const service = createSprite({
35
+ characters: builtinCharacters,
36
+ });
37
+
38
+ function Character() {
39
+ return (
40
+ <Sprite
41
+ service={service}
42
+ src={{ local: "mushroom" }}
43
+ activity="thinking"
44
+ role="img"
45
+ aria-label="Mushroom character"
46
+ />
47
+ );
48
+ }
49
+ ```
50
+
51
+ `builtinCharacters` provides lazy `mushroom`, `cat` and `burger` loaders without
52
+ remote asset access. The bundled character supplies its document and Zdog
53
+ renderer together. The tests cover built-in characters and player integration in
54
+ [`src/builtins.test.ts`](src/builtins.test.ts) and
55
+ [`src/mushroom.test.ts`](src/mushroom.test.ts).
56
+
57
+ ## Core concepts
58
+
59
+ The package root exports the Zdog renderer as the default export. To render a
60
+ served character document whose `renderer` is `zdog`, register it with Sprite.
61
+ This illustrative configuration uses `assetPolicy` as the host's configured
62
+ Sprite asset policy:
63
+
64
+ ```ts
65
+ const service = createSprite({
66
+ assets: assetPolicy,
67
+ renderers: {
68
+ zdog: () => import("@fungi.computer/sprite-zdog"),
69
+ },
70
+ });
71
+ ```
72
+
73
+ `assetPolicy` stands for the host's configured Sprite asset policy. Admit the
74
+ document's origin and set its byte and request limits. A local character does
75
+ not need remote asset access.
76
+
77
+ For authoring, `defineSprite` validates a trusted scene definition, `check`
78
+ returns a compact author-time summary, and `toCharacter` converts the definition
79
+ into a JSON character document. The resulting document contains data, not
80
+ executable authoring code. `@fungi.computer/sprite-zdog/builtins` exports the
81
+ base, mushroom, cat, and burger characters.
82
+
83
+ For stored avatars, import `avatarSchema` or `parseAvatar(data)` from
84
+ `@fungi.computer/sprite-zdog/avatar`. These validate against the built-in
85
+ character controls and expressions, rather than checking only the envelope.
86
+ `deriveAgentAvatar(member, agentColors, seed, avoid?)` uses that same catalog;
87
+ `agentColors` is `"keep"` or `"shift"`. `avatarCatalog` is also available from
88
+ `./catalog` for callers using Sprite's catalog-parameterized helpers.
89
+ `memberAvatarSchema` validates the strict `{avatar, agentColors}` preference;
90
+ `defaultMemberAvatar` supplies the uncustomized mushroom with colour shift on.
91
+
92
+ ## API reference
93
+
94
+ See the generated [package API](docs/api/README.md),
95
+ [authoring API](docs/api/author.md), and
96
+ [portable document API](docs/api/portable.md). The package also exposes
97
+ individual built-ins through `@fungi.computer/sprite-zdog/builtins/<name>`.
98
+
99
+ ## Examples and checks
100
+
101
+ The local Sprite stories live in `src/*.stories.tsx`. Run the package tests
102
+ with:
103
+
104
+ ```sh
105
+ pnpm --filter @fungi.computer/sprite-zdog test
106
+ ```
107
+
108
+ The authoring and portable-runtime tests cover definition validation,
109
+ serialization, decoding, and cleanup.
110
+
111
+ ## Limits and errors
112
+
113
+ The Zdog renderer requires a browser window and canvas. It decodes the
114
+ character's Zdog data before creating a renderer and removes its canvas and
115
+ animation resources when the player selection closes. Invalid scene data,
116
+ missing expressions, or invalid palette colors fail the selection.
117
+
118
+ The authoring callback is trusted code that runs while creating the portable
119
+ document. Runtime rendering reads the resulting JSON data. It does not execute
120
+ the authoring callback. Served documents still use Sprite's host-owned origin
121
+ and asset limits.
122
+
123
+ ## Contribute and license
124
+
125
+ Sprite Zdog is MIT licensed. See [`LICENSE`](LICENSE) and
126
+ [`THIRD_PARTY_NOTICES`](THIRD_PARTY_NOTICES).
@@ -0,0 +1,50 @@
1
+ declare const moth: Readonly<{
2
+ readonly apiVersion: 1;
3
+ readonly name: "moth";
4
+ readonly palette: {
5
+ readonly body: "#eee6d3";
6
+ readonly ink: "#322f35";
7
+ readonly glow: "#f2b84b";
8
+ };
9
+ readonly build: ({ scene, color }: import("@fungi.computer/sprite-zdog/author").AuthorContext) => {
10
+ root: import("@fungi.computer/sprite-zdog/author").SceneNode;
11
+ variants: {
12
+ eyes: {
13
+ normal: import("@fungi.computer/sprite-zdog/author").SceneNode;
14
+ };
15
+ };
16
+ };
17
+ readonly expressions: {
18
+ readonly normal: {
19
+ readonly variants: {
20
+ readonly eyes: "normal";
21
+ };
22
+ };
23
+ readonly alert: {
24
+ readonly variants: {
25
+ readonly eyes: "normal";
26
+ };
27
+ };
28
+ };
29
+ readonly activities: {
30
+ readonly idle: {};
31
+ readonly listening: {};
32
+ readonly processing: {};
33
+ readonly speaking: {
34
+ readonly mouthCycle: readonly [{
35
+ readonly durationMs: 20;
36
+ readonly mouth: "base";
37
+ }];
38
+ };
39
+ readonly thinking: {};
40
+ readonly error: {};
41
+ readonly flutter: {
42
+ readonly motion: {
43
+ readonly target: "root";
44
+ readonly durationMs: 20;
45
+ readonly repeat: "yoyo";
46
+ };
47
+ };
48
+ };
49
+ }>;
50
+ export default moth;
@@ -0,0 +1,52 @@
1
+ import { defineSprite } from "@fungi.computer/sprite-zdog/author";
2
+ const moth = defineSprite({
3
+ apiVersion: 1,
4
+ name: "moth",
5
+ palette: { body: "#eee6d3", ink: "#322f35", glow: "#f2b84b" },
6
+ build({ scene, color }) {
7
+ const root = scene.group({ name: "root" });
8
+ const eyes = scene.group({ parent: root, name: "eyes" });
9
+ scene.ellipse({
10
+ parent: root,
11
+ name: "body",
12
+ width: 18,
13
+ height: 26,
14
+ color: color("body"),
15
+ fill: true,
16
+ stroke: false,
17
+ });
18
+ scene.ellipse({
19
+ parent: eyes,
20
+ name: "eye.left",
21
+ width: 3,
22
+ height: 5,
23
+ x: -4,
24
+ color: color("ink"),
25
+ fill: true,
26
+ });
27
+ scene.ellipse({
28
+ parent: eyes,
29
+ name: "eye.right",
30
+ width: 3,
31
+ height: 5,
32
+ x: 4,
33
+ color: color("ink"),
34
+ fill: true,
35
+ });
36
+ return { root, variants: { eyes: { normal: eyes } } };
37
+ },
38
+ expressions: {
39
+ normal: { variants: { eyes: "normal" } },
40
+ alert: { variants: { eyes: "normal" } },
41
+ },
42
+ activities: {
43
+ idle: {},
44
+ listening: {},
45
+ processing: {},
46
+ speaking: { mouthCycle: [{ durationMs: 20, mouth: "base" }] },
47
+ thinking: {},
48
+ error: {},
49
+ flutter: { motion: { target: "root", durationMs: 20, repeat: "yoyo" } },
50
+ },
51
+ });
52
+ export default moth;
@@ -0,0 +1,217 @@
1
+ declare const sceneNodeBrand: unique symbol;
2
+ /** An opaque node in a renderer-neutral Sprite scene. */
3
+ export type SceneNode = {
4
+ /** Nominal marker that keeps renderer details out of the author surface. */
5
+ readonly [sceneNodeBrand]: true;
6
+ };
7
+ /** A point in Sprite scene space. */
8
+ export type Point = {
9
+ /** Horizontal scene coordinate. */
10
+ readonly x: number;
11
+ /** Vertical scene coordinate. */
12
+ readonly y: number;
13
+ /** Optional depth coordinate. */
14
+ readonly z?: number;
15
+ };
16
+ /** One cubic Bezier path segment. */
17
+ export type BezierStep = {
18
+ /** Two control points followed by the segment endpoint. */
19
+ readonly bezier: readonly [Point, Point, Point];
20
+ };
21
+ /** One renderer-neutral shape path segment. */
22
+ export type PathStep = Point | BezierStep;
23
+ /** Optional translation, rotation, or scale coordinates. */
24
+ export type Transform = {
25
+ /** Optional horizontal component. */
26
+ readonly x?: number;
27
+ /** Optional vertical component. */
28
+ readonly y?: number;
29
+ /** Optional depth component. */
30
+ readonly z?: number;
31
+ };
32
+ /** Shared renderer-neutral options for one scene node. */
33
+ export type SceneNodeOptions = {
34
+ /** Definition-local name used by authored references. */
35
+ readonly name?: string;
36
+ /** Parent node in the same definition. */
37
+ readonly parent?: SceneNode;
38
+ /** Horizontal translation that takes precedence over `translate.x`. */
39
+ readonly x?: number;
40
+ /** Vertical translation that takes precedence over `translate.y`. */
41
+ readonly y?: number;
42
+ /** Depth translation that takes precedence over `translate.z`. */
43
+ readonly z?: number;
44
+ /** Translation components not supplied by the direct coordinates. */
45
+ readonly translate?: Transform;
46
+ /** Rotation around each scene axis, in radians. */
47
+ readonly rotate?: Transform;
48
+ /** Scale applied along each scene axis. */
49
+ readonly scale?: Transform;
50
+ /** Whether the node participates in rendering. */
51
+ readonly visible?: boolean;
52
+ /** Literal paint or an opaque reference returned by `color`. */
53
+ readonly color?: string;
54
+ /** A false stroke keeps a solid primitive edge-free, as in Zdog fills. */
55
+ readonly stroke?: number | false;
56
+ readonly fill?: boolean;
57
+ /** Optional rear/forward surface palette slots for 3D solids. */
58
+ readonly backface?: string;
59
+ /** Paint used for a primitive's front face when supported. */
60
+ readonly frontFace?: string;
61
+ /** Whether supported primitives update child depth ordering. */
62
+ readonly updateSort?: boolean;
63
+ };
64
+ /** Renderer-neutral options for a freeform shape. */
65
+ export type PathOptions = {
66
+ /** Ordered points and cubic Bezier segments in the path. */
67
+ readonly path?: readonly PathStep[];
68
+ /** Whether the renderer closes the path. */
69
+ readonly closed?: boolean;
70
+ } & SceneNodeOptions;
71
+ /** Renderer-neutral options for an ellipse. */
72
+ export type EllipseOptions = {
73
+ /** Horizontal diameter. */
74
+ readonly width: number;
75
+ /** Vertical diameter. */
76
+ readonly height: number;
77
+ } & SceneNodeOptions;
78
+ /** Renderer-neutral options for a hemisphere. */
79
+ export type HemisphereOptions = {
80
+ /** Diameter of the hemisphere's base. */
81
+ readonly diameter: number;
82
+ } & SceneNodeOptions;
83
+ /** Renderer-neutral options for a cylinder. */
84
+ export type CylinderOptions = {
85
+ /** Diameter of the cylinder's circular faces. */
86
+ readonly diameter: number;
87
+ /** Distance between the cylinder's faces. */
88
+ readonly length: number;
89
+ } & SceneNodeOptions;
90
+ /** The complete renderer-neutral scene authoring surface. */
91
+ export type SceneBuilder = {
92
+ /** Create a grouping node. */
93
+ group(options?: SceneNodeOptions): SceneNode;
94
+ /** Create a freeform path node. */
95
+ path(options: PathOptions): SceneNode;
96
+ /** Create an ellipse node. */
97
+ ellipse(options: EllipseOptions): SceneNode;
98
+ /** Create a hemisphere node. */
99
+ hemisphere(options: HemisphereOptions): SceneNode;
100
+ /** Create a cylinder node. */
101
+ cylinder(options: CylinderOptions): SceneNode;
102
+ };
103
+ /** A named motion applied while presenting a Sprite. */
104
+ export type MotionSpec = {
105
+ /** Name of the scene node targeted by the motion. */
106
+ readonly target: string;
107
+ /** Authored translation change. */
108
+ readonly translate?: Transform;
109
+ /** Authored rotation change. */
110
+ readonly rotate?: Transform;
111
+ /** Duration of one motion pass in milliseconds. */
112
+ readonly durationMs?: number;
113
+ /** Repetition mode for the motion. */
114
+ readonly repeat?: "none" | "loop" | "yoyo";
115
+ };
116
+ /** The standard presentation activity names accepted by every Sprite. */
117
+ export type StandardActivity = "idle" | "listening" | "processing" | "speaking" | "thinking" | "error";
118
+ /** Variant selections applied to one expression or activity. */
119
+ export type StateGeometry = {
120
+ /** Expression selected by an activity. */
121
+ readonly expression?: string;
122
+ /** Value selected from the `eyes` variant channel. */
123
+ readonly eyes?: string;
124
+ /** Value selected from the `mouth` variant channel. */
125
+ readonly mouth?: string;
126
+ /** Normalized blush intensity. */
127
+ readonly blush?: number;
128
+ };
129
+ /** One timed mouth state in a speaking cycle. */
130
+ export type MouthCycleStep = {
131
+ /** Time spent in this mouth state, in milliseconds. */
132
+ readonly durationMs: number;
133
+ /** Mouth state shown during the step. */
134
+ readonly mouth: "base" | "open";
135
+ };
136
+ /** Presentation behavior associated with an activity. */
137
+ export type ActivitySpec = {
138
+ /** Optional motion authored for the activity. */
139
+ readonly motion?: MotionSpec;
140
+ /** Optional geometry selections authored for the activity. */
141
+ readonly geometry?: StateGeometry;
142
+ /** Authored pointer-influence strength. */
143
+ readonly mouseInfluence?: number;
144
+ /** Ordered timed mouth states for the activity. */
145
+ readonly mouthCycle?: readonly MouthCycleStep[];
146
+ };
147
+ /** Variant and motion behavior associated with an expression. */
148
+ export type ExpressionSpec = {
149
+ /** Fixed value selected for each variant channel. */
150
+ readonly variants?: Record<string, string>;
151
+ /** Candidate values authored for each variant channel. */
152
+ readonly variantChoices?: Record<string, readonly string[]>;
153
+ /** Normalized blush intensity. */
154
+ readonly blush?: number;
155
+ /** Optional motion authored for the expression. */
156
+ readonly motion?: MotionSpec;
157
+ };
158
+ /** The root and named variants produced by one author build. */
159
+ export type BuildResult = {
160
+ /** Root node of the rendered scene tree. */
161
+ readonly root: SceneNode;
162
+ /** Definition-local nodes grouped by variant channel and value. */
163
+ readonly variants?: Record<string, Record<string, SceneNode>>;
164
+ };
165
+ /** Renderer-neutral capabilities available while authoring a Sprite. */
166
+ export type AuthorContext = {
167
+ /** Scene builder valid only for the duration of `build`. */
168
+ readonly scene: SceneBuilder;
169
+ /** Create an opaque reference to an own palette slot. */
170
+ readonly color: (name: string) => string;
171
+ };
172
+ /** Input accepted by the Sprite authoring seam. */
173
+ export type SpriteDefinitionInput = {
174
+ /** Version of the authoring contract used by this definition. */
175
+ readonly apiVersion: 1;
176
+ /** Human-readable Sprite definition name. */
177
+ readonly name: string;
178
+ /** Named default paints available to the author callback. */
179
+ readonly palette: Record<string, string>;
180
+ /** Construct the renderer-neutral scene and its named variants. */
181
+ readonly build: (context: AuthorContext) => BuildResult;
182
+ /** Named expression specifications; at least one is required. */
183
+ readonly expressions: Record<string, ExpressionSpec>;
184
+ /** Optional custom activity specifications. */
185
+ readonly activities?: Record<string, ActivitySpec>;
186
+ /** Initial activity and expression selected when mounted. */
187
+ readonly defaultPresentation?: {
188
+ /** Standard or custom activity selected initially. */
189
+ readonly activity?: string;
190
+ /** Declared expression selected initially. */
191
+ readonly expression?: string;
192
+ };
193
+ };
194
+ /** An authored Sprite definition preserving the author's input shape. */
195
+ export type SpriteDefinition<Input extends SpriteDefinitionInput = SpriteDefinitionInput> = Readonly<Input>;
196
+ /** A compact receipt describing one already-authored Sprite definition. */
197
+ export type SpriteCheckResult = {
198
+ /** Whether the definition has completed author-time validation. */
199
+ readonly valid: true;
200
+ /** Human-readable name of the checked definition. */
201
+ readonly name: string;
202
+ /** Number of scene nodes reachable from the definition root. */
203
+ readonly nodeCount: number;
204
+ /** Expression names in author insertion order. */
205
+ readonly expressions: readonly string[];
206
+ /** Standard activities followed by unique custom activities in author order. */
207
+ readonly activities: readonly string[];
208
+ /** Variant values by channel, preserving author insertion order. */
209
+ readonly variants: Readonly<Record<string, readonly string[]>>;
210
+ };
211
+ /** The standard presentation activities every Sprite understands. */
212
+ export declare const STANDARD_ACTIVITIES: readonly ["idle", "listening", "processing", "speaking", "thinking", "error"];
213
+ /** Validate and freeze one renderer-neutral Sprite definition. */
214
+ export declare function defineSprite<const Input extends SpriteDefinitionInput>(input: Input): SpriteDefinition<Input>;
215
+ /** Return a compact, machine-readable receipt for an already authored definition. */
216
+ export declare const check: (definition: SpriteDefinition) => SpriteCheckResult;
217
+ export { toCharacter } from "./portable.js";