@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,26 @@
1
+ import type { ConversationLike } from './types.js';
2
+ import type { BlockHandlers, ConversationMessage } from '@chatlychat/core';
3
+ export interface CardAction {
4
+ readonly kind: string;
5
+ readonly id?: string;
6
+ readonly value?: string;
7
+ readonly payload?: Readonly<Record<string, unknown>>;
8
+ readonly silent?: boolean;
9
+ readonly event?: string;
10
+ readonly data?: Readonly<Record<string, unknown>>;
11
+ readonly href?: string;
12
+ readonly canvasId?: string;
13
+ readonly params?: Record<string, unknown>;
14
+ }
15
+ export interface HandlerHooks {
16
+ /** A host_event press. Resolves to whether something claimed it. */
17
+ readonly hostEvent: (event: string, data: Readonly<Record<string, unknown>>, action: {
18
+ readonly messageId: string;
19
+ readonly actionId: string;
20
+ }) => Promise<boolean>;
21
+ readonly openUrl: (href: string) => void;
22
+ }
23
+ /** A card's own actions, by explicit `id` or by position (`a0`, `a1`…). */
24
+ export declare function cardActions(block: Readonly<Record<string, unknown>>): readonly CardAction[];
25
+ export declare function makeHandlers(conversation: ConversationLike, message: ConversationMessage, title: string, actions: readonly CardAction[], hooks: HandlerHooks): BlockHandlers;
26
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,CAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvC,MAAM,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAC9D,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,UAAU,EAAE,CAE3F;AAED,wBAAgB,YAAY,CAC1B,YAAY,EAAE,gBAAgB,EAC9B,OAAO,EAAE,mBAAmB,EAC5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,KAAK,EAAE,YAAY,GAClB,aAAa,CA2Bf"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The three things a visitor can do to a block, as the calls the core already
3
+ * makes. Handed to every renderer — default or override — unchanged.
4
+ */
5
+ import { WorldError } from './types.js';
6
+ /** A card's own actions, by explicit `id` or by position (`a0`, `a1`…). */
7
+ export function cardActions(block) {
8
+ return Array.isArray(block['actions']) ? block['actions'] : [];
9
+ }
10
+ export function makeHandlers(conversation, message, title, actions, hooks) {
11
+ return {
12
+ select: (payload) => conversation.postback({ body: title, payload: { ...payload } }),
13
+ react: async (emoji) => {
14
+ await conversation.react(message.id, emoji);
15
+ },
16
+ press: async (actionId) => {
17
+ const idx = actions.findIndex((a, i) => (a.id ?? `a${String(i)}`) === actionId);
18
+ const a = idx < 0 ? undefined : actions[idx];
19
+ if (a === undefined) {
20
+ throw new WorldError('unknown_action', `no action "${actionId}" on this block`);
21
+ }
22
+ if (a.kind === 'postback' && a.value !== undefined) {
23
+ await conversation.postback({
24
+ body: a.value,
25
+ ...(a.payload === undefined ? {} : { payload: { ...a.payload } }),
26
+ ...(a.silent === true ? { silent: true } : {}),
27
+ });
28
+ }
29
+ else if (a.kind === 'host_event' && a.event !== undefined) {
30
+ await hooks.hostEvent(a.event, a.data ?? {}, { messageId: message.id, actionId });
31
+ }
32
+ else if (a.kind === 'url' && a.href !== undefined) {
33
+ hooks.openUrl(a.href);
34
+ }
35
+ else if (a.kind === 'step' && a.canvasId !== undefined) {
36
+ await conversation.requestStep(a.canvasId, a.params);
37
+ }
38
+ },
39
+ };
40
+ }
41
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA4BxC,2EAA2E;AAC3E,MAAM,UAAU,WAAW,CAAC,KAAwC;IAClE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAE,KAAK,CAAC,SAAS,CAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,YAA8B,EAC9B,OAA4B,EAC5B,KAAa,EACb,OAA8B,EAC9B,KAAmB;IAEnB,OAAO;QACL,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC;QACpF,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACrB,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YACxB,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC;YAChF,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC7C,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gBACpB,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,cAAc,QAAQ,iBAAiB,CAAC,CAAC;YAClF,CAAC;YACD,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACnD,MAAM,YAAY,CAAC,QAAQ,CAAC;oBAC1B,IAAI,EAAE,CAAC,CAAC,KAAK;oBACb,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;oBACjE,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC/C,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC5D,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YACpF,CAAC;iBAAM,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBACpD,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;iBAAM,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACzD,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `@chatlychat/world` — a Chatly conversation in a three.js scene.
3
+ *
4
+ * const world = createWorld({ conversation, camera, theme: core.worldTheme });
5
+ * scene.add(world.root);
6
+ * renderer.setAnimationLoop(() => world.update(clock.getDelta()));
7
+ *
8
+ * `three` and `@chatlychat/core` are peer dependencies. `@pixiv/three-vrm` is an
9
+ * OPTIONAL peer, needed only for VRM avatars (see `vrm.ts`).
10
+ */
11
+ export { createWorld } from './world.js';
12
+ export type { ChatlyWorld } from './world-api.js';
13
+ export type { Composer } from './composer.js';
14
+ export { WORLD_CONTRACT, WorldError, type ConversationLike, type PanelFollow, type SoundCue, type SoundKind, type WorldAnchors, type WorldErrorCode, type WorldNodeRenderers, type WorldObjectName, type WorldOptions, } from './types.js';
15
+ export { CapabilityRegistry, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReport, type RegisterOptions, type StandardAction, type WorldActionMap, } from './capabilities.js';
16
+ export { GRID_PLACEMENTS, layoutCards, type GridLayout, type GridPlacement, type Mount, type Pose, } from './layout.js';
17
+ export { bubbleScale } from './bubble.js';
18
+ export { DEAD_METRES, DEAD_YAW, lazyStep, type FollowPose, type FollowState } from './panel.js';
19
+ export { buildGrid, defaultCard, formatPrice, isHighlighted, readCard, type CardData, } from './cards.js';
20
+ export { anchorOffset, fitModel, gltfLoader, type GltfLoaderLike, type GltfLoaderOptions, type LoadedModel, type ModelAnchor, type ModelLoader, } from './model.js';
21
+ export { readVisemes, visemeAt, type Viseme, type VisemeTrack } from './visemes.js';
22
+ export { Selection } from './selection.js';
23
+ export { Motion } from './motion.js';
24
+ export { AgentBody, type GazeTarget } from './agent.js';
25
+ export { interactive, pickRay, type Hit, type Interactive, type InteractiveKind } from './input.js';
26
+ export { EXPRESSION_TO_VRM, VISEME_TO_VRM, VRM_PEER, VrmRig, hasVrmExtension, loadVrmModule, vrmVisemeFor, wantsVrm, type VrmLike, type VrmModule, type VrmModuleLoader, type VrmVowel, } from './vrm.js';
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,cAAc,EACd,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,eAAe,EACf,WAAW,EACX,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,IAAI,GACV,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAChG,OAAO,EACL,SAAS,EACT,WAAW,EACX,WAAW,EACX,aAAa,EACb,QAAQ,EACR,KAAK,QAAQ,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACpG,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,QAAQ,EACR,MAAM,EACN,eAAe,EACf,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,QAAQ,GACd,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `@chatlychat/world` — a Chatly conversation in a three.js scene.
3
+ *
4
+ * const world = createWorld({ conversation, camera, theme: core.worldTheme });
5
+ * scene.add(world.root);
6
+ * renderer.setAnimationLoop(() => world.update(clock.getDelta()));
7
+ *
8
+ * `three` and `@chatlychat/core` are peer dependencies. `@pixiv/three-vrm` is an
9
+ * OPTIONAL peer, needed only for VRM avatars (see `vrm.ts`).
10
+ */
11
+ export { createWorld } from './world.js';
12
+ export { WORLD_CONTRACT, WorldError, } from './types.js';
13
+ export { CapabilityRegistry, } from './capabilities.js';
14
+ export { GRID_PLACEMENTS, layoutCards, } from './layout.js';
15
+ export { bubbleScale } from './bubble.js';
16
+ export { DEAD_METRES, DEAD_YAW, lazyStep } from './panel.js';
17
+ export { buildGrid, defaultCard, formatPrice, isHighlighted, readCard, } from './cards.js';
18
+ export { anchorOffset, fitModel, gltfLoader, } from './model.js';
19
+ export { readVisemes, visemeAt } from './visemes.js';
20
+ export { Selection } from './selection.js';
21
+ export { Motion } from './motion.js';
22
+ export { AgentBody } from './agent.js';
23
+ export { interactive, pickRay } from './input.js';
24
+ export { EXPRESSION_TO_VRM, VISEME_TO_VRM, VRM_PEER, VrmRig, hasVrmExtension, loadVrmModule, vrmVisemeFor, wantsVrm, } from './vrm.js';
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,OAAO,EACL,cAAc,EACd,UAAU,GAUX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,GAQnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,eAAe,EACf,WAAW,GAKZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAqC,MAAM,YAAY,CAAC;AAChG,OAAO,EACL,SAAS,EACT,WAAW,EACX,WAAW,EACX,aAAa,EACb,QAAQ,GAET,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,QAAQ,EACR,UAAU,GAMX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAiC,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAmB,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAoD,MAAM,YAAY,CAAC;AACpG,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,QAAQ,EACR,MAAM,EACN,eAAe,EACf,aAAa,EACb,YAAY,EACZ,QAAQ,GAKT,MAAM,UAAU,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Picking: a ray in, an interactive thing out. The host owns input — its
3
+ * controllers, hands, gaze and mouse — so this is only the part that knows
4
+ * which of OUR objects a ray hit.
5
+ *
6
+ * Anything a renderer wants tappable is marked with `interactive(obj, kind,
7
+ * activate)`; `pick` walks up from whatever mesh the ray struck to the first
8
+ * marked ancestor, so a renderer marks the root of its node and every child
9
+ * works. An override can opt out of the world's default tap by setting
10
+ * `userData.cl3Handled`.
11
+ */
12
+ import { Vector3, type Camera, type Object3D } from 'three';
13
+ export type InteractiveKind = 'card' | 'release' | 'send' | 'field';
14
+ export interface Interactive {
15
+ readonly kind: InteractiveKind;
16
+ readonly activate: () => void;
17
+ }
18
+ export interface Hit extends Interactive {
19
+ readonly object: Object3D;
20
+ readonly distance: number;
21
+ }
22
+ export declare function interactive(obj: Object3D, kind: InteractiveKind, activate: () => void): void;
23
+ export declare function pickRay(root: Object3D, origin: Vector3, direction: Vector3, maxMetres?: number): Hit | null;
24
+ /** The pointing ray of a controller or hand: its world position, along its -z. */
25
+ export declare function rayOf(source: Object3D): {
26
+ origin: Vector3;
27
+ direction: Vector3;
28
+ };
29
+ /** Listen for `select` on a three XR controller (a trigger or a hand pinch). */
30
+ export declare function attachController(root: Object3D, controller: Object3D, onHit: (h: Hit) => void): () => void;
31
+ /**
32
+ * Gaze with dwell: looking at one thing for `dwellMs` activates it. Returns a
33
+ * stepper to call each frame; its result is progress 0..1 for a reticle.
34
+ */
35
+ export declare class Gaze {
36
+ private readonly root;
37
+ private readonly camera;
38
+ private readonly dwellMs;
39
+ private readonly onHit;
40
+ private target;
41
+ private elapsed;
42
+ progress: number;
43
+ constructor(root: Object3D, camera: Camera, dwellMs: number, onHit: (h: Hit) => void);
44
+ update(dtMs: number): void;
45
+ }
46
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAyB,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEnF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,GAAI,SAAQ,WAAW;IACtC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAE5F;AAKD,wBAAgB,OAAO,CACrB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,OAAO,EAClB,SAAS,SAAK,GACb,GAAG,GAAG,IAAI,CAYZ;AAID,kFAAkF;AAClF,wBAAgB,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAO/E;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,EACd,UAAU,EAAE,QAAQ,EACpB,KAAK,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,GACtB,MAAM,IAAI,CAcZ;AAED;;;GAGG;AACH,qBAAa,IAAI;IAMb,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IARxB,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,OAAO,CAAK;IACb,QAAQ,SAAK;gBAGD,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI;IAGnC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAiBlC"}
package/dist/input.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Picking: a ray in, an interactive thing out. The host owns input — its
3
+ * controllers, hands, gaze and mouse — so this is only the part that knows
4
+ * which of OUR objects a ray hit.
5
+ *
6
+ * Anything a renderer wants tappable is marked with `interactive(obj, kind,
7
+ * activate)`; `pick` walks up from whatever mesh the ray struck to the first
8
+ * marked ancestor, so a renderer marks the root of its node and every child
9
+ * works. An override can opt out of the world's default tap by setting
10
+ * `userData.cl3Handled`.
11
+ */
12
+ import { Quaternion, Raycaster, Vector3 } from 'three';
13
+ export function interactive(obj, kind, activate) {
14
+ obj.userData['cl3'] = { kind, activate };
15
+ }
16
+ const marked = (o) => o.userData['cl3'];
17
+ export function pickRay(root, origin, direction, maxMetres = 10) {
18
+ const ray = new Raycaster(origin, direction.clone().normalize(), 0, maxMetres);
19
+ root.updateMatrixWorld(true);
20
+ for (const h of ray.intersectObject(root, true)) {
21
+ for (let o = h.object; o !== null; o = o.parent) {
22
+ const m = marked(o);
23
+ if (m !== undefined) {
24
+ return { ...m, object: o, distance: h.distance };
25
+ }
26
+ }
27
+ }
28
+ return null;
29
+ }
30
+ const FORWARD = new Vector3(0, 0, -1);
31
+ /** The pointing ray of a controller or hand: its world position, along its -z. */
32
+ export function rayOf(source) {
33
+ source.updateWorldMatrix(true, false);
34
+ const q = source.getWorldQuaternion(new Quaternion());
35
+ return {
36
+ origin: source.getWorldPosition(new Vector3()),
37
+ direction: FORWARD.clone().applyQuaternion(q),
38
+ };
39
+ }
40
+ /** Listen for `select` on a three XR controller (a trigger or a hand pinch). */
41
+ export function attachController(root, controller, onHit) {
42
+ const listener = () => {
43
+ const { origin, direction } = rayOf(controller);
44
+ const h = pickRay(root, origin, direction);
45
+ if (h !== null) {
46
+ onHit(h);
47
+ }
48
+ };
49
+ const c = controller;
50
+ c.addEventListener('select', listener);
51
+ return () => c.removeEventListener('select', listener);
52
+ }
53
+ /**
54
+ * Gaze with dwell: looking at one thing for `dwellMs` activates it. Returns a
55
+ * stepper to call each frame; its result is progress 0..1 for a reticle.
56
+ */
57
+ export class Gaze {
58
+ root;
59
+ camera;
60
+ dwellMs;
61
+ onHit;
62
+ target = null;
63
+ elapsed = 0;
64
+ progress = 0;
65
+ constructor(root, camera, dwellMs, onHit) {
66
+ this.root = root;
67
+ this.camera = camera;
68
+ this.dwellMs = dwellMs;
69
+ this.onHit = onHit;
70
+ }
71
+ update(dtMs) {
72
+ const { origin, direction } = rayOf(this.camera);
73
+ const h = pickRay(this.root, origin, direction);
74
+ if (h === null || h.object !== this.target) {
75
+ this.target = h?.object ?? null;
76
+ this.elapsed = 0;
77
+ this.progress = 0;
78
+ return;
79
+ }
80
+ this.elapsed += dtMs;
81
+ this.progress = Math.min(1, this.elapsed / this.dwellMs);
82
+ if (this.progress >= 1) {
83
+ this.elapsed = 0;
84
+ this.progress = 0;
85
+ this.onHit(h);
86
+ }
87
+ }
88
+ }
89
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Where a `card_grid` puts its cards — pure math, no three.js.
3
+ *
4
+ * Frame: the grid's own origin, the viewer standing at (0, 0, 0) looking down
5
+ * -z, +y up. A card's FRONT is its local +z, so `yaw` rotates it about y to
6
+ * face the viewer and `pitch` tips it onto its back (a table). The world
7
+ * parents the result wherever the resolved placement says; none of this knows
8
+ * about the scene it ends up in.
9
+ */
10
+ export declare const GRID_PLACEMENTS: readonly ["arc", "shelf", "wall", "table"];
11
+ export type GridPlacement = (typeof GRID_PLACEMENTS)[number];
12
+ /** `stand` objects need a pedestal, `hang` ones a hanger, `lay` ones a surface. */
13
+ export type Mount = 'stand' | 'hang' | 'lay';
14
+ export interface Pose {
15
+ readonly position: readonly [number, number, number];
16
+ readonly yaw: number;
17
+ readonly pitch: number;
18
+ }
19
+ export interface GridLayout {
20
+ readonly poses: readonly Pose[];
21
+ readonly mount: Mount;
22
+ }
23
+ export declare function layoutCards(placement: GridPlacement, count: number, spacing: number): GridLayout;
24
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,4CAA6C,CAAC;AAC1E,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,mFAAmF;AACnF,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7C,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACrD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAYD,wBAAgB,WAAW,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAiDhG"}
package/dist/layout.js ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Where a `card_grid` puts its cards — pure math, no three.js.
3
+ *
4
+ * Frame: the grid's own origin, the viewer standing at (0, 0, 0) looking down
5
+ * -z, +y up. A card's FRONT is its local +z, so `yaw` rotates it about y to
6
+ * face the viewer and `pitch` tips it onto its back (a table). The world
7
+ * parents the result wherever the resolved placement says; none of this knows
8
+ * about the scene it ends up in.
9
+ */
10
+ export const GRID_PLACEMENTS = ['arc', 'shelf', 'wall', 'table'];
11
+ const ARC_RADIUS = 1.2;
12
+ /** 160 degrees: past that the outer cards are behind the viewer's shoulders. */
13
+ const ARC_MAX_SPAN = (160 * Math.PI) / 180;
14
+ const SHELF_COLUMNS = 4;
15
+ const WALL_COLUMNS = 5;
16
+ const ROW_HEIGHT = 0.4;
17
+ /** Index `i` of `n` as an offset from the centre, in steps. */
18
+ const centred = (i, n) => i - (n - 1) / 2;
19
+ export function layoutCards(placement, count, spacing) {
20
+ const n = Math.max(0, Math.floor(count));
21
+ const poses = [];
22
+ if (placement === 'arc') {
23
+ // Widen the circle rather than overshoot the span, so spacing is honoured.
24
+ const radius = Math.max(ARC_RADIUS, n > 1 ? ((n - 1) * spacing) / ARC_MAX_SPAN : 0);
25
+ const step = spacing / radius;
26
+ for (let i = 0; i < n; i += 1) {
27
+ const a = centred(i, n) * step;
28
+ const x = radius * Math.sin(a);
29
+ const z = -radius * Math.cos(a);
30
+ poses.push({ position: [x, 0, z], yaw: Math.atan2(-x, -z), pitch: 0 });
31
+ }
32
+ return { poses, mount: 'stand' };
33
+ }
34
+ if (placement === 'table') {
35
+ // Flat on a surface below eye height, rows coming toward the viewer.
36
+ const cols = Math.max(1, Math.ceil(Math.sqrt(n)));
37
+ const rows = Math.ceil(n / cols);
38
+ for (let i = 0; i < n; i += 1) {
39
+ const c = i % cols;
40
+ const r = Math.floor(i / cols);
41
+ poses.push({
42
+ position: [
43
+ centred(c, Math.min(cols, n - r * cols)) * spacing,
44
+ -0.4,
45
+ -0.7 - (rows - 1 - r) * spacing,
46
+ ],
47
+ yaw: 0,
48
+ pitch: -Math.PI / 2,
49
+ });
50
+ }
51
+ return { poses, mount: 'lay' };
52
+ }
53
+ const cols = placement === 'shelf' ? SHELF_COLUMNS : WALL_COLUMNS;
54
+ const rows = Math.ceil(n / cols);
55
+ for (let i = 0; i < n; i += 1) {
56
+ const c = i % cols;
57
+ const r = Math.floor(i / cols);
58
+ const inRow = Math.min(cols, n - r * cols);
59
+ // A shelf fills from the bottom; a wall reads top-left to bottom-right.
60
+ const y = placement === 'shelf' ? r * ROW_HEIGHT : 0.3 + (rows - 1 - r) * ROW_HEIGHT;
61
+ poses.push({
62
+ position: [centred(c, inRow) * spacing, y, placement === 'shelf' ? -1.4 : -1.8],
63
+ yaw: 0,
64
+ pitch: 0,
65
+ });
66
+ }
67
+ return { poses, mount: placement === 'shelf' ? 'stand' : 'hang' };
68
+ }
69
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * glTF loading and the `anchor` a model asks for.
3
+ *
4
+ * Chatly references a model and never fetches, validates or sizes one, so
5
+ * this is where the host's world does: three's own GLTFLoader (imported
6
+ * lazily, so a conversation with no models never pays for it), the block's
7
+ * `scale` as a multiplier on the file's own size, and `anchor` as the named
8
+ * point of the model that sits at the placement's origin.
9
+ */
10
+ import { Box3, Group, Vector3, type AnimationClip, type Object3D } from 'three';
11
+ import { type VrmLike, type VrmModuleLoader } from './vrm.js';
12
+ export declare const MODEL_ANCHORS: readonly ["center", "base", "top", "back"];
13
+ export type ModelAnchor = (typeof MODEL_ANCHORS)[number];
14
+ export interface LoadedModel {
15
+ readonly scene: Object3D;
16
+ readonly animations: readonly AnimationClip[];
17
+ /** Present when the file was loaded through three-vrm. */
18
+ readonly vrm?: VrmLike | null;
19
+ }
20
+ /** `hint.format` is the avatar's declared format; a loader may use it to pick a plugin. */
21
+ export type ModelLoader = (url: string, hint?: {
22
+ format?: string;
23
+ }) => Promise<LoadedModel>;
24
+ interface GltfResult extends LoadedModel {
25
+ readonly userData?: Record<string, unknown>;
26
+ readonly parser?: {
27
+ json?: {
28
+ extensionsUsed?: unknown;
29
+ };
30
+ };
31
+ }
32
+ /** The slice of three's `GLTFLoader` used here. */
33
+ export interface GltfLoaderLike {
34
+ register(plugin: (parser: unknown) => unknown): unknown;
35
+ loadAsync(url: string): Promise<GltfResult>;
36
+ }
37
+ export interface GltfLoaderOptions {
38
+ /** `() => import('@pixiv/three-vrm')` — needed only to load VRM avatars through a bundler. */
39
+ readonly loadVrm?: VrmModuleLoader;
40
+ /** Test seam: a fresh loader. Defaults to three's own `GLTFLoader`, imported lazily. */
41
+ readonly createLoader?: () => Promise<GltfLoaderLike>;
42
+ }
43
+ /**
44
+ * three's GLTFLoader, plus VRM when the avatar is one: by its declared
45
+ * `format: 'vrm'`, or because the loaded file carries the VRM extension.
46
+ * `@pixiv/three-vrm` is only touched on those two paths; a plain glTF never
47
+ * asks for it.
48
+ */
49
+ export declare const gltfLoader: (opts?: GltfLoaderOptions) => ModelLoader;
50
+ /** Load each URL once; every caller gets its own clone, because a scene can have one parent. */
51
+ export declare const cachedLoader: (load: ModelLoader) => ModelLoader;
52
+ /** The translation that moves `anchor` of `box` to the origin. */
53
+ export declare function anchorOffset(box: Box3, anchor: ModelAnchor): Vector3;
54
+ /** Wrap a loaded scene so its scale and anchor are applied and the wrapper sits at the origin. */
55
+ export declare function fitModel(model: Object3D, scale?: number, anchor?: ModelAnchor): Group;
56
+ export {};
57
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEhF,OAAO,EAA2B,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAEvF,eAAO,MAAM,aAAa,4CAA6C,CAAC;AACxE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;IAC9C,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B;AACD,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAE5F,UAAU,UAAW,SAAQ,WAAW;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE;YAAE,cAAc,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC;CAC3D;AACD,mDAAmD;AACnD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC;IACxD,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,iBAAiB;IAChC,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC;IACnC,wFAAwF;IACxF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC;CACvD;AAOD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,UAAU,iBAAiB,KAAQ,WAwBzD,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,YAAY,SAAU,WAAW,KAAG,WAahD,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAWpE;AAED,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,SAAI,EAAE,MAAM,GAAE,WAAsB,GAAG,KAAK,CAS1F"}
package/dist/model.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * glTF loading and the `anchor` a model asks for.
3
+ *
4
+ * Chatly references a model and never fetches, validates or sizes one, so
5
+ * this is where the host's world does: three's own GLTFLoader (imported
6
+ * lazily, so a conversation with no models never pays for it), the block's
7
+ * `scale` as a multiplier on the file's own size, and `anchor` as the named
8
+ * point of the model that sits at the placement's origin.
9
+ */
10
+ import { Box3, Group, Vector3 } from 'three';
11
+ import { loadVrmModule, wantsVrm } from './vrm.js';
12
+ export const MODEL_ANCHORS = ['center', 'base', 'top', 'back'];
13
+ const threeLoader = async () => {
14
+ const { GLTFLoader } = await import('three/examples/jsm/loaders/GLTFLoader.js');
15
+ return new GLTFLoader();
16
+ };
17
+ /**
18
+ * three's GLTFLoader, plus VRM when the avatar is one: by its declared
19
+ * `format: 'vrm'`, or because the loaded file carries the VRM extension.
20
+ * `@pixiv/three-vrm` is only touched on those two paths; a plain glTF never
21
+ * asks for it.
22
+ */
23
+ export const gltfLoader = (opts = {}) => {
24
+ const create = opts.createLoader ?? threeLoader;
25
+ let plain = null;
26
+ const withVrm = async (url) => {
27
+ const mod = await loadVrmModule(opts.loadVrm);
28
+ const loader = await create();
29
+ loader.register((parser) => new mod.VRMLoaderPlugin(parser));
30
+ const gltf = await loader.loadAsync(url);
31
+ const vrm = (gltf.userData?.['vrm'] ?? null);
32
+ if (vrm === null) {
33
+ // Declared VRM but the file has no VRM data: it is a plain glTF after all.
34
+ return gltf;
35
+ }
36
+ mod.VRMUtils?.rotateVRM0?.(vrm); // VRM 0.x faces -Z; this turns it to +Z, and ignores 1.0
37
+ return { scene: vrm.scene, animations: gltf.animations, vrm };
38
+ };
39
+ return async (url, hint) => {
40
+ if (wantsVrm(hint?.format)) {
41
+ return withVrm(url);
42
+ }
43
+ plain ??= await create();
44
+ const gltf = await plain.loadAsync(url);
45
+ return wantsVrm(undefined, gltf) ? withVrm(url) : gltf;
46
+ };
47
+ };
48
+ /** Load each URL once; every caller gets its own clone, because a scene can have one parent. */
49
+ export const cachedLoader = (load) => {
50
+ const cache = new Map();
51
+ return async (url, hint) => {
52
+ let p = cache.get(url);
53
+ if (p === undefined) {
54
+ p = hint === undefined ? load(url) : load(url, hint);
55
+ cache.set(url, p);
56
+ // A failure is not cached: the next card gets a fresh attempt.
57
+ p.catch(() => cache.delete(url));
58
+ }
59
+ const m = await p;
60
+ return { scene: m.scene.clone(true), animations: m.animations };
61
+ };
62
+ };
63
+ /** The translation that moves `anchor` of `box` to the origin. */
64
+ export function anchorOffset(box, anchor) {
65
+ const c = box.getCenter(new Vector3());
66
+ const p = anchor === 'base'
67
+ ? new Vector3(c.x, box.min.y, c.z)
68
+ : anchor === 'top'
69
+ ? new Vector3(c.x, box.max.y, c.z)
70
+ : anchor === 'back'
71
+ ? new Vector3(c.x, c.y, box.min.z)
72
+ : c;
73
+ return p.negate();
74
+ }
75
+ /** Wrap a loaded scene so its scale and anchor are applied and the wrapper sits at the origin. */
76
+ export function fitModel(model, scale = 1, anchor = 'center') {
77
+ const inner = new Group();
78
+ inner.add(model);
79
+ inner.scale.setScalar(scale);
80
+ inner.updateMatrixWorld(true);
81
+ model.position.copy(anchorOffset(new Box3().setFromObject(inner), anchor).divideScalar(scale));
82
+ const outer = new Group();
83
+ outer.add(inner);
84
+ return outer;
85
+ }
86
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Entrance and pick animation, and the one switch that stops all of it.
3
+ *
4
+ * Reduced motion is a viewer's accessibility setting, so it is enforced HERE
5
+ * rather than asked of each caller: with it on, `run` applies the final frame
6
+ * synchronously and schedules nothing. A renderer that animates through this
7
+ * cannot forget to honour it.
8
+ */
9
+ import type { Object3D } from 'three';
10
+ export type Easing = (t: number) => number;
11
+ export declare const easeOut: Easing;
12
+ export declare class Motion {
13
+ private readonly tweens;
14
+ reduced: boolean;
15
+ constructor(reduced: boolean);
16
+ /** `apply(0..1)`; always ends with `apply(1)`. */
17
+ run(durationMs: number, apply: (t: number) => void): void;
18
+ update(dtMs: number): void;
19
+ get running(): number;
20
+ clear(): void;
21
+ }
22
+ /** Set opacity on every material under `obj`. Materials are made transparent first. */
23
+ export declare function setOpacity(obj: Object3D, k: number): void;
24
+ export type Entrance = 'fade' | 'scale' | 'slide' | 'none';
25
+ /** The theme's `motionEntrance` applied to a freshly built object. */
26
+ export declare function enter(motion: Motion, obj: Object3D, kind: Entrance, durationMs?: number): void;
27
+ //# sourceMappingURL=motion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"motion.d.ts","sourceRoot":"","sources":["../src/motion.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAC3C,eAAO,MAAM,OAAO,EAAE,MAAgC,CAAC;AAQvD,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IACpC,OAAO,EAAE,OAAO,CAAC;gBAEL,OAAO,EAAE,OAAO;IAInC,kDAAkD;IAC3C,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IASzD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAWjC,IAAW,OAAO,IAAI,MAAM,CAE3B;IAEM,KAAK,IAAI,IAAI;CAGrB;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAUzD;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D,sEAAsE;AACtE,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,SAAM,GAAG,IAAI,CAe3F"}