@doki-land/live2d 0.0.15 → 0.0.17

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/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  The public runtime facade for browser-native Live2D rendering.
4
4
 
5
- Use this package in browser games, game-engine integrations, interactive content, model tools, and custom webpage experiences. It composes the default loader, MOC runtimes, and rendering backends behind one small API.
5
+ Use this package in browser games, game-engine integrations, interactive content, model tools, and custom webpage
6
+ experiences. It composes the default loader, MOC runtimes, and rendering backends behind one small API.
6
7
 
7
8
  ## ✨ Features
8
9
 
@@ -24,19 +25,28 @@ pnpm add @doki-land/live2d
24
25
 
25
26
  The implementation packages are installed transitively. Most applications should not depend on them directly.
26
27
 
28
+ ## 🧭 Source Layout
29
+
30
+ ```text
31
+ src/facade/ createLive2D() — default stage + single actor
32
+ src/motion/ motion3 parse, curves, MotionPlayer
33
+ src/stage/ Live2dStage, actors, asset registry, transforms
34
+ src/reexports/ optional subpath exports for core / loader / renderer
35
+ ```
36
+
27
37
  ## 🚀 Quick Start
28
38
 
29
39
  ```ts
30
- import { createLive2D } from "@doki-land/live2d";
40
+ import {createLive2D} from "@doki-land/live2d";
31
41
 
32
42
  const canvas = document.querySelector<HTMLCanvasElement>("#live2d");
33
43
 
34
44
  if (!canvas) {
35
- throw new Error("Missing Live2D canvas");
45
+ throw new Error("Missing Live2D canvas");
36
46
  }
37
47
 
38
48
  const runtime = createLive2D({
39
- prefer: ["webgpu", "webgl2", "canvas2d"],
49
+ prefer: ["webgpu", "webgl2", "canvas2d"],
40
50
  });
41
51
 
42
52
  runtime.mount(canvas);
@@ -45,9 +55,9 @@ await runtime.loadModel("/models/character.model3.json");
45
55
  let previous = performance.now();
46
56
 
47
57
  function frame(now: number) {
48
- runtime.update((now - previous) / 1000);
49
- previous = now;
50
- requestAnimationFrame(frame);
58
+ runtime.update((now - previous) / 1000);
59
+ previous = now;
60
+ requestAnimationFrame(frame);
51
61
  }
52
62
 
53
63
  requestAnimationFrame(frame);
@@ -59,11 +69,12 @@ The runtime does not require ownership of `requestAnimationFrame`. Drive it from
59
69
 
60
70
  ```ts
61
71
  engine.onUpdate((deltaTime) => {
62
- runtime.update(deltaTime);
72
+ runtime.update(deltaTime);
63
73
  });
64
74
  ```
65
75
 
66
- The delta is expressed in seconds. Keep the value bounded after tab suspension or long pauses to avoid unstable animation and physics once those systems are enabled.
76
+ The delta is expressed in seconds. Keep the value bounded after tab suspension or long pauses to avoid unstable
77
+ animation and physics once those systems are enabled.
67
78
 
68
79
  ## 📥 Loading Models
69
80
 
@@ -71,19 +82,19 @@ The delta is expressed in seconds. Keep the value bounded after tab suspension o
71
82
  await runtime.loadModel("/models/actor.model3.json");
72
83
 
73
84
  await runtime.loadModel(
74
- "https://cdn.example.com/models/actor.model3.json",
85
+ "https://cdn.example.com/models/actor.model3.json",
75
86
  );
76
87
 
77
88
  await runtime.loadModel(
78
- "npm:live2d-widget-model-hijiki@1.0.5/assets/hijiki.model.json",
89
+ "npm:live2d-widget-model-hijiki@1.0.5/assets/hijiki.model.json",
79
90
  );
80
91
  ```
81
92
 
82
93
  Listen for progress when presenting a loading interface:
83
94
 
84
95
  ```ts
85
- runtime.events.on("progress", ({ stage, progress, detail }) => {
86
- console.log(stage, Math.round(progress * 100), detail);
96
+ runtime.events.on("progress", ({stage, progress, detail}) => {
97
+ console.log(stage, Math.round(progress * 100), detail);
87
98
  });
88
99
  ```
