@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.
- package/LICENSE +21 -0
- package/README.md +125 -2
- package/dist/agent-proof/moth.d.ts +50 -0
- package/dist/agent-proof/moth.js +52 -0
- package/dist/author.d.ts +217 -0
- package/dist/author.js +372 -0
- package/dist/avatar.d.ts +69 -0
- package/dist/avatar.js +40 -0
- package/dist/builtins/base-face.d.ts +290 -0
- package/dist/builtins/base-face.js +615 -0
- package/dist/builtins/base.d.ts +331 -0
- package/dist/builtins/base.js +579 -0
- package/dist/builtins/burger-input.d.ts +310 -0
- package/dist/builtins/burger-input.js +517 -0
- package/dist/builtins/burger.d.ts +305 -0
- package/dist/builtins/burger.js +4 -0
- package/dist/builtins/cat-input.d.ts +316 -0
- package/dist/builtins/cat-input.js +255 -0
- package/dist/builtins/cat.d.ts +311 -0
- package/dist/builtins/cat.js +4 -0
- package/dist/builtins/index.d.ts +4 -0
- package/dist/builtins/index.js +4 -0
- package/dist/builtins/mushroom-input.d.ts +314 -0
- package/dist/builtins/mushroom-input.js +94 -0
- package/dist/builtins/mushroom.d.ts +310 -0
- package/dist/builtins/mushroom.js +4 -0
- package/dist/burger.d.ts +9 -0
- package/dist/burger.js +15 -0
- package/dist/cat.d.ts +9 -0
- package/dist/cat.js +15 -0
- package/dist/catalog.d.ts +3 -0
- package/dist/catalog.js +63 -0
- package/dist/document.d.ts +444 -0
- package/dist/document.js +204 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/internal.d.ts +41 -0
- package/dist/internal.js +21 -0
- package/dist/mushroom.character.json +1930 -0
- package/dist/mushroom.d.ts +4 -0
- package/dist/mushroom.js +9 -0
- package/dist/palette.d.ts +3 -0
- package/dist/palette.js +5 -0
- package/dist/portable.d.ts +4 -0
- package/dist/portable.js +61 -0
- package/dist/renderer.d.ts +4 -0
- package/dist/renderer.js +106 -0
- package/dist/zdog-runtime.d.ts +21 -0
- package/dist/zdog-runtime.js +622 -0
- package/package.json +112 -3
package/dist/document.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { colorKeyFromValue } from "./palette.js";
|
|
3
|
+
const transform = z.strictObject({
|
|
4
|
+
x: z.number().optional(),
|
|
5
|
+
y: z.number().optional(),
|
|
6
|
+
z: z.number().optional(),
|
|
7
|
+
});
|
|
8
|
+
const point = z.strictObject({
|
|
9
|
+
x: z.number(),
|
|
10
|
+
y: z.number(),
|
|
11
|
+
z: z.number().optional(),
|
|
12
|
+
});
|
|
13
|
+
const options = z.strictObject({
|
|
14
|
+
name: z.string().min(1).optional(),
|
|
15
|
+
x: z.number().optional(),
|
|
16
|
+
y: z.number().optional(),
|
|
17
|
+
z: z.number().optional(),
|
|
18
|
+
translate: transform.optional(),
|
|
19
|
+
rotate: transform.optional(),
|
|
20
|
+
scale: transform.optional(),
|
|
21
|
+
visible: z.boolean().optional(),
|
|
22
|
+
color: z.string().optional(),
|
|
23
|
+
stroke: z.union([z.number().nonnegative(), z.literal(false)]).optional(),
|
|
24
|
+
fill: z.boolean().optional(),
|
|
25
|
+
backface: z.string().optional(),
|
|
26
|
+
frontFace: z.string().optional(),
|
|
27
|
+
updateSort: z.boolean().optional(),
|
|
28
|
+
});
|
|
29
|
+
const identity = {
|
|
30
|
+
id: z.string().min(1),
|
|
31
|
+
parent: z.string().min(1).optional(),
|
|
32
|
+
};
|
|
33
|
+
export const zdogNodeSchema = z.discriminatedUnion("kind", [
|
|
34
|
+
z.strictObject({ ...identity, kind: z.literal("group"), options }),
|
|
35
|
+
z.strictObject({
|
|
36
|
+
...identity,
|
|
37
|
+
kind: z.literal("shape"),
|
|
38
|
+
options: options.extend({
|
|
39
|
+
path: z
|
|
40
|
+
.array(z.union([
|
|
41
|
+
point,
|
|
42
|
+
z.strictObject({ bezier: z.tuple([point, point, point]) }),
|
|
43
|
+
]))
|
|
44
|
+
.optional(),
|
|
45
|
+
closed: z.boolean().optional(),
|
|
46
|
+
}),
|
|
47
|
+
}),
|
|
48
|
+
z.strictObject({
|
|
49
|
+
...identity,
|
|
50
|
+
kind: z.literal("ellipse"),
|
|
51
|
+
options: options.extend({ width: z.number(), height: z.number() }),
|
|
52
|
+
}),
|
|
53
|
+
z.strictObject({
|
|
54
|
+
...identity,
|
|
55
|
+
kind: z.literal("hemisphere"),
|
|
56
|
+
options: options.extend({ diameter: z.number() }),
|
|
57
|
+
}),
|
|
58
|
+
z.strictObject({
|
|
59
|
+
...identity,
|
|
60
|
+
kind: z.literal("cylinder"),
|
|
61
|
+
options: options.extend({ diameter: z.number(), length: z.number() }),
|
|
62
|
+
}),
|
|
63
|
+
]);
|
|
64
|
+
const motion = z.strictObject({
|
|
65
|
+
target: z.string().min(1),
|
|
66
|
+
translate: transform.optional(),
|
|
67
|
+
rotate: transform.optional(),
|
|
68
|
+
durationMs: z.number().nonnegative().optional(),
|
|
69
|
+
repeat: z.enum(["none", "loop", "yoyo"]).optional(),
|
|
70
|
+
});
|
|
71
|
+
const expression = z.strictObject({
|
|
72
|
+
variants: z.record(z.string(), z.string()).optional(),
|
|
73
|
+
variantChoices: z.record(z.string(), z.array(z.string()).min(1)).optional(),
|
|
74
|
+
blush: z.number().optional(),
|
|
75
|
+
motion: motion.optional(),
|
|
76
|
+
});
|
|
77
|
+
const activity = z.strictObject({
|
|
78
|
+
motion: motion.optional(),
|
|
79
|
+
mouseInfluence: z.number().optional(),
|
|
80
|
+
geometry: z
|
|
81
|
+
.strictObject({
|
|
82
|
+
expression: z.string().optional(),
|
|
83
|
+
eyes: z.string().optional(),
|
|
84
|
+
mouth: z.string().optional(),
|
|
85
|
+
blush: z.number().optional(),
|
|
86
|
+
})
|
|
87
|
+
.optional(),
|
|
88
|
+
mouthCycle: z
|
|
89
|
+
.array(z.strictObject({
|
|
90
|
+
durationMs: z.number().positive(),
|
|
91
|
+
mouth: z.enum(["base", "open"]),
|
|
92
|
+
}))
|
|
93
|
+
.min(1)
|
|
94
|
+
.optional(),
|
|
95
|
+
});
|
|
96
|
+
/** Zdog's portable native data, not a new cross-renderer animation language. */
|
|
97
|
+
export const zdogDocumentSchema = z
|
|
98
|
+
.strictObject({
|
|
99
|
+
root: z.string().min(1),
|
|
100
|
+
nodes: z.array(zdogNodeSchema).min(1),
|
|
101
|
+
palette: z.record(z.string(), z.string()),
|
|
102
|
+
variants: z.record(z.string(), z.record(z.string(), z.string())),
|
|
103
|
+
expressions: z.record(z.string(), expression),
|
|
104
|
+
activities: z.record(z.string(), activity),
|
|
105
|
+
defaultPresentation: z.strictObject({
|
|
106
|
+
activity: z.string(),
|
|
107
|
+
expression: z.string(),
|
|
108
|
+
}),
|
|
109
|
+
})
|
|
110
|
+
.superRefine((document, context) => {
|
|
111
|
+
const visited = new Set();
|
|
112
|
+
const names = new Set();
|
|
113
|
+
const issue = (message) => {
|
|
114
|
+
context.addIssue({ code: "custom", message });
|
|
115
|
+
};
|
|
116
|
+
for (const node of document.nodes) {
|
|
117
|
+
if (visited.has(node.id) ||
|
|
118
|
+
(node.parent !== undefined && !visited.has(node.parent)) ||
|
|
119
|
+
(node.parent === undefined && node.id !== document.root)) {
|
|
120
|
+
issue("Scene needs unique, parent-first nodes and one root");
|
|
121
|
+
}
|
|
122
|
+
visited.add(node.id);
|
|
123
|
+
if (node.options.name) {
|
|
124
|
+
if (names.has(node.options.name))
|
|
125
|
+
issue(`Duplicate Sprite node name: ${node.options.name}`);
|
|
126
|
+
names.add(node.options.name);
|
|
127
|
+
}
|
|
128
|
+
for (const value of [
|
|
129
|
+
node.options.color,
|
|
130
|
+
node.options.backface,
|
|
131
|
+
node.options.frontFace,
|
|
132
|
+
]) {
|
|
133
|
+
const key = colorKeyFromValue(value);
|
|
134
|
+
if (key !== undefined && !Object.hasOwn(document.palette, key))
|
|
135
|
+
issue(`Unknown Sprite palette slot: ${key}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (!visited.has(document.root))
|
|
139
|
+
issue("Scene root is missing");
|
|
140
|
+
for (const variants of Object.values(document.variants)) {
|
|
141
|
+
for (const id of Object.values(variants)) {
|
|
142
|
+
if (!visited.has(id))
|
|
143
|
+
issue("Variant node is missing");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (!Object.hasOwn(document.expressions, document.defaultPresentation.expression))
|
|
147
|
+
issue(`Unknown Sprite default expression: ${document.defaultPresentation.expression}`);
|
|
148
|
+
const standard = [
|
|
149
|
+
"idle",
|
|
150
|
+
"listening",
|
|
151
|
+
"processing",
|
|
152
|
+
"speaking",
|
|
153
|
+
"thinking",
|
|
154
|
+
"error",
|
|
155
|
+
];
|
|
156
|
+
if (!standard.includes(document.defaultPresentation.activity) &&
|
|
157
|
+
!Object.hasOwn(document.activities, document.defaultPresentation.activity))
|
|
158
|
+
issue(`Unknown Sprite default activity: ${document.defaultPresentation.activity}`);
|
|
159
|
+
const variant = (channel, value) => {
|
|
160
|
+
if (!Object.hasOwn(document.variants, channel) ||
|
|
161
|
+
!Object.hasOwn(document.variants[channel] ?? {}, value))
|
|
162
|
+
issue(`Unknown Sprite variant: ${channel}.${value}`);
|
|
163
|
+
};
|
|
164
|
+
const motionTarget = (target) => {
|
|
165
|
+
if (!names.has(target))
|
|
166
|
+
issue(`Unknown Sprite motion target: ${target}`);
|
|
167
|
+
};
|
|
168
|
+
const blush = (value) => value === 0
|
|
169
|
+
? "off"
|
|
170
|
+
: value <= 0.5
|
|
171
|
+
? "small"
|
|
172
|
+
: value <= 0.8
|
|
173
|
+
? "medium"
|
|
174
|
+
: "big";
|
|
175
|
+
for (const [name, expression] of Object.entries(document.expressions)) {
|
|
176
|
+
for (const [channel, value] of Object.entries(expression.variants ?? {}))
|
|
177
|
+
variant(channel, value);
|
|
178
|
+
for (const [channel, choices] of Object.entries(expression.variantChoices ?? {}))
|
|
179
|
+
for (const value of choices)
|
|
180
|
+
variant(channel, value);
|
|
181
|
+
if (expression.blush !== undefined)
|
|
182
|
+
variant("blush", blush(expression.blush));
|
|
183
|
+
if (expression.motion)
|
|
184
|
+
motionTarget(expression.motion.target);
|
|
185
|
+
if (!name.trim())
|
|
186
|
+
issue("Sprite expression name cannot be empty");
|
|
187
|
+
}
|
|
188
|
+
for (const [name, activity] of Object.entries(document.activities)) {
|
|
189
|
+
if (activity.motion)
|
|
190
|
+
motionTarget(activity.motion.target);
|
|
191
|
+
const geometry = activity.geometry;
|
|
192
|
+
if (geometry?.expression &&
|
|
193
|
+
!Object.hasOwn(document.expressions, geometry.expression))
|
|
194
|
+
issue(`Unknown Sprite activity.${name}.geometry.expression: ${geometry.expression}`);
|
|
195
|
+
if (geometry?.eyes)
|
|
196
|
+
variant("eyes", geometry.eyes);
|
|
197
|
+
if (geometry?.mouth)
|
|
198
|
+
variant("mouth", geometry.mouth);
|
|
199
|
+
if (geometry?.blush !== undefined)
|
|
200
|
+
variant("blush", blush(geometry.blush));
|
|
201
|
+
if (!name.trim())
|
|
202
|
+
issue("Sprite activity name cannot be empty");
|
|
203
|
+
}
|
|
204
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { default } from "./renderer.js";
|
|
2
|
+
/** Lazy loaders for the bundled local characters; no remote asset access. */
|
|
3
|
+
export declare const builtinCharacters: Readonly<{
|
|
4
|
+
/** Load the bundled mushroom document and renderer. */
|
|
5
|
+
mushroom: () => Promise<import("@fungi.computer/sprite").LocalCharacter>;
|
|
6
|
+
/** Load the bundled cat document and renderer. */
|
|
7
|
+
cat: () => Promise<import("@fungi.computer/sprite").LocalCharacter>;
|
|
8
|
+
/** Load the bundled burger document and renderer. */
|
|
9
|
+
burger: () => Promise<import("@fungi.computer/sprite").LocalCharacter>;
|
|
10
|
+
}>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { default } from "./renderer.js";
|
|
2
|
+
/** Lazy loaders for the bundled local characters; no remote asset access. */
|
|
3
|
+
export const builtinCharacters = Object.freeze({
|
|
4
|
+
/** Load the bundled mushroom document and renderer. */
|
|
5
|
+
mushroom: () => import("./mushroom.js").then(({ default: character }) => character),
|
|
6
|
+
/** Load the bundled cat document and renderer. */
|
|
7
|
+
cat: () => import("./cat.js").then(({ default: character }) => character),
|
|
8
|
+
/** Load the bundled burger document and renderer. */
|
|
9
|
+
burger: () => import("./burger.js").then(({ default: character }) => character),
|
|
10
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ActivitySpec, ExpressionSpec, PathStep, SceneNode, SceneNodeOptions, SpriteDefinition } from "./author.js";
|
|
2
|
+
export { COLOR_PREFIX } from "./palette.js";
|
|
3
|
+
export type InternalNodeKind = "group" | "shape" | "ellipse" | "hemisphere" | "cylinder";
|
|
4
|
+
export type InternalTransform = {
|
|
5
|
+
readonly x?: number | undefined;
|
|
6
|
+
readonly y?: number | undefined;
|
|
7
|
+
readonly z?: number | undefined;
|
|
8
|
+
};
|
|
9
|
+
export type InternalSceneOptions = Omit<SceneNodeOptions, "translate"> & {
|
|
10
|
+
readonly translate?: InternalTransform | undefined;
|
|
11
|
+
readonly path?: readonly PathStep[] | undefined;
|
|
12
|
+
readonly closed?: boolean | undefined;
|
|
13
|
+
readonly width?: number | undefined;
|
|
14
|
+
readonly height?: number | undefined;
|
|
15
|
+
readonly diameter?: number | undefined;
|
|
16
|
+
readonly length?: number | undefined;
|
|
17
|
+
};
|
|
18
|
+
export type InternalSceneNode = {
|
|
19
|
+
readonly owner: symbol;
|
|
20
|
+
readonly kind: InternalNodeKind;
|
|
21
|
+
readonly name: string | undefined;
|
|
22
|
+
readonly parent: InternalSceneNode | undefined;
|
|
23
|
+
readonly children: InternalSceneNode[];
|
|
24
|
+
readonly options: InternalSceneOptions;
|
|
25
|
+
};
|
|
26
|
+
export type InternalDefinition = {
|
|
27
|
+
readonly owner: symbol;
|
|
28
|
+
readonly root: InternalSceneNode;
|
|
29
|
+
readonly nodesByName: ReadonlyMap<string, InternalSceneNode>;
|
|
30
|
+
readonly variants: ReadonlyMap<string, ReadonlyMap<string, InternalSceneNode>>;
|
|
31
|
+
readonly variantNodes: ReadonlySet<InternalSceneNode>;
|
|
32
|
+
readonly palette: Record<string, string>;
|
|
33
|
+
readonly activities: Record<string, ActivitySpec>;
|
|
34
|
+
readonly expressions: Record<string, ExpressionSpec>;
|
|
35
|
+
readonly defaultActivity: string;
|
|
36
|
+
readonly defaultExpression: string;
|
|
37
|
+
};
|
|
38
|
+
export declare const registerInternalNode: (publicNode: SceneNode, internalNode: InternalSceneNode) => void;
|
|
39
|
+
export declare const setDefinitionInternals: (definition: SpriteDefinition, internals: InternalDefinition) => void;
|
|
40
|
+
export declare const getDefinitionInternals: (definition: SpriteDefinition) => InternalDefinition;
|
|
41
|
+
export declare const asInternalNode: (node: SceneNode) => InternalSceneNode;
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { COLOR_PREFIX } from "./palette.js";
|
|
2
|
+
const definitions = new WeakMap();
|
|
3
|
+
const publicNodes = new WeakMap();
|
|
4
|
+
export const registerInternalNode = (publicNode, internalNode) => {
|
|
5
|
+
publicNodes.set(publicNode, internalNode);
|
|
6
|
+
};
|
|
7
|
+
export const setDefinitionInternals = (definition, internals) => {
|
|
8
|
+
definitions.set(definition, internals);
|
|
9
|
+
};
|
|
10
|
+
export const getDefinitionInternals = (definition) => {
|
|
11
|
+
const internals = definitions.get(definition);
|
|
12
|
+
if (!internals)
|
|
13
|
+
throw new Error("Invalid Sprite definition");
|
|
14
|
+
return internals;
|
|
15
|
+
};
|
|
16
|
+
export const asInternalNode = (node) => {
|
|
17
|
+
const internal = publicNodes.get(node);
|
|
18
|
+
if (internal === undefined)
|
|
19
|
+
throw new Error("Invalid Sprite scene node");
|
|
20
|
+
return internal;
|
|
21
|
+
};
|