@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
@@ -0,0 +1,4 @@
1
+ import { type LocalCharacter } from "@fungi.computer/sprite";
2
+ /** The retained mushroom as one portable character plus its native renderer. */
3
+ declare const mushroomCharacter: LocalCharacter;
4
+ export default mushroomCharacter;
@@ -0,0 +1,9 @@
1
+ import { characterSchema } from "@fungi.computer/sprite";
2
+ import document from "./mushroom.character.json" with { type: "json" };
3
+ import renderZdog from "./renderer.js";
4
+ /** The retained mushroom as one portable character plus its native renderer. */
5
+ const mushroomCharacter = {
6
+ document: characterSchema.parse(document),
7
+ render: renderZdog,
8
+ };
9
+ export default mushroomCharacter;
@@ -0,0 +1,3 @@
1
+ /** Author palette references remain plain strings in portable Zdog scene data. */
2
+ export declare const COLOR_PREFIX = "\0sprite-color:";
3
+ export declare const colorKeyFromValue: (value: string | undefined) => string | undefined;
@@ -0,0 +1,5 @@
1
+ /** Author palette references remain plain strings in portable Zdog scene data. */
2
+ export const COLOR_PREFIX = "\u0000sprite-color:";
3
+ export const colorKeyFromValue = (value) => value?.startsWith(COLOR_PREFIX)
4
+ ? value.slice(COLOR_PREFIX.length)
5
+ : undefined;
@@ -0,0 +1,4 @@
1
+ import { type CharacterDocument } from "@fungi.computer/sprite";
2
+ import type { SpriteDefinition } from "./author.js";
3
+ /** Compile trusted scene-authoring code into a document that contains no code. */
4
+ export declare function toCharacter(definition: SpriteDefinition): CharacterDocument;
@@ -0,0 +1,61 @@
1
+ import { characterSchema, } from "@fungi.computer/sprite";
2
+ import { getDefinitionInternals } from "./internal.js";
3
+ import { zdogDocumentSchema, zdogNodeSchema, } from "./document.js";
4
+ /** Compile trusted scene-authoring code into a document that contains no code. */
5
+ export function toCharacter(definition) {
6
+ const internals = getDefinitionInternals(definition);
7
+ const ids = new Map();
8
+ const nodes = [];
9
+ const visit = (node, parent) => {
10
+ const id = `node-${String(ids.size)}`;
11
+ ids.set(node, id);
12
+ const candidate = parent === undefined
13
+ ? { id, kind: node.kind, options: node.options }
14
+ : { id, parent, kind: node.kind, options: node.options };
15
+ nodes.push(zdogNodeSchema.parse(candidate));
16
+ for (const child of node.children)
17
+ visit(child, id);
18
+ };
19
+ visit(internals.root);
20
+ const variants = Object.fromEntries([...internals.variants].map(([channel, values]) => [
21
+ channel,
22
+ Object.fromEntries([...values].map(([name, node]) => {
23
+ const id = ids.get(node);
24
+ if (!id)
25
+ throw new Error("Cannot export a variant outside the scene root");
26
+ return [name, id];
27
+ })),
28
+ ]));
29
+ const data = zdogDocumentSchema.parse({
30
+ root: ids.get(internals.root),
31
+ nodes,
32
+ variants,
33
+ palette: internals.palette,
34
+ expressions: internals.expressions,
35
+ activities: internals.activities,
36
+ defaultPresentation: {
37
+ activity: internals.defaultActivity,
38
+ expression: internals.defaultExpression,
39
+ },
40
+ });
41
+ return characterSchema.parse(JSON.parse(JSON.stringify({
42
+ version: 1,
43
+ name: definition.name,
44
+ renderer: "zdog",
45
+ controls: Object.fromEntries(Object.entries(internals.palette).map(([name, value]) => [
46
+ name,
47
+ {
48
+ type: "color",
49
+ label: name,
50
+ default: value.length === 4
51
+ ? `#${value
52
+ .slice(1)
53
+ .split("")
54
+ .map((digit) => digit + digit)
55
+ .join("")}`
56
+ : value,
57
+ },
58
+ ])),
59
+ data,
60
+ })));
61
+ }
@@ -0,0 +1,4 @@
1
+ import type { Renderer } from "@fungi.computer/sprite";
2
+ /** Optional native Zdog adapter. Scene data is decoded before creating the canvas. */
3
+ declare const renderZdog: Renderer;
4
+ export default renderZdog;
@@ -0,0 +1,106 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as z from "zod";
3
+ import { zdogDocumentSchema } from "./document.js";
4
+ import { createZdogRenderer } from "./zdog-runtime.js";
5
+ /** Optional native Zdog adapter. Scene data is decoded before creating the canvas. */
6
+ const renderZdog = (context) => Effect.gen(function* () {
7
+ const scene = zdogDocumentSchema.parse(context.document.data);
8
+ const canvas = yield* Effect.acquireRelease(Effect.sync(() => context.target.ownerDocument.createElement("canvas")), (canvas) => Effect.sync(() => {
9
+ canvas.remove();
10
+ }));
11
+ canvas.style.cssText = "width:100%;height:100%;display:block";
12
+ context.target.replaceChildren(canvas);
13
+ const view = context.target.ownerDocument.defaultView;
14
+ if (!view)
15
+ throw new Error("Zdog avatar requires a browser window");
16
+ let frame;
17
+ let paused = true;
18
+ let destroyed = false;
19
+ const schedule = () => {
20
+ if (paused || destroyed || frame !== undefined)
21
+ return;
22
+ frame = view.requestAnimationFrame((time) => {
23
+ frame = undefined;
24
+ if (native.tick(time))
25
+ schedule();
26
+ });
27
+ };
28
+ // A paused player (reduced motion, hidden page, host pause) runs no frame
29
+ // loop, so every change it must show, including the canvas clear that a
30
+ // resize causes, is drawn at once as one still frame.
31
+ const invalidate = () => {
32
+ if (destroyed)
33
+ return;
34
+ if (paused)
35
+ native.renderStill();
36
+ else
37
+ schedule();
38
+ };
39
+ const native = yield* Effect.acquireRelease(Effect.sync(() => createZdogRenderer({
40
+ target: canvas,
41
+ scene,
42
+ onInvalidate: invalidate,
43
+ maxPixels: context.maxPixels,
44
+ })), (native) => Effect.sync(() => {
45
+ native.destroy();
46
+ }));
47
+ yield* Effect.addFinalizer(() => Effect.sync(() => {
48
+ destroyed = true;
49
+ if (frame !== undefined)
50
+ view.cancelAnimationFrame(frame);
51
+ }));
52
+ native.pause(true);
53
+ let presentationKey;
54
+ let paletteKey;
55
+ return {
56
+ activities: [
57
+ "idle",
58
+ "listening",
59
+ "processing",
60
+ "speaking",
61
+ "thinking",
62
+ "error",
63
+ ...Object.keys(scene.activities),
64
+ ],
65
+ expressions: [
66
+ scene.defaultPresentation.expression,
67
+ ...Object.keys(scene.expressions),
68
+ ].filter((value, index, values) => values.indexOf(value) === index),
69
+ set(presentation) {
70
+ const palette = {};
71
+ for (const [key, value] of Object.entries(presentation.appearance)) {
72
+ const color = z.string().safeParse(value);
73
+ if (!color.success)
74
+ throw new Error(`Zdog palette value must be a color: ${key}`);
75
+ palette[key] = color.data;
76
+ }
77
+ const nextPalette = JSON.stringify(palette);
78
+ if (nextPalette !== paletteKey) {
79
+ native.setPalette(palette);
80
+ paletteKey = nextPalette;
81
+ }
82
+ const expression = presentation.expression ?? scene.defaultPresentation.expression;
83
+ if (!expression)
84
+ throw new Error("Zdog avatar needs an expression");
85
+ const nextPresentation = JSON.stringify([
86
+ presentation.activity,
87
+ expression,
88
+ ]);
89
+ if (nextPresentation !== presentationKey) {
90
+ native.present({ activity: presentation.activity, expression });
91
+ presentationKey = nextPresentation;
92
+ }
93
+ invalidate();
94
+ },
95
+ pause(value) {
96
+ paused = value;
97
+ native.pause(value);
98
+ if (paused && frame !== undefined) {
99
+ view.cancelAnimationFrame(frame);
100
+ frame = undefined;
101
+ }
102
+ invalidate();
103
+ },
104
+ };
105
+ });
106
+ export default renderZdog;
@@ -0,0 +1,21 @@
1
+ import type { ZdogDocument } from "./document.js";
2
+ export type SpriteRenderer = {
3
+ present(presentation: {
4
+ readonly activity: string;
5
+ readonly expression: string;
6
+ }): void;
7
+ setPalette(palette: Readonly<Record<string, string>>): void;
8
+ pause(paused: boolean): void;
9
+ tick(timestamp: number): boolean;
10
+ /** Draw pending changes now, unthrottled, as a paused player's still frame. */
11
+ renderStill(): void;
12
+ resize(): void;
13
+ destroy(): void;
14
+ };
15
+ export declare const createZdogRenderer: (options: {
16
+ readonly target: HTMLCanvasElement;
17
+ readonly scene: ZdogDocument;
18
+ readonly onInvalidate: () => void;
19
+ readonly maxPixels: number;
20
+ readonly palette?: Partial<Record<string, string>>;
21
+ }) => SpriteRenderer;