89
100
 
@@ -95,8 +106,8 @@ Remote servers must allow cross-origin access to settings, model binaries, and t
95
106
  runtime.setParameter("PARAM_ANGLE_X", 15);
96
107
 
97
108
  const angleX = runtime
98
- .listParameters()
99
- .find((parameter) => parameter.id === "PARAM_ANGLE_X");
109
+ .listParameters()
110
+ .find((parameter) => parameter.id === "PARAM_ANGLE_X");
100
111
 
101
112
  console.log(angleX);
102
113
  ```
@@ -111,27 +122,29 @@ Parameter availability and ranges belong to the loaded model. Do not assume ever
111
122
  const area = runtime.hitTest(modelX, modelY);
112
123
 
113
124
  if (area) {
114
- console.log("Hit", area);
125
+ console.log("Hit", area);
115
126
  }
116
127
  ```
117
128
 
118
- Current fallback hit testing can identify visible drawables. Semantic names such as `Head` or `Body` require corresponding model metadata and runtime support.
129
+ Current fallback hit testing can identify visible drawables. Semantic names such as `Head` or `Body` require
130
+ corresponding model metadata and runtime support.
119
131
 
120
132
  ## 📊 Frame Profiling
121
133
 
122
134
  ```ts
123
135
  runtime.events.on("profile", (profile) => {
124
- console.log({
125
- fps: profile.fpsSmooth,
126
- frameMs: profile.frameMs,
127
- evaluateMs: profile.evaluateMs,
128
- drawMs: profile.drawMs,
129
- drawables: profile.drawableCount,
130
- });
136
+ console.log({
137
+ fps: profile.fpsSmooth,
138
+ frameMs: profile.frameMs,
139
+ evaluateMs: profile.evaluateMs,
140
+ drawMs: profile.drawMs,
141
+ drawables: profile.drawableCount,
142
+ });
131
143
  });
132
144
  ```
133
145
 
134
- These timings are runtime-side measurements. Use browser GPU profiling when diagnosing shader, mask, upload, or device scheduling costs.
146
+ These timings are runtime-side measurements. Use browser GPU profiling when diagnosing shader, mask, upload, or device
147
+ scheduling costs.
135
148
 
136
149
  ## 🧩 Custom Pipeline
137
150
 
@@ -139,12 +152,13 @@ Advanced applications can provide a renderer or model backends:
139
152
 
140
153
  ```ts
141
154
  const runtime = createLive2D({
142
- renderer: customRenderer,
143
- backends: [customBackend],
155
+ renderer: customRenderer,
156
+ backends: [customBackend],
144
157
  });
145
158
  ```
146
159
 
147
- Custom implementations must preserve the contracts exported by the renderer package. Avoid moving format or renderer logic into application adapters.
160
+ Custom implementations must preserve the contracts exported by the renderer package. Avoid moving format or renderer
161
+ logic into application adapters.
148
162
 
149
163
  ## 🧹 Lifecycle
150
164
 
@@ -152,7 +166,8 @@ Custom implementations must preserve the contracts exported by the renderer pack
152
166
  runtime.destroy();
153
167
  ```
154
168
 
155
- Destroy the runtime when its canvas or host scene is permanently removed. This releases model state, textures, draw passes, event listeners owned by the runtime, and graphics resources owned by the selected renderer.
169
+ Destroy the runtime when its canvas or host scene is permanently removed. This releases model state, textures, draw
170
+ passes, event listeners owned by the runtime, and graphics resources owned by the selected renderer.
156
171
 
157
172
  ## ⚡ Performance Notes
158
173
 
@@ -160,7 +175,8 @@ Destroy the runtime when its canvas or host scene is permanently removed. This r
160
175
  - Keep canvas backing dimensions intentional; CSS size alone does not limit GPU pixel work.
161
176
  - Prefer an engine-owned loop when integrating with a game.
162
177
  - Avoid repeatedly enumerating parameters in a hot loop.
163
- - Measure the complete frame path before attributing a bottleneck to TypeScript, WebAssembly, or a specific graphics API.
178
+ - Measure the complete frame path before attributing a bottleneck to TypeScript, WebAssembly, or a specific graphics
179
+ API.
164
180
 
165
181
  ## 🧪 Development
166
182
 
@@ -171,12 +187,38 @@ pnpm typecheck
171
187
  pnpm --filter @doki-land/live2d build
172
188
  ```
