@chatlychat/world 0.0.0-stage → 0.2.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +184 -2
  4. package/dist/agent.d.ts +63 -0
  5. package/dist/agent.d.ts.map +1 -0
  6. package/dist/agent.js +251 -0
  7. package/dist/agent.js.map +1 -0
  8. package/dist/bubble.d.ts +36 -0
  9. package/dist/bubble.d.ts.map +1 -0
  10. package/dist/bubble.js +108 -0
  11. package/dist/bubble.js.map +1 -0
  12. package/dist/capabilities.d.ts +77 -0
  13. package/dist/capabilities.d.ts.map +1 -0
  14. package/dist/capabilities.js +129 -0
  15. package/dist/capabilities.js.map +1 -0
  16. package/dist/cards.d.ts +51 -0
  17. package/dist/cards.d.ts.map +1 -0
  18. package/dist/cards.js +136 -0
  19. package/dist/cards.js.map +1 -0
  20. package/dist/composer.d.ts +25 -0
  21. package/dist/composer.d.ts.map +1 -0
  22. package/dist/composer.js +53 -0
  23. package/dist/composer.js.map +1 -0
  24. package/dist/handlers.d.ts +26 -0
  25. package/dist/handlers.d.ts.map +1 -0
  26. package/dist/handlers.js +41 -0
  27. package/dist/handlers.js.map +1 -0
  28. package/dist/index.d.ts +27 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +25 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/input.d.ts +46 -0
  33. package/dist/input.d.ts.map +1 -0
  34. package/dist/input.js +89 -0
  35. package/dist/input.js.map +1 -0
  36. package/dist/layout.d.ts +24 -0
  37. package/dist/layout.d.ts.map +1 -0
  38. package/dist/layout.js +69 -0
  39. package/dist/layout.js.map +1 -0
  40. package/dist/model.d.ts +57 -0
  41. package/dist/model.d.ts.map +1 -0
  42. package/dist/model.js +86 -0
  43. package/dist/model.js.map +1 -0
  44. package/dist/motion.d.ts +27 -0
  45. package/dist/motion.d.ts.map +1 -0
  46. package/dist/motion.js +65 -0
  47. package/dist/motion.js.map +1 -0
  48. package/dist/panel.d.ts +77 -0
  49. package/dist/panel.d.ts.map +1 -0
  50. package/dist/panel.js +214 -0
  51. package/dist/panel.js.map +1 -0
  52. package/dist/picks.d.ts +45 -0
  53. package/dist/picks.d.ts.map +1 -0
  54. package/dist/picks.js +186 -0
  55. package/dist/picks.js.map +1 -0
  56. package/dist/selection.d.ts +14 -0
  57. package/dist/selection.d.ts.map +1 -0
  58. package/dist/selection.js +21 -0
  59. package/dist/selection.js.map +1 -0
  60. package/dist/text.d.ts +26 -0
  61. package/dist/text.d.ts.map +1 -0
  62. package/dist/text.js +100 -0
  63. package/dist/text.js.map +1 -0
  64. package/dist/theme-apply.d.ts +19 -0
  65. package/dist/theme-apply.d.ts.map +1 -0
  66. package/dist/theme-apply.js +88 -0
  67. package/dist/theme-apply.js.map +1 -0
  68. package/dist/types.d.ts +108 -0
  69. package/dist/types.d.ts.map +1 -0
  70. package/dist/types.js +41 -0
  71. package/dist/types.js.map +1 -0
  72. package/dist/visemes.d.ts +28 -0
  73. package/dist/visemes.d.ts.map +1 -0
  74. package/dist/visemes.js +42 -0
  75. package/dist/visemes.js.map +1 -0
  76. package/dist/vrm.d.ts +97 -0
  77. package/dist/vrm.d.ts.map +1 -0
  78. package/dist/vrm.js +212 -0
  79. package/dist/vrm.js.map +1 -0
  80. package/dist/world-api.d.ts +39 -0
  81. package/dist/world-api.d.ts.map +1 -0
  82. package/dist/world-api.js +2 -0
  83. package/dist/world-api.js.map +1 -0
  84. package/dist/world.d.ts +5 -0
  85. package/dist/world.d.ts.map +1 -0
  86. package/dist/world.js +414 -0
  87. package/dist/world.js.map +1 -0
  88. package/package.json +75 -3
