@chatlychat/world 0.0.0-stage → 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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +120 -2
- package/dist/agent.d.ts +59 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +232 -0
- package/dist/agent.js.map +1 -0
- package/dist/bubble.d.ts +36 -0
- package/dist/bubble.d.ts.map +1 -0
- package/dist/bubble.js +108 -0
- package/dist/bubble.js.map +1 -0
- package/dist/capabilities.d.ts +77 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +118 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cards.d.ts +51 -0
- package/dist/cards.d.ts.map +1 -0
- package/dist/cards.js +136 -0
- package/dist/cards.js.map +1 -0
- package/dist/composer.d.ts +25 -0
- package/dist/composer.d.ts.map +1 -0
- package/dist/composer.js +53 -0
- package/dist/composer.js.map +1 -0
- package/dist/examples/tsconfig.tsbuildinfo +1 -0
- package/dist/handlers.d.ts +26 -0
- package/dist/handlers.d.ts.map +1 -0
- package/dist/handlers.js +41 -0
- package/dist/handlers.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/input.d.ts +46 -0
- package/dist/input.d.ts.map +1 -0
- package/dist/input.js +89 -0
- package/dist/input.js.map +1 -0
- package/dist/layout.d.ts +24 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +69 -0
- package/dist/layout.js.map +1 -0
- package/dist/model.d.ts +25 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +60 -0
- package/dist/model.js.map +1 -0
- package/dist/motion.d.ts +27 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +65 -0
- package/dist/motion.js.map +1 -0
- package/dist/panel.d.ts +77 -0
- package/dist/panel.d.ts.map +1 -0
- package/dist/panel.js +214 -0
- package/dist/panel.js.map +1 -0
- package/dist/selection.d.ts +14 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +21 -0
- package/dist/selection.js.map +1 -0
- package/dist/text.d.ts +26 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +100 -0
- package/dist/text.js.map +1 -0
- package/dist/theme-apply.d.ts +19 -0
- package/dist/theme-apply.d.ts.map +1 -0
- package/dist/theme-apply.js +88 -0
- package/dist/theme-apply.js.map +1 -0
- package/dist/types.d.ts +102 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +41 -0
- package/dist/types.js.map +1 -0
- package/dist/visemes.d.ts +28 -0
- package/dist/visemes.d.ts.map +1 -0
- package/dist/visemes.js +42 -0
- package/dist/visemes.js.map +1 -0
- package/dist/world-api.d.ts +39 -0
- package/dist/world-api.d.ts.map +1 -0
- package/dist/world-api.js +2 -0
- package/dist/world-api.js.map +1 -0
- package/dist/world.d.ts +5 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +573 -0
- package/dist/world.js.map +1 -0
- package/package.json +67 -3
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host capabilities: what the visitor's world can DO, declared to the bot and
|
|
3
|
+
* dispatched to handlers the host registers.
|
|
4
|
+
*
|
|
5
|
+
* The world never walks, dresses or spawns anything itself — those are the
|
|
6
|
+
* host's. This surfaces the four standard intents as typed handlers and keeps
|
|
7
|
+
* the contract every capability carries:
|
|
8
|
+
*
|
|
9
|
+
* - an `equivalent` is REQUIRED at registration, because a bot's offer must
|
|
10
|
+
* mean something to a visitor whose world cannot do it. It is announced
|
|
11
|
+
* whenever a handler is missing, declines or throws;
|
|
12
|
+
* - the host is the gate: a handler may return `false` or throw to refuse, and
|
|
13
|
+
* a refusal is reported as `failed` with `refused: true` (two refusals in ten
|
|
14
|
+
* minutes stop the bot firing it — server-side);
|
|
15
|
+
* - args are checked here against the declared shape before a handler sees
|
|
16
|
+
* them, because a bot-fired invocation is data from outside.
|
|
17
|
+
*/
|
|
18
|
+
import type { ConversationLike } from './types.js';
|
|
19
|
+
import type { CapabilityEquivalent, HostCapabilityDeclaration, HostSurface, HostSurfaceState } from '@chatlychat/core';
|
|
20
|
+
/** The standard intents and their arguments. Names are verbs, never positions. */
|
|
21
|
+
export interface WorldActionMap {
|
|
22
|
+
'world.walk_to': {
|
|
23
|
+
place: string;
|
|
24
|
+
};
|
|
25
|
+
'avatar.try_on': {
|
|
26
|
+
item: string;
|
|
27
|
+
};
|
|
28
|
+
'scene.highlight': {
|
|
29
|
+
ref: string;
|
|
30
|
+
};
|
|
31
|
+
'scene.spawn': {
|
|
32
|
+
ref: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export type StandardAction = keyof WorldActionMap;
|
|
36
|
+
/** What a handler may answer. `false` or a throw is a refusal; `void`/`true` is done. */
|
|
37
|
+
export type ActionOutcome = void | boolean | {
|
|
38
|
+
readonly ok: boolean;
|
|
39
|
+
readonly text?: string;
|
|
40
|
+
};
|
|
41
|
+
export interface ActionContext {
|
|
42
|
+
readonly equivalent: CapabilityEquivalent;
|
|
43
|
+
/** True when the bot fired it without a press. */
|
|
44
|
+
readonly unprompted: boolean;
|
|
45
|
+
}
|
|
46
|
+
export type ActionHandler<A extends Readonly<Record<string, unknown>>> = (args: A, ctx: ActionContext) => ActionOutcome | Promise<ActionOutcome>;
|
|
47
|
+
export interface RegisterOptions {
|
|
48
|
+
/** What a person or screen reader gets instead of the world doing it. Required. */
|
|
49
|
+
readonly equivalent: CapabilityEquivalent;
|
|
50
|
+
/** Let the bot fire it without a press. Off by default. */
|
|
51
|
+
readonly unprompted?: boolean;
|
|
52
|
+
readonly label?: string;
|
|
53
|
+
readonly description?: string;
|
|
54
|
+
/** Required for a custom (non-standard) name; a small JSON-Schema subset. */
|
|
55
|
+
readonly args?: Readonly<Record<string, unknown>>;
|
|
56
|
+
}
|
|
57
|
+
export interface ActionReport {
|
|
58
|
+
readonly status: 'done' | 'failed';
|
|
59
|
+
readonly refused: boolean;
|
|
60
|
+
readonly text: string | null;
|
|
61
|
+
}
|
|
62
|
+
export declare class CapabilityRegistry {
|
|
63
|
+
private readonly announce;
|
|
64
|
+
private readonly entries;
|
|
65
|
+
constructor(announce?: (text: string) => void);
|
|
66
|
+
register<N extends StandardAction>(name: N, handler: ActionHandler<WorldActionMap[N]>, opts: RegisterOptions): () => void;
|
|
67
|
+
register(name: string, handler: ActionHandler<Readonly<Record<string, unknown>>>, opts: RegisterOptions): () => void;
|
|
68
|
+
declarations(): readonly HostCapabilityDeclaration[];
|
|
69
|
+
/** The surface to hand `core.setSurface`. */
|
|
70
|
+
surface(state?: HostSurfaceState, kind?: string): HostSurface;
|
|
71
|
+
has(name: string): boolean;
|
|
72
|
+
/** Run a handler, with every failure mode folded into a report. Never throws. */
|
|
73
|
+
invoke(name: string, args: Readonly<Record<string, unknown>>, unprompted: boolean): Promise<ActionReport>;
|
|
74
|
+
/** Route a bot-fired invocation to its handler and answer it into the thread. */
|
|
75
|
+
bind(conversation: ConversationLike): () => void;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const STANDARD = {
|
|
2
|
+
'world.walk_to': {
|
|
3
|
+
label: 'Take me there',
|
|
4
|
+
description: 'Walk the visitor to a named place.',
|
|
5
|
+
arg: 'place',
|
|
6
|
+
},
|
|
7
|
+
'avatar.try_on': {
|
|
8
|
+
label: 'Try it on',
|
|
9
|
+
description: "Put an item on the visitor's avatar.",
|
|
10
|
+
arg: 'item',
|
|
11
|
+
},
|
|
12
|
+
'scene.highlight': {
|
|
13
|
+
label: 'Show me',
|
|
14
|
+
description: 'Highlight a named object in the scene.',
|
|
15
|
+
arg: 'ref',
|
|
16
|
+
},
|
|
17
|
+
'scene.spawn': {
|
|
18
|
+
label: 'Bring it here',
|
|
19
|
+
description: 'Place a named object in front of the visitor.',
|
|
20
|
+
arg: 'ref',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const ARG_MAX = 40;
|
|
24
|
+
const equivalentText = (e) => e.kind === 'text' ? e.text : (e.text ?? e.href);
|
|
25
|
+
export class CapabilityRegistry {
|
|
26
|
+
announce;
|
|
27
|
+
entries = new Map();
|
|
28
|
+
constructor(announce = () => undefined) {
|
|
29
|
+
this.announce = announce;
|
|
30
|
+
}
|
|
31
|
+
register(name, handler, opts) {
|
|
32
|
+
const std = STANDARD[name];
|
|
33
|
+
const decl = {
|
|
34
|
+
name,
|
|
35
|
+
label: opts.label ?? std?.label ?? name,
|
|
36
|
+
...((opts.description ?? std?.description)
|
|
37
|
+
? { description: (opts.description ?? std?.description) }
|
|
38
|
+
: {}),
|
|
39
|
+
...(opts.args !== undefined || std !== undefined
|
|
40
|
+
? {
|
|
41
|
+
args: opts.args ?? {
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: { [std?.arg]: { type: 'string', maxLength: ARG_MAX } },
|
|
44
|
+
required: [std?.arg],
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
: {}),
|
|
48
|
+
...(opts.unprompted === true ? { unprompted: true } : {}),
|
|
49
|
+
equivalent: opts.equivalent,
|
|
50
|
+
};
|
|
51
|
+
this.entries.set(name, {
|
|
52
|
+
decl,
|
|
53
|
+
handler: handler,
|
|
54
|
+
argName: std?.arg ?? null,
|
|
55
|
+
});
|
|
56
|
+
return () => {
|
|
57
|
+
this.entries.delete(name);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
declarations() {
|
|
61
|
+
return [...this.entries.values()].map((e) => e.decl);
|
|
62
|
+
}
|
|
63
|
+
/** The surface to hand `core.setSurface`. */
|
|
64
|
+
surface(state, kind = 'world') {
|
|
65
|
+
return { kind, capabilities: this.declarations(), ...(state === undefined ? {} : { state }) };
|
|
66
|
+
}
|
|
67
|
+
has(name) {
|
|
68
|
+
return this.entries.has(name);
|
|
69
|
+
}
|
|
70
|
+
/** Run a handler, with every failure mode folded into a report. Never throws. */
|
|
71
|
+
async invoke(name, args, unprompted) {
|
|
72
|
+
const e = this.entries.get(name);
|
|
73
|
+
if (e === undefined) {
|
|
74
|
+
return { status: 'failed', refused: true, text: null };
|
|
75
|
+
}
|
|
76
|
+
const fail = (refused) => {
|
|
77
|
+
this.announce(equivalentText(e.decl.equivalent));
|
|
78
|
+
return { status: 'failed', refused, text: equivalentText(e.decl.equivalent) };
|
|
79
|
+
};
|
|
80
|
+
if (e.argName !== null) {
|
|
81
|
+
const v = args[e.argName];
|
|
82
|
+
if (typeof v !== 'string' || v === '' || v.length > ARG_MAX) {
|
|
83
|
+
return fail(false);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const out = await e.handler(args, { equivalent: e.decl.equivalent, unprompted });
|
|
88
|
+
const ok = out === undefined || out === true || (typeof out === 'object' && out.ok);
|
|
89
|
+
if (!ok) {
|
|
90
|
+
return fail(true);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
status: 'done',
|
|
94
|
+
refused: false,
|
|
95
|
+
text: typeof out === 'object' ? (out.text ?? null) : null,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return fail(true);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Route a bot-fired invocation to its handler and answer it into the thread. */
|
|
103
|
+
bind(conversation) {
|
|
104
|
+
return conversation.onCapability((inv) => {
|
|
105
|
+
void this.invoke(inv.capability, inv.args, true)
|
|
106
|
+
.then((r) => conversation.reportAction({
|
|
107
|
+
messageId: inv.messageId,
|
|
108
|
+
actionId: inv.invocationId,
|
|
109
|
+
status: r.status,
|
|
110
|
+
...(r.text === null ? {} : { text: r.text }),
|
|
111
|
+
...(r.refused ? { data: { refused: true } } : {}),
|
|
112
|
+
}))
|
|
113
|
+
// Reporting is best-effort: the visitor already saw the announcement.
|
|
114
|
+
.catch(() => undefined);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"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"}
|
package/dist/cards.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picks: a `card_grid` rendered as objects in the scene.
|
|
3
|
+
*
|
|
4
|
+
* `buildGrid` lays the cards out (`layout.ts`), asks the card renderer — the
|
|
5
|
+
* default below or a host's override — for each one and parents them. The
|
|
6
|
+
* default card is a plate with title, subtitle and price label, a glTF model
|
|
7
|
+
* if the card has one, and the theme's pedestal, beam and selection ring.
|
|
8
|
+
*/
|
|
9
|
+
import { Group, type Object3D } from 'three';
|
|
10
|
+
import { type GridPlacement, type Mount } from './layout.js';
|
|
11
|
+
import { type ModelAnchor, type ModelLoader } from './model.js';
|
|
12
|
+
import type { BlockOf, CardRenderProps, ConversationMessage, ResolvedWorldTheme } from '@chatlychat/core';
|
|
13
|
+
export interface CardData {
|
|
14
|
+
readonly title: string;
|
|
15
|
+
readonly subtitle: string | null;
|
|
16
|
+
readonly price: {
|
|
17
|
+
readonly amount: number;
|
|
18
|
+
readonly currency: string;
|
|
19
|
+
} | null;
|
|
20
|
+
readonly model: {
|
|
21
|
+
readonly url: string;
|
|
22
|
+
readonly format?: string;
|
|
23
|
+
readonly scale?: number;
|
|
24
|
+
readonly anchor?: ModelAnchor;
|
|
25
|
+
} | null;
|
|
26
|
+
}
|
|
27
|
+
/** Read the fields a world draws off a card block, tolerantly: the block is wire data. */
|
|
28
|
+
export declare function readCard(block: Readonly<Record<string, unknown>>): CardData;
|
|
29
|
+
/** Minor units to a locale string. The fraction digits come from the currency, not from "100". */
|
|
30
|
+
export declare function formatPrice(amount: number, currency: string, locale?: string): string;
|
|
31
|
+
export interface CardDeps {
|
|
32
|
+
readonly loadModel: ModelLoader;
|
|
33
|
+
readonly onError: (e: unknown) => void;
|
|
34
|
+
}
|
|
35
|
+
export declare const cardKey: (message: ConversationMessage, block: Readonly<Record<string, unknown>>, index: number) => string;
|
|
36
|
+
/** The default `renderCard`. */
|
|
37
|
+
export declare function defaultCard(props: CardRenderProps, deps: CardDeps): Object3D;
|
|
38
|
+
/** Whether a card node is drawn selected — the default's ring, readable by tests and hosts. */
|
|
39
|
+
export declare function isHighlighted(node: Object3D): boolean;
|
|
40
|
+
export interface GridBuild {
|
|
41
|
+
readonly group: Group;
|
|
42
|
+
readonly mount: Mount;
|
|
43
|
+
/** card key -> node, so one card can be redrawn when its selection changes. */
|
|
44
|
+
readonly nodes: Map<string, {
|
|
45
|
+
node: Object3D;
|
|
46
|
+
index: number;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
export declare function buildGrid(placement: GridPlacement, count: number, theme: ResolvedWorldTheme, draw: (index: number) => Object3D, keyOf: (index: number) => string): GridBuild;
|
|
50
|
+
export type { BlockOf };
|
|
51
|
+
//# sourceMappingURL=cards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cards.d.ts","sourceRoot":"","sources":["../src/cards.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAEL,KAAK,EAKL,KAAK,QAAQ,EACd,MAAM,OAAO,CAAC;AAEf,OAAO,EAAe,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAY,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAK1E,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAK1B,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9E,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;KAC/B,GAAG,IAAI,CAAC;CACV;AAED,0FAA0F;AAC1F,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,QAAQ,CAsB3E;AAED,kGAAkG;AAClG,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAOrF;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,OAAO,YACT,mBAAmB,SACrB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,SACjC,MAAM,KACZ,MAA0F,CAAC;AAE9F,gCAAgC;AAChC,wBAAgB,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,CA2E5E;AAED,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAErD;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChE;AAED,wBAAgB,SAAS,CACvB,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,kBAAkB,EACzB,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,QAAQ,EACjC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAC/B,SAAS,CAcX;AAED,YAAY,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/cards.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picks: a `card_grid` rendered as objects in the scene.
|
|
3
|
+
*
|
|
4
|
+
* `buildGrid` lays the cards out (`layout.ts`), asks the card renderer — the
|
|
5
|
+
* default below or a host's override — for each one and parents them. The
|
|
6
|
+
* default card is a plate with title, subtitle and price label, a glTF model
|
|
7
|
+
* if the card has one, and the theme's pedestal, beam and selection ring.
|
|
8
|
+
*/
|
|
9
|
+
import { CylinderGeometry, Group, Mesh, MeshBasicMaterial, RingGeometry, DoubleSide, } from 'three';
|
|
10
|
+
import { layoutCards } from './layout.js';
|
|
11
|
+
import { fitModel } from './model.js';
|
|
12
|
+
import { createTextMesh } from './text.js';
|
|
13
|
+
import { accentMaterial, panelBacking } from './theme-apply.js';
|
|
14
|
+
import { WORLD_CONTRACT } from './types.js';
|
|
15
|
+
const PLATE_W = 0.28;
|
|
16
|
+
const PLATE_H = 0.2;
|
|
17
|
+
/** Read the fields a world draws off a card block, tolerantly: the block is wire data. */
|
|
18
|
+
export function readCard(block) {
|
|
19
|
+
const s = (k) => typeof block[k] === 'string' && block[k] !== '' ? block[k] : null;
|
|
20
|
+
const p = block['price'];
|
|
21
|
+
const m = block['model'];
|
|
22
|
+
return {
|
|
23
|
+
title: s('title') ?? '',
|
|
24
|
+
subtitle: s('subtitle'),
|
|
25
|
+
price: typeof p?.amount === 'number' && typeof p.currency === 'string'
|
|
26
|
+
? { amount: p.amount, currency: p.currency }
|
|
27
|
+
: null,
|
|
28
|
+
model: typeof m?.['url'] === 'string'
|
|
29
|
+
? {
|
|
30
|
+
url: m['url'],
|
|
31
|
+
...(typeof m['format'] === 'string' ? { format: m['format'] } : {}),
|
|
32
|
+
...(typeof m['scale'] === 'number' ? { scale: m['scale'] } : {}),
|
|
33
|
+
...(typeof m['anchor'] === 'string' ? { anchor: m['anchor'] } : {}),
|
|
34
|
+
}
|
|
35
|
+
: null,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Minor units to a locale string. The fraction digits come from the currency, not from "100". */
|
|
39
|
+
export function formatPrice(amount, currency, locale) {
|
|
40
|
+
try {
|
|
41
|
+
const f = new Intl.NumberFormat(locale, { style: 'currency', currency });
|
|
42
|
+
return f.format(amount / 10 ** (f.resolvedOptions().maximumFractionDigits ?? 2));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return `${String(amount / 100)} ${currency}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export const cardKey = (message, block, index) => `${message.id}:${typeof block['id'] === 'string' ? block['id'] : String(index)}`;
|
|
49
|
+
/** The default `renderCard`. */
|
|
50
|
+
export function defaultCard(props, deps) {
|
|
51
|
+
const { theme } = props;
|
|
52
|
+
const card = readCard(props.block);
|
|
53
|
+
const g = new Group();
|
|
54
|
+
g.name = WORLD_CONTRACT.objects.card;
|
|
55
|
+
g.userData['float'] = theme.cardPedestal === 'float';
|
|
56
|
+
if (theme.cardPedestal === 'plinth') {
|
|
57
|
+
const plinth = new Mesh(new CylinderGeometry(0.16, 0.18, 0.1, 24), accentMaterial(theme));
|
|
58
|
+
plinth.name = 'cl3-card-pedestal';
|
|
59
|
+
plinth.position.y = -0.1;
|
|
60
|
+
g.add(plinth);
|
|
61
|
+
}
|
|
62
|
+
else if (theme.cardPedestal === 'hanger') {
|
|
63
|
+
const rod = new Mesh(new CylinderGeometry(0.004, 0.004, 0.5, 6), accentMaterial(theme));
|
|
64
|
+
rod.name = 'cl3-card-pedestal';
|
|
65
|
+
rod.position.y = 0.35;
|
|
66
|
+
g.add(rod);
|
|
67
|
+
}
|
|
68
|
+
if (theme.cardBeam) {
|
|
69
|
+
const beam = new Mesh(new CylinderGeometry(0.12, 0.16, 1.2, 24, 1, true), accentMaterial(theme, 0.2));
|
|
70
|
+
beam.name = 'cl3-card-beam';
|
|
71
|
+
beam.position.y = 0.55;
|
|
72
|
+
g.add(beam);
|
|
73
|
+
}
|
|
74
|
+
const plate = panelBacking(theme, PLATE_W, PLATE_H);
|
|
75
|
+
const body = new Group();
|
|
76
|
+
if (plate !== null) {
|
|
77
|
+
body.add(plate);
|
|
78
|
+
}
|
|
79
|
+
const title = createTextMesh(card.title, theme, { maxWidthMetres: PLATE_W - 0.02, size: 0.8 });
|
|
80
|
+
title.position.set(0, card.subtitle === null ? 0.02 : 0.04, 0.002);
|
|
81
|
+
body.add(title);
|
|
82
|
+
if (card.subtitle !== null) {
|
|
83
|
+
const sub = createTextMesh(card.subtitle, theme, { maxWidthMetres: PLATE_W - 0.02, size: 0.6 });
|
|
84
|
+
sub.position.set(0, -0.03, 0.002);
|
|
85
|
+
body.add(sub);
|
|
86
|
+
}
|
|
87
|
+
if (theme.cardPriceLabel && card.price !== null) {
|
|
88
|
+
const price = createTextMesh(formatPrice(card.price.amount, card.price.currency), theme, {
|
|
89
|
+
maxWidthMetres: PLATE_W,
|
|
90
|
+
size: 0.8,
|
|
91
|
+
color: theme.accentColor,
|
|
92
|
+
});
|
|
93
|
+
price.name = 'cl3-card-price';
|
|
94
|
+
price.position.set(0, -PLATE_H / 2 - 0.03, 0.002);
|
|
95
|
+
body.add(price);
|
|
96
|
+
}
|
|
97
|
+
g.add(body);
|
|
98
|
+
if (card.model !== null && card.model.format !== 'usdz') {
|
|
99
|
+
const { url, scale, anchor } = card.model;
|
|
100
|
+
deps.loadModel(url).then((m) => {
|
|
101
|
+
const fitted = fitModel(m.scene, scale ?? 1, anchor ?? 'center');
|
|
102
|
+
fitted.name = 'cl3-card-model';
|
|
103
|
+
// The model stands above its label plate.
|
|
104
|
+
body.position.y = -0.2;
|
|
105
|
+
fitted.position.y = 0.1;
|
|
106
|
+
g.add(fitted);
|
|
107
|
+
}, deps.onError);
|
|
108
|
+
}
|
|
109
|
+
const ring = new Mesh(new RingGeometry(0.2, 0.23, 32), new MeshBasicMaterial({ color: theme.cardHighlightColor, side: DoubleSide }));
|
|
110
|
+
ring.name = 'cl3-card-highlight';
|
|
111
|
+
ring.rotation.x = -Math.PI / 2;
|
|
112
|
+
ring.position.y = -0.14;
|
|
113
|
+
ring.visible = props.selected;
|
|
114
|
+
g.add(ring);
|
|
115
|
+
return g;
|
|
116
|
+
}
|
|
117
|
+
/** Whether a card node is drawn selected — the default's ring, readable by tests and hosts. */
|
|
118
|
+
export function isHighlighted(node) {
|
|
119
|
+
return node.getObjectByName('cl3-card-highlight')?.visible === true;
|
|
120
|
+
}
|
|
121
|
+
export function buildGrid(placement, count, theme, draw, keyOf) {
|
|
122
|
+
const group = new Group();
|
|
123
|
+
group.name = WORLD_CONTRACT.objects.grid;
|
|
124
|
+
group.userData['placement'] = placement;
|
|
125
|
+
const { poses, mount } = layoutCards(placement, count, theme.cardSpacingMetres);
|
|
126
|
+
const nodes = new Map();
|
|
127
|
+
poses.forEach((p, i) => {
|
|
128
|
+
const node = draw(i);
|
|
129
|
+
node.position.set(...p.position);
|
|
130
|
+
node.rotation.set(p.pitch, p.yaw, 0, 'YXZ');
|
|
131
|
+
group.add(node);
|
|
132
|
+
nodes.set(keyOf(i), { node, index: i });
|
|
133
|
+
});
|
|
134
|
+
return { group, mount, nodes };
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=cards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cards.js","sourceRoot":"","sources":["../src/cards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composer's state: a draft the HOST fills (a virtual keyboard, dictation,
|
|
3
|
+
* a DOM overlay, voice) and a submit the world sends. Typing in a headset is
|
|
4
|
+
* the host's problem; what is ours is that composing turns the agent's body to
|
|
5
|
+
* listen, so the draft going empty/non-empty is reported to the conversation.
|
|
6
|
+
*/
|
|
7
|
+
import type { ConversationLike } from './types.js';
|
|
8
|
+
export interface Composer {
|
|
9
|
+
readonly draft: string;
|
|
10
|
+
readonly composing: boolean;
|
|
11
|
+
readonly busy: boolean;
|
|
12
|
+
setDraft(text: string): void;
|
|
13
|
+
/** Report composing without a draft (a custom composer with its own field). */
|
|
14
|
+
setComposing(composing: boolean): void;
|
|
15
|
+
submit(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export interface ComposerDeps {
|
|
18
|
+
readonly conversation: ConversationLike;
|
|
19
|
+
readonly onError: (e: unknown) => void;
|
|
20
|
+
readonly onSent: () => void;
|
|
21
|
+
/** The draft changed; `composingChanged` when it crossed empty/non-empty. */
|
|
22
|
+
readonly onChange: (composingChanged: boolean) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function createComposer(d: ComposerDeps): Composer;
|
|
25
|
+
//# sourceMappingURL=composer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+EAA+E;IAC/E,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,CAAC,gBAAgB,EAAE,OAAO,KAAK,IAAI,CAAC;CACxD;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,YAAY,GAAG,QAAQ,CAiDxD"}
|
package/dist/composer.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export function createComposer(d) {
|
|
2
|
+
let draft = '';
|
|
3
|
+
let composing = false;
|
|
4
|
+
let busy = false;
|
|
5
|
+
const flip = (next) => {
|
|
6
|
+
if (next === composing) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
composing = next;
|
|
10
|
+
d.conversation.setTyping(next);
|
|
11
|
+
return true;
|
|
12
|
+
};
|
|
13
|
+
const composer = {
|
|
14
|
+
get draft() {
|
|
15
|
+
return draft;
|
|
16
|
+
},
|
|
17
|
+
get composing() {
|
|
18
|
+
return composing;
|
|
19
|
+
},
|
|
20
|
+
get busy() {
|
|
21
|
+
return busy;
|
|
22
|
+
},
|
|
23
|
+
setDraft(text) {
|
|
24
|
+
draft = text;
|
|
25
|
+
d.onChange(flip(text !== ''));
|
|
26
|
+
},
|
|
27
|
+
setComposing(c) {
|
|
28
|
+
if (flip(c)) {
|
|
29
|
+
d.onChange(true);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
async submit() {
|
|
33
|
+
const body = draft.trim();
|
|
34
|
+
if (body === '' || busy) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
busy = true;
|
|
38
|
+
try {
|
|
39
|
+
await d.conversation.send(body);
|
|
40
|
+
composer.setDraft('');
|
|
41
|
+
d.onSent();
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
d.onError(e);
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
busy = false;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
return composer;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=composer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer.js","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"AA0BA,MAAM,UAAU,cAAc,CAAC,CAAe;IAC5C,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,MAAM,IAAI,GAAG,CAAC,IAAa,EAAW,EAAE;QACtC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,SAAS,GAAG,IAAI,CAAC;QACjB,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IACF,MAAM,QAAQ,GAAa;QACzB,IAAI,KAAK;YACP,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,SAAS;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,IAAI;YACN,OAAO,IAAI,CAAC;QACd,CAAC;QACD,QAAQ,CAAC,IAAI;YACX,KAAK,GAAG,IAAI,CAAC;YACb,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;QAChC,CAAC;QACD,YAAY,CAAC,CAAC;YACZ,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBACZ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QACD,KAAK,CAAC,MAAM;YACV,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YAC1B,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC;gBACxB,OAAO;YACT,CAAC;YACD,IAAI,GAAG,IAAI,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBACtB,CAAC,CAAC,MAAM,EAAE,CAAC;YACb,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACf,CAAC;oBAAS,CAAC;gBACT,IAAI,GAAG,KAAK,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;IACF,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|