173
189
 
174
- Changes to the facade should include tests for state transitions, cancellation, events, and resource cleanup where applicable.
190
+ Changes to the facade should include tests for state transitions, cancellation, events, and resource cleanup where
191
+ applicable.
175
192
 
176
193
  ## 🤝 Contributing
177
194
 
178
- Keep the facade small. Model-format behavior belongs in `@doki-land/live2d-renderer`, source resolution belongs in `@doki-land/live2d-loader`, and webpage chrome belongs in `@doki-land/live2d-widget`.
195
+ ### Package ownership
196
+
197
+ - Keep the facade small and host-independent.
198
+ - Put model-format behavior in `@doki-land/live2d-renderer`.
199
+ - Put source resolution in `@doki-land/live2d-loader`.
200
+ - Put webpage chrome in `@doki-land/live2d-widget`.
201
+ - Include tests for state transitions, cancellation, events, and resource cleanup where applicable.
179
202
 
180
203
  ## 📄 License
181
204
 
182
- See the repository license. Model and artwork licenses are separate from the runtime license.
205
+ ### Implementation independence
206
+
207
+ - This package composes an independently developed clean-room runtime.
208
+ - It does not load, link against, wrap, translate, port, or derive its implementation from an official Cubism SDK or
209
+ Core binary.
210
+ - Compatible model support is an interoperability goal, not evidence of a shared implementation, endorsement,
211
+ affiliation, sponsorship, or employment relationship.
212
+ - The project and its contributors are independent and do not act on behalf of the official Cubism SDK vendor.
213
+
214
+ ### Contribution boundary
215
+
216
+ - Do not submit official SDK or shader source, disassembly-derived code, mechanically translated implementation code, or
217
+ changes that require an official runtime.
218
+ - Support compatibility-sensitive work with public format facts, neutral fixtures, reproducible independent
219
+ observations, or independently authored technical rationale.
220
+
221
+ ### Terms
222
+
223
+ - See the repository license for source-code terms.
224
+ - Model and artwork licenses are separate from the runtime license.
package/dist/index.d.ts CHANGED
@@ -367,11 +367,11 @@ interface Live2DRuntime extends Live2DSession {
367
367
  declare function createLive2D(options?: CreateLive2DOptions): Live2DRuntime;
368
368
 
369
369
  /**
370
- * Map canvas focus (-1..1, Y-up) onto standard Cubism drag parameters.
370
+ * Map canvas focus (-1..1, Y-up) onto commonly used model parameter IDs.
371
371
  *
372
- * Matches the Cubism sample / community widget weights:
373
- * ANGLE_X/Y full range, ANGLE_Z = -dragX*dragY, BODY_ANGLE_X, EYE_BALL_*.
374
- * Missing ids on a given model are skipped.
372
+ * ANGLE_X/Y use the full declared range, ANGLE_Z combines both axes, and body
373
+ * and eye parameters receive the corresponding normalized axis. Parameters not
374
+ * declared by a model are skipped.
375
375
  */
376
376
  declare function focusParameterUpdates(parameters: readonly ParameterBinding[], dragX: number, dragY: number): Array<{
377
377
  id: string;
@@ -381,6 +381,12 @@ declare function focusParameterUpdates(parameters: readonly ParameterBinding[],
381
381
  /**
382
382
  * `@doki-land/live2d` — public facade.
383
383
  *
384
+ * Layout:
385
+ * - `facade/` — `createLive2D()` default stage + actor entry
386
+ * - `motion/` — motion3 parse + playback
387
+ * - `stage/` — multi-actor stage, assets, transforms
388
+ * - `reexports/` — optional subpath `@doki-land/live2d/{core,loader,renderer}`
389
+ *
384
390
  * ```ts
385
391
  * import { createLive2D } from "@doki-land/live2d";
386
392
  * ```
package/dist/index.js CHANGED
@@ -20,14 +20,14 @@ import {
20
20
  serializeCpuProgram
21
21
  } from "@doki-land/live2d-renderer";
22
22
 
23
- // src/create-live2d.ts
23
+ // src/facade/create-live2d.ts
24
24
  import {
25
25
  createMoc2Backend as createMoc2Backend2,
26
26
  createMoc3Backend as createMoc3Backend2,
27
27
  createRenderer as createRenderer2
28
28
  } from "@doki-land/live2d-renderer";
29
29
 
30
- // src/focus.ts
30
+ // src/stage/assets/focus.ts
31
31
  function focusParameterUpdates(parameters, dragX, dragY) {
32
32
  const byId = new Map(parameters.map((p) => [p.id, p]));
33
33
  const x = clampUnit(dragX);
@@ -1195,7 +1195,7 @@ import {
1195
1195
  selectModelBackend
1196
1196
  } from "@doki-land/live2d-renderer";
1197
1197
 
1198
- // src/load-textures.ts
1198
+ // src/stage/assets/load-textures.ts
1199
1199
  function guessMime(path) {
1200
1200
  const lower = path.toLowerCase();
1201
1201
  if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
@@ -1816,7 +1816,7 @@ function createLive2dStage(options) {
1816
1816
  return new Live2dStageImpl(options);
1817
1817
  }
1818
1818
 
1819
- // src/create-live2d.ts
1819
+ // src/facade/create-live2d.ts
1820
1820
  function createLive2D(options = {}) {
1821
1821
  const backends = options.backends ?? [
1822
1822
  createMoc2Backend2(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doki-land/live2d",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "Live2D in the browser — load moc2/moc3 models, Stage + multi-actor, motion; WebGPU/WebGL2/Canvas2D. Main entry for live2d.ts.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -59,9 +59,9 @@
59
59
  "test": "vitest run --passWithNoTests"
60
60
  },
61
61
  "dependencies": {
62
- "@doki-land/live2d-core": "0.0.15",
63
- "@doki-land/live2d-loader": "0.0.15",
64
- "@doki-land/live2d-renderer": "0.0.15"
62
+ "@doki-land/live2d-core": "0.0.17",
63
+ "@doki-land/live2d-loader": "0.0.17",
64
+ "@doki-land/live2d-renderer": "0.0.17"
65
65
  },
66
66
  "sideEffects": false
67
67
  }
@@ -3,22 +3,22 @@ import {
3
3
  createMoc3Backend,
4
4
  createRenderer,
5
5
  } from "@doki-land/live2d-renderer";
6
- import { allocateActorId } from "./stage/actor.js";
6
+ import { allocateActorId } from "../stage/actor.js";
7
7
  import {
8
8
  type CreateLive2DOptions,
9
9
  createSingleActorFacade,
10
10
  type Live2DRuntime,
11
- } from "./stage/single-facade.js";
12
- import { createLive2dStage } from "./stage/stage.js";
11
+ } from "../stage/single-facade.js";
12
+ import { createLive2dStage } from "../stage/stage.js";
13
13
 
14
14
  export type {
15
15
  CreateLive2DOptions,
16
16
  Live2DRuntime,
17
- } from "./stage/single-facade.js";
17
+ } from "../stage/single-facade.js";
18
18
  export {
19
19
  MotionPriority,
20
20
  type PlayMotionOptions,
21
- } from "./stage/single-facade.js";
21
+ } from "../stage/single-facade.js";
22
22
 
23
23
  /** Wire moc backends and a renderer into one single-actor session. */
24
24
  export function createLive2D(options: CreateLive2DOptions = {}): Live2DRuntime {
@@ -31,9 +31,9 @@ export function createLive2D(options: CreateLive2DOptions = {}): Live2DRuntime {
31
31
  renderer:
32
32
  options.renderer ?? createRenderer({ prefer: options.prefer }),
33
33
  updateMode: options.updateMode ?? "manual",
34
- }) as import("./stage/stage.js").Live2dStageImpl;
34
+ }) as import("../stage/stage.js").Live2dStageImpl;
35
35
  const actor = stage.createActor({
36
36
  id: allocateActorId("default"),
37
- }) as import("./stage/actor.js").Live2dActorImpl;
37
+ }) as import("../stage/actor.js").Live2dActorImpl;
38
38
  return createSingleActorFacade(stage, actor, backends);