@@ -0,0 +1,21 @@
1
+ export class Selection {
2
+ current = null;
3
+ listeners = new Set();
4
+ get id() {
5
+ return this.current;
6
+ }
7
+ set(id) {
8
+ if (id === this.current) {
9
+ return;
10
+ }
11
+ this.current = id;
12
+ for (const l of [...this.listeners]) {
13
+ l(id);
14
+ }
15
+ }
16
+ subscribe = (l) => {
17
+ this.listeners.add(l);
18
+ return () => this.listeners.delete(l);
19
+ };
20
+ }
21
+ //# sourceMappingURL=selection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.js","sourceRoot":"","sources":["../src/selection.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,SAAS;IACZ,OAAO,GAAkB,IAAI,CAAC;IACrB,SAAS,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE1D,IAAW,EAAE;QACX,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAEM,GAAG,CAAC,EAAiB;QAC1B,IAAI,EAAE,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACpC,CAAC,CAAC,EAAE,CAAC,CAAC;QACR,CAAC;IACH,CAAC;IAEM,SAAS,GAAG,CAAC,CAAoB,EAAgB,EAAE;QACxD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACtB,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC;CACH"}
package/dist/text.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Text on a plane, styled by the resolved `worldTheme`.
3
+ *
4
+ * Text is drawn to a canvas texture when a canvas exists. Without one (a
5
+ * Node test, a worker) the mesh is still built — same geometry, same
6
+ * material, `userData.text` set — just with no map, which is what lets the
7
+ * scene-graph specs run with no GL and no DOM.
8
+ *
9
+ * Layout is measured by a fixed advance (half an em per character) rather
10
+ * than by the canvas, so a plane's size is the same in a browser and in a
11
+ * test, and wrapping never depends on which font happened to load.
12
+ */
13
+ import { Mesh } from 'three';
14
+ import type { ResolvedWorldTheme } from '@chatlychat/core';
15
+ /** Metres of cap-height-ish type at textScale 1: legible at arm's length. */
16
+ export declare const BASE_FONT_METRES = 0.035;
17
+ export interface TextOptions {
18
+ readonly maxWidthMetres: number;
19
+ /** Multiplier on `BASE_FONT_METRES`, on top of the theme's `textScale`. */
20
+ readonly size?: number;
21
+ readonly color?: string;
22
+ }
23
+ export declare function wrapText(text: string, maxChars: number): string[];
24
+ export declare function ensureFont(url: string | null): void;
25
+ export declare function createTextMesh(text: string, theme: ResolvedWorldTheme, opts: TextOptions): Mesh;
26
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAiB,IAAI,EAAuD,MAAM,OAAO,CAAC;AAEjG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAMtC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBjE;AAID,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAmBnD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAmD/F"}
package/dist/text.js ADDED
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Text on a plane, styled by the resolved `worldTheme`.
3
+ *
4
+ * Text is drawn to a canvas texture when a canvas exists. Without one (a
5
+ * Node test, a worker) the mesh is still built — same geometry, same
6
+ * material, `userData.text` set — just with no map, which is what lets the
7
+ * scene-graph specs run with no GL and no DOM.
8
+ *
9
+ * Layout is measured by a fixed advance (half an em per character) rather
10
+ * than by the canvas, so a plane's size is the same in a browser and in a
11
+ * test, and wrapping never depends on which font happened to load.
12
+ */
13
+ import { CanvasTexture, Mesh, MeshStandardMaterial, PlaneGeometry, SRGBColorSpace } from 'three';
14
+ /** Metres of cap-height-ish type at textScale 1: legible at arm's length. */
15
+ export const BASE_FONT_METRES = 0.035;
16
+ const ADVANCE = 0.5;
17
+ const LINE_HEIGHT = 1.3;
18
+ const MAX_CANVAS_PX = 2048;
19
+ const FONT_FAMILY = 'cl3-font, system-ui, sans-serif';
20
+ export function wrapText(text, maxChars) {
21
+ const lines = [];
22
+ for (const para of text.split('\n')) {
23
+ let line = '';
24
+ for (const word of para.split(/\s+/).filter(Boolean)) {
25
+ const w = word.length > maxChars ? word.slice(0, maxChars - 1) + '…' : word;
26
+ if (line !== '' && line.length + 1 + w.length > maxChars) {
27
+ lines.push(line);
28
+ line = w;
29
+ }
30
+ else {
31
+ line = line === '' ? w : `${line} ${w}`;
32
+ }
33
+ }
34
+ lines.push(line);
35
+ }
36
+ return lines;
37
+ }
38
+ /** Load the theme's font once; text drawn before it arrives uses the fallback. */
39
+ const loadedFonts = new Set();
40
+ export function ensureFont(url) {
41
+ const g = globalThis;
42
+ if (url === null ||
43
+ loadedFonts.has(url) ||
44
+ g.FontFace === undefined ||
45
+ g.document?.fonts === undefined) {
46
+ return;
47
+ }
48
+ loadedFonts.add(url);
49
+ const face = new g.FontFace('cl3-font', `url(${JSON.stringify(url)})`);
50
+ face.load().then(() => g.document?.fonts?.add(face), () => loadedFonts.delete(url));
51
+ }
52
+ export function createTextMesh(text, theme, opts) {
53
+ const font = BASE_FONT_METRES * theme.textScale * (opts.size ?? 1);
54
+ const maxChars = Math.max(4, Math.floor(opts.maxWidthMetres / (font * ADVANCE)));
55
+ const lines = wrapText(text, maxChars);
56
+ const longest = Math.max(1, ...lines.map((l) => l.length));
57
+ const width = Math.min(opts.maxWidthMetres, longest * font * ADVANCE + font);
58
+ const height = lines.length * font * LINE_HEIGHT + font * 0.4;
59
+ const color = opts.color ?? theme.textColor;
60
+ const material = new MeshStandardMaterial({
61
+ color: '#ffffff',
62
+ emissive: '#ffffff',
63
+ emissiveIntensity: theme.textEmissive,
64
+ transparent: true,
65
+ roughness: 1,
66
+ metalness: 0,
67
+ });
68
+ const mesh = new Mesh(new PlaneGeometry(width, height), material);
69
+ mesh.userData['text'] = text;
70
+ mesh.userData['lines'] = lines;
71
+ mesh.userData['size'] = [width, height];
72
+ const canvas = globalThis.document?.createElement('canvas');
73
+ const ctx = canvas?.getContext('2d') ?? null;
74
+ if (canvas !== undefined && ctx !== null) {
75
+ const pxPerMetre = Math.min(1200, MAX_CANVAS_PX / width);
76
+ canvas.width = Math.ceil(width * pxPerMetre);
77
+ canvas.height = Math.ceil(height * pxPerMetre);
78
+ const fontPx = font * pxPerMetre;
79
+ ctx.font = `${String(theme.fontWeight)} ${String(fontPx)}px ${FONT_FAMILY}`;
80
+ ctx.textBaseline = 'top';
81
+ ctx.lineJoin = 'round';
82
+ lines.forEach((l, i) => {
83
+ const y = fontPx * 0.2 + i * fontPx * LINE_HEIGHT;
84
+ if (theme.textOutlineWidth > 0) {
85
+ ctx.strokeStyle = theme.textOutlineColor;
86
+ ctx.lineWidth = theme.textOutlineWidth * pxPerMetre * 2;
87
+ ctx.strokeText(l, fontPx / 2, y);
88
+ }
89
+ ctx.fillStyle = color;
90
+ ctx.fillText(l, fontPx / 2, y);
91
+ });
92
+ const map = new CanvasTexture(canvas);
93
+ map.colorSpace = SRGBColorSpace;
94
+ material.map = map;
95
+ material.emissiveMap = map;
96
+ material.needsUpdate = true;
97
+ }
98
+ return mesh;
99
+ }
100
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `worldTheme` tokens -> three.js materials and shapes. Every token a
3
+ * renderer needs comes through here, so a default renderer and a host's own
4
+ * override read the same look from one place.
5
+ */
6
+ import { Mesh, MeshBasicMaterial, MeshPhysicalMaterial, MeshStandardMaterial, ShapeGeometry } from 'three';
7
+ import type { ResolvedWorldTheme } from '@chatlychat/core';
8
+ type Surface = MeshStandardMaterial | MeshPhysicalMaterial;
9
+ /** The panel's fill, or null for `panelMaterial: 'none'` (text floats on nothing). */
10
+ export declare function panelSurface(theme: ResolvedWorldTheme, color?: string): Surface | null;
11
+ /** A rounded rectangle centred on the origin, in the xy plane. */
12
+ export declare function roundedRect(width: number, height: number, radius: number): ShapeGeometry;
13
+ /** The panel's backing plate, or null when the material is `none`. */
14
+ export declare function panelBacking(theme: ResolvedWorldTheme, width: number, height: number): Mesh | null;
15
+ /** A speech bubble's plate: `none` has no plate, `square` has no radius, `cloud` is extra round. */
16
+ export declare function bubbleBacking(theme: ResolvedWorldTheme, width: number, height: number): Mesh | null;
17
+ export declare function accentMaterial(theme: ResolvedWorldTheme, opacity?: number): MeshBasicMaterial;
18
+ export {};
19
+ //# sourceMappingURL=theme-apply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-apply.d.ts","sourceRoot":"","sources":["../src/theme-apply.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAEL,IAAI,EACJ,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EAGpB,aAAa,EACd,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,KAAK,OAAO,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAE3D,sFAAsF;AACtF,wBAAgB,YAAY,CAC1B,KAAK,EAAE,kBAAkB,EACzB,KAAK,GAAE,MAAyB,GAC/B,OAAO,GAAG,IAAI,CAyBhB;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAexF;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAC1B,KAAK,EAAE,kBAAkB,EACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,IAAI,GAAG,IAAI,CAQb;AAED,oGAAoG;AACpG,wBAAgB,aAAa,CAC3B,KAAK,EAAE,kBAAkB,EACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,IAAI,GAAG,IAAI,CAsBb;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,SAAI,GAAG,iBAAiB,CAOxF"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * `worldTheme` tokens -> three.js materials and shapes. Every token a
3
+ * renderer needs comes through here, so a default renderer and a host's own
4
+ * override read the same look from one place.
5
+ */
6
+ import { DoubleSide, Mesh, MeshBasicMaterial, MeshPhysicalMaterial, MeshStandardMaterial, PlaneGeometry, Shape, ShapeGeometry, } from 'three';
7
+ /** The panel's fill, or null for `panelMaterial: 'none'` (text floats on nothing). */
8
+ export function panelSurface(theme, color = theme.panelColor) {
9
+ if (theme.panelMaterial === 'none') {
10
+ return null;
11
+ }
12
+ const common = {
13
+ color,
14
+ emissive: color,
15
+ emissiveIntensity: theme.panelEmissive,
16
+ side: DoubleSide,
17
+ };
18
+ if (theme.panelMaterial === 'glass') {
19
+ return new MeshPhysicalMaterial({
20
+ ...common,
21
+ transparent: true,
22
+ opacity: theme.panelOpacity,
23
+ transmission: 0.6,
24
+ roughness: 0.15,
25
+ });
26
+ }
27
+ return new MeshStandardMaterial({
28
+ ...common,
29
+ transparent: theme.panelMaterial !== 'solid' && theme.panelOpacity < 1,
30
+ opacity: theme.panelMaterial === 'solid' ? 1 : theme.panelOpacity,
31
+ roughness: theme.panelMaterial === 'matte' ? 1 : 0.4,
32
+ });
33
+ }
34
+ /** A rounded rectangle centred on the origin, in the xy plane. */
35
+ export function roundedRect(width, height, radius) {
36
+ const r = Math.min(radius, width / 2, height / 2);
37
+ const x = -width / 2;
38
+ const y = -height / 2;
39
+ const s = new Shape();
40
+ s.moveTo(x + r, y);
41
+ s.lineTo(x + width - r, y);
42
+ s.quadraticCurveTo(x + width, y, x + width, y + r);
43
+ s.lineTo(x + width, y + height - r);
44
+ s.quadraticCurveTo(x + width, y + height, x + width - r, y + height);
45
+ s.lineTo(x + r, y + height);
46
+ s.quadraticCurveTo(x, y + height, x, y + height - r);
47
+ s.lineTo(x, y + r);
48
+ s.quadraticCurveTo(x, y, x + r, y);
49
+ return new ShapeGeometry(s);
50
+ }
51
+ /** The panel's backing plate, or null when the material is `none`. */
52
+ export function panelBacking(theme, width, height) {
53
+ const mat = panelSurface(theme);
54
+ if (mat === null) {
55
+ return null;
56
+ }
57
+ const mesh = new Mesh(roundedRect(width, height, theme.panelRadiusMetres), mat);
58
+ mesh.name = 'cl3-panel-backing';
59
+ return mesh;
60
+ }
61
+ /** A speech bubble's plate: `none` has no plate, `square` has no radius, `cloud` is extra round. */
62
+ export function bubbleBacking(theme, width, height) {
63
+ const shape = theme.bubbleShape;
64
+ if (shape === 'none') {
65
+ return null;
66
+ }
67
+ const mat = new MeshStandardMaterial({
68
+ color: theme.bubbleColor,
69
+ emissive: theme.bubbleColor,
70
+ emissiveIntensity: theme.panelEmissive,
71
+ side: DoubleSide,
72
+ });
73
+ const geometry = shape === 'square'
74
+ ? new PlaneGeometry(width, height)
75
+ : roundedRect(width, height, shape === 'cloud' ? height / 2 : Math.max(theme.panelRadiusMetres, 0.03));
76
+ const mesh = new Mesh(geometry, mat);
77
+ mesh.userData['shape'] = shape;
78
+ return mesh;
79
+ }
80
+ export function accentMaterial(theme, opacity = 1) {
81
+ return new MeshBasicMaterial({
82
+ color: theme.accentColor,
83
+ transparent: opacity < 1,
84
+ opacity,
85
+ side: DoubleSide,
86
+ });
87
+ }
88
+ //# sourceMappingURL=theme-apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-apply.js","sourceRoot":"","sources":["../src/theme-apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * The public contract: options, anchors, errors, and the renderer contract's
3
+ * names and version.
4
+ */
5
+ import type { ModelLoader } from './model.js';
6
+ import type { VrmModuleLoader } from './vrm.js';
7
+ import type { AgentWorldPresence, Conversation, PresenceMap, WorldHostAbilities, WorldPlacementRequest, WorldRenderers, WorldTheme } from '@chatlychat/core';
8
+ import type { Camera, Object3D, Vector3 } from 'three';
9
+ /**
10
+ * The renderer contract, versioned like the widget's `cl-` class contract.
11
+ *
12
+ * `objects` are the `Object3D.name` every default renderer gives its output,
13
+ * and the world gives the same name to an override's output when the override
14
+ * left it blank, so `scene.getObjectByName('cl3-card')` finds the card
15
+ * whoever drew it. A name is part of the contract: renaming one is a major
16
+ * version, adding one is a minor. A host that pins `contract: 1` on its
17
+ * renderers is refused, loudly, by a world that no longer speaks it.
18
+ */
19
+ export declare const WORLD_CONTRACT: {
20
+ readonly version: 1;
21
+ readonly renderers: readonly ["renderCard", "renderPick", "renderBubble", "renderPanel", "renderComposer", "renderAgent"];
22
+ readonly objects: {
23
+ readonly root: "cl3-world";
24
+ readonly grid: "cl3-grid";
25
+ readonly card: "cl3-card";
26
+ readonly pick: "cl3-pick";
27
+ readonly bubble: "cl3-bubble";
28
+ readonly typing: "cl3-typing";
29
+ readonly panel: "cl3-panel";
30
+ readonly composer: "cl3-composer";
31
+ readonly agent: "cl3-agent";
32
+ };
33
+ };
34
+ export type WorldObjectName = (typeof WORLD_CONTRACT.objects)[keyof typeof WORLD_CONTRACT.objects];
35
+ export type WorldNodeRenderers = WorldRenderers<Object3D> & {
36
+ /** Pin the contract version these renderers were written against. */
37
+ readonly contract?: number;
38
+ };
39
+ export type WorldErrorCode = 'unsupported_contract' | 'disposed' | 'unknown_action' | 'unsupported_format' | 'missing_peer';
40
+ export declare class WorldError extends Error {
41
+ readonly code: WorldErrorCode;
42
+ constructor(code: WorldErrorCode, message: string);
43
+ }
44
+ /** The slice of a `Conversation` the world uses, so a test or a proxy can stand in. */
45
+ export type ConversationLike = Pick<Conversation, 'conversationId' | 'getSnapshot' | 'subscribe' | 'onCapability' | 'postback' | 'react' | 'send' | 'setTyping' | 'requestStep' | 'reportAction'>;
46
+ /**
47
+ * Where things are in the HOST's scene. Every member optional: an absent one
48
+ * means the world falls back to something sensible (a bubble with no speaker
49
+ * anchor hangs over the agent; a pick with no hand floats where it was taken).
50
+ */
51
+ export interface WorldAnchors {
52
+ /** The object a message's author stands for. `null` = the agent's body. */
53
+ readonly speaker?: (actorId: string | null) => Object3D | null;
54
+ /** The visitor's own avatar, for their bubbles. Without it they get none. */
55
+ readonly visitor?: Object3D | null;
56
+ /** A named place a `lookAt` or `scene.highlight` points at. */
57
+ readonly resolve?: (ref: string) => Object3D | Vector3 | null;
58
+ /** A controller grip or hand: the panel in `wrist` mode and a held pick attach here. */
59
+ readonly wrist?: Object3D | null;
60
+ readonly hand?: Object3D | null;
61
+ }
62
+ export type PanelFollow = 'fixed' | 'lazy' | 'wrist';
63
+ export type SoundKind = 'send' | 'receive' | 'pick' | 'select';
64
+ export interface SoundCue {
65
+ readonly kind: SoundKind;
66
+ readonly url: string;
67
+ readonly volume: number;
68
+ /** Play it from `position` (world space) rather than flat. */
69
+ readonly spatial: boolean;
70
+ readonly position: Vector3 | null;
71
+ }
72
+ export interface WorldOptions {
73
+ readonly conversation: ConversationLike;
74
+ /** The camera the visitor sees through (the XR camera in a headset). */
75
+ readonly camera: Camera;
76
+ /** The channel's `worldTheme` (`core.worldTheme`). */
77
+ readonly theme?: WorldTheme | null;
78
+ readonly themeLayers?: readonly WorldTheme[];
79
+ /** What the scene's light is; consulted when the theme's scheme is `auto`. */
80
+ readonly scene?: 'light' | 'dark';
81
+ /** The viewer's setting. A function is re-read every `update`. */
82
+ readonly reducedMotion?: boolean | (() => boolean);
83
+ readonly presences?: PresenceMap;
84
+ readonly placement?: WorldPlacementRequest;
85
+ readonly abilities?: WorldHostAbilities;
86
+ readonly follow?: PanelFollow;
87
+ readonly anchors?: WorldAnchors;
88
+ readonly renderers?: WorldNodeRenderers;
89
+ readonly loadModel?: ModelLoader;
90
+ /**
91
+ * Only for VRM avatars, and only if you bundle: `() => import('@pixiv/three-vrm')`.
92
+ * `@pixiv/three-vrm` is an optional peer dependency; a glTF-only host never needs it.
93
+ */
94
+ readonly loadVrm?: VrmModuleLoader;
95
+ readonly onSound?: (cue: SoundCue) => void;
96
+ /** Polite live-region text: the agent's state, new messages, an action's equivalent. */
97
+ readonly announce?: (text: string) => void;
98
+ /** The visitor pressed the composer's field: open your keyboard, mic or DOM input. */
99
+ readonly onComposeRequest?: () => void;
100
+ /** A `host_event` card action no registered capability claimed. */
101
+ readonly onHostEvent?: (event: string, data: Readonly<Record<string, unknown>>) => void;
102
+ /** A `url` card action. The world never navigates. */
103
+ readonly onOpenUrl?: (href: string) => void;
104
+ readonly onError?: (error: unknown) => void;
105
+ readonly now?: () => number;
106
+ }
107
+ export type { AgentWorldPresence };
108
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The renderer contract, versioned like the widget's `cl-` class contract.
3
+ *
4
+ * `objects` are the `Object3D.name` every default renderer gives its output,
5
+ * and the world gives the same name to an override's output when the override
6
+ * left it blank, so `scene.getObjectByName('cl3-card')` finds the card
7
+ * whoever drew it. A name is part of the contract: renaming one is a major
8
+ * version, adding one is a minor. A host that pins `contract: 1` on its
9
+ * renderers is refused, loudly, by a world that no longer speaks it.
10
+ */
11
+ export const WORLD_CONTRACT = {
12
+ version: 1,
13
+ renderers: [
14
+ 'renderCard',
15
+ 'renderPick',
16
+ 'renderBubble',
17
+ 'renderPanel',
18
+ 'renderComposer',
19
+ 'renderAgent',
20
+ ],
21
+ objects: {
22
+ root: 'cl3-world',
23
+ grid: 'cl3-grid',
24
+ card: 'cl3-card',
25
+ pick: 'cl3-pick',
26
+ bubble: 'cl3-bubble',
27
+ typing: 'cl3-typing',
28
+ panel: 'cl3-panel',
29
+ composer: 'cl3-composer',
30
+ agent: 'cl3-agent',
31
+ },
32
+ };
33
+ export class WorldError extends Error {
34
+ code;
35
+ constructor(code, message) {
36
+ super(message);
37
+ this.name = 'WorldError';
38
+ this.code = code;
39
+ }
40
+ }
41
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,CAAC;IACV,SAAS,EAAE;QACT,YAAY;QACZ,YAAY;QACZ,cAAc;QACd,aAAa;QACb,gBAAgB;QAChB,aAAa;KACd;IACD,OAAO,EAAE;QACP,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE,YAAY;QACpB,KAAK,EAAE,WAAW;QAClB,QAAQ,EAAE,cAAc;QACxB,KAAK,EAAE,WAAW;KACnB;CACO,CAAC;AAgBX,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnB,IAAI,CAAiB;IAErC,YAAmB,IAAoB,EAAE,OAAe;QACtD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Viseme-driven mouth — optional input only.
3
+ *
4
+ * Voice is built in a parallel lane and its message fields are not final, so
5
+ * this reads ONE tolerant shape off `message.metadata.visemes`:
6
+ * `[{ t: <ms from the start of the utterance>, v: <viseme name>, w?: 0..1 }]`.
7
+ * Anything else — absent, malformed, unsorted garbage — is null, and a null
8
+ * track means the mouth is simply not driven. A mouth is ornament; the body of
9
+ * the message is the message.
10
+ */
11
+ import type { ConversationMessage } from '@chatlychat/core';
12
+ export interface Viseme {
13
+ readonly t: number;
14
+ readonly v: string;
15
+ readonly w: number;
16
+ }
17
+ export type VisemeTrack = readonly Viseme[];
18
+ export declare function readVisemes(message: ConversationMessage): VisemeTrack | null;
19
+ /** The viseme held at `tMs`, or null before the first and after the last has been held 250ms. */
20
+ export declare function visemeAt(track: VisemeTrack, tMs: number): Viseme | null;
21
+ /**
22
+ * Morph-target names to try for a viseme, in order. Covers the Oculus/ARKit
23
+ * `viseme_*` set and VRM's five vowels, because a VRM avatar is a glTF the
24
+ * loader can read and drive by morph target even though its bones are not
25
+ * ours to animate.
26
+ */
27
+ export declare function morphNamesFor(v: string): readonly string[];
28
+ //# sourceMappingURL=visemes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visemes.d.ts","sourceRoot":"","sources":["../src/visemes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,SAAS,MAAM,EAAE,CAAC;AAE5C,wBAAgB,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,WAAW,GAAG,IAAI,CAqB5E;AAED,iGAAiG;AACjG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUvE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE1D"}
@@ -0,0 +1,42 @@
1
+ export function readVisemes(message) {
2
+ const raw = message.metadata['visemes'];
3
+ if (!Array.isArray(raw)) {
4
+ return null;
5
+ }
6
+ const out = [];
7
+ for (const e of raw) {
8
+ const r = (typeof e === 'object' && e !== null ? e : {});
9
+ const { t, v, w } = r;
10
+ if (typeof t !== 'number' ||
11
+ !Number.isFinite(t) ||
12
+ t < 0 ||
13
+ typeof v !== 'string' ||
14
+ v === '') {
15
+ continue;
16
+ }
17
+ out.push({ t, v, w: typeof w === 'number' && w >= 0 && w <= 1 ? w : 1 });
18
+ }
19
+ return out.length === 0 ? null : out.sort((a, b) => a.t - b.t);
20
+ }
21
+ /** The viseme held at `tMs`, or null before the first and after the last has been held 250ms. */
22
+ export function visemeAt(track, tMs) {
23
+ let held = null;
24
+ for (const e of track) {
25
+ if (e.t > tMs) {
26
+ break;
27
+ }
28
+ held = e;
29
+ }
30
+ const last = track[track.length - 1];
31
+ return held === null || (held === last && tMs - held.t > 250) ? null : held;
32
+ }
33
+ /**
34
+ * Morph-target names to try for a viseme, in order. Covers the Oculus/ARKit
35
+ * `viseme_*` set and VRM's five vowels, because a VRM avatar is a glTF the
36
+ * loader can read and drive by morph target even though its bones are not
37
+ * ours to animate.
38
+ */
39
+ export function morphNamesFor(v) {
40
+ return [v, `viseme_${v}`, `Viseme_${v}`];
41
+ }
42
+ //# sourceMappingURL=visemes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visemes.js","sourceRoot":"","sources":["../src/visemes.ts"],"names":[],"mappings":"AAoBA,MAAM,UAAU,WAAW,CAAC,OAA4B;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,GAAgB,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAA4B,CAAC;QACpF,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QACtB,IACE,OAAO,CAAC,KAAK,QAAQ;YACrB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YACnB,CAAC,GAAG,CAAC;YACL,OAAO,CAAC,KAAK,QAAQ;YACrB,CAAC,KAAK,EAAE,EACR,CAAC;YACD,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,QAAQ,CAAC,KAAkB,EAAE,GAAW;IACtD,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC;YACd,MAAM;QACR,CAAC;QACD,IAAI,GAAG,CAAC,CAAC;IACX,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,OAAO,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC;AAC3C,CAAC"}
package/dist/vrm.d.ts ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * VRM avatars — the optional half of the agent's body.
3
+ *
4
+ * `@pixiv/three-vrm` is an OPTIONAL peer dependency. This file never imports
5
+ * it statically, and the dynamic import below names it through a computed
6
+ * specifier, so no bundler resolves it while building a glTF-only host: that
7
+ * host neither installs it nor ships a byte of it. A host that does use VRM
8
+ * installs it and, if it bundles, hands the import over as `loadVrm`:
9
+ * `loadVrm: () => import('@pixiv/three-vrm')`. That one line is what lets ITS
10
+ * bundler see the package.
11
+ *
12
+ * API used (three-vrm v3, https://pixiv.github.io/three-vrm/packages/three-vrm/docs/):
13
+ * `VRMLoaderPlugin` registered on a `GLTFLoader` leaves the `VRM` on
14
+ * `gltf.userData.vrm`; `vrm.expressionManager.setValue(name, 0..1)`;
15
+ * `vrm.lookAt.target`; `vrm.humanoid.getNormalizedBoneNode(bone)`;
16
+ * `vrm.update(deltaSeconds)`; `VRMUtils.rotateVRM0(vrm)`.
17
+ */
18
+ import { Vector3, type Camera, type Object3D } from 'three';
19
+ import type { AgentExpression } from '@chatlychat/core';
20
+ export declare const VRM_PEER = "@pixiv/three-vrm";
21
+ /** The slice of three-vrm's `VRM` the SDK touches, so a spec can stand in. */
22
+ export interface VrmLike {
23
+ readonly scene: Object3D;
24
+ readonly expressionManager?: {
25
+ setValue(name: string, weight: number): void;
26
+ } | null;
27
+ readonly lookAt?: {
28
+ target?: Object3D | null;
29
+ } | null;
30
+ readonly humanoid?: {
31
+ getNormalizedBoneNode(name: string): Object3D | null;
32
+ } | null;
33
+ update(deltaSeconds: number): void;
34
+ }
35
+ /** The slice of the `@pixiv/three-vrm` module the loader needs. */
36
+ export interface VrmModule {
37
+ readonly VRMLoaderPlugin: new (parser: unknown) => unknown;
38
+ readonly VRMUtils?: {
39
+ rotateVRM0?(vrm: VrmLike): void;
40
+ };
41
+ }
42
+ /** What a host passes as `loadVrm`: `() => import('@pixiv/three-vrm')`. */
43
+ export type VrmModuleLoader = () => Promise<VrmModule>;
44
+ /** The module, or a typed error that names the missing peer and how to fix it. */
45
+ export declare function loadVrmModule(custom?: VrmModuleLoader): Promise<VrmModule>;
46
+ /** The glTF carries a VRM 0.x (`VRM`) or 1.0 (`VRMC_vrm`) extension. */
47
+ export declare function hasVrmExtension(gltf: {
48
+ userData?: Record<string, unknown>;
49
+ parser?: {
50
+ json?: {
51
+ extensionsUsed?: unknown;
52
+ };
53
+ };
54
+ }): boolean;
55
+ /** Which loader an avatar needs: its declared format wins; the extension catches an unlabelled file. */
56
+ export declare const wantsVrm: (format: string | undefined, gltf?: Parameters<typeof hasVrmExtension>[0]) => boolean;
57
+ export type VrmVowel = 'aa' | 'ih' | 'ou' | 'ee' | 'oh';
58
+ /**
59
+ * Chatly viseme -> one of VRM's five mouth expressions, and how far to open it.
60
+ * Keys are compared lower-case with any `viseme_` prefix removed. A viseme not
61
+ * listed, `sil` and `PP` (lips shut) all close the mouth.
62
+ */
63
+ export declare const VISEME_TO_VRM: Readonly<Record<string, readonly [VrmVowel, number] | null>>;
64
+ export declare const VRM_VOWELS: readonly VrmVowel[];
65
+ export declare function vrmVisemeFor(v: string): readonly [VrmVowel, number] | null;
66
+ /**
67
+ * Chatly `embodiment.expression` -> VRM preset and weight. The rest (`nod`,
68
+ * `shake_head`, `point`, `wave`, `shrug`, `think`) are gestures, not faces: they
69
+ * play only as the host's clip from `presence.expressions`. No Chatly expression
70
+ * is `angry` or `relaxed`, so those presets are never driven.
71
+ */
72
+ export declare const EXPRESSION_TO_VRM: Readonly<Partial<Record<AgentExpression, readonly [string, number]>>>;
73
+ /** Drives one loaded VRM: mouth, face, blink, gaze, and `vrm.update`. */
74
+ export declare class VrmRig {
75
+ readonly vrm: VrmLike;
76
+ reduced: boolean;
77
+ private readonly target;
78
+ private face;
79
+ private mouth;
80
+ private clock;
81
+ private head;
82
+ constructor(vrm: VrmLike, reduced: boolean);
83
+ get gazeTarget(): Object3D;
84
+ private set;
85
+ /** Open one of the five vowels (or close the mouth with null). Always zeroes the other four. */
86
+ setMouth(v: string | null, w: number): void;
87
+ /** Show a face for a cue; false when the expression is a gesture with no VRM preset. */
88
+ express(e: AgentExpression | null): boolean;
89
+ /** Point the eyes and head at a world position (null = release the head). */
90
+ gazeAt(root: Object3D, at: Vector3 | null, dt: number): void;
91
+ /** Advance the face and blink, then `vrm.update`. Call after the mixer and the gaze. */
92
+ update(dt: number): void;
93
+ get openVowel(): VrmVowel | null;
94
+ }
95
+ /** Where the agent should look, as a world position, for `gazeAt`. */
96
+ export declare function gazePoint(gaze: Object3D | Vector3 | 'visitor' | null, camera: Camera): Vector3 | null;
97
+ //# sourceMappingURL=vrm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vrm.d.ts","sourceRoot":"","sources":["../src/vrm.ts"],"names":[],"mappings":"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"}