@caperjs/plugin-3d 0.0.0-stage → 0.8.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/README.md +190 -2
- package/lib/Entity3D.d.ts +28 -0
- package/lib/Entity3D.d.ts.map +1 -0
- package/lib/Model.d.ts +13 -0
- package/lib/Model.d.ts.map +1 -0
- package/lib/Plugin3D.d.ts +20 -0
- package/lib/Plugin3D.d.ts.map +1 -0
- package/lib/View3D.d.ts +58 -0
- package/lib/View3D.d.ts.map +1 -0
- package/lib/caper-plugin-3d.mjs +396 -0
- package/lib/caper-plugin-3d.mjs.map +1 -0
- package/lib/factory3d.d.ts +34 -0
- package/lib/factory3d.d.ts.map +1 -0
- package/lib/fit.d.ts +7 -0
- package/lib/fit.d.ts.map +1 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/owned.d.ts +22 -0
- package/lib/owned.d.ts.map +1 -0
- package/lib/props.d.ts +60 -0
- package/lib/props.d.ts.map +1 -0
- package/lib/quality.d.ts +9 -0
- package/lib/quality.d.ts.map +1 -0
- package/lib/renderer.d.ts +2 -0
- package/lib/renderer.d.ts.map +1 -0
- package/lib/version.d.ts +2 -0
- package/lib/version.d.ts.map +1 -0
- package/package.json +46 -3
- package/src/Entity3D.ts +72 -0
- package/src/Model.ts +73 -0
- package/src/Plugin3D.ts +35 -0
- package/src/View3D.ts +173 -0
- package/src/factory3d.ts +188 -0
- package/src/fit.ts +10 -0
- package/src/index.ts +13 -0
- package/src/owned.ts +42 -0
- package/src/props.ts +96 -0
- package/src/quality.ts +12 -0
- package/src/renderer.ts +22 -0
- package/src/version.ts +1 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { Application as e, Plugin as t, WithLifecycle as n, WithSignals as r, bindAllMethods as i, getEntityCtor as a, getRegisteredEntityIds as o, isMobile as s, registerFactoryMethods as c } from "@caperjs/core";
|
|
2
|
+
import { AmbientLight as l, Camera3D as u, Container3D as d, CubeGeometry as f, CylinderGeometry as p, DirectionalLight as m, Material3D as h, Mesh3D as g, Model3D as _, PlaneGeometry as v, PointLight as y, SphereGeometry as b, SpotLight as x, Vector3 as S, View3D as C } from "@pixi/3d";
|
|
3
|
+
import { Assets as w, Point as T } from "pixi.js";
|
|
4
|
+
//#region src/fit.ts
|
|
5
|
+
function E(e, t, n) {
|
|
6
|
+
if (!n || !(t > 0) || t >= n) return e;
|
|
7
|
+
let r = Math.tan(e * Math.PI / 360);
|
|
8
|
+
return 2 * Math.atan(r * n / t) * 180 / Math.PI;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/Model.ts
|
|
12
|
+
var D = class extends _ {
|
|
13
|
+
play(e, t = {}) {
|
|
14
|
+
let n = this.player;
|
|
15
|
+
if (!n || !n.animationLabels.includes(e)) throw Error(`Animation '${e}' is unavailable; available clips: ${n?.animationLabels.join(", ") || "(none)"}.`);
|
|
16
|
+
let r = n.getState(e), i = this.transition;
|
|
17
|
+
if (t.layer) i && (i.outgoing = i.outgoing.filter((e) => e.state !== r));
|
|
18
|
+
else {
|
|
19
|
+
for (let { state: e } of i?.outgoing ?? []) e.onComplete = e.onLoop = null, e.stop();
|
|
20
|
+
this.transition = void 0;
|
|
21
|
+
}
|
|
22
|
+
let a = t.layer ? [] : n.animationLabels.map((e) => n.getState(e)).filter((e) => e !== r && e.playing);
|
|
23
|
+
for (let e of a) e.onComplete = e.onLoop = null;
|
|
24
|
+
let { fade: o = 0, layer: s, ...c } = t;
|
|
25
|
+
if (Object.assign(r, {
|
|
26
|
+
loop: !0,
|
|
27
|
+
animationSpeed: 1,
|
|
28
|
+
weight: 1,
|
|
29
|
+
onComplete: null,
|
|
30
|
+
onLoop: null
|
|
31
|
+
}, c), o > 0 && a.length) this.transition = {
|
|
32
|
+
elapsed: 0,
|
|
33
|
+
duration: o,
|
|
34
|
+
incoming: r,
|
|
35
|
+
weight: r.weight,
|
|
36
|
+
outgoing: a.map((e) => ({
|
|
37
|
+
state: e,
|
|
38
|
+
weight: e.weight
|
|
39
|
+
}))
|
|
40
|
+
}, r.weight = 0;
|
|
41
|
+
else for (let e of a) e.stop();
|
|
42
|
+
return r.gotoAndPlay(0), r;
|
|
43
|
+
}
|
|
44
|
+
stop() {
|
|
45
|
+
this.transition = void 0, this.player?.stop();
|
|
46
|
+
}
|
|
47
|
+
update(e) {
|
|
48
|
+
let t = this.transition;
|
|
49
|
+
if (t) {
|
|
50
|
+
t.elapsed = Math.min(t.duration, t.elapsed + e.deltaMS / 1e3);
|
|
51
|
+
let n = t.elapsed / t.duration;
|
|
52
|
+
t.incoming.weight = t.weight * n;
|
|
53
|
+
for (let { state: e, weight: r } of t.outgoing) e.weight = r * (1 - n), n === 1 && e.stop();
|
|
54
|
+
n === 1 && (this.transition = void 0);
|
|
55
|
+
}
|
|
56
|
+
this.player?.update(e);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/props.ts
|
|
61
|
+
function O(e) {
|
|
62
|
+
return Array.isArray(e) ? {
|
|
63
|
+
x: e[0],
|
|
64
|
+
y: e[1],
|
|
65
|
+
z: e[2]
|
|
66
|
+
} : e;
|
|
67
|
+
}
|
|
68
|
+
function k(e) {
|
|
69
|
+
let t = { ...e };
|
|
70
|
+
delete t.lookAt;
|
|
71
|
+
for (let e of [
|
|
72
|
+
"position",
|
|
73
|
+
"rotation",
|
|
74
|
+
"scale"
|
|
75
|
+
]) {
|
|
76
|
+
let n = t[e];
|
|
77
|
+
Array.isArray(n) && (t[e] = O(n));
|
|
78
|
+
}
|
|
79
|
+
return t;
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/factory3d.ts
|
|
83
|
+
var A = {
|
|
84
|
+
container: !0,
|
|
85
|
+
mesh: !0,
|
|
86
|
+
material: !0,
|
|
87
|
+
entity: !0,
|
|
88
|
+
model: !0,
|
|
89
|
+
light: !0,
|
|
90
|
+
camera: !0,
|
|
91
|
+
existing: !0
|
|
92
|
+
}, j = /* @__PURE__ */ new Map();
|
|
93
|
+
function M(e) {
|
|
94
|
+
let t = Object.entries(e);
|
|
95
|
+
for (let [e, n] of t) {
|
|
96
|
+
if (Object.hasOwn(A, e)) throw Error(`[caper] registerFactory3DMethods: "${e}" is a built-in 3D factory method and cannot be replaced. Pick another name.`);
|
|
97
|
+
if (typeof n != "function") throw Error(`[caper] registerFactory3DMethods: "${e}" must be a function.`);
|
|
98
|
+
let t = j.get(e);
|
|
99
|
+
if (t && t !== n) throw Error(`[caper] registerFactory3DMethods: "${e}" is already registered (by function "${t.name || "anonymous"}"); cannot register function "${n.name || "anonymous"}" under the same name.`);
|
|
100
|
+
}
|
|
101
|
+
let n = t.filter(([e]) => !j.has(e));
|
|
102
|
+
for (let [e, t] of n) j.set(e, t);
|
|
103
|
+
return () => {
|
|
104
|
+
for (let [e, t] of n) j.get(e) === t && j.delete(e);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
var N = {
|
|
108
|
+
box: () => new f(),
|
|
109
|
+
cylinder: () => new p({
|
|
110
|
+
radiusTop: .5,
|
|
111
|
+
radiusBottom: .5,
|
|
112
|
+
height: 1
|
|
113
|
+
}),
|
|
114
|
+
plane: () => new v(),
|
|
115
|
+
sphere: () => new b({ radius: .5 })
|
|
116
|
+
}, P = [
|
|
117
|
+
"position",
|
|
118
|
+
"rotation",
|
|
119
|
+
"scale",
|
|
120
|
+
"x",
|
|
121
|
+
"y",
|
|
122
|
+
"z",
|
|
123
|
+
"visible",
|
|
124
|
+
"lookAt",
|
|
125
|
+
"parent"
|
|
126
|
+
], F = {
|
|
127
|
+
directional: m,
|
|
128
|
+
point: y,
|
|
129
|
+
spot: x,
|
|
130
|
+
ambient: l
|
|
131
|
+
};
|
|
132
|
+
function I(e, t, n, r) {
|
|
133
|
+
let i = (t) => {
|
|
134
|
+
let r = k(t);
|
|
135
|
+
return n && !r.parent ? {
|
|
136
|
+
...r,
|
|
137
|
+
parent: e
|
|
138
|
+
} : r;
|
|
139
|
+
}, s = (e, t) => (t.lookAt && e.lookAt(O(t.lookAt)), e), c = (t, r = {}) => {
|
|
140
|
+
let { parent: i = e, ...a } = k(r);
|
|
141
|
+
return Object.assign(t, a), n && i.addChild(t), s(t, r);
|
|
142
|
+
}, l = {
|
|
143
|
+
container(e = {}) {
|
|
144
|
+
return s(new d(i(e)), e);
|
|
145
|
+
},
|
|
146
|
+
material(e = {}) {
|
|
147
|
+
let { color: n, ...r } = e;
|
|
148
|
+
return t.material(new h(n === void 0 ? r : {
|
|
149
|
+
baseColor: n,
|
|
150
|
+
...r
|
|
151
|
+
}));
|
|
152
|
+
},
|
|
153
|
+
entity(e, t) {
|
|
154
|
+
let n = a(e);
|
|
155
|
+
if (!n) {
|
|
156
|
+
let t = o();
|
|
157
|
+
throw Error(`Unknown entity id '${e}'. Known: ${t.length ? t.map((e) => `'${e}'`).join(", ") : "(none)"}`);
|
|
158
|
+
}
|
|
159
|
+
if (!(n.prototype instanceof d)) throw Error(`Entity '${e}' is not a 3D entity (its class does not extend Container3D). Use this.add.entity for 2D entities.`);
|
|
160
|
+
return c(new n(t), Object.fromEntries(P.filter((e) => t && e in t).map((e) => [e, t[e]])));
|
|
161
|
+
},
|
|
162
|
+
mesh(e = {}) {
|
|
163
|
+
let { geometry: n = "box", material: r, color: a, roughness: o, metallic: c, ...l } = e, u;
|
|
164
|
+
if (typeof n != "string") u = n;
|
|
165
|
+
else if (n in N) u = t.geometry(n, N[n]);
|
|
166
|
+
else throw Error(`Unknown 3D geometry '${n}'. Use box, plane, sphere, or cylinder.`);
|
|
167
|
+
let d = r ?? t.material(new h({
|
|
168
|
+
baseColor: a ?? 16777215,
|
|
169
|
+
...o !== void 0 && { roughness: o },
|
|
170
|
+
...c !== void 0 && { metallic: c }
|
|
171
|
+
}));
|
|
172
|
+
return s(new g({
|
|
173
|
+
...i(l),
|
|
174
|
+
geometry: u,
|
|
175
|
+
material: d
|
|
176
|
+
}), e);
|
|
177
|
+
},
|
|
178
|
+
model(e) {
|
|
179
|
+
let { asset: n, ...r } = e, a = typeof n == "string" ? w.get(n) : n;
|
|
180
|
+
if (!a) throw Error(`Model asset '${n}' is not loaded. Add its bundle to the scene's assets.preload.`);
|
|
181
|
+
let o = s(new D({
|
|
182
|
+
...i(r),
|
|
183
|
+
source: a,
|
|
184
|
+
autoUpdate: !1
|
|
185
|
+
}), e);
|
|
186
|
+
return o.player && t.player(o), o;
|
|
187
|
+
},
|
|
188
|
+
light(e = {}) {
|
|
189
|
+
let { type: t = "directional", ...n } = e, r = i(n);
|
|
190
|
+
return t === "directional" && !e.rotation && !e.quaternion && !e.lookAt && (r.rotation = {
|
|
191
|
+
x: -Math.PI / 4,
|
|
192
|
+
y: Math.PI / 6,
|
|
193
|
+
z: 0
|
|
194
|
+
}), s(new F[t](r), e);
|
|
195
|
+
},
|
|
196
|
+
camera(e = {}) {
|
|
197
|
+
return s(new u(i(e)), e);
|
|
198
|
+
},
|
|
199
|
+
existing: c
|
|
200
|
+
}, f = Object.fromEntries([...j].map(([e, t]) => [e, (...e) => t(r, ...e)]));
|
|
201
|
+
return Object.assign(l, f);
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/owned.ts
|
|
205
|
+
var L = /* @__PURE__ */ new WeakMap(), R = class {
|
|
206
|
+
constructor() {
|
|
207
|
+
this.geometries = /* @__PURE__ */ new Map(), this.materials = /* @__PURE__ */ new Set(), this.players = /* @__PURE__ */ new Set();
|
|
208
|
+
}
|
|
209
|
+
geometry(e, t) {
|
|
210
|
+
return this.geometries.has(e) || this.geometries.set(e, t()), this.geometries.get(e);
|
|
211
|
+
}
|
|
212
|
+
material(e) {
|
|
213
|
+
return this.materials.add(e), e;
|
|
214
|
+
}
|
|
215
|
+
player(e) {
|
|
216
|
+
return this.players.add(e), e;
|
|
217
|
+
}
|
|
218
|
+
update(e) {
|
|
219
|
+
for (let t of this.players) t.destroyed ? this.players.delete(t) : t.update(e);
|
|
220
|
+
}
|
|
221
|
+
destroy() {
|
|
222
|
+
for (let e of [...this.geometries.values(), ...this.materials]) e.destroy();
|
|
223
|
+
this.geometries.clear(), this.materials.clear(), this.players.clear();
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/quality.ts
|
|
228
|
+
function z(e, t) {
|
|
229
|
+
return e === "high" ? {
|
|
230
|
+
shadowQuality: "high",
|
|
231
|
+
resolution: "inherit"
|
|
232
|
+
} : e === "low" ? {
|
|
233
|
+
shadowQuality: "low",
|
|
234
|
+
resolution: Math.min(t.resolution, 1)
|
|
235
|
+
} : t.isMobile ? {
|
|
236
|
+
shadowQuality: "low",
|
|
237
|
+
resolution: Math.min(t.resolution, 2)
|
|
238
|
+
} : {
|
|
239
|
+
shadowQuality: "medium",
|
|
240
|
+
resolution: "inherit"
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/renderer.ts
|
|
245
|
+
function B(e) {
|
|
246
|
+
let t = e;
|
|
247
|
+
if (!t) throw Error("[@caperjs/plugin-3d] No renderer is available. Create the renderer before a 3D view.");
|
|
248
|
+
if (t.name === "canvas") throw Error("[@caperjs/plugin-3d] Canvas renderer cannot draw 3D. Use WebGL2 or WebGPU.");
|
|
249
|
+
if (t.name === "webgl" && typeof (t.gl ?? t.context?.gl)?.texImage3D != "function") throw Error("[@caperjs/plugin-3d] WebGL2 is required; this renderer is using WebGL1.");
|
|
250
|
+
if (!t.lighting3d) throw Error("[@caperjs/plugin-3d] @pixi/3d was loaded after the renderer was created. Add '3d' to plugins in caper.config.ts and do not mark it autoLoad: false.");
|
|
251
|
+
}
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/View3D.ts
|
|
254
|
+
var V = new S(), H = new T(), U = class extends n(r(C)) {
|
|
255
|
+
constructor(t = {}) {
|
|
256
|
+
let n = e.getInstance();
|
|
257
|
+
B(n.renderer);
|
|
258
|
+
let r = n.getPlugin("3d"), { camera: a, interactive: o = !0, ...c } = t, l = t.width === void 0 && t.height === void 0, d = z(r?.options.quality ?? "auto", {
|
|
259
|
+
isMobile: s,
|
|
260
|
+
resolution: n.renderer.resolution
|
|
261
|
+
});
|
|
262
|
+
super({
|
|
263
|
+
...d,
|
|
264
|
+
environment: {
|
|
265
|
+
skyColor: 12375280,
|
|
266
|
+
groundColor: 7037520,
|
|
267
|
+
intensity: .7
|
|
268
|
+
},
|
|
269
|
+
autoResize: l,
|
|
270
|
+
eventMode: o ? "static" : "none",
|
|
271
|
+
...c,
|
|
272
|
+
...a instanceof u ? { camera: a } : {}
|
|
273
|
+
}), this.owned = new R(), this.parts = /* @__PURE__ */ new Set(), this.pins = /* @__PURE__ */ new Map(), this.fillsScreen = l, L.set(this, this.owned), i(this), this._initLifecycle({
|
|
274
|
+
autoResize: !0,
|
|
275
|
+
autoUpdate: !0
|
|
276
|
+
}), a instanceof u || (this.camera.position = O(a?.position ?? [
|
|
277
|
+
0,
|
|
278
|
+
1.5,
|
|
279
|
+
4
|
|
280
|
+
]), this.camera.lookAt(O(a?.lookAt ?? [
|
|
281
|
+
0,
|
|
282
|
+
0,
|
|
283
|
+
0
|
|
284
|
+
])), a?.fov !== void 0 && (this.camera.fov = a.fov), a?.near !== void 0 && (this.camera.near = a.near), a?.far !== void 0 && (this.camera.far = a.far), a?.fitAspect && (this.fit = {
|
|
285
|
+
fov: this.camera.fov,
|
|
286
|
+
aspect: a.fitAspect
|
|
287
|
+
})), this.add = I(this.root, this.owned, !0, this), this.make = I(this.root, this.owned, !1, this), this.fitCamera();
|
|
288
|
+
}
|
|
289
|
+
own(e) {
|
|
290
|
+
return this.parts.add(e), e.resize?.(this.viewSize), e;
|
|
291
|
+
}
|
|
292
|
+
pin(e, t, n = {}) {
|
|
293
|
+
let r = {
|
|
294
|
+
target: t instanceof d ? t : O(t),
|
|
295
|
+
offset: O(n.offset ?? [
|
|
296
|
+
0,
|
|
297
|
+
0,
|
|
298
|
+
0
|
|
299
|
+
])
|
|
300
|
+
};
|
|
301
|
+
return this.pins.set(e, r), () => {
|
|
302
|
+
this.pins.get(e) === r && (this.pins.delete(e), e.visible = !0);
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
added() {
|
|
306
|
+
this.resize();
|
|
307
|
+
}
|
|
308
|
+
resize(e) {
|
|
309
|
+
this.placeFullScreen(), this.fitCamera();
|
|
310
|
+
for (let e of this.parts) e.resize?.(this.viewSize);
|
|
311
|
+
}
|
|
312
|
+
update(e) {
|
|
313
|
+
this.owned.update(this.app.ticker);
|
|
314
|
+
for (let e of this.parts) e.update?.(this.app.ticker);
|
|
315
|
+
this.placePins();
|
|
316
|
+
}
|
|
317
|
+
placePins() {
|
|
318
|
+
for (let [e, { target: t, offset: n }] of this.pins) {
|
|
319
|
+
let r = t instanceof d ? t : null;
|
|
320
|
+
if (e.destroyed || r?.destroyed) {
|
|
321
|
+
this.pins.delete(e), e.destroyed || (e.visible = !0);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
let i = r ? r.getGlobalPosition(V) : t;
|
|
325
|
+
V.set(i.x + n.x, i.y + n.y, i.z + n.z);
|
|
326
|
+
let a = this.worldToScreen(V, H);
|
|
327
|
+
e.visible = a !== null, a && (e.parent ? e.parent.toLocal(a, void 0, e.position) : e.position.copyFrom(a));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
destroy(e) {
|
|
331
|
+
this.pins.clear();
|
|
332
|
+
for (let e of this.parts) e.destroy();
|
|
333
|
+
this.parts.clear(), super.destroy({ children: !0 }), this.owned.destroy();
|
|
334
|
+
}
|
|
335
|
+
fitCamera() {
|
|
336
|
+
if (!this.fit) return;
|
|
337
|
+
let { width: e, height: t } = this.viewSize;
|
|
338
|
+
this.camera.fov = E(this.fit.fov, e / t, this.fit.aspect);
|
|
339
|
+
}
|
|
340
|
+
get viewSize() {
|
|
341
|
+
let e = this.fillsScreen ? this.app.size : this;
|
|
342
|
+
return {
|
|
343
|
+
width: e.width,
|
|
344
|
+
height: e.height
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
placeFullScreen() {
|
|
348
|
+
this.fillsScreen && this.position.set(-this.app.size.width / 2, -this.app.size.height / 2);
|
|
349
|
+
}
|
|
350
|
+
}, W = (e) => new U(e), G = class extends t {
|
|
351
|
+
constructor(...e) {
|
|
352
|
+
super(...e), this.id = "3d";
|
|
353
|
+
}
|
|
354
|
+
initialize(e = {}) {
|
|
355
|
+
this._options = {
|
|
356
|
+
quality: "auto",
|
|
357
|
+
...e
|
|
358
|
+
}, this.addDisposer(c({ view3d: W }));
|
|
359
|
+
}
|
|
360
|
+
postInitialize(e) {
|
|
361
|
+
B(e.renderer);
|
|
362
|
+
}
|
|
363
|
+
}, K = class extends n(r(d)) {
|
|
364
|
+
constructor(e) {
|
|
365
|
+
super(), this.on = ((e, t, n) => (this.enablePointerEvents(e), super.on(e, t, n))), this.once = ((e, t, n) => (this.enablePointerEvents(e), super.once(e, t, n))), this.props = e ?? {}, i(this), this._initLifecycle({
|
|
366
|
+
autoResize: !1,
|
|
367
|
+
autoUpdate: !0
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
enablePointerEvents(e) {
|
|
371
|
+
typeof e == "string" && /^(global)?(pointer|mouse|touch)|^(click|tap|wheel|right|contextmenu)/.test(e) && this.eventMode === "passive" && (this.eventMode = "static");
|
|
372
|
+
}
|
|
373
|
+
get add() {
|
|
374
|
+
return this.resolveFactories().add;
|
|
375
|
+
}
|
|
376
|
+
get make() {
|
|
377
|
+
return this.resolveFactories().make;
|
|
378
|
+
}
|
|
379
|
+
resolveFactories() {
|
|
380
|
+
let e = this.view3d && L.get(this.view3d);
|
|
381
|
+
if (!e) throw Error("This Entity3D is not in a View3D yet. Build its parts in added(), after view.add.entity(...) or view.add.existing(entity).");
|
|
382
|
+
if (this.factories?.owned !== e) {
|
|
383
|
+
let t = this.view3d;
|
|
384
|
+
this.factories = {
|
|
385
|
+
owned: e,
|
|
386
|
+
add: I(this, e, !0, t),
|
|
387
|
+
make: I(this, e, !1, t)
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
return this.factories;
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
//#endregion
|
|
394
|
+
export { K as Entity3D, D as Model, G as Plugin3D, G as default, U as View3D, E as fitFov, M as registerFactory3DMethods };
|
|
395
|
+
|
|
396
|
+
//# sourceMappingURL=caper-plugin-3d.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caper-plugin-3d.mjs","names":[],"sources":["../src/fit.ts","../src/Model.ts","../src/props.ts","../src/factory3d.ts","../src/owned.ts","../src/quality.ts","../src/renderer.ts","../src/View3D.ts","../src/Plugin3D.ts","../src/Entity3D.ts"],"sourcesContent":["/**\n * The vertical field of view (degrees) that keeps everything a `fitAspect` screen would show in frame.\n * Screens at least as wide as `fitAspect` keep `fov`; narrower ones (portrait) get a taller field of view,\n * so the sides are not cropped. Without `fitAspect` the answer is always `fov`.\n */\nexport function fitFov(fov: number, aspect: number, fitAspect?: number): number {\n if (!fitAspect || !(aspect > 0) || aspect >= fitAspect) return fov;\n const halfTan = Math.tan((fov * Math.PI) / 360);\n return (2 * Math.atan((halfTan * fitAspect) / aspect) * 180) / Math.PI;\n}\n","import { Model3D } from '@pixi/3d';\nimport type { AnimationState } from '@pixi/3d';\nimport type { Ticker } from 'pixi.js';\n\nexport type PlayOptions = Partial<Pick<AnimationState, 'loop' | 'animationSpeed' | 'weight' | 'onComplete' | 'onLoop'>> & {\n fade?: number;\n layer?: boolean;\n};\n\ntype Fade = { elapsed: number; duration: number; incoming: AnimationState; weight: number; outgoing: { state: AnimationState; weight: number }[] };\n\nexport class Model extends Model3D {\n private transition?: Fade;\n\n play(name: string, options: PlayOptions = {}): AnimationState {\n const player = this.player;\n if (!player || !player.animationLabels.includes(name)) {\n throw new Error(\n `Animation '${name}' is unavailable; available clips: ${player?.animationLabels.join(', ') || '(none)'}.`,\n );\n }\n const state = player.getState(name);\n const running = this.transition;\n if (options.layer) {\n // A fade under way carries on; it just lets go of this clip if it was fading it out.\n if (running) running.outgoing = running.outgoing.filter((old) => old.state !== state);\n } else {\n // A fade under way ends here: its outgoing clips stop at once.\n for (const { state: old } of running?.outgoing ?? []) {\n old.onComplete = old.onLoop = null;\n old.stop();\n }\n this.transition = undefined;\n }\n const outgoing = options.layer ? [] : player.animationLabels\n .map((label) => player.getState(label))\n .filter((other) => other !== state && other.playing);\n for (const other of outgoing) other.onComplete = other.onLoop = null;\n const { fade = 0, layer: _layer, ...stateOptions } = options;\n Object.assign(state, { loop: true, animationSpeed: 1, weight: 1, onComplete: null, onLoop: null }, stateOptions);\n if (fade > 0 && outgoing.length) {\n this.transition = {\n elapsed: 0, duration: fade, incoming: state, weight: state.weight,\n outgoing: outgoing.map((other) => ({ state: other, weight: other.weight })),\n };\n state.weight = 0;\n } else {\n for (const other of outgoing) other.stop();\n }\n state.gotoAndPlay(0);\n return state;\n }\n\n stop(): void {\n this.transition = undefined;\n this.player?.stop();\n }\n\n update(ticker: Ticker): void {\n const fade = this.transition;\n if (fade) {\n fade.elapsed = Math.min(fade.duration, fade.elapsed + ticker.deltaMS / 1000);\n const progress = fade.elapsed / fade.duration;\n fade.incoming.weight = fade.weight * progress;\n for (const { state, weight } of fade.outgoing) {\n state.weight = weight * (1 - progress);\n if (progress === 1) state.stop();\n }\n if (progress === 1) this.transition = undefined;\n }\n this.player?.update(ticker);\n }\n}\n","import type {\n AmbientLightOptions,\n Camera3DOptions,\n Container3D,\n Container3DOptions,\n DirectionalLightOptions,\n Geometry3D,\n Material3DOptions,\n Mesh3DOptions as PixiMesh3DOptions,\n Model3DOptions as PixiModel3DOptions,\n PointLightOptions,\n Scene3DSource,\n SpotLightOptions,\n} from '@pixi/3d';\nimport type { BaseMaterial3D } from '@pixi/3d';\nimport type { AppTypeOverrides, AssetTypeOverrides } from '@caperjs/core';\n\nexport type Vec3 = [number, number, number] | { x: number; y: number; z: number };\n\nexport type Node3DProps = Omit<Container3DOptions, 'position' | 'rotation' | 'scale'> & {\n position?: Vec3;\n rotation?: Vec3;\n scale?: Vec3 | number;\n lookAt?: Vec3;\n};\n\nexport type Material3DProps = Material3DOptions & { /** Shorthand for `baseColor`. */ color?: number };\n\ntype EntityClasses = AppTypeOverrides extends { EntityClasses: infer E } ? E : {};\ntype Entity3DCtor = abstract new (...args: any[]) => Container3D;\n/** Ids of discovered entities whose class extends `Container3D` (usually through `Entity3D`). */\nexport type Entity3DId = {\n [K in keyof EntityClasses]: EntityClasses[K] extends Entity3DCtor ? K : never;\n}[keyof EntityClasses] & string;\ntype OwnProps<C extends Entity3DCtor> = Exclude<ConstructorParameters<C>[0], void | undefined>;\n/** The entity's own constructor props; `{}` for a class that takes none (`Entity3D` with no `Props`). */\nexport type Entity3DProps<K extends Entity3DId> = EntityClasses[K] extends Entity3DCtor\n ? [OwnProps<EntityClasses[K]>] extends [never]\n ? {}\n : OwnProps<EntityClasses[K]>\n : never;\nexport type Entity3DInstance<K extends Entity3DId> = EntityClasses[K] extends Entity3DCtor\n ? InstanceType<EntityClasses[K]>\n : never;\n/** Placement props `view.add.entity` applies to the new entity; everything else is the entity's own. */\nexport type Entity3DNodeProps = Pick<\n Node3DProps,\n 'position' | 'rotation' | 'scale' | 'x' | 'y' | 'z' | 'visible' | 'lookAt' | 'parent'\n>;\n\nexport type Mesh3DProps = Omit<PixiMesh3DOptions, keyof Node3DProps | 'geometry' | 'material'> &\n Node3DProps & {\n geometry?: 'box' | 'plane' | 'sphere' | 'cylinder' | Geometry3D;\n material?: BaseMaterial3D;\n color?: number;\n roughness?: number;\n metallic?: number;\n };\n\n/**\n * A model's manifest name. Once the app's generated `caper-assets.d.ts` lists models (any `.glb` in the assets\n * folder), this is that union, so unknown names are type errors; until then it is `string`. A model loaded by\n * hand is passed as its `Scene3DSource`.\n */\n// Known names autocomplete; any other string is still allowed, the same as texture and spritesheet names.\nexport type ModelAsset = AssetTypeOverrides extends { Model: infer Name extends string }\n ? Name | (string & {})\n : string;\n\nexport type Model3DProps = Omit<PixiModel3DOptions, keyof Node3DProps | 'source'> &\n Node3DProps & { asset: ModelAsset | Scene3DSource };\n\nexport type Light3DProps = Omit<\n DirectionalLightOptions & PointLightOptions & SpotLightOptions & AmbientLightOptions,\n keyof Node3DProps\n> &\n Node3DProps & { type?: 'directional' | 'point' | 'spot' | 'ambient' };\n\nexport type Camera3DProps = Omit<Camera3DOptions, keyof Node3DProps> & Node3DProps;\n\nexport function toVec3(value: Vec3): { x: number; y: number; z: number } {\n return Array.isArray(value) ? { x: value[0], y: value[1], z: value[2] } : value;\n}\n\nexport function resolveNodeOptions<T extends Node3DProps>(\n props: T,\n): Omit<T, 'lookAt' | 'position' | 'rotation' | 'scale'> & Pick<Container3DOptions, 'position' | 'rotation' | 'scale'> {\n const options: Record<string, unknown> = { ...props };\n delete options.lookAt;\n for (const key of ['position', 'rotation', 'scale'] as const) {\n const value = options[key];\n if (Array.isArray(value)) options[key] = toVec3(value as Vec3);\n }\n return options as Omit<T, 'lookAt' | 'position' | 'rotation' | 'scale'> &\n Pick<Container3DOptions, 'position' | 'rotation' | 'scale'>;\n}\n","import {\n AmbientLight,\n Camera3D,\n Container3D,\n CubeGeometry,\n CylinderGeometry,\n DirectionalLight,\n Material3D,\n Mesh3D,\n PlaneGeometry,\n PointLight,\n SphereGeometry,\n SpotLight,\n} from '@pixi/3d';\nimport type { Geometry3D, Light, Scene3DSource } from '@pixi/3d';\nimport { Assets } from 'pixi.js';\nimport { getEntityCtor, getRegisteredEntityIds } from '@caperjs/core';\nimport { Model } from './Model';\nimport { Owned3D } from './owned';\nimport type {\n Camera3DProps,\n Entity3DId,\n Entity3DInstance,\n Entity3DNodeProps,\n Entity3DProps,\n Light3DProps,\n Material3DProps,\n Mesh3DProps,\n Model3DProps,\n Node3DProps,\n} from './props';\nimport { resolveNodeOptions, toVec3 } from './props';\nimport type { View3D } from './View3D';\n\n/** Add-on methods on every 3D factory. Augment with the call-site shape:\n * declare module '@caperjs/plugin-3d' { interface Factory3DOverrides { cameraRig: (props?: P) => CameraRig } } */\nexport interface Factory3DOverrides {}\n\n/** Registered methods receive the view before their call-site arguments. */\nexport type Factory3DMethods = {\n [K in keyof Factory3DOverrides]: Factory3DOverrides[K] extends (...args: infer A) => infer R\n ? (view: View3D, ...args: A) => R : never;\n};\n\ninterface BuiltInFactory3D {\n container(props?: Node3DProps): Container3D;\n mesh(props?: Mesh3DProps): Mesh3D;\n /** A material owned by the view: freed with it. Pass it to many meshes. A material has no parent, so add.material and make.material are the same. */\n material(props?: Material3DProps): Material3D;\n entity<K extends Entity3DId>(id: K, props?: Entity3DProps<K> & Entity3DNodeProps): Entity3DInstance<K>;\n model(props: Model3DProps): Model;\n light(props?: Light3DProps): Light;\n camera(props?: Camera3DProps): Camera3D;\n existing<T extends Container3D>(node: T, props?: Node3DProps): T;\n}\n\nexport interface Factory3D extends BuiltInFactory3D, Factory3DOverrides {}\n\nconst BUILT_IN_METHODS = {\n container: true, mesh: true, material: true, entity: true,\n model: true, light: true, camera: true, existing: true,\n} satisfies Record<keyof BuiltInFactory3D, true>;\nconst registered = new Map<string, (...args: any[]) => any>();\n\n/** Register methods for factories built afterwards. Register before creating views: a view builds its\n * factories in its constructor, and an entity builds them on first add/make use. A disposer only affects\n * future factories. Registered methods have the same behavior on add and make; neither parents their result.\n */\nexport function registerFactory3DMethods(methods: Partial<Factory3DMethods>): () => void {\n const entries = Object.entries(methods) as Array<[string, (...args: any[]) => any]>;\n for (const [name, method] of entries) {\n if (Object.hasOwn(BUILT_IN_METHODS, name)) {\n throw new Error(`[caper] registerFactory3DMethods: \"${name}\" is a built-in 3D factory method and cannot be replaced. Pick another name.`);\n }\n if (typeof method !== 'function') {\n throw new Error(`[caper] registerFactory3DMethods: \"${name}\" must be a function.`);\n }\n const previous = registered.get(name);\n if (previous && previous !== method) {\n throw new Error(`[caper] registerFactory3DMethods: \"${name}\" is already registered (by function \"${previous.name || 'anonymous'}\"); cannot register function \"${method.name || 'anonymous'}\" under the same name.`);\n }\n }\n const added = entries.filter(([name]) => !registered.has(name));\n for (const [name, method] of added) registered.set(name, method);\n return () => {\n for (const [name, method] of added) {\n if (registered.get(name) === method) registered.delete(name);\n }\n };\n}\n\nconst BUILT_IN_GEOMETRY = {\n box: () => new CubeGeometry(),\n cylinder: () => new CylinderGeometry({ radiusTop: 0.5, radiusBottom: 0.5, height: 1 }),\n plane: () => new PlaneGeometry(),\n sphere: () => new SphereGeometry({ radius: 0.5 }),\n};\n\nconst ENTITY_PLACEMENT = ['position', 'rotation', 'scale', 'x', 'y', 'z', 'visible', 'lookAt', 'parent'] as const;\n\nconst LIGHTS = { directional: DirectionalLight, point: PointLight, spot: SpotLight, ambient: AmbientLight };\n\nexport function createFactory3D(root: Container3D, owned: Owned3D, parent: boolean, view: View3D): Factory3D {\n const options = <T extends Node3DProps>(props: T) => {\n const resolved = resolveNodeOptions(props);\n return parent && !resolved.parent ? { ...resolved, parent: root } : resolved;\n };\n const finish = <T extends Container3D>(node: T, props: Node3DProps): T => {\n if (props.lookAt) node.lookAt(toVec3(props.lookAt));\n return node;\n };\n const existing = <T extends Container3D>(node: T, props: Node3DProps = {}): T => {\n const { parent: to = root, ...rest } = resolveNodeOptions(props);\n Object.assign(node, rest);\n if (parent) to.addChild(node);\n // After parenting: lookAt aims in world space.\n return finish(node, props);\n };\n\n const builtIns: BuiltInFactory3D = {\n container(props = {}) {\n return finish(new Container3D(options(props)), props);\n },\n material(props = {}) {\n const { color, ...options } = props;\n return owned.material(new Material3D(color === undefined ? options : { baseColor: color, ...options }));\n },\n entity(id, props) {\n const Ctor = getEntityCtor(id);\n if (!Ctor) {\n const known = getRegisteredEntityIds();\n throw new Error(\n `Unknown entity id '${id}'. Known: ${known.length ? known.map((key) => `'${key}'`).join(', ') : '(none)'}`,\n );\n }\n if (!(Ctor.prototype instanceof Container3D)) {\n throw new Error(\n `Entity '${id}' is not a 3D entity (its class does not extend Container3D). Use this.add.entity for 2D entities.`,\n );\n }\n const node = new (Ctor as new (props?: unknown) => Container3D)(props);\n // Only placement is applied to the node; every other prop is the entity's own.\n const placement: Entity3DNodeProps = Object.fromEntries(\n ENTITY_PLACEMENT.filter((key) => props && key in props).map((key) => [key, props![key]]),\n );\n return existing(node, placement) as Entity3DInstance<typeof id>;\n },\n mesh(props = {}) {\n const { geometry = 'box', material, color, roughness, metallic, ...nodeProps } = props;\n let actualGeometry: Geometry3D;\n if (typeof geometry !== 'string') actualGeometry = geometry;\n else if (geometry in BUILT_IN_GEOMETRY) actualGeometry = owned.geometry(geometry, BUILT_IN_GEOMETRY[geometry]);\n else throw new Error(`Unknown 3D geometry '${geometry}'. Use box, plane, sphere, or cylinder.`);\n const actualMaterial = material ?? owned.material(new Material3D({\n baseColor: color ?? 0xffffff,\n ...(roughness !== undefined && { roughness }),\n ...(metallic !== undefined && { metallic }),\n }));\n return finish(new Mesh3D({ ...options(nodeProps), geometry: actualGeometry, material: actualMaterial }), props);\n },\n model(props) {\n const { asset, ...nodeProps } = props;\n const source = typeof asset === 'string' ? Assets.get<Scene3DSource>(asset) : asset;\n if (!source)\n throw new Error(`Model asset '${asset}' is not loaded. Add its bundle to the scene's assets.preload.`);\n const model = finish(new Model({ ...options(nodeProps), source, autoUpdate: false }), props);\n if (model.player) owned.player(model);\n return model;\n },\n light(props = {}) {\n const { type = 'directional', ...nodeProps } = props;\n const lightOptions = options(nodeProps);\n if (type === 'directional' && !props.rotation && !props.quaternion && !props.lookAt) {\n lightOptions.rotation = { x: -Math.PI / 4, y: Math.PI / 6, z: 0 };\n }\n const light = new LIGHTS[type](lightOptions);\n return finish(light, props);\n },\n camera(props = {}) {\n return finish(new Camera3D(options(props)), props);\n },\n existing,\n };\n const bound = Object.fromEntries(\n [...registered].map(([name, method]) => [name, (...args: any[]) => method(view, ...args)]),\n );\n return Object.assign(builtIns, bound) as Factory3D;\n}\n","import type { Ticker } from 'pixi.js';\n\ntype Resource = { destroy(): void };\ntype Player = { destroyed: boolean; update(ticker: Ticker): void };\n\nexport const ownedByView = new WeakMap<object, Owned3D>();\n\nexport class Owned3D {\n private readonly geometries = new Map<string, Resource>();\n private readonly materials = new Set<Resource>();\n private readonly players = new Set<Player>();\n\n /** One geometry per kind per view: bounded, and meshes that share a geometry can batch. */\n geometry<T extends Resource>(kind: string, build: () => T): T {\n if (!this.geometries.has(kind)) this.geometries.set(kind, build());\n return this.geometries.get(kind) as T;\n }\n\n material<T extends Resource>(material: T): T {\n this.materials.add(material);\n return material;\n }\n\n player<T extends Player>(player: T): T {\n this.players.add(player);\n return player;\n }\n\n update(ticker: Ticker): void {\n for (const player of this.players) {\n if (player.destroyed) this.players.delete(player);\n else player.update(ticker);\n }\n }\n\n destroy(): void {\n for (const resource of [...this.geometries.values(), ...this.materials]) resource.destroy();\n this.geometries.clear();\n this.materials.clear();\n this.players.clear();\n }\n}\n","export type Quality3D = 'auto' | 'low' | 'high';\n\nexport function resolveQuality(\n quality: Quality3D,\n device: { isMobile: boolean; resolution: number },\n): { shadowQuality: 'low' | 'medium' | 'high'; resolution: number | 'inherit' } {\n if (quality === 'high') return { shadowQuality: 'high', resolution: 'inherit' };\n if (quality === 'low') return { shadowQuality: 'low', resolution: Math.min(device.resolution, 1) };\n return device.isMobile\n ? { shadowQuality: 'low', resolution: Math.min(device.resolution, 2) }\n : { shadowQuality: 'medium', resolution: 'inherit' };\n}\n","type Renderer3D = {\n name?: string;\n gl?: { texImage3D?: unknown };\n context?: { gl?: { texImage3D?: unknown } };\n lighting3d?: unknown;\n};\n\nexport function assertRenderer3D(value: unknown): void {\n const renderer = value as Renderer3D | null | undefined;\n if (!renderer)\n throw new Error('[@caperjs/plugin-3d] No renderer is available. Create the renderer before a 3D view.');\n if (renderer.name === 'canvas')\n throw new Error('[@caperjs/plugin-3d] Canvas renderer cannot draw 3D. Use WebGL2 or WebGPU.');\n if (renderer.name === 'webgl' && typeof (renderer.gl ?? renderer.context?.gl)?.texImage3D !== 'function') {\n throw new Error('[@caperjs/plugin-3d] WebGL2 is required; this renderer is using WebGL1.');\n }\n if (!renderer.lighting3d) {\n throw new Error(\n \"[@caperjs/plugin-3d] @pixi/3d was loaded after the renderer was created. Add '3d' to plugins in caper.config.ts and do not mark it autoLoad: false.\",\n );\n }\n}\n","import { Camera3D, Container3D, Vector3, View3D as PixiView3D } from '@pixi/3d';\nimport type { View3DOptions } from '@pixi/3d';\nimport { Application, bindAllMethods, isMobile, WithLifecycle, WithSignals } from '@caperjs/core';\nimport type { Size } from '@caperjs/core';\nimport { Point, type Container, type Ticker } from 'pixi.js';\nimport { fitFov } from './fit';\nimport { createFactory3D } from './factory3d';\nimport type { Factory3D } from './factory3d';\nimport { Owned3D, ownedByView } from './owned';\nimport type { Vec3 } from './props';\nimport { toVec3 } from './props';\nimport type { IPlugin3D } from './Plugin3D';\nimport { resolveQuality } from './quality';\nimport { assertRenderer3D } from './renderer';\n\ntype CameraProps = {\n position?: Vec3;\n lookAt?: Vec3;\n /** Vertical field of view in degrees. */\n fov?: number;\n near?: number;\n far?: number;\n /**\n * The aspect ratio (width / height) the scene is framed for, e.g. `16 / 9`. On a narrower view (a phone\n * held upright) the field of view grows so the sides stay in frame. Leave it out to keep `fov` fixed.\n */\n fitAspect?: number;\n};\n\nexport interface View3DProps extends Omit<View3DOptions, 'camera'> {\n camera?: Camera3D | CameraProps;\n interactive?: boolean;\n}\n\n/** Something an add-on attaches to a view. The view drives it; games never call these. */\nexport interface View3DPart {\n /** Every frame the view updates (on app.ticker), after model clips. */\n update?(ticker: Ticker): void;\n /** Once when owned with the current size, then on every view resize. */\n resize?(size: Size): void;\n /** Before the view frees its nodes and resources, while the view is still usable. */\n destroy(): void;\n}\n\nconst world = new Vector3();\nconst screen = new Point();\ntype Point3 = ReturnType<typeof toVec3>;\ntype Pin = { target: Container3D | Point3; offset: Point3 };\n\nexport class View3D extends WithLifecycle(WithSignals(PixiView3D)) {\n readonly add: Factory3D;\n readonly make: Factory3D;\n private readonly owned = new Owned3D();\n private readonly parts = new Set<View3DPart>();\n private readonly pins = new Map<Container, Pin>();\n private readonly fillsScreen: boolean;\n private readonly fit?: { fov: number; aspect: number };\n\n constructor(props: View3DProps = {}) {\n const app = Application.getInstance();\n assertRenderer3D(app.renderer);\n const plugin = app.getPlugin<IPlugin3D>('3d');\n const { camera, interactive = true, ...viewProps } = props;\n const fillsScreen = props.width === undefined && props.height === undefined;\n const quality = resolveQuality(plugin?.options.quality ?? 'auto', {\n isMobile,\n resolution: app.renderer.resolution,\n });\n super({\n ...quality,\n environment: { skyColor: 0xbcd4f0, groundColor: 0x6b6250, intensity: 0.7 },\n autoResize: fillsScreen,\n // 'static' picks 3D and takes taps over the whole view; 'none' lets them reach 2D behind it.\n // Never 'passive': it turns picking off and still blocks.\n eventMode: interactive ? 'static' : 'none',\n ...viewProps,\n ...(camera instanceof Camera3D ? { camera } : {}),\n });\n this.fillsScreen = fillsScreen;\n ownedByView.set(this, this.owned);\n bindAllMethods(this);\n this._initLifecycle({ autoResize: true, autoUpdate: true });\n if (!(camera instanceof Camera3D)) {\n this.camera.position = toVec3(camera?.position ?? [0, 1.5, 4]);\n this.camera.lookAt(toVec3(camera?.lookAt ?? [0, 0, 0]));\n if (camera?.fov !== undefined) this.camera.fov = camera.fov;\n if (camera?.near !== undefined) this.camera.near = camera.near;\n if (camera?.far !== undefined) this.camera.far = camera.far;\n if (camera?.fitAspect) this.fit = { fov: this.camera.fov, aspect: camera.fitAspect };\n }\n this.add = createFactory3D(this.root, this.owned, true, this);\n this.make = createFactory3D(this.root, this.owned, false, this);\n this.fitCamera();\n }\n\n /** For add-ons: the view updates `part` every frame, tells it about resizes, and destroys it with itself. */\n own<T extends View3DPart>(part: T): T {\n this.parts.add(part);\n part.resize?.(this.viewSize);\n return part;\n }\n\n /** Keeps a 2D node over a 3D point, hidden while the point is behind the camera. Returns the function that unpins it. */\n pin(node: Container, target: Container3D | Vec3, options: { offset?: Vec3 } = {}): () => void {\n const pin: Pin = { target: target instanceof Container3D ? target : toVec3(target), offset: toVec3(options.offset ?? [0, 0, 0]) };\n this.pins.set(node, pin);\n // A pin hides its node behind the camera, so a pin that ends shows it again.\n return () => {\n if (this.pins.get(node) !== pin) return;\n this.pins.delete(node);\n node.visible = true;\n };\n }\n\n added(): void {\n this.resize();\n }\n\n resize(_size?: Size): void {\n this.placeFullScreen();\n this.fitCamera();\n for (const part of this.parts) part.resize?.(this.viewSize);\n }\n\n update(_ticker?: Ticker | number): void {\n this.owned.update(this.app.ticker);\n for (const part of this.parts) part.update?.(this.app.ticker);\n this.placePins();\n }\n\n private placePins(): void {\n for (const [node, { target, offset }] of this.pins) {\n const node3d = target instanceof Container3D ? target : null;\n if (node.destroyed || node3d?.destroyed) {\n this.pins.delete(node);\n if (!node.destroyed) node.visible = true;\n continue;\n }\n const at = node3d ? node3d.getGlobalPosition(world) : (target as Point3);\n world.set(at.x + offset.x, at.y + offset.y, at.z + offset.z);\n // null: the point is at or behind the camera.\n const point = this.worldToScreen(world, screen);\n node.visible = point !== null;\n if (!point) continue;\n if (node.parent) node.parent.toLocal(point, undefined, node.position);\n else node.position.copyFrom(point);\n }\n }\n\n destroy(_options?: Parameters<PixiView3D['destroy']>[0] | boolean): void {\n this.pins.clear();\n for (const part of this.parts) part.destroy();\n this.parts.clear();\n // glTF sources share materials; destroying them crashes the next visit.\n super.destroy({ children: true });\n this.owned.destroy();\n }\n\n private fitCamera(): void {\n if (!this.fit) return;\n const { width, height } = this.viewSize;\n this.camera.fov = fitFov(this.fit.fov, width / height, this.fit.aspect);\n }\n\n private get viewSize(): Size {\n const size = this.fillsScreen ? this.app.size : this;\n return { width: size.width, height: size.height };\n }\n\n private placeFullScreen(): void {\n if (this.fillsScreen) this.position.set(-this.app.size.width / 2, -this.app.size.height / 2);\n }\n}\n","import { Plugin, registerFactoryMethods } from '@caperjs/core';\nimport type { IApplication, IPlugin } from '@caperjs/core';\nimport { View3D } from './View3D';\nimport type { View3DProps } from './View3D';\nimport type { Quality3D } from './quality';\nimport { assertRenderer3D } from './renderer';\n\nexport interface Plugin3DOptions {\n quality: Quality3D;\n}\nexport interface IPlugin3D extends IPlugin<Plugin3DOptions> {}\n\ndeclare module '@caperjs/core' {\n interface FactoryMethodOverrides {\n view3d: (props?: View3DProps) => View3D;\n }\n}\n\n// One stable function, so a re-run `initialize` registers the same method again (a no-op) instead of colliding.\nconst view3d = (props?: View3DProps) => new View3D(props);\n\nexport class Plugin3D extends Plugin<Plugin3DOptions> implements IPlugin3D {\n id = '3d';\n\n initialize(options: Partial<Plugin3DOptions> = {}): void {\n this._options = { quality: 'auto', ...options };\n this.addDisposer(registerFactoryMethods({ view3d }));\n }\n\n postInitialize(app: IApplication): void {\n assertRenderer3D(app.renderer);\n }\n}\n\nexport default Plugin3D;\n","import { Container3D } from '@pixi/3d';\nimport { bindAllMethods, WithLifecycle, WithSignals } from '@caperjs/core';\nimport { createFactory3D } from './factory3d';\nimport type { Factory3D } from './factory3d';\nimport { ownedByView } from './owned';\nimport type { Owned3D } from './owned';\nimport type { View3D } from './View3D';\n\ntype Listen<Self> = (event: string | symbol, fn: (...args: any[]) => void, context?: any) => Self;\n\n/**\n * Base class for 3D entities: a `Container3D` with the Caper lifecycle (`added` / `removed` / `update`),\n * signals, and its own 3D factory. Declare one like any entity (`defineEntity` + default export under\n * `src/entities/`) and build it with `view.add.entity(id, props)`.\n *\n * Build parts in `added()`, not in the constructor: `this.add` / `this.make` belong to the view the entity is\n * in, so they work once it has been added to one. Parts are parented to the entity; the resources they\n * create are freed with the view, and model animations are driven by the view.\n * Adding a pointer listener makes a passive entity interactive so it hears taps on its parts.\n */\nexport class Entity3D<Props = void> extends WithLifecycle(WithSignals(Container3D)) {\n readonly props: Props;\n private factories?: { owned: Owned3D; add: Factory3D; make: Factory3D };\n\n constructor(props?: Props) {\n super();\n this.props = (props ?? {}) as Props;\n bindAllMethods(this);\n this._initLifecycle({ autoResize: false, autoUpdate: true });\n }\n\n // Fields, not methods, so `entity.on('pointertap', (e) => ...)` keeps upstream's per-event typing.\n override on: Container3D['on'] & Listen<this> = ((event: string | symbol, fn: (...args: any[]) => void, context?: any) => {\n this.enablePointerEvents(event);\n return super.on(event, fn, context);\n }) as Container3D['on'] & Listen<this>;\n\n override once: Container3D['once'] & Listen<this> = ((event: string | symbol, fn: (...args: any[]) => void, context?: any) => {\n this.enablePointerEvents(event);\n return super.once(event, fn, context);\n }) as Container3D['once'] & Listen<this>;\n\n /** Listening is the opt-in: a passive ancestor is skipped when a part's event bubbles. */\n private enablePointerEvents(event: string | symbol): void {\n if (typeof event === 'string' && /^(global)?(pointer|mouse|touch)|^(click|tap|wheel|right|contextmenu)/.test(event) && this.eventMode === 'passive') {\n this.eventMode = 'static';\n }\n }\n\n get add(): Factory3D {\n return this.resolveFactories().add;\n }\n\n get make(): Factory3D {\n return this.resolveFactories().make;\n }\n\n private resolveFactories(): { add: Factory3D; make: Factory3D } {\n const owned = this.view3d && ownedByView.get(this.view3d);\n if (!owned) {\n throw new Error(\n 'This Entity3D is not in a View3D yet. Build its parts in added(), after view.add.entity(...) or view.add.existing(entity).',\n );\n }\n // Rebuilt only if the entity moved to another view.\n if (this.factories?.owned !== owned) {\n const view = this.view3d as View3D;\n this.factories = { owned, add: createFactory3D(this, owned, true, view), make: createFactory3D(this, owned, false, view) };\n }\n return this.factories;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Camera3D, Container3D, Material3D, Mesh3D, Light } from '@pixi/3d';
|
|
2
|
+
import { Model } from './Model';
|
|
3
|
+
import { Owned3D } from './owned';
|
|
4
|
+
import { Camera3DProps, Entity3DId, Entity3DInstance, Entity3DNodeProps, Entity3DProps, Light3DProps, Material3DProps, Mesh3DProps, Model3DProps, Node3DProps } from './props';
|
|
5
|
+
import { View3D } from './View3D';
|
|
6
|
+
/** Add-on methods on every 3D factory. Augment with the call-site shape:
|
|
7
|
+
* declare module '@caperjs/plugin-3d' { interface Factory3DOverrides { cameraRig: (props?: P) => CameraRig } } */
|
|
8
|
+
export interface Factory3DOverrides {
|
|
9
|
+
}
|
|
10
|
+
/** Registered methods receive the view before their call-site arguments. */
|
|
11
|
+
export type Factory3DMethods = {
|
|
12
|
+
[K in keyof Factory3DOverrides]: Factory3DOverrides[K] extends (...args: infer A) => infer R ? (view: View3D, ...args: A) => R : never;
|
|
13
|
+
};
|
|
14
|
+
interface BuiltInFactory3D {
|
|
15
|
+
container(props?: Node3DProps): Container3D;
|
|
16
|
+
mesh(props?: Mesh3DProps): Mesh3D;
|
|
17
|
+
/** A material owned by the view: freed with it. Pass it to many meshes. A material has no parent, so add.material and make.material are the same. */
|
|
18
|
+
material(props?: Material3DProps): Material3D;
|
|
19
|
+
entity<K extends Entity3DId>(id: K, props?: Entity3DProps<K> & Entity3DNodeProps): Entity3DInstance<K>;
|
|
20
|
+
model(props: Model3DProps): Model;
|
|
21
|
+
light(props?: Light3DProps): Light;
|
|
22
|
+
camera(props?: Camera3DProps): Camera3D;
|
|
23
|
+
existing<T extends Container3D>(node: T, props?: Node3DProps): T;
|
|
24
|
+
}
|
|
25
|
+
export interface Factory3D extends BuiltInFactory3D, Factory3DOverrides {
|
|
26
|
+
}
|
|
27
|
+
/** Register methods for factories built afterwards. Register before creating views: a view builds its
|
|
28
|
+
* factories in its constructor, and an entity builds them on first add/make use. A disposer only affects
|
|
29
|
+
* future factories. Registered methods have the same behavior on add and make; neither parents their result.
|
|
30
|
+
*/
|
|
31
|
+
export declare function registerFactory3DMethods(methods: Partial<Factory3DMethods>): () => void;
|
|
32
|
+
export declare function createFactory3D(root: Container3D, owned: Owned3D, parent: boolean, view: View3D): Factory3D;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=factory3d.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory3d.d.ts","sourceRoot":"","sources":["../src/factory3d.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EACR,WAAW,EAIX,UAAU,EACV,MAAM,EAKP,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAc,KAAK,EAAiB,MAAM,UAAU,CAAC;AAGjE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,eAAe,EACf,WAAW,EACX,YAAY,EACZ,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;kHACkH;AAClH,MAAM,WAAW,kBAAkB;CAAG;AAEtC,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG;KAC5B,CAAC,IAAI,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,GACxF,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK;CAC5C,CAAC;AAEF,UAAU,gBAAgB;IACxB,SAAS,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC;IAC5C,IAAI,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAClC,qJAAqJ;IACrJ,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,UAAU,CAAC;IAC9C,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,iBAAiB,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;IACvG,KAAK,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,CAAC;IAClC,KAAK,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,QAAQ,CAAC;IACxC,QAAQ,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,SAAU,SAAQ,gBAAgB,EAAE,kBAAkB;CAAG;AAQ1E;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,MAAM,IAAI,CAqBvF;AAaD,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAqF3G"}
|
package/lib/fit.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vertical field of view (degrees) that keeps everything a `fitAspect` screen would show in frame.
|
|
3
|
+
* Screens at least as wide as `fitAspect` keep `fov`; narrower ones (portrait) get a taller field of view,
|
|
4
|
+
* so the sides are not cropped. Without `fitAspect` the answer is always `fov`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function fitFov(fov: number, aspect: number, fitAspect?: number): number;
|
|
7
|
+
//# sourceMappingURL=fit.d.ts.map
|
package/lib/fit.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fit.d.ts","sourceRoot":"","sources":["../src/fit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAI9E"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { default, Plugin3D } from './Plugin3D';
|
|
2
|
+
export type { IPlugin3D, Plugin3DOptions } from './Plugin3D';
|
|
3
|
+
export { View3D } from './View3D';
|
|
4
|
+
export { Entity3D } from './Entity3D';
|
|
5
|
+
export type { View3DProps, View3DPart } from './View3D';
|
|
6
|
+
export { Model } from './Model';
|
|
7
|
+
export type { PlayOptions } from './Model';
|
|
8
|
+
export { registerFactory3DMethods } from './factory3d';
|
|
9
|
+
export type { Factory3D, Factory3DOverrides, Factory3DMethods } from './factory3d';
|
|
10
|
+
export { fitFov } from './fit';
|
|
11
|
+
export type { Node3DProps, Mesh3DProps, Model3DProps, ModelAsset, Light3DProps, Camera3DProps, Vec3 } from './props';
|
|
12
|
+
export type { Entity3DId, Entity3DNodeProps, Material3DProps } from './props';
|
|
13
|
+
export type { Quality3D } from './quality';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACrH,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC9E,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
|
package/lib/owned.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Ticker } from 'pixi.js';
|
|
2
|
+
type Resource = {
|
|
3
|
+
destroy(): void;
|
|
4
|
+
};
|
|
5
|
+
type Player = {
|
|
6
|
+
destroyed: boolean;
|
|
7
|
+
update(ticker: Ticker): void;
|
|
8
|
+
};
|
|
9
|
+
export declare const ownedByView: WeakMap<object, Owned3D>;
|
|
10
|
+
export declare class Owned3D {
|
|
11
|
+
private readonly geometries;
|
|
12
|
+
private readonly materials;
|
|
13
|
+
private readonly players;
|
|
14
|
+
/** One geometry per kind per view: bounded, and meshes that share a geometry can batch. */
|
|
15
|
+
geometry<T extends Resource>(kind: string, build: () => T): T;
|
|
16
|
+
material<T extends Resource>(material: T): T;
|
|
17
|
+
player<T extends Player>(player: T): T;
|
|
18
|
+
update(ticker: Ticker): void;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=owned.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owned.d.ts","sourceRoot":"","sources":["../src/owned.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,KAAK,QAAQ,GAAG;IAAE,OAAO,IAAI,IAAI,CAAA;CAAE,CAAC;AACpC,KAAK,MAAM,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAEnE,eAAO,MAAM,WAAW,0BAAiC,CAAC;AAE1D,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;IAC1D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C,2FAA2F;IAC3F,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;IAK7D,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC;IAK5C,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC;IAKtC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO5B,OAAO,IAAI,IAAI;CAMhB"}
|
package/lib/props.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { AmbientLightOptions, Camera3DOptions, Container3D, Container3DOptions, DirectionalLightOptions, Geometry3D, Material3DOptions, Mesh3DOptions as PixiMesh3DOptions, Model3DOptions as PixiModel3DOptions, PointLightOptions, Scene3DSource, SpotLightOptions, BaseMaterial3D } from '@pixi/3d';
|
|
2
|
+
import { AppTypeOverrides, AssetTypeOverrides } from '@caperjs/core';
|
|
3
|
+
export type Vec3 = [number, number, number] | {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
z: number;
|
|
7
|
+
};
|
|
8
|
+
export type Node3DProps = Omit<Container3DOptions, 'position' | 'rotation' | 'scale'> & {
|
|
9
|
+
position?: Vec3;
|
|
10
|
+
rotation?: Vec3;
|
|
11
|
+
scale?: Vec3 | number;
|
|
12
|
+
lookAt?: Vec3;
|
|
13
|
+
};
|
|
14
|
+
export type Material3DProps = Material3DOptions & {
|
|
15
|
+
color?: number;
|
|
16
|
+
};
|
|
17
|
+
type EntityClasses = AppTypeOverrides extends {
|
|
18
|
+
EntityClasses: infer E;
|
|
19
|
+
} ? E : {};
|
|
20
|
+
type Entity3DCtor = abstract new (...args: any[]) => Container3D;
|
|
21
|
+
/** Ids of discovered entities whose class extends `Container3D` (usually through `Entity3D`). */
|
|
22
|
+
export type Entity3DId = {
|
|
23
|
+
[K in keyof EntityClasses]: EntityClasses[K] extends Entity3DCtor ? K : never;
|
|
24
|
+
}[keyof EntityClasses] & string;
|
|
25
|
+
type OwnProps<C extends Entity3DCtor> = Exclude<ConstructorParameters<C>[0], void | undefined>;
|
|
26
|
+
/** The entity's own constructor props; `{}` for a class that takes none (`Entity3D` with no `Props`). */
|
|
27
|
+
export type Entity3DProps<K extends Entity3DId> = EntityClasses[K] extends Entity3DCtor ? [OwnProps<EntityClasses[K]>] extends [never] ? {} : OwnProps<EntityClasses[K]> : never;
|
|
28
|
+
export type Entity3DInstance<K extends Entity3DId> = EntityClasses[K] extends Entity3DCtor ? InstanceType<EntityClasses[K]> : never;
|
|
29
|
+
/** Placement props `view.add.entity` applies to the new entity; everything else is the entity's own. */
|
|
30
|
+
export type Entity3DNodeProps = Pick<Node3DProps, 'position' | 'rotation' | 'scale' | 'x' | 'y' | 'z' | 'visible' | 'lookAt' | 'parent'>;
|
|
31
|
+
export type Mesh3DProps = Omit<PixiMesh3DOptions, keyof Node3DProps | 'geometry' | 'material'> & Node3DProps & {
|
|
32
|
+
geometry?: 'box' | 'plane' | 'sphere' | 'cylinder' | Geometry3D;
|
|
33
|
+
material?: BaseMaterial3D;
|
|
34
|
+
color?: number;
|
|
35
|
+
roughness?: number;
|
|
36
|
+
metallic?: number;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* A model's manifest name. Once the app's generated `caper-assets.d.ts` lists models (any `.glb` in the assets
|
|
40
|
+
* folder), this is that union, so unknown names are type errors; until then it is `string`. A model loaded by
|
|
41
|
+
* hand is passed as its `Scene3DSource`.
|
|
42
|
+
*/
|
|
43
|
+
export type ModelAsset = AssetTypeOverrides extends {
|
|
44
|
+
Model: infer Name extends string;
|
|
45
|
+
} ? Name | (string & {}) : string;
|
|
46
|
+
export type Model3DProps = Omit<PixiModel3DOptions, keyof Node3DProps | 'source'> & Node3DProps & {
|
|
47
|
+
asset: ModelAsset | Scene3DSource;
|
|
48
|
+
};
|
|
49
|
+
export type Light3DProps = Omit<DirectionalLightOptions & PointLightOptions & SpotLightOptions & AmbientLightOptions, keyof Node3DProps> & Node3DProps & {
|
|
50
|
+
type?: 'directional' | 'point' | 'spot' | 'ambient';
|
|
51
|
+
};
|
|
52
|
+
export type Camera3DProps = Omit<Camera3DOptions, keyof Node3DProps> & Node3DProps;
|
|
53
|
+
export declare function toVec3(value: Vec3): {
|
|
54
|
+
x: number;
|
|
55
|
+
y: number;
|
|
56
|
+
z: number;
|
|
57
|
+
};
|
|
58
|
+
export declare function resolveNodeOptions<T extends Node3DProps>(props: T): Omit<T, 'lookAt' | 'position' | 'rotation' | 'scale'> & Pick<Container3DOptions, 'position' | 'rotation' | 'scale'>;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=props.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../src/props.ts"],"names":[],"mappings":"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"}
|