39
39
  }
package/src/index.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  /**
2
2
  * `@doki-land/live2d` — public facade.
3
3
  *
4
+ * Layout:
5
+ * - `facade/` — `createLive2D()` default stage + actor entry
6
+ * - `motion/` — motion3 parse + playback
7
+ * - `stage/` — multi-actor stage, assets, transforms
8
+ * - `reexports/` — optional subpath `@doki-land/live2d/{core,loader,renderer}`
9
+ *
4
10
  * ```ts
5
11
  * import { createLive2D } from "@doki-land/live2d";
6
12
  * ```
@@ -66,8 +72,8 @@ export {
66
72
  type Live2DRuntime,
67
73
  MotionPriority,
68
74
  type PlayMotionOptions,
69
- } from "./create-live2d.js";
70
- export { focusParameterUpdates } from "./focus.js";
75
+ } from "./facade/create-live2d.js";
76
+ export { focusParameterUpdates } from "./stage/assets/focus.js";
71
77
  export {
72
78
  blendMotionLayers,
73
79
  evaluateCurve,
@@ -8,7 +8,7 @@ import type {
8
8
  PlayMotionActorOptions,
9
9
  } from "@doki-land/live2d-core";
10
10
  import type { DrawableMesh, Renderer } from "@doki-land/live2d-renderer";
11
- import { focusParameterUpdates } from "../focus.js";
11
+ import { focusParameterUpdates } from "./assets/focus.js";
12
12
  import type { PlayMotionOptions } from "../motion/index.js";
13
13
  import { ActorModelSlot } from "./actor-model-slot.js";
14
14
  import type { ModelAssetRegistry } from "./model-asset-registry.js";
@@ -1,11 +1,11 @@
1
1
  import type { ParameterBinding } from "@doki-land/live2d-renderer";
2
2
 
3
3
  /**
4
- * Map canvas focus (-1..1, Y-up) onto standard Cubism drag parameters.
4
+ * Map canvas focus (-1..1, Y-up) onto commonly used model parameter IDs.
5
5
  *
6
- * Matches the Cubism sample / community widget weights:
7
- * ANGLE_X/Y full range, ANGLE_Z = -dragX*dragY, BODY_ANGLE_X, EYE_BALL_*.
8
- * Missing ids on a given model are skipped.
6
+ * ANGLE_X/Y use the full declared range, ANGLE_Z combines both axes, and body
7
+ * and eye parameters receive the corresponding normalized axis. Parameters not
8
+ * declared by a model are skipped.
9
9
  */
10
10
  export function focusParameterUpdates(
11
11
  parameters: readonly ParameterBinding[],
@@ -26,8 +26,7 @@ export function focusParameterUpdates(
26
26
  set("PARAM_ANGLE_X", x);
27
27
  set("PARAM_ANGLE_Y", y);
28
28
  set("PARAM_ANGLE_Z", clampUnit(x * y * -1));
29
- // Official sample uses dragX*10 vs ANGLE's *30; BODY range is typically ±10,
30
- // so full-range normalized drag still matches that relative weight.
29
+ // Each binding maps normalized input through its own declared range.
31
30
  set("PARAM_BODY_ANGLE_X", x);
32
31
  set("PARAM_BODY_ANGLE_Y", y);
33
32
  set("PARAM_EYE_BALL_X", x);
@@ -23,7 +23,7 @@ import {
23
23
  compileSharedModelCompile,
24
24
  selectModelBackend,
25
25
  } from "@doki-land/live2d-renderer";
26
- import { loadTextureData, releaseTextureData } from "../load-textures.js";
26
+ import { loadTextureData, releaseTextureData } from "./assets/load-textures.js";
27
27
  import type { Motion3Clip } from "../motion/index.js";
28
28
  import { resolveModelAssetKey } from "./model-asset-key.js";
29
29