phoria2 1.1.0 → 1.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.
- package/README.md +71 -13
- package/dist/bloom.js +4 -4
- package/dist/bloom.js.map +1 -1
- package/dist/charts.js +358 -345
- package/dist/charts.js.map +1 -1
- package/dist/core.js +3989 -3600
- package/dist/core.js.map +1 -1
- package/dist/edit.js +43 -43
- package/dist/edit.js.map +1 -1
- package/dist/explain.js +5 -1
- package/dist/explain.js.map +1 -1
- package/dist/gltf.js +96 -96
- package/dist/gltf.js.map +1 -1
- package/dist/motion.js +3 -3
- package/dist/motion.js.map +1 -1
- package/dist/particles.js +16 -16
- package/dist/particles.js.map +1 -1
- package/dist/passes.js +26 -26
- package/dist/passes.js.map +1 -1
- package/dist/phoria2.js +1 -1
- package/dist/picking.js +16 -16
- package/dist/picking.js.map +1 -1
- package/dist/types/OrbitControl.d.ts +6 -2
- package/dist/types/Raycaster.d.ts +10 -0
- package/dist/types/View.d.ts +59 -1
- package/dist/types/charts/Chart.d.ts +7 -0
- package/dist/types/explain.d.ts +3 -0
- package/dist/types/frame.d.ts +7 -0
- package/dist/types/geometry/Geometry.d.ts +8 -2
- package/dist/types/keyboard.d.ts +48 -0
- package/dist/types/labels.d.ts +4 -0
- package/dist/types/scene/Node.d.ts +19 -14
- package/dist/types/scene/drawables.d.ts +32 -14
- package/dist/types/scene/lights.d.ts +16 -2
- package/dist/types/shadow.d.ts +2 -1
- package/dist/types/types.d.ts +14 -0
- package/dist/types/value/Color.d.ts +0 -4
- package/dist/types/value/Quat.d.ts +4 -2
- package/llms-full.txt +58 -9
- package/package.json +4 -1
- package/schema/scene.schema.json +19 -1
- package/src/OrbitControl.js +7 -3
- package/src/Raycaster.js +58 -0
- package/src/View.js +204 -41
- package/src/charts/Chart.js +20 -2
- package/src/explain.js +6 -2
- package/src/frame.js +29 -9
- package/src/geometry/Geometry.js +16 -3
- package/src/keyboard.js +298 -0
- package/src/labels.js +4 -1
- package/src/scene/Node.js +20 -9
- package/src/scene/Scene.js +2 -0
- package/src/scene/cameras.js +4 -1
- package/src/scene/drawables.js +48 -12
- package/src/scene/lights.js +40 -6
- package/src/shadow.js +27 -4
- package/src/types.js +6 -0
- package/src/value/Color.js +21 -0
- package/src/value/Quat.js +15 -6
- package/src/watch.js +6 -1
package/dist/gltf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gltf.js","names":["quat.normalize","quat.fromMat3","DirectionalLight","Mesh","Material","Geometry","Lines","PointLight","SpotLight","fromMat3","slerp","warnOnce","PerspectiveCamera","Texture","Group","OrthographicCamera","normalize","Points","PhoriaError","Drawable","Animation","name","tracks","d","t","dt","track","scratch","sample","size","path","cubic","interpolation","stride","at","k","last","times","out","i","values","lo","hi","mid","t0","u","u2","u3","h00","h10","h01","h11","a","b","node","SUPPORTED","COMPRESSION","COMPONENTS","ARRAYS","NORMALIZE","WRAP","Model","n","which","x","names","loadGLTF","response","url","e","base","options","parseGLTF","unpack","data","version","json","ext","hint","model","build","Builder","bin","textures","bytes","view","length","type","chunk","uri","#buffers","#resolve","#textures","#objectUrls","#nodes","#node","c","scene","roots","#animation","index","parts","#mesh","part","decompose","camera","#camera","light","#light","m","geometry","#geometry","p","material","#defaultMaterial","#material","mode","pointMaterial","lineList","triangleList","key","cached","#geometries","#accessor","srgbColors","acc","count","integers","scale","#read","s","bv","viewIndex","buffer","Type","start","offset","get","o","#materials","pbr","#texture","clamp","v","transmission","coat","sheen","specular","brushed","translucent","transform","info","texCoord","colorSpace","sampler","image","texture","l","outer","inner","ch","sx","sy","sz","r","q","g","withIndices","triangles"],"sources":["../src/gltf/Animation.js","../src/gltf/load.js"],"sourcesContent":["// glTF node animations: keyframed position, rotation and scale, played by the scene clock through\n// the model's onUpdate, so they pause and run with the View like everything else.\nimport * as quat from '../math/quat.js'\n\n/** @import { Node } from '../scene/Node.js' */\n\n/**\n * One animated property of one node.\n * @typedef {object} Track\n * @property {Node} node\n * @property {'position' | 'quaternion' | 'scale'} path\n * @property {Float32Array} times seconds, ascending\n * @property {Float32Array} values per key: 3 numbers (4 for rotation); cubic splines store in-tangent, value, out-tangent\n * @property {'LINEAR' | 'STEP' | 'CUBICSPLINE'} interpolation\n */\n\n/** A named clip from a model: play(), stop(), and a few settings. */\nexport class Animation {\n /** @type {string} */ name\n /** Seconds. @type {number} */ duration\n /** @type {Track[]} */ tracks\n /** Seconds into the clip. */\n time = 0\n /** 1 = as authored; 2 = twice as fast; negative plays backwards. */\n speed = 1\n /** Start again at the end (default), or stop on the last frame. */\n loop = true\n playing = false\n\n /** @param {string} name @param {Track[]} tracks */\n constructor(name, tracks) {\n this.name = name\n this.tracks = tracks\n this.duration = tracks.reduce((d, t) => Math.max(d, t.times[t.times.length - 1] ?? 0), 0)\n }\n\n /** Start (or carry on) playing - from the start again, for a clip that doesn't loop and has finished. @returns {this} */\n play() {\n if (!this.loop && this.duration) {\n // at the end it is heading for: start over (from the end, playing backwards)\n if (this.speed >= 0 && this.time >= this.duration) this.seek(0)\n else if (this.speed < 0 && this.time <= 0) this.seek(this.duration)\n }\n this.playing = true\n return this\n }\n\n /** Pause where it is. @returns {this} */\n pause() {\n this.playing = false\n return this\n }\n\n /** Stop and go back to the first frame. @returns {this} */\n stop() {\n this.playing = false\n this.seek(0)\n return this\n }\n\n /** Jump to a time, in seconds, and pose the nodes there. @param {number} t @returns {this} */\n seek(t) {\n this.time = t\n this.apply()\n return this\n }\n\n /** @internal Advance by dt seconds when playing. @param {number} dt */\n advance(dt) {\n if (!this.playing) return\n // a clip of one key is a pose: hold it\n if (!this.duration) {\n this.apply()\n return\n }\n let t = this.time + dt * this.speed\n if (this.loop) t = ((t % this.duration) + this.duration) % this.duration\n else if (this.speed >= 0 ? t >= this.duration : t <= 0) {\n // it has run off the end it is heading for - not the one it starts at, as on the first frame\n t = Math.min(Math.max(t, 0), this.duration)\n this.playing = false\n }\n this.seek(t)\n }\n\n /** @internal Pose every animated node for the current time. */\n apply() {\n for (const track of this.tracks) sample(track, this.time)\n }\n}\n\nconst scratch = new Float32Array(4)\n\n/** @param {Track} track @param {number} t */\nfunction sample(track, t) {\n const { times, values, node, path, interpolation } = track\n const size = path === 'quaternion' ? 4 : 3\n const cubic = interpolation === 'CUBICSPLINE'\n // values per key: cubic splines hold [in-tangent, value, out-tangent]\n const stride = cubic ? size * 3 : size\n const at = (/** @type {number} */ k) => (cubic ? k * stride + size : k * stride)\n const last = times.length - 1\n const out = scratch\n if (t <= times[0] || last === 0) {\n for (let i = 0; i < size; i++) out[i] = values[at(0) + i]\n } else if (t >= times[last]) {\n for (let i = 0; i < size; i++) out[i] = values[at(last) + i]\n } else {\n // binary search for the key at or before t\n let lo = 0, hi = last\n while (hi - lo > 1) {\n const mid = (lo + hi) >> 1\n if (times[mid] <= t) lo = mid\n else hi = mid\n }\n const t0 = times[lo], t1 = times[hi], dt = t1 - t0\n const u = dt > 0 ? (t - t0) / dt : 0\n if (interpolation === 'STEP') {\n for (let i = 0; i < size; i++) out[i] = values[at(lo) + i]\n } else if (cubic) {\n // Hermite: p0, out-tangent of the first key, in-tangent of the second, p1\n const u2 = u * u, u3 = u2 * u\n const h00 = 2 * u3 - 3 * u2 + 1, h10 = u3 - 2 * u2 + u, h01 = -2 * u3 + 3 * u2, h11 = u3 - u2\n const a = lo * stride, b = hi * stride\n for (let i = 0; i < size; i++) {\n out[i] = h00 * values[a + size + i] + h10 * dt * values[a + size * 2 + i] + h01 * values[b + size + i] + h11 * dt * values[b + i]\n }\n if (size === 4) quat.normalize(out, out)\n } else if (size === 4) {\n quat.slerp(out, values.subarray(lo * 4, lo * 4 + 4), values.subarray(hi * 4, hi * 4 + 4), u)\n } else {\n for (let i = 0; i < 3; i++) out[i] = values[lo * 3 + i] + (values[hi * 3 + i] - values[lo * 3 + i]) * u\n }\n }\n if (path === 'quaternion') node.quaternion.set(out[0], out[1], out[2], out[3])\n else node[path].set(out[0], out[1], out[2])\n}\n","// glTF 2.0 (.gltf and .glb) to phoria2 nodes: meshes, the metallic-roughness material and its maps,\n// textures, the node hierarchy, cameras, KHR_lights_punctual and node animations. glTF's\n// conventions are phoria2's (+Y up, metres, counter-clockwise front faces, linear colour), so\n// little needs converting.\nimport * as quat from '../math/quat.js'\nimport { Group } from '../scene/Node.js'\nimport { Drawable, Mesh, Points, Lines } from '../scene/drawables.js'\nimport { PerspectiveCamera, OrthographicCamera } from '../scene/cameras.js'\nimport { DirectionalLight, PointLight, SpotLight } from '../scene/lights.js'\nimport { Geometry } from '../geometry/Geometry.js'\nimport { Material } from '../material/Material.js'\nimport { Texture } from '../material/Texture.js'\nimport { PhoriaError, warnOnce } from '../validate.js'\nimport { Animation } from './Animation.js'\n\n/** @import { Node } from '../scene/Node.js' */\n/** @import { Camera } from '../scene/cameras.js' */\n/** @import { Track } from './Animation.js' */\n\n/**\n * @typedef {object} GLTFOptions\n * @property {string} [baseUrl] where relative uris resolve from (default: the file's own url)\n * @property {boolean} [waitForTextures] resolve once every texture has loaded, so the first frame\n * is complete (default true)\n */\n\nconst SUPPORTED = new Set(['KHR_materials_emissive_strength', 'KHR_texture_transform', 'KHR_lights_punctual',\n 'KHR_materials_unlit', 'KHR_mesh_quantization', 'KHR_materials_transmission', 'KHR_materials_clearcoat', 'KHR_materials_sheen',\n 'KHR_materials_ior', 'KHR_materials_specular', 'KHR_materials_anisotropy', 'KHR_materials_diffuse_transmission'])\nconst COMPRESSION = new Set(['KHR_draco_mesh_compression', 'EXT_meshopt_compression', 'KHR_texture_basisu'])\n\nconst COMPONENTS = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 4, MAT3: 9, MAT4: 16 }\nconst ARRAYS = { 5120: Int8Array, 5121: Uint8Array, 5122: Int16Array, 5123: Uint16Array, 5125: Uint32Array, 5126: Float32Array }\n// normalized integers map to 0-1 (unsigned) or -1-1 (signed)\nconst NORMALIZE = { 5120: 127, 5121: 255, 5122: 32767, 5123: 65535, 5125: 1 }\nconst WRAP = { 33071: 'clamp', 33648: 'mirror', 10497: 'repeat' }\n\n/** A loaded glTF scene: a Group, plus the file's animations and cameras. */\nexport class Model extends Group {\n static type = 'model'\n /** @type {Animation[]} */ animations = []\n /** @type {Camera[]} */ cameras = []\n\n /**\n * Every mesh, point set and line set in the model - to change them together:\n * `for (const m of model.meshes) m.castShadow = true`.\n * @returns {Drawable[]}\n */\n get meshes() {\n return /** @type {Drawable[]} */ (this.findAll((n) => n instanceof Drawable))\n }\n\n /**\n * Play an animation by name or index (the first when not given).\n * @param {string | number} [which]\n * @returns {Animation | null}\n */\n play(which = 0) {\n const a = typeof which === 'number' ? this.animations[which] : this.animations.find((x) => x.name === which)\n if (!a) {\n const names = this.animations.map((x) => `'${x.name}'`).join(', ')\n warnOnce(this, `no animation ${typeof which === 'number' ? which : `'${which}'`} - this model has ${names || 'none'}`)\n return null\n }\n return a.play()\n }\n\n /**\n * A plain group of its parts, so create() can build it back without phoria2/gltf - with their\n * vertex data, but not the animations, or textures embedded in a .glb (they have no url).\n * @returns {Record<string, any>}\n */\n toJSON() {\n return { ...super.toJSON(), type: 'group' }\n }\n}\n\n/**\n * Load a .gltf or .glb file into a Model (a Group): add it to the scene, frame it, find its parts by\n * name. Resolves once its textures have loaded.\n *\n * const model = await loadGLTF('chair.glb')\n * view.scene.add(model)\n * view.frame(model)\n * model.find('Cushion').material.color.set('#2a6')\n *\n * @param {string} url\n * @param {GLTFOptions} [options]\n * @returns {Promise<Model>}\n */\nexport async function loadGLTF(url, options = {}) {\n const response = await fetch(url).catch((e) => { throw new PhoriaError(`loadGLTF: couldn't fetch '${url}' - ${e.message}`) })\n if (!response.ok) throw new PhoriaError(`loadGLTF: couldn't fetch '${url}' (${response.status} ${response.statusText})`)\n const base = options.baseUrl ?? new URL(url, globalThis.location?.href ?? 'file:///').href\n return parseGLTF(await response.arrayBuffer(), { ...options, baseUrl: base })\n}\n\n/**\n * Build a Model from a .glb file's bytes, a .gltf file's bytes or text, or its parsed JSON.\n * @param {ArrayBuffer | Uint8Array | string | Record<string, any>} data\n * @param {GLTFOptions} [options]\n * @returns {Promise<Model>}\n */\nexport async function parseGLTF(data, options = {}) {\n const { json, bin } = unpack(data)\n const version = String(json.asset?.version ?? '')\n if (!version.startsWith('2.')) throw new PhoriaError(`loadGLTF: glTF ${version || '(no version)'} isn't supported - only glTF 2.0`)\n for (const ext of json.extensionsRequired ?? []) {\n if (SUPPORTED.has(ext)) continue\n const hint = COMPRESSION.has(ext) ? ' - export the model without compression for now' : ''\n throw new PhoriaError(`loadGLTF: the model requires '${ext}', which isn't supported${hint}`)\n }\n const model = new Model({ name: json.scenes?.[json.scene ?? 0]?.name ?? 'model' })\n for (const ext of json.extensionsUsed ?? []) {\n if (!SUPPORTED.has(ext)) warnOnce(model, `the model uses '${ext}', which isn't supported - it is ignored`)\n }\n const build = new Builder(json, bin, options.baseUrl ?? '', model)\n await build.buffers()\n build.scene()\n // either way, embedded images' object urls are released once their textures settle\n const textures = build.textures()\n if (options.waitForTextures ?? true) await textures\n return model\n}\n\n/** @param {ArrayBuffer | Uint8Array | string | Record<string, any>} data */\nfunction unpack(data) {\n if (typeof data === 'string') return { json: JSON.parse(data), bin: null }\n if (!(data instanceof ArrayBuffer) && !ArrayBuffer.isView(data)) return { json: data, bin: null }\n const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength)\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n // 'glTF' little-endian: a binary container of a JSON chunk and an optional binary chunk\n if (bytes.length >= 12 && view.getUint32(0, true) === 0x46546c67) {\n let json = null, bin = null\n for (let at = 12; at + 8 <= bytes.length;) {\n const length = view.getUint32(at, true), type = view.getUint32(at + 4, true)\n const chunk = bytes.subarray(at + 8, at + 8 + length)\n if (type === 0x4e4f534a) json = JSON.parse(new TextDecoder().decode(chunk))\n else if (type === 0x004e4942) bin = chunk\n at += 8 + length\n }\n if (!json) throw new PhoriaError('loadGLTF: the .glb file has no JSON chunk')\n return { json, bin }\n }\n return { json: JSON.parse(new TextDecoder().decode(bytes)), bin: null }\n}\n\nclass Builder {\n /** @type {Uint8Array[]} */ #buffers = []\n /** @type {Map<string, Texture>} */ #textures = new Map()\n /** @type {Map<number, Material>} */ #materials = new Map()\n /** @type {Map<string, Geometry>} */ #geometries = new Map()\n /** @type {Node[]} */ #nodes = []\n /** @type {string[]} */ #objectUrls = []\n\n /** @param {Record<string, any>} json @param {Uint8Array | null} bin @param {string} base @param {Model} model */\n constructor(json, bin, base, model) {\n this.json = json\n this.bin = bin\n this.base = base\n this.model = model\n }\n\n /** @param {string} uri */\n #resolve(uri) {\n try {\n return new URL(uri, this.base || undefined).href\n } catch {\n return uri\n }\n }\n\n async buffers() {\n this.#buffers = await Promise.all((this.json.buffers ?? []).map(async (b, i) => {\n if (b.uri === undefined) {\n if (i !== 0 || !this.bin) throw new PhoriaError(`loadGLTF: buffer ${i} has no uri and there is no binary chunk`)\n return this.bin\n }\n const url = this.#resolve(b.uri)\n const response = await fetch(url).catch((e) => { throw new PhoriaError(`loadGLTF: couldn't fetch buffer '${b.uri}' - ${e.message}`) })\n if (!response.ok) throw new PhoriaError(`loadGLTF: couldn't fetch buffer '${b.uri}' (${response.status})`)\n return new Uint8Array(await response.arrayBuffer())\n }))\n }\n\n /** Resolves when every texture has loaded (failures are warned about, not thrown). */\n async textures() {\n await Promise.all([...this.#textures.values()].map((t) => t.ready.catch((e) => warnOnce(this.model, e.message))))\n for (const url of this.#objectUrls) URL.revokeObjectURL(url)\n }\n\n scene() {\n const json = this.json\n this.#nodes = (json.nodes ?? []).map((_, i) => this.#node(i))\n // parent after every node exists, since children can come before their parents\n ;(json.nodes ?? []).forEach((n, i) => {\n for (const c of n.children ?? []) this.#nodes[i].add(this.#nodes[c])\n })\n const scene = json.scenes?.[json.scene ?? 0]\n const roots = scene ? scene.nodes ?? [] : this.#nodes.map((_, i) => i).filter((i) => !this.#nodes[i].parent)\n for (const i of roots) this.model.add(this.#nodes[i])\n this.model.animations = (json.animations ?? []).map((a, i) => this.#animation(a, i))\n if (this.model.animations.length) {\n const model = this.model\n model.onUpdate((_node, dt) => {\n for (const a of model.animations) a.advance(dt)\n })\n }\n }\n\n /** @param {number} index @returns {Node} */\n #node(index) {\n const n = this.json.nodes[index]\n const name = n.name ?? `node ${index}`\n if (n.skin !== undefined) warnOnce(this.model, `skinned meshes aren't supported - '${name}' is drawn in its bind pose`)\n if (n.weights || (n.mesh !== undefined && this.json.meshes[n.mesh].weights)) warnOnce(this.model, \"morph targets aren't supported - meshes are drawn without them\")\n\n const parts = n.mesh !== undefined ? this.#mesh(n.mesh) : []\n // a node with one primitive is that drawable; with several, a group of them\n /** @type {Node} */\n const node = parts.length === 1 ? parts[0] : new Group()\n for (const part of parts.length > 1 ? parts : []) node.add(part)\n node.name = name\n if (n.matrix) decompose(node, n.matrix)\n else {\n if (n.translation) node.position.set(n.translation[0], n.translation[1], n.translation[2])\n if (n.rotation) node.quaternion.set(n.rotation[0], n.rotation[1], n.rotation[2], n.rotation[3])\n if (n.scale) node.scale.set(n.scale[0], n.scale[1], n.scale[2])\n }\n if (n.camera !== undefined) {\n const camera = this.#camera(n.camera)\n node.add(camera)\n this.model.cameras.push(camera)\n }\n const light = n.extensions?.KHR_lights_punctual?.light\n if (light !== undefined) node.add(this.#light(light))\n if (n.extras && typeof n.extras === 'object') node.userData = { ...n.extras }\n return node\n }\n\n /** @param {number} index @returns {Node[]} */\n #mesh(index) {\n const m = this.json.meshes[index]\n return m.primitives.map((p, i) => {\n const geometry = this.#geometry(p)\n const material = p.material !== undefined ? this.#material(p.material) : this.#defaultMaterial()\n const mode = p.mode ?? 4\n /** @type {Node} */\n let node\n if (mode === 0) node = new Points({ geometry, material: pointMaterial(material) })\n else if (mode === 1 || mode === 2 || mode === 3) node = new Lines({ geometry: lineList(geometry, mode), material: pointMaterial(material) })\n else node = new Mesh({ geometry: mode === 4 ? geometry : triangleList(geometry, mode), material })\n node.name = m.primitives.length > 1 ? `${m.name ?? `mesh ${index}`} ${i}` : m.name ?? `mesh ${index}`\n return node\n })\n }\n\n /** @param {Record<string, any>} p */\n #geometry(p) {\n // primitives often share accessors; share their geometry too\n const key = JSON.stringify([p.attributes, p.indices])\n const cached = this.#geometries.get(key)\n if (cached) return cached\n const a = p.attributes\n if (a.POSITION === undefined) throw new PhoriaError('loadGLTF: a mesh primitive has no POSITION')\n /** @type {import('../geometry/Geometry.js').GeometryOptions} */\n const options = { positions: this.#accessor(a.POSITION) }\n if (a.NORMAL !== undefined) options.normals = this.#accessor(a.NORMAL)\n if (a.TEXCOORD_0 !== undefined) options.uvs = this.#accessor(a.TEXCOORD_0)\n if (a.TEXCOORD_1 !== undefined) options.uvs2 = this.#accessor(a.TEXCOORD_1)\n if (a.COLOR_0 !== undefined) options.colors = srgbColors(/** @type {Float32Array} */ (this.#accessor(a.COLOR_0)), COMPONENTS[this.json.accessors[a.COLOR_0].type])\n if (p.indices !== undefined) options.indices = this.#accessor(p.indices, true)\n const geometry = new Geometry(options)\n this.#geometries.set(key, geometry)\n return geometry\n }\n\n /**\n * An accessor's numbers, as floats (normalized integers scaled), or as integers for indices.\n * @param {number} index @param {boolean} [integers]\n * @returns {Float32Array | Uint32Array}\n */\n #accessor(index, integers = false) {\n const acc = this.json.accessors[index]\n const size = COMPONENTS[acc.type]\n const count = acc.count * size\n const out = integers ? new Uint32Array(count) : new Float32Array(count)\n const scale = acc.normalized && !integers ? 1 / NORMALIZE[acc.componentType] : 1\n if (acc.bufferView !== undefined) this.#read(acc.bufferView, acc.byteOffset ?? 0, acc.componentType, size, acc.count, out, scale)\n if (acc.sparse) {\n // a few elements replaced: indices of the elements, then their values\n const s = acc.sparse\n const at = new Uint32Array(s.count)\n this.#read(s.indices.bufferView, s.indices.byteOffset ?? 0, s.indices.componentType, 1, s.count, at, 1)\n const values = integers ? new Uint32Array(s.count * size) : new Float32Array(s.count * size)\n this.#read(s.values.bufferView, s.values.byteOffset ?? 0, acc.componentType, size, s.count, values, scale)\n for (let i = 0; i < s.count; i++) out.set(values.subarray(i * size, i * size + size), at[i] * size)\n }\n if (acc.normalized && !integers && (acc.componentType === 5120 || acc.componentType === 5122)) {\n for (let i = 0; i < out.length; i++) out[i] = Math.max(out[i], -1)\n }\n return out\n }\n\n /**\n * Copy elements out of a buffer view, honouring its stride.\n * @param {number} viewIndex @param {number} offset @param {number} type component type\n * @param {number} size components per element @param {number} count elements\n * @param {Float32Array | Uint32Array} out @param {number} scale\n */\n #read(viewIndex, offset, type, size, count, out, scale) {\n const bv = this.json.bufferViews[viewIndex]\n const buffer = this.#buffers[bv.buffer]\n const Type = ARRAYS[type]\n if (!Type) throw new PhoriaError(`loadGLTF: unknown component type ${type}`)\n const bytes = Type.BYTES_PER_ELEMENT\n const stride = bv.byteStride || size * bytes\n const start = buffer.byteOffset + (bv.byteOffset ?? 0) + offset\n const view = new DataView(buffer.buffer)\n const get = {\n 5120: (/** @type {number} */ o) => view.getInt8(o),\n 5121: (/** @type {number} */ o) => view.getUint8(o),\n 5122: (/** @type {number} */ o) => view.getInt16(o, true),\n 5123: (/** @type {number} */ o) => view.getUint16(o, true),\n 5125: (/** @type {number} */ o) => view.getUint32(o, true),\n 5126: (/** @type {number} */ o) => view.getFloat32(o, true),\n }[type]\n // the common case - tightly packed and aligned floats - is one copy\n if (type === 5126 && stride === size * 4 && start % 4 === 0 && scale === 1 && out instanceof Float32Array) {\n out.set(new Float32Array(buffer.buffer, start, count * size))\n return\n }\n for (let i = 0; i < count; i++) {\n for (let c = 0; c < size; c++) out[i * size + c] = get(start + i * stride + c * bytes) * scale\n }\n }\n\n /** @param {number} index @returns {Material} */\n #material(index) {\n const cached = this.#materials.get(index)\n if (cached) return cached\n const m = this.json.materials[index]\n const pbr = m.pbrMetallicRoughness ?? {}\n const material = new Material({ name: m.name ?? `material ${index}` })\n const base = pbr.baseColorFactor ?? [1, 1, 1, 1]\n material.color.setLinear(base[0], base[1], base[2])\n material.metalness = pbr.metallicFactor ?? 1\n material.roughness = pbr.roughnessFactor ?? 1\n if (pbr.baseColorTexture) material.map = this.#texture(pbr.baseColorTexture, 'srgb')\n if (pbr.metallicRoughnessTexture) {\n // one texture: roughness in green, metalness in blue - exactly what the two slots read\n material.roughnessMap = material.metalnessMap = this.#texture(pbr.metallicRoughnessTexture, 'linear')\n }\n if (m.normalTexture) {\n material.normalMap = this.#texture(m.normalTexture, 'linear')\n material.normalScale = m.normalTexture.scale ?? 1\n }\n if (m.occlusionTexture) {\n material.aoMap = this.#texture(m.occlusionTexture, 'linear')\n material.aoMapIntensity = Math.min(Math.max(m.occlusionTexture.strength ?? 1, 0), 1)\n }\n if (m.emissiveFactor) material.emissive.setLinear(m.emissiveFactor[0], m.emissiveFactor[1], m.emissiveFactor[2])\n if (m.emissiveTexture) {\n material.emissiveMap = this.#texture(m.emissiveTexture, 'srgb')\n if (!m.emissiveFactor) material.emissive.setLinear(1, 1, 1)\n }\n material.emissiveIntensity = m.extensions?.KHR_materials_emissive_strength?.emissiveStrength ?? 1\n if (m.extensions?.KHR_materials_unlit) material.unlit = true\n // glass, clear coat, cloth, reflectance, brushed metal and translucency, by their factors - their\n // own textures aren't read\n const clamp = (/** @type {number} */ v) => Math.min(Math.max(v, 0), 1)\n const x = m.extensions ?? {}\n const transmission = x.KHR_materials_transmission, coat = x.KHR_materials_clearcoat, sheen = x.KHR_materials_sheen\n if (transmission) material.transmission = clamp(transmission.transmissionFactor ?? 0)\n if (coat) {\n material.clearcoat = clamp(coat.clearcoatFactor ?? 0)\n material.clearcoatRoughness = clamp(coat.clearcoatRoughnessFactor ?? 0)\n }\n if (sheen) {\n const c = sheen.sheenColorFactor ?? [0, 0, 0]\n // glTF's sheen is its colour alone: black is none\n if (Math.max(c[0], c[1], c[2]) > 0) {\n material.sheen = 1\n material.sheenColor.setLinear(c[0], c[1], c[2])\n }\n material.sheenRoughness = clamp(sheen.sheenRoughnessFactor ?? 0)\n }\n if (x.KHR_materials_ior?.ior >= 1) material.ior = x.KHR_materials_ior.ior\n const specular = x.KHR_materials_specular\n if (specular) {\n material.specularIntensity = clamp(specular.specularFactor ?? 1)\n const c = specular.specularColorFactor ?? [1, 1, 1]\n material.specularColor.setLinear(c[0], c[1], c[2])\n }\n const brushed = x.KHR_materials_anisotropy\n if (brushed) {\n material.anisotropy = clamp(brushed.anisotropyStrength ?? 0)\n material.anisotropyRotation = brushed.anisotropyRotation ?? 0\n }\n const translucent = x.KHR_materials_diffuse_transmission\n if (translucent) {\n material.translucency = clamp(translucent.diffuseTransmissionFactor ?? 0)\n const c = translucent.diffuseTransmissionColorFactor ?? [1, 1, 1]\n material.translucencyColor.setLinear(c[0], c[1], c[2])\n }\n if (m.alphaMode === 'BLEND') {\n material.opacity = base[3]\n material.transparent = true\n material.depthWrite = false\n } else if (m.alphaMode === 'MASK') {\n material.alphaTest = m.alphaCutoff ?? 0.5\n }\n material.doubleSided = !!m.doubleSided\n this.#materials.set(index, material)\n return material\n }\n\n // glTF's default for primitives without a material\n #defaultMaterial() {\n let material = this.#materials.get(-1)\n if (!material) this.#materials.set(-1, material = new Material({ name: 'default', metalness: 1, roughness: 1 }))\n return material\n }\n\n /**\n * @param {Record<string, any>} info a textureInfo: index, texCoord, extensions\n * @param {'srgb' | 'linear'} colorSpace what the slot holds\n * @returns {Texture}\n */\n #texture(info, colorSpace) {\n const transform = info.extensions?.KHR_texture_transform\n let texCoord = transform?.texCoord ?? info.texCoord ?? 0\n if (texCoord > 1) {\n warnOnce(this.model, `textures on a third UV set or later (TEXCOORD_${texCoord}) are drawn with the first`)\n texCoord = 0\n }\n const key = JSON.stringify([info.index, colorSpace, transform?.offset, transform?.scale, transform?.rotation, texCoord])\n const cached = this.#textures.get(key)\n if (cached) return cached\n\n const t = this.json.textures[info.index]\n const sampler = this.json.samplers?.[t.sampler] ?? {}\n const image = this.json.images[t.source]\n if (t.source === undefined || !image) throw new PhoriaError(`loadGLTF: texture ${info.index} has no image (compressed textures aren't supported)`)\n let url\n if (image.bufferView !== undefined) {\n const bv = this.json.bufferViews[image.bufferView]\n const buffer = this.#buffers[bv.buffer]\n const bytes = buffer.subarray(bv.byteOffset ?? 0, (bv.byteOffset ?? 0) + bv.byteLength)\n url = URL.createObjectURL(new Blob([/** @type {Uint8Array<ArrayBuffer>} */ (bytes)], { type: image.mimeType ?? 'image/png' }))\n this.#objectUrls.push(url)\n } else {\n url = this.#resolve(image.uri)\n }\n const texture = new Texture({\n url,\n colorSpace,\n wrap: WRAP[sampler.wrapS ?? 10497] ?? 'repeat',\n filter: sampler.magFilter === 9728 ? 'nearest' : 'linear',\n // glTF UVs start at the image's top left, as phoria2's do\n flipY: false,\n repeat: transform?.scale ?? [1, 1],\n offset: transform?.offset ?? [0, 0],\n rotation: transform?.rotation ?? 0,\n uvSet: texCoord,\n })\n this.#textures.set(key, texture)\n return texture\n }\n\n /** @param {number} index @returns {Camera} */\n #camera(index) {\n const c = this.json.cameras[index]\n const name = c.name ?? `camera ${index}`\n if (c.type === 'orthographic') {\n const o = c.orthographic\n return new OrthographicCamera({ name, height: o.ymag * 2, near: o.znear, far: o.zfar })\n }\n const p = c.perspective\n return new PerspectiveCamera({ name, fov: (p.yfov * 180) / Math.PI, near: p.znear, far: p.zfar ?? 1e6 })\n }\n\n /** @param {number} index */\n #light(index) {\n const l = this.json.extensions?.KHR_lights_punctual?.lights?.[index]\n if (!l) throw new PhoriaError(`loadGLTF: KHR_lights_punctual light ${index} doesn't exist`)\n const c = l.color ?? [1, 1, 1]\n // glTF lights shine down their node's -Z; intensities are lux and candela, divided by PI for\n // phoria2's lights (where 1 lights a white surface to white)\n const options = { name: l.name, intensity: (l.intensity ?? 1) / Math.PI }\n let light\n if (l.type === 'directional') light = new DirectionalLight({ ...options, direction: [0, 0, -1] })\n else if (l.type === 'spot') {\n const outer = l.spot?.outerConeAngle ?? Math.PI / 4, inner = l.spot?.innerConeAngle ?? 0\n light = new SpotLight({ ...options, direction: [0, 0, -1], range: l.range ?? 0, angle: outer, penumbra: outer > 0 ? 1 - inner / outer : 0 })\n } else light = new PointLight({ ...options, range: l.range ?? 0 })\n light.color.setLinear(c[0], c[1], c[2])\n return light\n }\n\n /** @param {Record<string, any>} a @param {number} index @returns {Animation} */\n #animation(a, index) {\n /** @type {Track[]} */\n const tracks = []\n for (const ch of a.channels) {\n const path = { translation: 'position', rotation: 'quaternion', scale: 'scale' }[ch.target.path]\n if (!path) {\n warnOnce(this.model, `'${ch.target.path}' animations aren't supported - only translation, rotation and scale`)\n continue\n }\n const node = this.#nodes[ch.target.node]\n if (!node) continue\n const s = a.samplers[ch.sampler]\n tracks.push({\n node, path,\n times: /** @type {Float32Array} */ (this.#accessor(s.input)),\n values: /** @type {Float32Array} */ (this.#accessor(s.output)),\n interpolation: s.interpolation ?? 'LINEAR',\n })\n }\n return new Animation(a.name ?? `animation ${index}`, tracks)\n }\n}\n\n/** Set a node's position, rotation and scale from a column-major matrix. @param {Node} node @param {number[]} m */\nfunction decompose(node, m) {\n let sx = Math.hypot(m[0], m[1], m[2])\n const sy = Math.hypot(m[4], m[5], m[6]), sz = Math.hypot(m[8], m[9], m[10])\n // a mirroring matrix: put the flip in x\n const det = m[0] * (m[5] * m[10] - m[6] * m[9]) - m[4] * (m[1] * m[10] - m[2] * m[9]) + m[8] * (m[1] * m[6] - m[2] * m[5])\n if (det < 0) sx = -sx\n const r = [m[0] / sx, m[1] / sx, m[2] / sx, m[4] / sy, m[5] / sy, m[6] / sy, m[8] / sz, m[9] / sz, m[10] / sz]\n const q = quat.normalize([0, 0, 0, 1], quat.fromMat3([0, 0, 0, 1], r))\n node.position.set(m[12], m[13], m[14])\n node.quaternion.set(q[0], q[1], q[2], q[3])\n node.scale.set(sx, sy, sz)\n}\n\n/** glTF vertex colours are linear RGB(A); phoria2's are sRGB RGB. @param {Float32Array} c @param {number} size */\nfunction srgbColors(c, size) {\n const n = c.length / size\n const out = new Float32Array(n * 3)\n for (let i = 0; i < n; i++) {\n for (let k = 0; k < 3; k++) {\n const v = Math.min(Math.max(c[i * size + k], 0), 1)\n out[i * 3 + k] = v <= 0.0031308 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - 0.055\n }\n }\n return out\n}\n\n/** Points and Lines take their colour and size from a lit material's basics. @param {Material} m */\nfunction pointMaterial(m) {\n return new Material({ name: m.name, color: m.color.getStyle(), opacity: m.opacity, map: m.map, vertexColors: true, size: 2, sizeAttenuation: false })\n}\n\n/** Triangle strips and fans as a plain triangle list. @param {Geometry} g @param {number} mode */\nfunction triangleList(g, mode) {\n const index = g.indices ?? Uint32Array.from({ length: g.vertexCount }, (_, i) => i)\n const out = []\n for (let i = 2; i < index.length; i++) {\n if (mode === 6) out.push(index[0], index[i - 1], index[i])\n // strips alternate winding, so every other triangle swaps two corners\n else if (i % 2 === 0) out.push(index[i - 2], index[i - 1], index[i])\n else out.push(index[i - 1], index[i - 2], index[i])\n }\n return withIndices(g, out, true)\n}\n\n/** Line strips and loops as segment pairs. @param {Geometry} g @param {number} mode */\nfunction lineList(g, mode) {\n if (mode === 1) return g\n const index = g.indices ?? Uint32Array.from({ length: g.vertexCount }, (_, i) => i)\n const out = []\n for (let i = 1; i < index.length; i++) out.push(index[i - 1], index[i])\n if (mode === 2 && index.length > 2) out.push(index[index.length - 1], index[0])\n return withIndices(g, out, false)\n}\n\n/** @param {Geometry} g @param {number[]} indices @param {boolean} triangles keep normals (lines have none) */\nfunction withIndices(g, indices, triangles) {\n // only normals the file gave - reading g.normals would work them out from the strip's own indices,\n // taken as a triangle list; the new geometry works them out from its real triangles instead\n return new Geometry({ positions: g.positions, normals: triangles && g.hasNormals ? g.normals : undefined, uvs: g.uvs ?? undefined, uvs2: g.uvs2 ?? undefined,\n colors: g.colors ?? undefined, indices })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gltf.js","names":["quat.normalize","quat.fromMat3","Lines","PointLight","OrthographicCamera","SpotLight","PerspectiveCamera","DirectionalLight","Drawable","Material","Geometry","Mesh","normalize","warnOnce","slerp","Group","Texture","Points","fromMat3","PhoriaError","Animation","name","tracks","d","t","dt","track","scratch","sample","size","path","cubic","interpolation","stride","at","k","last","times","out","i","values","lo","hi","mid","t0","u","u2","u3","h00","h10","h01","h11","a","b","node","SUPPORTED","COMPRESSION","COMPONENTS","ARRAYS","NORMALIZE","WRAP","Model","n","which","x","names","loadGLTF","response","url","e","base","options","parseGLTF","unpack","data","version","json","ext","hint","model","build","Builder","bin","textures","bytes","view","length","type","chunk","uri","#buffers","#resolve","#textures","#objectUrls","#nodes","#node","c","scene","roots","#animation","index","parts","#mesh","part","decompose","camera","#camera","light","#light","m","geometry","#geometry","p","material","#defaultMaterial","#material","mode","pointMaterial","lineList","triangleList","key","cached","#geometries","#accessor","srgbColors","acc","count","integers","scale","#read","s","bv","viewIndex","buffer","Type","start","offset","get","o","#materials","pbr","#texture","clamp","v","transmission","coat","sheen","specular","brushed","translucent","transform","info","texCoord","colorSpace","sampler","image","texture","l","outer","inner","ch","sx","sy","sz","r","q","g","withIndices","triangles"],"sources":["../src/gltf/Animation.js","../src/gltf/load.js"],"sourcesContent":["// glTF node animations: keyframed position, rotation and scale, played by the scene clock through\n// the model's onUpdate, so they pause and run with the View like everything else.\nimport * as quat from '../math/quat.js'\n\n/** @import { Node } from '../scene/Node.js' */\n\n/**\n * One animated property of one node.\n * @typedef {object} Track\n * @property {Node} node\n * @property {'position' | 'quaternion' | 'scale'} path\n * @property {Float32Array} times seconds, ascending\n * @property {Float32Array} values per key: 3 numbers (4 for rotation); cubic splines store in-tangent, value, out-tangent\n * @property {'LINEAR' | 'STEP' | 'CUBICSPLINE'} interpolation\n */\n\n/** A named clip from a model: play(), stop(), and a few settings. */\nexport class Animation {\n /** @type {string} */ name\n /** Seconds. @type {number} */ duration\n /** @type {Track[]} */ tracks\n /** Seconds into the clip. */\n time = 0\n /** 1 = as authored; 2 = twice as fast; negative plays backwards. */\n speed = 1\n /** Start again at the end (default), or stop on the last frame. */\n loop = true\n playing = false\n\n /** @param {string} name @param {Track[]} tracks */\n constructor(name, tracks) {\n this.name = name\n this.tracks = tracks\n this.duration = tracks.reduce((d, t) => Math.max(d, t.times[t.times.length - 1] ?? 0), 0)\n }\n\n /** Start (or carry on) playing - from the start again, for a clip that doesn't loop and has finished. @returns {this} */\n play() {\n if (!this.loop && this.duration) {\n // at the end it is heading for: start over (from the end, playing backwards)\n if (this.speed >= 0 && this.time >= this.duration) this.seek(0)\n else if (this.speed < 0 && this.time <= 0) this.seek(this.duration)\n }\n this.playing = true\n return this\n }\n\n /** Pause where it is. @returns {this} */\n pause() {\n this.playing = false\n return this\n }\n\n /** Stop and go back to the first frame. @returns {this} */\n stop() {\n this.playing = false\n this.seek(0)\n return this\n }\n\n /** Jump to a time, in seconds, and pose the nodes there. @param {number} t @returns {this} */\n seek(t) {\n this.time = t\n this.apply()\n return this\n }\n\n /** @internal Advance by dt seconds when playing. @param {number} dt */\n advance(dt) {\n if (!this.playing) return\n // a clip of one key is a pose: hold it\n if (!this.duration) {\n this.apply()\n return\n }\n let t = this.time + dt * this.speed\n if (this.loop) t = ((t % this.duration) + this.duration) % this.duration\n else if (this.speed >= 0 ? t >= this.duration : t <= 0) {\n // it has run off the end it is heading for - not the one it starts at, as on the first frame\n t = Math.min(Math.max(t, 0), this.duration)\n this.playing = false\n }\n this.seek(t)\n }\n\n /** @internal Pose every animated node for the current time. */\n apply() {\n for (const track of this.tracks) sample(track, this.time)\n }\n}\n\nconst scratch = new Float32Array(4)\n\n/** @param {Track} track @param {number} t */\nfunction sample(track, t) {\n const { times, values, node, path, interpolation } = track\n const size = path === 'quaternion' ? 4 : 3\n const cubic = interpolation === 'CUBICSPLINE'\n // values per key: cubic splines hold [in-tangent, value, out-tangent]\n const stride = cubic ? size * 3 : size\n const at = (/** @type {number} */ k) => (cubic ? k * stride + size : k * stride)\n const last = times.length - 1\n const out = scratch\n if (t <= times[0] || last === 0) {\n for (let i = 0; i < size; i++) out[i] = values[at(0) + i]\n } else if (t >= times[last]) {\n for (let i = 0; i < size; i++) out[i] = values[at(last) + i]\n } else {\n // binary search for the key at or before t\n let lo = 0, hi = last\n while (hi - lo > 1) {\n const mid = (lo + hi) >> 1\n if (times[mid] <= t) lo = mid\n else hi = mid\n }\n const t0 = times[lo], t1 = times[hi], dt = t1 - t0\n const u = dt > 0 ? (t - t0) / dt : 0\n if (interpolation === 'STEP') {\n for (let i = 0; i < size; i++) out[i] = values[at(lo) + i]\n } else if (cubic) {\n // Hermite: p0, out-tangent of the first key, in-tangent of the second, p1\n const u2 = u * u, u3 = u2 * u\n const h00 = 2 * u3 - 3 * u2 + 1, h10 = u3 - 2 * u2 + u, h01 = -2 * u3 + 3 * u2, h11 = u3 - u2\n const a = lo * stride, b = hi * stride\n for (let i = 0; i < size; i++) {\n out[i] = h00 * values[a + size + i] + h10 * dt * values[a + size * 2 + i] + h01 * values[b + size + i] + h11 * dt * values[b + i]\n }\n if (size === 4) quat.normalize(out, out)\n } else if (size === 4) {\n quat.slerp(out, values.subarray(lo * 4, lo * 4 + 4), values.subarray(hi * 4, hi * 4 + 4), u)\n } else {\n for (let i = 0; i < 3; i++) out[i] = values[lo * 3 + i] + (values[hi * 3 + i] - values[lo * 3 + i]) * u\n }\n }\n if (path === 'quaternion') node.quaternion.set(out[0], out[1], out[2], out[3])\n else node[path].set(out[0], out[1], out[2])\n}\n","// glTF 2.0 (.gltf and .glb) to phoria2 nodes: meshes, the metallic-roughness material and its maps,\n// textures, the node hierarchy, cameras, KHR_lights_punctual and node animations. glTF's\n// conventions are phoria2's (+Y up, metres, counter-clockwise front faces, linear colour), so\n// little needs converting.\nimport * as quat from '../math/quat.js'\nimport { Group } from '../scene/Node.js'\nimport { Drawable, Mesh, Points, Lines } from '../scene/drawables.js'\nimport { PerspectiveCamera, OrthographicCamera } from '../scene/cameras.js'\nimport { DirectionalLight, PointLight, SpotLight } from '../scene/lights.js'\nimport { Geometry } from '../geometry/Geometry.js'\nimport { Material } from '../material/Material.js'\nimport { Texture } from '../material/Texture.js'\nimport { PhoriaError, warnOnce } from '../validate.js'\nimport { Animation } from './Animation.js'\n\n/** @import { Node } from '../scene/Node.js' */\n/** @import { Camera } from '../scene/cameras.js' */\n/** @import { Track } from './Animation.js' */\n\n/**\n * @typedef {object} GLTFOptions\n * @property {string} [baseUrl] where relative uris resolve from (default: the file's own url)\n * @property {boolean} [waitForTextures] resolve once every texture has loaded, so the first frame\n * is complete (default true)\n */\n\nconst SUPPORTED = new Set(['KHR_materials_emissive_strength', 'KHR_texture_transform', 'KHR_lights_punctual',\n 'KHR_materials_unlit', 'KHR_mesh_quantization', 'KHR_materials_transmission', 'KHR_materials_clearcoat', 'KHR_materials_sheen',\n 'KHR_materials_ior', 'KHR_materials_specular', 'KHR_materials_anisotropy', 'KHR_materials_diffuse_transmission'])\nconst COMPRESSION = new Set(['KHR_draco_mesh_compression', 'EXT_meshopt_compression', 'KHR_texture_basisu'])\n\nconst COMPONENTS = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 4, MAT3: 9, MAT4: 16 }\nconst ARRAYS = { 5120: Int8Array, 5121: Uint8Array, 5122: Int16Array, 5123: Uint16Array, 5125: Uint32Array, 5126: Float32Array }\n// normalized integers map to 0-1 (unsigned) or -1-1 (signed)\nconst NORMALIZE = { 5120: 127, 5121: 255, 5122: 32767, 5123: 65535, 5125: 1 }\nconst WRAP = { 33071: 'clamp', 33648: 'mirror', 10497: 'repeat' }\n\n/** A loaded glTF scene: a Group, plus the file's animations and cameras. */\nexport class Model extends Group {\n static type = 'model'\n /** @type {Animation[]} */ animations = []\n /** @type {Camera[]} */ cameras = []\n\n /**\n * Every mesh, point set and line set in the model - to change them together:\n * `for (const m of model.meshes) m.castShadow = true`.\n * @returns {Drawable[]}\n */\n get meshes() {\n return /** @type {Drawable[]} */ (this.findAll((n) => n instanceof Drawable))\n }\n\n /**\n * Play an animation by name or index (the first when not given).\n * @param {string | number} [which]\n * @returns {Animation | null}\n */\n play(which = 0) {\n const a = typeof which === 'number' ? this.animations[which] : this.animations.find((x) => x.name === which)\n if (!a) {\n const names = this.animations.map((x) => `'${x.name}'`).join(', ')\n warnOnce(this, `no animation ${typeof which === 'number' ? which : `'${which}'`} - this model has ${names || 'none'}`)\n return null\n }\n return a.play()\n }\n\n /**\n * A plain group of its parts, so create() can build it back without phoria2/gltf - with their\n * vertex data, but not the animations, or textures embedded in a .glb (they have no url).\n * @returns {Record<string, any>}\n */\n toJSON() {\n return { ...super.toJSON(), type: 'group' }\n }\n}\n\n/**\n * Load a .gltf or .glb file into a Model (a Group): add it to the scene, frame it, find its parts by\n * name. Resolves once its textures have loaded.\n *\n * const model = await loadGLTF('chair.glb')\n * view.scene.add(model)\n * view.frame(model)\n * model.find('Cushion').material.color.set('#2a6')\n *\n * @param {string} url\n * @param {GLTFOptions} [options]\n * @returns {Promise<Model>}\n */\nexport async function loadGLTF(url, options = {}) {\n const response = await fetch(url).catch((e) => { throw new PhoriaError(`loadGLTF: couldn't fetch '${url}' - ${e.message}`) })\n if (!response.ok) throw new PhoriaError(`loadGLTF: couldn't fetch '${url}' (${response.status} ${response.statusText})`)\n const base = options.baseUrl ?? new URL(url, globalThis.location?.href ?? 'file:///').href\n return parseGLTF(await response.arrayBuffer(), { ...options, baseUrl: base })\n}\n\n/**\n * Build a Model from a .glb file's bytes, a .gltf file's bytes or text, or its parsed JSON.\n * @param {ArrayBuffer | Uint8Array | string | Record<string, any>} data\n * @param {GLTFOptions} [options]\n * @returns {Promise<Model>}\n */\nexport async function parseGLTF(data, options = {}) {\n const { json, bin } = unpack(data)\n const version = String(json.asset?.version ?? '')\n if (!version.startsWith('2.')) throw new PhoriaError(`loadGLTF: glTF ${version || '(no version)'} isn't supported - only glTF 2.0`)\n for (const ext of json.extensionsRequired ?? []) {\n if (SUPPORTED.has(ext)) continue\n const hint = COMPRESSION.has(ext) ? ' - export the model without compression for now' : ''\n throw new PhoriaError(`loadGLTF: the model requires '${ext}', which isn't supported${hint}`)\n }\n const model = new Model({ name: json.scenes?.[json.scene ?? 0]?.name ?? 'model' })\n for (const ext of json.extensionsUsed ?? []) {\n if (!SUPPORTED.has(ext)) warnOnce(model, `the model uses '${ext}', which isn't supported - it is ignored`)\n }\n const build = new Builder(json, bin, options.baseUrl ?? '', model)\n await build.buffers()\n build.scene()\n // either way, embedded images' object urls are released once their textures settle\n const textures = build.textures()\n if (options.waitForTextures ?? true) await textures\n return model\n}\n\n/** @param {ArrayBuffer | Uint8Array | string | Record<string, any>} data */\nfunction unpack(data) {\n if (typeof data === 'string') return { json: JSON.parse(data), bin: null }\n if (!(data instanceof ArrayBuffer) && !ArrayBuffer.isView(data)) return { json: data, bin: null }\n const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength)\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n // 'glTF' little-endian: a binary container of a JSON chunk and an optional binary chunk\n if (bytes.length >= 12 && view.getUint32(0, true) === 0x46546c67) {\n let json = null, bin = null\n for (let at = 12; at + 8 <= bytes.length;) {\n const length = view.getUint32(at, true), type = view.getUint32(at + 4, true)\n const chunk = bytes.subarray(at + 8, at + 8 + length)\n if (type === 0x4e4f534a) json = JSON.parse(new TextDecoder().decode(chunk))\n else if (type === 0x004e4942) bin = chunk\n at += 8 + length\n }\n if (!json) throw new PhoriaError('loadGLTF: the .glb file has no JSON chunk')\n return { json, bin }\n }\n return { json: JSON.parse(new TextDecoder().decode(bytes)), bin: null }\n}\n\nclass Builder {\n /** @type {Uint8Array[]} */ #buffers = []\n /** @type {Map<string, Texture>} */ #textures = new Map()\n /** @type {Map<number, Material>} */ #materials = new Map()\n /** @type {Map<string, Geometry>} */ #geometries = new Map()\n /** @type {Node[]} */ #nodes = []\n /** @type {string[]} */ #objectUrls = []\n\n /** @param {Record<string, any>} json @param {Uint8Array | null} bin @param {string} base @param {Model} model */\n constructor(json, bin, base, model) {\n this.json = json\n this.bin = bin\n this.base = base\n this.model = model\n }\n\n /** @param {string} uri */\n #resolve(uri) {\n try {\n return new URL(uri, this.base || undefined).href\n } catch {\n return uri\n }\n }\n\n async buffers() {\n this.#buffers = await Promise.all((this.json.buffers ?? []).map(async (b, i) => {\n if (b.uri === undefined) {\n if (i !== 0 || !this.bin) throw new PhoriaError(`loadGLTF: buffer ${i} has no uri and there is no binary chunk`)\n return this.bin\n }\n const url = this.#resolve(b.uri)\n const response = await fetch(url).catch((e) => { throw new PhoriaError(`loadGLTF: couldn't fetch buffer '${b.uri}' - ${e.message}`) })\n if (!response.ok) throw new PhoriaError(`loadGLTF: couldn't fetch buffer '${b.uri}' (${response.status})`)\n return new Uint8Array(await response.arrayBuffer())\n }))\n }\n\n /** Resolves when every texture has loaded (failures are warned about, not thrown). */\n async textures() {\n await Promise.all([...this.#textures.values()].map((t) => t.ready.catch((e) => warnOnce(this.model, e.message))))\n for (const url of this.#objectUrls) URL.revokeObjectURL(url)\n }\n\n scene() {\n const json = this.json\n this.#nodes = (json.nodes ?? []).map((_, i) => this.#node(i))\n // parent after every node exists, since children can come before their parents\n ;(json.nodes ?? []).forEach((n, i) => {\n for (const c of n.children ?? []) this.#nodes[i].add(this.#nodes[c])\n })\n const scene = json.scenes?.[json.scene ?? 0]\n const roots = scene ? scene.nodes ?? [] : this.#nodes.map((_, i) => i).filter((i) => !this.#nodes[i].parent)\n for (const i of roots) this.model.add(this.#nodes[i])\n this.model.animations = (json.animations ?? []).map((a, i) => this.#animation(a, i))\n if (this.model.animations.length) {\n const model = this.model\n model.onUpdate((_node, dt) => {\n for (const a of model.animations) a.advance(dt)\n })\n }\n }\n\n /** @param {number} index @returns {Node} */\n #node(index) {\n const n = this.json.nodes[index]\n const name = n.name ?? `node ${index}`\n if (n.skin !== undefined) warnOnce(this.model, `skinned meshes aren't supported - '${name}' is drawn in its bind pose`)\n if (n.weights || (n.mesh !== undefined && this.json.meshes[n.mesh].weights)) warnOnce(this.model, \"morph targets aren't supported - meshes are drawn without them\")\n\n const parts = n.mesh !== undefined ? this.#mesh(n.mesh) : []\n // a node with one primitive is that drawable; with several, a group of them\n /** @type {Node} */\n const node = parts.length === 1 ? parts[0] : new Group()\n for (const part of parts.length > 1 ? parts : []) node.add(part)\n node.name = name\n if (n.matrix) decompose(node, n.matrix)\n else {\n if (n.translation) node.position.set(n.translation[0], n.translation[1], n.translation[2])\n if (n.rotation) node.quaternion.set(n.rotation[0], n.rotation[1], n.rotation[2], n.rotation[3])\n if (n.scale) node.scale.set(n.scale[0], n.scale[1], n.scale[2])\n }\n if (n.camera !== undefined) {\n const camera = this.#camera(n.camera)\n node.add(camera)\n this.model.cameras.push(camera)\n }\n const light = n.extensions?.KHR_lights_punctual?.light\n if (light !== undefined) node.add(this.#light(light))\n if (n.extras && typeof n.extras === 'object') node.userData = { ...n.extras }\n return node\n }\n\n /** @param {number} index @returns {Node[]} */\n #mesh(index) {\n const m = this.json.meshes[index]\n return m.primitives.map((p, i) => {\n const geometry = this.#geometry(p)\n const material = p.material !== undefined ? this.#material(p.material) : this.#defaultMaterial()\n const mode = p.mode ?? 4\n /** @type {Node} */\n let node\n if (mode === 0) node = new Points({ geometry, material: pointMaterial(material) })\n else if (mode === 1 || mode === 2 || mode === 3) node = new Lines({ geometry: lineList(geometry, mode), material: pointMaterial(material) })\n else node = new Mesh({ geometry: mode === 4 ? geometry : triangleList(geometry, mode), material })\n node.name = m.primitives.length > 1 ? `${m.name ?? `mesh ${index}`} ${i}` : m.name ?? `mesh ${index}`\n return node\n })\n }\n\n /** @param {Record<string, any>} p */\n #geometry(p) {\n // primitives often share accessors; share their geometry too\n const key = JSON.stringify([p.attributes, p.indices])\n const cached = this.#geometries.get(key)\n if (cached) return cached\n const a = p.attributes\n if (a.POSITION === undefined) throw new PhoriaError('loadGLTF: a mesh primitive has no POSITION')\n /** @type {import('../geometry/Geometry.js').GeometryOptions} */\n const options = { positions: this.#accessor(a.POSITION) }\n if (a.NORMAL !== undefined) options.normals = this.#accessor(a.NORMAL)\n if (a.TEXCOORD_0 !== undefined) options.uvs = this.#accessor(a.TEXCOORD_0)\n if (a.TEXCOORD_1 !== undefined) options.uvs2 = this.#accessor(a.TEXCOORD_1)\n if (a.COLOR_0 !== undefined) options.colors = srgbColors(/** @type {Float32Array} */ (this.#accessor(a.COLOR_0)), COMPONENTS[this.json.accessors[a.COLOR_0].type])\n if (p.indices !== undefined) options.indices = this.#accessor(p.indices, true)\n const geometry = new Geometry(options)\n this.#geometries.set(key, geometry)\n return geometry\n }\n\n /**\n * An accessor's numbers, as floats (normalized integers scaled), or as integers for indices.\n * @param {number} index @param {boolean} [integers]\n * @returns {Float32Array | Uint32Array}\n */\n #accessor(index, integers = false) {\n const acc = this.json.accessors[index]\n const size = COMPONENTS[acc.type]\n const count = acc.count * size\n const out = integers ? new Uint32Array(count) : new Float32Array(count)\n const scale = acc.normalized && !integers ? 1 / NORMALIZE[acc.componentType] : 1\n if (acc.bufferView !== undefined) this.#read(acc.bufferView, acc.byteOffset ?? 0, acc.componentType, size, acc.count, out, scale)\n if (acc.sparse) {\n // a few elements replaced: indices of the elements, then their values\n const s = acc.sparse\n const at = new Uint32Array(s.count)\n this.#read(s.indices.bufferView, s.indices.byteOffset ?? 0, s.indices.componentType, 1, s.count, at, 1)\n const values = integers ? new Uint32Array(s.count * size) : new Float32Array(s.count * size)\n this.#read(s.values.bufferView, s.values.byteOffset ?? 0, acc.componentType, size, s.count, values, scale)\n for (let i = 0; i < s.count; i++) out.set(values.subarray(i * size, i * size + size), at[i] * size)\n }\n if (acc.normalized && !integers && (acc.componentType === 5120 || acc.componentType === 5122)) {\n for (let i = 0; i < out.length; i++) out[i] = Math.max(out[i], -1)\n }\n return out\n }\n\n /**\n * Copy elements out of a buffer view, honouring its stride.\n * @param {number} viewIndex @param {number} offset @param {number} type component type\n * @param {number} size components per element @param {number} count elements\n * @param {Float32Array | Uint32Array} out @param {number} scale\n */\n #read(viewIndex, offset, type, size, count, out, scale) {\n const bv = this.json.bufferViews[viewIndex]\n const buffer = this.#buffers[bv.buffer]\n const Type = ARRAYS[type]\n if (!Type) throw new PhoriaError(`loadGLTF: unknown component type ${type}`)\n const bytes = Type.BYTES_PER_ELEMENT\n const stride = bv.byteStride || size * bytes\n const start = buffer.byteOffset + (bv.byteOffset ?? 0) + offset\n const view = new DataView(buffer.buffer)\n const get = {\n 5120: (/** @type {number} */ o) => view.getInt8(o),\n 5121: (/** @type {number} */ o) => view.getUint8(o),\n 5122: (/** @type {number} */ o) => view.getInt16(o, true),\n 5123: (/** @type {number} */ o) => view.getUint16(o, true),\n 5125: (/** @type {number} */ o) => view.getUint32(o, true),\n 5126: (/** @type {number} */ o) => view.getFloat32(o, true),\n }[type]\n // the common case - tightly packed and aligned floats - is one copy\n if (type === 5126 && stride === size * 4 && start % 4 === 0 && scale === 1 && out instanceof Float32Array) {\n out.set(new Float32Array(buffer.buffer, start, count * size))\n return\n }\n for (let i = 0; i < count; i++) {\n for (let c = 0; c < size; c++) out[i * size + c] = get(start + i * stride + c * bytes) * scale\n }\n }\n\n /** @param {number} index @returns {Material} */\n #material(index) {\n const cached = this.#materials.get(index)\n if (cached) return cached\n const m = this.json.materials[index]\n const pbr = m.pbrMetallicRoughness ?? {}\n const material = new Material({ name: m.name ?? `material ${index}` })\n const base = pbr.baseColorFactor ?? [1, 1, 1, 1]\n material.color.setLinear(base[0], base[1], base[2])\n material.metalness = pbr.metallicFactor ?? 1\n material.roughness = pbr.roughnessFactor ?? 1\n if (pbr.baseColorTexture) material.map = this.#texture(pbr.baseColorTexture, 'srgb')\n if (pbr.metallicRoughnessTexture) {\n // one texture: roughness in green, metalness in blue - exactly what the two slots read\n material.roughnessMap = material.metalnessMap = this.#texture(pbr.metallicRoughnessTexture, 'linear')\n }\n if (m.normalTexture) {\n material.normalMap = this.#texture(m.normalTexture, 'linear')\n material.normalScale = m.normalTexture.scale ?? 1\n }\n if (m.occlusionTexture) {\n material.aoMap = this.#texture(m.occlusionTexture, 'linear')\n material.aoMapIntensity = Math.min(Math.max(m.occlusionTexture.strength ?? 1, 0), 1)\n }\n if (m.emissiveFactor) material.emissive.setLinear(m.emissiveFactor[0], m.emissiveFactor[1], m.emissiveFactor[2])\n if (m.emissiveTexture) {\n material.emissiveMap = this.#texture(m.emissiveTexture, 'srgb')\n if (!m.emissiveFactor) material.emissive.setLinear(1, 1, 1)\n }\n material.emissiveIntensity = m.extensions?.KHR_materials_emissive_strength?.emissiveStrength ?? 1\n if (m.extensions?.KHR_materials_unlit) material.unlit = true\n // glass, clear coat, cloth, reflectance, brushed metal and translucency, by their factors - their\n // own textures aren't read\n const clamp = (/** @type {number} */ v) => Math.min(Math.max(v, 0), 1)\n const x = m.extensions ?? {}\n const transmission = x.KHR_materials_transmission, coat = x.KHR_materials_clearcoat, sheen = x.KHR_materials_sheen\n if (transmission) material.transmission = clamp(transmission.transmissionFactor ?? 0)\n if (coat) {\n material.clearcoat = clamp(coat.clearcoatFactor ?? 0)\n material.clearcoatRoughness = clamp(coat.clearcoatRoughnessFactor ?? 0)\n }\n if (sheen) {\n const c = sheen.sheenColorFactor ?? [0, 0, 0]\n // glTF's sheen is its colour alone: black is none\n if (Math.max(c[0], c[1], c[2]) > 0) {\n material.sheen = 1\n material.sheenColor.setLinear(c[0], c[1], c[2])\n }\n material.sheenRoughness = clamp(sheen.sheenRoughnessFactor ?? 0)\n }\n if (x.KHR_materials_ior?.ior >= 1) material.ior = x.KHR_materials_ior.ior\n const specular = x.KHR_materials_specular\n if (specular) {\n material.specularIntensity = clamp(specular.specularFactor ?? 1)\n const c = specular.specularColorFactor ?? [1, 1, 1]\n material.specularColor.setLinear(c[0], c[1], c[2])\n }\n const brushed = x.KHR_materials_anisotropy\n if (brushed) {\n material.anisotropy = clamp(brushed.anisotropyStrength ?? 0)\n material.anisotropyRotation = brushed.anisotropyRotation ?? 0\n }\n const translucent = x.KHR_materials_diffuse_transmission\n if (translucent) {\n material.translucency = clamp(translucent.diffuseTransmissionFactor ?? 0)\n const c = translucent.diffuseTransmissionColorFactor ?? [1, 1, 1]\n material.translucencyColor.setLinear(c[0], c[1], c[2])\n }\n if (m.alphaMode === 'BLEND') {\n material.opacity = base[3]\n material.transparent = true\n material.depthWrite = false\n } else if (m.alphaMode === 'MASK') {\n material.alphaTest = m.alphaCutoff ?? 0.5\n }\n material.doubleSided = !!m.doubleSided\n this.#materials.set(index, material)\n return material\n }\n\n // glTF's default for primitives without a material\n #defaultMaterial() {\n let material = this.#materials.get(-1)\n if (!material) this.#materials.set(-1, material = new Material({ name: 'default', metalness: 1, roughness: 1 }))\n return material\n }\n\n /**\n * @param {Record<string, any>} info a textureInfo: index, texCoord, extensions\n * @param {'srgb' | 'linear'} colorSpace what the slot holds\n * @returns {Texture}\n */\n #texture(info, colorSpace) {\n const transform = info.extensions?.KHR_texture_transform\n let texCoord = transform?.texCoord ?? info.texCoord ?? 0\n if (texCoord > 1) {\n warnOnce(this.model, `textures on a third UV set or later (TEXCOORD_${texCoord}) are drawn with the first`)\n texCoord = 0\n }\n const key = JSON.stringify([info.index, colorSpace, transform?.offset, transform?.scale, transform?.rotation, texCoord])\n const cached = this.#textures.get(key)\n if (cached) return cached\n\n const t = this.json.textures[info.index]\n const sampler = this.json.samplers?.[t.sampler] ?? {}\n const image = this.json.images[t.source]\n if (t.source === undefined || !image) throw new PhoriaError(`loadGLTF: texture ${info.index} has no image (compressed textures aren't supported)`)\n let url\n if (image.bufferView !== undefined) {\n const bv = this.json.bufferViews[image.bufferView]\n const buffer = this.#buffers[bv.buffer]\n const bytes = buffer.subarray(bv.byteOffset ?? 0, (bv.byteOffset ?? 0) + bv.byteLength)\n url = URL.createObjectURL(new Blob([/** @type {Uint8Array<ArrayBuffer>} */ (bytes)], { type: image.mimeType ?? 'image/png' }))\n this.#objectUrls.push(url)\n } else {\n url = this.#resolve(image.uri)\n }\n const texture = new Texture({\n url,\n colorSpace,\n wrap: WRAP[sampler.wrapS ?? 10497] ?? 'repeat',\n filter: sampler.magFilter === 9728 ? 'nearest' : 'linear',\n // glTF UVs start at the image's top left, as phoria2's do\n flipY: false,\n repeat: transform?.scale ?? [1, 1],\n offset: transform?.offset ?? [0, 0],\n rotation: transform?.rotation ?? 0,\n uvSet: texCoord,\n })\n this.#textures.set(key, texture)\n return texture\n }\n\n /** @param {number} index @returns {Camera} */\n #camera(index) {\n const c = this.json.cameras[index]\n const name = c.name ?? `camera ${index}`\n if (c.type === 'orthographic') {\n const o = c.orthographic\n return new OrthographicCamera({ name, height: o.ymag * 2, near: o.znear, far: o.zfar })\n }\n const p = c.perspective\n return new PerspectiveCamera({ name, fov: (p.yfov * 180) / Math.PI, near: p.znear, far: p.zfar ?? 1e6 })\n }\n\n /** @param {number} index */\n #light(index) {\n const l = this.json.extensions?.KHR_lights_punctual?.lights?.[index]\n if (!l) throw new PhoriaError(`loadGLTF: KHR_lights_punctual light ${index} doesn't exist`)\n const c = l.color ?? [1, 1, 1]\n // glTF lights shine down their node's -Z; intensities are lux and candela, divided by PI for\n // phoria2's lights (where 1 lights a white surface to white)\n const options = { name: l.name, intensity: (l.intensity ?? 1) / Math.PI }\n let light\n if (l.type === 'directional') light = new DirectionalLight({ ...options, direction: [0, 0, -1] })\n else if (l.type === 'spot') {\n const outer = l.spot?.outerConeAngle ?? Math.PI / 4, inner = l.spot?.innerConeAngle ?? 0\n light = new SpotLight({ ...options, direction: [0, 0, -1], range: l.range ?? 0, angle: outer, penumbra: outer > 0 ? 1 - inner / outer : 0 })\n } else light = new PointLight({ ...options, range: l.range ?? 0 })\n light.color.setLinear(c[0], c[1], c[2])\n return light\n }\n\n /** @param {Record<string, any>} a @param {number} index @returns {Animation} */\n #animation(a, index) {\n /** @type {Track[]} */\n const tracks = []\n for (const ch of a.channels) {\n const path = { translation: 'position', rotation: 'quaternion', scale: 'scale' }[ch.target.path]\n if (!path) {\n warnOnce(this.model, `'${ch.target.path}' animations aren't supported - only translation, rotation and scale`)\n continue\n }\n const node = this.#nodes[ch.target.node]\n if (!node) continue\n const s = a.samplers[ch.sampler]\n tracks.push({\n node, path,\n times: /** @type {Float32Array} */ (this.#accessor(s.input)),\n values: /** @type {Float32Array} */ (this.#accessor(s.output)),\n interpolation: s.interpolation ?? 'LINEAR',\n })\n }\n return new Animation(a.name ?? `animation ${index}`, tracks)\n }\n}\n\n/** Set a node's position, rotation and scale from a column-major matrix. @param {Node} node @param {number[]} m */\nfunction decompose(node, m) {\n let sx = Math.hypot(m[0], m[1], m[2])\n const sy = Math.hypot(m[4], m[5], m[6]), sz = Math.hypot(m[8], m[9], m[10])\n // a mirroring matrix: put the flip in x\n const det = m[0] * (m[5] * m[10] - m[6] * m[9]) - m[4] * (m[1] * m[10] - m[2] * m[9]) + m[8] * (m[1] * m[6] - m[2] * m[5])\n if (det < 0) sx = -sx\n const r = [m[0] / sx, m[1] / sx, m[2] / sx, m[4] / sy, m[5] / sy, m[6] / sy, m[8] / sz, m[9] / sz, m[10] / sz]\n const q = quat.normalize([0, 0, 0, 1], quat.fromMat3([0, 0, 0, 1], r))\n node.position.set(m[12], m[13], m[14])\n node.quaternion.set(q[0], q[1], q[2], q[3])\n node.scale.set(sx, sy, sz)\n}\n\n/** glTF vertex colours are linear RGB(A); phoria2's are sRGB RGB. @param {Float32Array} c @param {number} size */\nfunction srgbColors(c, size) {\n const n = c.length / size\n const out = new Float32Array(n * 3)\n for (let i = 0; i < n; i++) {\n for (let k = 0; k < 3; k++) {\n const v = Math.min(Math.max(c[i * size + k], 0), 1)\n out[i * 3 + k] = v <= 0.0031308 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - 0.055\n }\n }\n return out\n}\n\n/** Points and Lines take their colour and size from a lit material's basics. @param {Material} m */\nfunction pointMaterial(m) {\n return new Material({ name: m.name, color: m.color.getStyle(), opacity: m.opacity, map: m.map, vertexColors: true, size: 2, sizeAttenuation: false })\n}\n\n/** Triangle strips and fans as a plain triangle list. @param {Geometry} g @param {number} mode */\nfunction triangleList(g, mode) {\n const index = g.indices ?? Uint32Array.from({ length: g.vertexCount }, (_, i) => i)\n const out = []\n for (let i = 2; i < index.length; i++) {\n if (mode === 6) out.push(index[0], index[i - 1], index[i])\n // strips alternate winding, so every other triangle swaps two corners\n else if (i % 2 === 0) out.push(index[i - 2], index[i - 1], index[i])\n else out.push(index[i - 1], index[i - 2], index[i])\n }\n return withIndices(g, out, true)\n}\n\n/** Line strips and loops as segment pairs. @param {Geometry} g @param {number} mode */\nfunction lineList(g, mode) {\n if (mode === 1) return g\n const index = g.indices ?? Uint32Array.from({ length: g.vertexCount }, (_, i) => i)\n const out = []\n for (let i = 1; i < index.length; i++) out.push(index[i - 1], index[i])\n if (mode === 2 && index.length > 2) out.push(index[index.length - 1], index[0])\n return withIndices(g, out, false)\n}\n\n/** @param {Geometry} g @param {number[]} indices @param {boolean} triangles keep normals (lines have none) */\nfunction withIndices(g, indices, triangles) {\n // only normals the file gave - reading g.normals would work them out from the strip's own indices,\n // taken as a triangle list; the new geometry works them out from its real triangles instead\n return new Geometry({ positions: g.positions, normals: triangles && g.hasNormals ? g.normals : undefined, uvs: g.uvs ?? undefined, uvs2: g.uvs2 ?? undefined,\n colors: g.colors ?? undefined, indices })\n}\n"],"mappings":"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"}
|
package/dist/motion.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as e, Ct as t, Dt as n, Et as r, Mt as i, Ot as a, Tt as o,
|
|
1
|
+
import { At as e, Ct as t, Dt as n, Et as r, Mt as i, Ot as a, Tt as o, V as s, dt as c, pt as l, r as u } from "./core.js";
|
|
2
2
|
// src/motion/Timeline.js
|
|
3
3
|
var d = ["loop", "speed"], f = {
|
|
4
4
|
repeat: "use 'loop: true'",
|
|
@@ -145,8 +145,8 @@ function S(e, a, o = {}) {
|
|
|
145
145
|
e.lookAt(u, d);
|
|
146
146
|
let p = x[s];
|
|
147
147
|
if (p) {
|
|
148
|
-
let t =
|
|
149
|
-
e.quaternion.copy(
|
|
148
|
+
let t = l(/* @__PURE__ */ new Float32Array(4), p[0], p[1]);
|
|
149
|
+
e.quaternion.copy(c(/* @__PURE__ */ new Float32Array(4), e.quaternion, t));
|
|
150
150
|
}
|
|
151
151
|
return e;
|
|
152
152
|
}
|
package/dist/motion.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"motion.js","names":["fail","Vec3","checkOptions","checkOneOf","transformMat4","describe","checkNumber","EASES","setAxisAngle","multiply","Curve","OPTIONS","HINTS","STEP_OPTIONS","STEP_HINTS","Timeline","options","duration","run","ease","#steps","#apply","last","#time","#current","#playing","time","i","step","s","target","fn","#onStep","dt","steps","now","current","raw","FORWARD","FACE_OPTIONS","FACE_HINTS","FOLLOW_OPTIONS","FOLLOW_HINTS","TO_MINUS_Z","face","forward","ahead","node","direction","up","parent","m","turn","q","follow","path","t","reveal","g","lines","pieces"],"sources":["../src/motion/Timeline.js","../src/motion/follow.js"],"sourcesContent":["// A timeline of named steps played one after another - for stories, explainers and guided tours.\n// Each step is a function given its own progress (0 before it starts, 0-1 while it plays, 1 once\n// it's done), every frame. Steps set the scene from their progress rather than nudging it, so\n// seeking, stepping back and looping always leave the scene right.\n\nimport { checkNumber, checkOptions, describe, fail } from '../validate.js'\nimport { EASES } from './ease.js'\n\n/** @import { EaseName } from './ease.js' */\n\n/**\n * @typedef {object} StepOptions\n * @property {string} [label] what the step shows, for captions - timeline.label is the current one\n * @property {EaseName | ((t: number) => number)} [ease] how progress runs through the step, default 'linear'\n */\n\n/**\n * @typedef {object} TimelineOptions\n * @property {boolean} [loop] start again at the end, default false\n * @property {number} [speed] 1 is real time, default 1\n */\n\n/** @typedef {{ start: number, duration: number, run: (t: number) => void, label: string, ease: (t: number) => number }} Step */\n\n/**\n * Steps played in order, each a function of its progress.\n *\n * const story = new Timeline({ loop: true })\n * story.add(3, (t) => follow(rocket, ascent, t), { label: 'Launch' })\n * story.add(2, (t) => { capsule.visible = t > 0 }, { label: 'Separation' })\n * view.start((dt) => story.update(dt))\n */\nconst OPTIONS = ['loop', 'speed']\nconst HINTS = { repeat: \"use 'loop: true'\", autoplay: 'a timeline plays from the start - call pause() to hold it' }\n/** What add() takes, and hints for names people reach for instead. */\nexport const STEP_OPTIONS = ['label', 'ease']\nexport const STEP_HINTS = { name: \"use 'label'\", easing: \"use 'ease'\" }\n\nexport class Timeline {\n /** The options it takes, and hints for names people reach for instead. */\n static OPTIONS = OPTIONS\n static HINTS = HINTS\n /** @type {Step[]} */ #steps = []\n #time = 0\n #playing = true\n #current = -1\n /** @type {((index: number, label: string) => void)[]} */ #onStep = []\n loop = false\n speed = 1\n\n /** @param {TimelineOptions} [options] */\n constructor(options = {}) {\n checkOptions('Timeline', options, OPTIONS, HINTS)\n if (options.loop !== undefined) this.loop = !!options.loop\n if (options.speed !== undefined) this.speed = checkNumber('Timeline', 'speed', options.speed)\n }\n\n /**\n * Add a step after the last one.\n * @param {number} duration seconds; 0 for an instant change\n * @param {(t: number) => void} run called every frame with this step's progress, 0-1\n * @param {StepOptions} [options]\n * @returns {this}\n */\n add(duration, run, options = {}) {\n checkNumber('Timeline.add()', 'duration', duration)\n if (duration < 0) fail('Timeline.add()', `'duration' is seconds, 0 or more, got ${duration}`)\n if (typeof run !== 'function') fail('Timeline.add()', `takes (duration, (t) => { ... }), got ${describe(run)} for the step`)\n checkOptions('Timeline.add()', options, STEP_OPTIONS, STEP_HINTS)\n const ease = typeof options.ease === 'function' ? options.ease : EASES[options.ease ?? 'linear']\n if (!ease) fail('Timeline.add()', `ease '${options.ease}' - expected ${Object.keys(EASES).map((e) => `'${e}'`).join(', ')}, or a function`)\n this.#steps.push({ start: this.duration, duration, run, label: options.label ?? '', ease })\n this.#apply()\n return this\n }\n\n /** Total length in seconds. */\n get duration() {\n const last = this.#steps[this.#steps.length - 1]\n return last ? last.start + last.duration : 0\n }\n\n /** Seconds since the start. */\n get time() {\n return this.#time\n }\n\n /** The step playing now, by index - -1 before any are added. */\n get step() {\n return this.#current\n }\n\n /** The label of the step playing now. */\n get label() {\n return this.#steps[this.#current]?.label ?? ''\n }\n\n /** The steps, in order, with their start times and labels. */\n get steps() {\n return this.#steps.map(({ start, duration, label }) => ({ start, duration, label }))\n }\n\n get playing() {\n return this.#playing\n }\n\n /** @returns {this} */\n play() {\n if (this.#time >= this.duration && !this.loop) this.#time = 0\n this.#playing = true\n return this\n }\n\n /** @returns {this} */\n pause() {\n this.#playing = false\n return this\n }\n\n /**\n * Jump to a time in seconds, setting the scene to match.\n * @param {number} time @returns {this}\n */\n seek(time) {\n this.#time = Math.min(this.duration, Math.max(0, checkNumber('Timeline.seek()', 'time', time)))\n this.#apply()\n return this\n }\n\n /**\n * Jump to the start of a step, by index or label.\n * @param {number | string} step @returns {this}\n */\n seekStep(step) {\n const i = typeof step === 'string' ? this.#steps.findIndex((s) => s.label === step) : step\n const target = this.#steps[i]\n if (!target) fail('Timeline.seekStep()', `no step ${describe(step)} - there are ${this.#steps.length}${typeof step === 'string' ? `: ${this.#steps.map((s) => `'${s.label}'`).join(', ')}` : ''}`)\n return this.seek(target.start)\n }\n\n /**\n * Call with the step playing now, and again whenever it changes: (index, label). Called straight\n * away too, so a caption set up after the steps starts right.\n * @param {(index: number, label: string) => void} fn @returns {this}\n */\n onStep(fn) {\n if (typeof fn !== 'function') fail('Timeline.onStep()', `takes (index, label) => { ... }, got ${describe(fn)}`)\n this.#onStep.push(fn)\n if (this.#current >= 0) fn(this.#current, this.label)\n return this\n }\n\n /**\n * Move time on by dt seconds (while playing) and set the scene - call every frame.\n * @param {number} dt @returns {this}\n */\n update(dt) {\n if (this.#playing && this.#steps.length) {\n let t = this.#time + dt * this.speed\n if (t >= this.duration) {\n if (this.loop && this.duration > 0) t %= this.duration\n else {\n t = this.duration\n this.#playing = false\n }\n }\n this.#time = t\n }\n this.#apply()\n return this\n }\n\n // set every step from the time: later steps back to their start, latest first, then each step\n // up to now in order - so whatever a step controls ends up as the latest one to touch it says\n #apply() {\n const steps = this.#steps, now = this.#time\n let current = steps.length - 1\n for (let i = 0; i < steps.length; i++) {\n if (now < steps[i].start + steps[i].duration || (steps[i].duration === 0 && now <= steps[i].start)) {\n current = i\n break\n }\n }\n for (let i = steps.length - 1; i > current; i--) steps[i].run(0)\n for (let i = 0; i <= current; i++) {\n const s = steps[i]\n const raw = s.duration > 0 ? Math.min(1, Math.max(0, (now - s.start) / s.duration)) : (now >= s.start ? 1 : 0)\n s.run(s.ease(raw))\n }\n if (current !== this.#current) {\n this.#current = current\n for (const fn of this.#onStep) fn(current, steps[current]?.label ?? '')\n }\n }\n}\n","// Moving things along curves, and drawing curves in as they're travelled.\n\nimport { transformMat4 } from '../math/vec3.js'\nimport { multiply, setAxisAngle } from '../math/quat.js'\nimport { Curve } from '../geometry/Curve.js'\nimport { Vec3 } from '../value/Vec3.js'\nimport { checkOneOf, checkOptions, describe, fail } from '../validate.js'\n\n/** @import { Node } from '../scene/Node.js' */\n/** @import { Lines } from '../scene/drawables.js' */\n\n/** @import { Vec3Input } from '../types.js' */\n\n/**\n * Which of a model's own axes is its nose. Cameras, lights and lookAt use -Z; a model built\n * upright - a rocket along +Y - says '+y'.\n * @typedef {'-z' | '+z' | '-y' | '+y' | '-x' | '+x'} Forward\n */\n\n/**\n * @typedef {object} FaceOptions\n * @property {Forward} [forward] the model's nose axis, default '-z'\n * @property {Vec3Input} [up] which way is up as it turns, in the parent's space, default [0, 1, 0].\n * Heading straight along it leaves the roll undefined, so a craft that turns through every\n * heading in the x-y plane (seen face on) needs one out of the plane: [0, 0, 1]\n */\n\n/**\n * @typedef {object} FollowOptions\n * @property {boolean} [orient] turn the node to face along the curve, default true\n * @property {Forward} [forward] the model's nose axis, default '-z'\n * @property {Vec3Input} [up] which way is up as it turns, default [0, 1, 0] - see face()\n */\n\nconst FORWARD = ['-z', '+z', '-y', '+y', '-x', '+x']\n/** What face() and follow() take, and hints for names people reach for instead. */\nexport const FACE_OPTIONS = ['forward', 'up']\nexport const FACE_HINTS = { nose: \"use 'forward' - which of the model's axes is its nose\" }\nexport const FOLLOW_OPTIONS = ['orient', 'forward', 'up']\nexport const FOLLOW_HINTS = { rotate: \"use 'orient'\", lookAhead: 'the node faces along the curve - orient: false leaves it as it is', nose: \"use 'forward' - which of the model's axes is its nose\" }\n// the turn that takes each nose axis onto -Z, as [axis, angle]\nconst TO_MINUS_Z = {\n '-z': null,\n '+z': [[0, 1, 0], Math.PI],\n '-y': [[1, 0, 0], Math.PI / 2],\n '+y': [[1, 0, 0], -Math.PI / 2],\n '-x': [[0, 1, 0], -Math.PI / 2],\n '+x': [[0, 1, 0], Math.PI / 2],\n}\n\n/**\n * Turn a node so its nose points along a direction, in its parent's space - for a model built\n * along another axis, say which with forward.\n *\n * face(lander, [0, 1, 0], { forward: '+y' }) // stand it upright\n * @param {Node} node\n * @param {Vec3Input} direction\n * @param {FaceOptions} [options]\n * @returns {Node}\n */\nexport function face(node, direction, options = {}) {\n checkOptions('face()', options, FACE_OPTIONS, FACE_HINTS)\n const forward = /** @type {Forward} */ (options.forward === undefined ? '-z' : checkOneOf('face()', 'forward', options.forward, FORWARD))\n const ahead = node.position.clone().add(Vec3.fromInput(direction, 'face()'))\n let up = options.up === undefined ? undefined : Vec3.fromInput(options.up, 'face() up')\n const parent = node.parent\n if (parent) {\n const m = parent.updateWorld().worldMatrix\n if (up) up = transformMat4(up, up.add(node.position), m).sub(transformMat4(new Vec3(), node.position, m))\n transformMat4(ahead, ahead, m)\n }\n node.lookAt(ahead, up)\n const turn = TO_MINUS_Z[forward]\n if (turn) {\n const q = setAxisAngle(new Float32Array(4), turn[0], turn[1])\n node.quaternion.copy(multiply(new Float32Array(4), node.quaternion, q))\n }\n return node\n}\n\n/**\n * Put a node t of the way along a curve (0 start, 1 end, by distance), facing the way it runs.\n * The curve is in the node's parent's space - the same space as its position. A model built along\n * another axis than -Z says which is its nose with forward.\n *\n * story.add(4, (t) => follow(lander, transfer, t))\n * follow(rocket, ascent, t, { forward: '+y' }) // a rocket modelled upright\n * @param {Node} node\n * @param {Curve} path\n * @param {number} t\n * @param {FollowOptions} [options]\n * @returns {Node}\n */\nexport function follow(node, path, t, options = {}) {\n if (!(path instanceof Curve)) fail('follow()', `takes (node, curve, t) - make the curve with curve([...points]) or ellipse({...}), got ${describe(path)}`)\n checkOptions('follow()', options, FOLLOW_OPTIONS, FOLLOW_HINTS)\n node.position.copy(path.at(t))\n if (options.orient !== false) face(node, path.tangentAt(t), { forward: options.forward, up: options.up })\n return node\n}\n\n/**\n * Draw only the first part of a line - t of it (0 nothing, 1 all) - so a path draws in as it's\n * travelled. For Lines made from curve.line(): its pieces run in order from the start.\n *\n * story.add(4, (t) => { follow(lander, transfer, t); reveal(transferLine, t) })\n * @param {Lines} lines\n * @param {number} t\n * @returns {Lines}\n */\nexport function reveal(lines, t) {\n const g = lines?.geometry\n if (!g || /** @type {any} */ (lines).drawMode !== 'lines') fail('reveal()', `takes a Lines node, got ${describe(lines)}`)\n const pieces = g.vertexCount / 2\n g.drawCount = Math.round(Math.min(1, Math.max(0, t)) * pieces) * 2\n lines.visible = g.drawCount > 0\n return lines\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"motion.js","names":["fail","Vec3","checkOptions","checkOneOf","transformMat4","describe","checkNumber","EASES","multiply","setAxisAngle","Curve","OPTIONS","HINTS","STEP_OPTIONS","STEP_HINTS","Timeline","options","duration","run","ease","#steps","#apply","last","#time","#current","#playing","time","i","step","s","target","fn","#onStep","dt","steps","now","current","raw","FORWARD","FACE_OPTIONS","FACE_HINTS","FOLLOW_OPTIONS","FOLLOW_HINTS","TO_MINUS_Z","face","forward","ahead","node","direction","up","parent","m","turn","q","follow","path","t","reveal","g","lines","pieces"],"sources":["../src/motion/Timeline.js","../src/motion/follow.js"],"sourcesContent":["// A timeline of named steps played one after another - for stories, explainers and guided tours.\n// Each step is a function given its own progress (0 before it starts, 0-1 while it plays, 1 once\n// it's done), every frame. Steps set the scene from their progress rather than nudging it, so\n// seeking, stepping back and looping always leave the scene right.\n\nimport { checkNumber, checkOptions, describe, fail } from '../validate.js'\nimport { EASES } from './ease.js'\n\n/** @import { EaseName } from './ease.js' */\n\n/**\n * @typedef {object} StepOptions\n * @property {string} [label] what the step shows, for captions - timeline.label is the current one\n * @property {EaseName | ((t: number) => number)} [ease] how progress runs through the step, default 'linear'\n */\n\n/**\n * @typedef {object} TimelineOptions\n * @property {boolean} [loop] start again at the end, default false\n * @property {number} [speed] 1 is real time, default 1\n */\n\n/** @typedef {{ start: number, duration: number, run: (t: number) => void, label: string, ease: (t: number) => number }} Step */\n\n/**\n * Steps played in order, each a function of its progress.\n *\n * const story = new Timeline({ loop: true })\n * story.add(3, (t) => follow(rocket, ascent, t), { label: 'Launch' })\n * story.add(2, (t) => { capsule.visible = t > 0 }, { label: 'Separation' })\n * view.start((dt) => story.update(dt))\n */\nconst OPTIONS = ['loop', 'speed']\nconst HINTS = { repeat: \"use 'loop: true'\", autoplay: 'a timeline plays from the start - call pause() to hold it' }\n/** What add() takes, and hints for names people reach for instead. */\nexport const STEP_OPTIONS = ['label', 'ease']\nexport const STEP_HINTS = { name: \"use 'label'\", easing: \"use 'ease'\" }\n\nexport class Timeline {\n /** The options it takes, and hints for names people reach for instead. */\n static OPTIONS = OPTIONS\n static HINTS = HINTS\n /** @type {Step[]} */ #steps = []\n #time = 0\n #playing = true\n #current = -1\n /** @type {((index: number, label: string) => void)[]} */ #onStep = []\n loop = false\n speed = 1\n\n /** @param {TimelineOptions} [options] */\n constructor(options = {}) {\n checkOptions('Timeline', options, OPTIONS, HINTS)\n if (options.loop !== undefined) this.loop = !!options.loop\n if (options.speed !== undefined) this.speed = checkNumber('Timeline', 'speed', options.speed)\n }\n\n /**\n * Add a step after the last one.\n * @param {number} duration seconds; 0 for an instant change\n * @param {(t: number) => void} run called every frame with this step's progress, 0-1\n * @param {StepOptions} [options]\n * @returns {this}\n */\n add(duration, run, options = {}) {\n checkNumber('Timeline.add()', 'duration', duration)\n if (duration < 0) fail('Timeline.add()', `'duration' is seconds, 0 or more, got ${duration}`)\n if (typeof run !== 'function') fail('Timeline.add()', `takes (duration, (t) => { ... }), got ${describe(run)} for the step`)\n checkOptions('Timeline.add()', options, STEP_OPTIONS, STEP_HINTS)\n const ease = typeof options.ease === 'function' ? options.ease : EASES[options.ease ?? 'linear']\n if (!ease) fail('Timeline.add()', `ease '${options.ease}' - expected ${Object.keys(EASES).map((e) => `'${e}'`).join(', ')}, or a function`)\n this.#steps.push({ start: this.duration, duration, run, label: options.label ?? '', ease })\n this.#apply()\n return this\n }\n\n /** Total length in seconds. */\n get duration() {\n const last = this.#steps[this.#steps.length - 1]\n return last ? last.start + last.duration : 0\n }\n\n /** Seconds since the start. */\n get time() {\n return this.#time\n }\n\n /** The step playing now, by index - -1 before any are added. */\n get step() {\n return this.#current\n }\n\n /** The label of the step playing now. */\n get label() {\n return this.#steps[this.#current]?.label ?? ''\n }\n\n /** The steps, in order, with their start times and labels. */\n get steps() {\n return this.#steps.map(({ start, duration, label }) => ({ start, duration, label }))\n }\n\n get playing() {\n return this.#playing\n }\n\n /** @returns {this} */\n play() {\n if (this.#time >= this.duration && !this.loop) this.#time = 0\n this.#playing = true\n return this\n }\n\n /** @returns {this} */\n pause() {\n this.#playing = false\n return this\n }\n\n /**\n * Jump to a time in seconds, setting the scene to match.\n * @param {number} time @returns {this}\n */\n seek(time) {\n this.#time = Math.min(this.duration, Math.max(0, checkNumber('Timeline.seek()', 'time', time)))\n this.#apply()\n return this\n }\n\n /**\n * Jump to the start of a step, by index or label.\n * @param {number | string} step @returns {this}\n */\n seekStep(step) {\n const i = typeof step === 'string' ? this.#steps.findIndex((s) => s.label === step) : step\n const target = this.#steps[i]\n if (!target) fail('Timeline.seekStep()', `no step ${describe(step)} - there are ${this.#steps.length}${typeof step === 'string' ? `: ${this.#steps.map((s) => `'${s.label}'`).join(', ')}` : ''}`)\n return this.seek(target.start)\n }\n\n /**\n * Call with the step playing now, and again whenever it changes: (index, label). Called straight\n * away too, so a caption set up after the steps starts right.\n * @param {(index: number, label: string) => void} fn @returns {this}\n */\n onStep(fn) {\n if (typeof fn !== 'function') fail('Timeline.onStep()', `takes (index, label) => { ... }, got ${describe(fn)}`)\n this.#onStep.push(fn)\n if (this.#current >= 0) fn(this.#current, this.label)\n return this\n }\n\n /**\n * Move time on by dt seconds (while playing) and set the scene - call every frame.\n * @param {number} dt @returns {this}\n */\n update(dt) {\n if (this.#playing && this.#steps.length) {\n let t = this.#time + dt * this.speed\n if (t >= this.duration) {\n if (this.loop && this.duration > 0) t %= this.duration\n else {\n t = this.duration\n this.#playing = false\n }\n }\n this.#time = t\n }\n this.#apply()\n return this\n }\n\n // set every step from the time: later steps back to their start, latest first, then each step\n // up to now in order - so whatever a step controls ends up as the latest one to touch it says\n #apply() {\n const steps = this.#steps, now = this.#time\n let current = steps.length - 1\n for (let i = 0; i < steps.length; i++) {\n if (now < steps[i].start + steps[i].duration || (steps[i].duration === 0 && now <= steps[i].start)) {\n current = i\n break\n }\n }\n for (let i = steps.length - 1; i > current; i--) steps[i].run(0)\n for (let i = 0; i <= current; i++) {\n const s = steps[i]\n const raw = s.duration > 0 ? Math.min(1, Math.max(0, (now - s.start) / s.duration)) : (now >= s.start ? 1 : 0)\n s.run(s.ease(raw))\n }\n if (current !== this.#current) {\n this.#current = current\n for (const fn of this.#onStep) fn(current, steps[current]?.label ?? '')\n }\n }\n}\n","// Moving things along curves, and drawing curves in as they're travelled.\n\nimport { transformMat4 } from '../math/vec3.js'\nimport { multiply, setAxisAngle } from '../math/quat.js'\nimport { Curve } from '../geometry/Curve.js'\nimport { Vec3 } from '../value/Vec3.js'\nimport { checkOneOf, checkOptions, describe, fail } from '../validate.js'\n\n/** @import { Node } from '../scene/Node.js' */\n/** @import { Lines } from '../scene/drawables.js' */\n\n/** @import { Vec3Input } from '../types.js' */\n\n/**\n * Which of a model's own axes is its nose. Cameras, lights and lookAt use -Z; a model built\n * upright - a rocket along +Y - says '+y'.\n * @typedef {'-z' | '+z' | '-y' | '+y' | '-x' | '+x'} Forward\n */\n\n/**\n * @typedef {object} FaceOptions\n * @property {Forward} [forward] the model's nose axis, default '-z'\n * @property {Vec3Input} [up] which way is up as it turns, in the parent's space, default [0, 1, 0].\n * Heading straight along it leaves the roll undefined, so a craft that turns through every\n * heading in the x-y plane (seen face on) needs one out of the plane: [0, 0, 1]\n */\n\n/**\n * @typedef {object} FollowOptions\n * @property {boolean} [orient] turn the node to face along the curve, default true\n * @property {Forward} [forward] the model's nose axis, default '-z'\n * @property {Vec3Input} [up] which way is up as it turns, default [0, 1, 0] - see face()\n */\n\nconst FORWARD = ['-z', '+z', '-y', '+y', '-x', '+x']\n/** What face() and follow() take, and hints for names people reach for instead. */\nexport const FACE_OPTIONS = ['forward', 'up']\nexport const FACE_HINTS = { nose: \"use 'forward' - which of the model's axes is its nose\" }\nexport const FOLLOW_OPTIONS = ['orient', 'forward', 'up']\nexport const FOLLOW_HINTS = { rotate: \"use 'orient'\", lookAhead: 'the node faces along the curve - orient: false leaves it as it is', nose: \"use 'forward' - which of the model's axes is its nose\" }\n// the turn that takes each nose axis onto -Z, as [axis, angle]\nconst TO_MINUS_Z = {\n '-z': null,\n '+z': [[0, 1, 0], Math.PI],\n '-y': [[1, 0, 0], Math.PI / 2],\n '+y': [[1, 0, 0], -Math.PI / 2],\n '-x': [[0, 1, 0], -Math.PI / 2],\n '+x': [[0, 1, 0], Math.PI / 2],\n}\n\n/**\n * Turn a node so its nose points along a direction, in its parent's space - for a model built\n * along another axis, say which with forward.\n *\n * face(lander, [0, 1, 0], { forward: '+y' }) // stand it upright\n * @param {Node} node\n * @param {Vec3Input} direction\n * @param {FaceOptions} [options]\n * @returns {Node}\n */\nexport function face(node, direction, options = {}) {\n checkOptions('face()', options, FACE_OPTIONS, FACE_HINTS)\n const forward = /** @type {Forward} */ (options.forward === undefined ? '-z' : checkOneOf('face()', 'forward', options.forward, FORWARD))\n const ahead = node.position.clone().add(Vec3.fromInput(direction, 'face()'))\n let up = options.up === undefined ? undefined : Vec3.fromInput(options.up, 'face() up')\n const parent = node.parent\n if (parent) {\n const m = parent.updateWorld().worldMatrix\n if (up) up = transformMat4(up, up.add(node.position), m).sub(transformMat4(new Vec3(), node.position, m))\n transformMat4(ahead, ahead, m)\n }\n node.lookAt(ahead, up)\n const turn = TO_MINUS_Z[forward]\n if (turn) {\n const q = setAxisAngle(new Float32Array(4), turn[0], turn[1])\n node.quaternion.copy(multiply(new Float32Array(4), node.quaternion, q))\n }\n return node\n}\n\n/**\n * Put a node t of the way along a curve (0 start, 1 end, by distance), facing the way it runs.\n * The curve is in the node's parent's space - the same space as its position. A model built along\n * another axis than -Z says which is its nose with forward.\n *\n * story.add(4, (t) => follow(lander, transfer, t))\n * follow(rocket, ascent, t, { forward: '+y' }) // a rocket modelled upright\n * @param {Node} node\n * @param {Curve} path\n * @param {number} t\n * @param {FollowOptions} [options]\n * @returns {Node}\n */\nexport function follow(node, path, t, options = {}) {\n if (!(path instanceof Curve)) fail('follow()', `takes (node, curve, t) - make the curve with curve([...points]) or ellipse({...}), got ${describe(path)}`)\n checkOptions('follow()', options, FOLLOW_OPTIONS, FOLLOW_HINTS)\n node.position.copy(path.at(t))\n if (options.orient !== false) face(node, path.tangentAt(t), { forward: options.forward, up: options.up })\n return node\n}\n\n/**\n * Draw only the first part of a line - t of it (0 nothing, 1 all) - so a path draws in as it's\n * travelled. For Lines made from curve.line(): its pieces run in order from the start.\n *\n * story.add(4, (t) => { follow(lander, transfer, t); reveal(transferLine, t) })\n * @param {Lines} lines\n * @param {number} t\n * @returns {Lines}\n */\nexport function reveal(lines, t) {\n const g = lines?.geometry\n if (!g || /** @type {any} */ (lines).drawMode !== 'lines') fail('reveal()', `takes a Lines node, got ${describe(lines)}`)\n const pieces = g.vertexCount / 2\n g.drawCount = Math.round(Math.min(1, Math.max(0, t)) * pieces) * 2\n lines.visible = g.drawCount > 0\n return lines\n}\n\n"],"mappings":";;AAgCA,IAAMW,IAAU,CAAC,QAAQ,OAAO,GAC1BC,IAAQ;CAAE,QAAQ;CAAoB,UAAU;AAA4D,GAErGC,IAAe,CAAC,SAAS,MAAM,GAC/BC,IAAa;CAAE,MAAM;CAAe,QAAQ;AAAa,GAEzDC,IAAb,MAAsB;CAEpB,OAAO,UAAUJ;CACjB,OAAO,QAAQC;CACO,KAAS,CAAC;CAChC,KAAQ;CACR,KAAW;CACX,KAAW;CAC+C,KAAU,CAAC;CACrE,OAAO;CACP,QAAQ;CAGR,YAAY,IAAU,CAAC,GAAG;EAGxB,AAFAV,EAAa,YAAYc,GAASL,GAASC,CAAK,GAC5CI,EAAQ,SAAS,KAAA,MAAW,KAAK,OAAO,CAAC,CAACA,EAAQ,OAClDA,EAAQ,UAAU,KAAA,MAAW,KAAK,QAAQV,EAAY,YAAY,SAASU,EAAQ,KAAK;CAC9F;CASA,IAAI,GAAU,GAAK,IAAU,CAAC,GAAG;EAI/B,AAHAV,EAAY,kBAAkB,YAAYW,CAAQ,GAC9CA,IAAW,KAAGjB,EAAK,kBAAkB,yCAAyCiB,GAAU,GACxF,OAAOC,KAAQ,cAAYlB,EAAK,kBAAkB,yCAAyCK,EAASa,CAAG,EAAE,cAAc,GAC3HhB,EAAa,kBAAkBc,GAASH,GAAcC,CAAU;EAChE,IAAMK,IAAO,OAAOH,EAAQ,QAAS,aAAaA,EAAQ,OAAOT,EAAMS,EAAQ,QAAQ;EAIvF,OAHKG,KAAMnB,EAAK,kBAAkB,SAASgB,EAAQ,KAAK,eAAe,OAAO,KAAKT,CAAK,CAAC,CAAC,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,gBAAgB,GAC1I,KAAKa,GAAO,KAAK;GAAE,OAAO,KAAK;GAAU;GAAU;GAAK,OAAOJ,EAAQ,SAAS;GAAI;EAAK,CAAC,GAC1F,KAAKK,GAAO,GACL;CACT;CAGA,IAAI,WAAW;EACb,IAAMC,IAAO,KAAKF,GAAO,KAAKA,GAAO,SAAS;EAC9C,OAAOE,IAAOA,EAAK,QAAQA,EAAK,WAAW;CAC7C;CAGA,IAAI,OAAO;EACT,OAAO,KAAKC;CACd;CAGA,IAAI,OAAO;EACT,OAAO,KAAKC;CACd;CAGA,IAAI,QAAQ;EACV,OAAO,KAAKJ,GAAO,KAAKI,GAAS,EAAE,SAAS;CAC9C;CAGA,IAAI,QAAQ;EACV,OAAO,KAAKJ,GAAO,KAAK,EAAE,UAAO,aAAU,gBAAa;GAAE;GAAO;GAAU;EAAM,EAAE;CACrF;CAEA,IAAI,UAAU;EACZ,OAAO,KAAKK;CACd;CAGA,OAAO;EAGL,OAFI,KAAKF,MAAS,KAAK,YAAY,CAAC,KAAK,SAAM,KAAKA,KAAQ,IAC5D,KAAKE,KAAW,IACT;CACT;CAGA,QAAQ;EAEN,OADA,KAAKA,KAAW,IACT;CACT;CAMA,KAAK,GAAM;EAGT,OAFA,KAAKF,KAAQ,KAAK,IAAI,KAAK,UAAU,KAAK,IAAI,GAAGjB,EAAY,mBAAmB,QAAQoB,CAAI,CAAC,CAAC,GAC9F,KAAKL,GAAO,GACL;CACT;CAMA,SAAS,GAAM;EACb,IAAMM,IAAI,OAAOC,KAAS,WAAW,KAAKR,GAAO,WAAW,MAAMS,EAAE,UAAUD,CAAI,IAAIA,GAChFE,IAAS,KAAKV,GAAOO;EAE3B,OADKG,KAAQ9B,EAAK,uBAAuB,WAAWK,EAASuB,CAAI,EAAE,eAAe,KAAKR,GAAO,SAAS,OAAOQ,KAAS,WAAW,KAAK,KAAKR,GAAO,KAAK,MAAM,IAAIS,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,MAAM,IAAI,GAC1L,KAAK,KAAKC,EAAO,KAAK;CAC/B;CAOA,OAAO,GAAI;EAIT,OAHI,OAAOC,KAAO,cAAY/B,EAAK,qBAAqB,wCAAwCK,EAAS0B,CAAE,GAAG,GAC9G,KAAKC,GAAQ,KAAKD,CAAE,GAChB,KAAKP,MAAY,KAAGO,EAAG,KAAKP,IAAU,KAAK,KAAK,GAC7C;CACT;CAMA,OAAO,GAAI;EACT,IAAI,KAAKC,MAAY,KAAKL,GAAO,QAAQ;GACvC,IAAI,IAAI,KAAKG,KAAQU,IAAK,KAAK;GAQ/B,AAPI,KAAK,KAAK,aACR,KAAK,QAAQ,KAAK,WAAW,IAAG,KAAK,KAAK,YAE5C,IAAI,KAAK,UACT,KAAKR,KAAW,MAGpB,KAAKF,KAAQ;EACf;EAEA,OADA,KAAKF,GAAO,GACL;CACT;CAIA,KAAS;EACP,IAAMa,IAAQ,KAAKd,IAAQe,IAAM,KAAKZ,IAClCa,IAAUF,EAAM,SAAS;EAC7B,KAAK,IAAIP,IAAI,GAAGA,IAAIO,EAAM,QAAQ,KAChC,IAAIC,IAAMD,EAAMP,EAAE,CAAC,QAAQO,EAAMP,EAAE,CAAC,YAAaO,EAAMP,EAAE,CAAC,aAAa,KAAKQ,KAAOD,EAAMP,EAAE,CAAC,OAAQ;GAClG,IAAUA;GACV;EACF;EAEF,KAAK,IAAIA,IAAIO,EAAM,SAAS,GAAGP,IAAIS,GAAS,KAAK,EAAMT,EAAE,CAAC,IAAI,CAAC;EAC/D,KAAK,IAAIA,IAAI,GAAGA,KAAKS,GAAS,KAAK;GACjC,IAAMP,IAAIK,EAAMP,IACVU,IAAMR,EAAE,WAAW,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,IAAIM,IAAMN,EAAE,SAASA,EAAE,QAAQ,CAAC,IAAK,OAAOA,EAAE;GAChG,EAAE,IAAIA,EAAE,KAAKQ,CAAG,CAAC;EACnB;EACA,IAAID,MAAY,KAAKZ,IAAU;GAC7B,KAAKA,KAAWY;GAChB,KAAK,IAAML,KAAM,KAAKC,IAAS,EAAGI,GAASF,EAAME,EAAQ,EAAE,SAAS,EAAE;EACxE;CACF;AACF,GChKME,IAAU;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,GAEtCC,IAAe,CAAC,WAAW,IAAI,GAC/BC,IAAa,EAAE,MAAM,wDAAwD,GAC7EC,IAAiB;CAAC;CAAU;CAAW;AAAI,GAC3CC,IAAe;CAAE,QAAQ;CAAgB,WAAW;CAAqE,MAAM;AAAwD,GAE9LC,IAAa;CACjB,MAAM;CACN,MAAM,CAAC;EAAC;EAAG;EAAG;CAAC,GAAG,KAAK,EAAE;CACzB,MAAM,CAAC;EAAC;EAAG;EAAG;CAAC,GAAG,KAAK,KAAK,CAAC;CAC7B,MAAM,CAAC;EAAC;EAAG;EAAG;CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;CAC9B,MAAM,CAAC;EAAC;EAAG;EAAG;CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;CAC9B,MAAM,CAAC;EAAC;EAAG;EAAG;CAAC,GAAG,KAAK,KAAK,CAAC;AAC/B;AAYA,SAAgBC,EAAK,GAAM,GAAW,IAAU,CAAC,GAAG;CAClD,EAAa,UAAU5B,GAASuB,GAAcC,CAAU;CACxD,IAAMK,IAAkC7B,EAAQ,YAAY,KAAA,IAAY,OAAOb,EAAW,UAAU,WAAWa,EAAQ,SAASsB,CAAO,GACjIQ,IAAQC,EAAK,SAAS,MAAM,CAAC,CAAC,IAAI9C,EAAK,UAAU+C,GAAW,QAAQ,CAAC,GACvEC,IAAKjC,EAAQ,OAAO,KAAA,IAAY,KAAA,IAAYf,EAAK,UAAUe,EAAQ,IAAI,WAAW,GAChFkC,IAASH,EAAK;CACpB,IAAIG,GAAQ;EACV,IAAMC,IAAID,EAAO,YAAY,CAAC,CAAC;EAE/B,AADA,AAAQD,MAAK7C,EAAc6C,GAAIA,EAAG,IAAIF,EAAK,QAAQ,GAAGI,CAAC,CAAC,CAAC,IAAI/C,EAAc,IAAIH,EAAK,GAAG8C,EAAK,UAAUI,CAAC,CAAC,GACxG/C,EAAc0C,GAAOA,GAAOK,CAAC;CAC/B;CACA,EAAK,OAAOL,GAAOG,CAAE;CACrB,IAAMG,IAAOT,EAAWE;CACxB,IAAIO,GAAM;EACR,IAAMC,IAAI5C,kBAAa,IAAI,aAAa,CAAC,GAAG2C,EAAK,IAAIA,EAAK,EAAE;EAC5D,EAAK,WAAW,KAAK5C,kBAAS,IAAI,aAAa,CAAC,GAAGuC,EAAK,YAAYM,CAAC,CAAC;CACxE;CACA,OAAON;AACT;AAeA,SAAgBO,EAAO,GAAM,GAAM,GAAG,IAAU,CAAC,GAAG;CAKlD,OAJMC,aAAgB7C,KAAQV,EAAK,YAAY,0FAA0FK,EAASkD,CAAI,GAAG,GACzJrD,EAAa,YAAYc,GAASyB,GAAgBC,CAAY,GAC9DK,EAAK,SAAS,KAAKQ,EAAK,GAAGC,CAAC,CAAC,GACzBxC,EAAQ,WAAW,MAAO4B,EAAKG,GAAMQ,EAAK,UAAUC,CAAC,GAAG;EAAE,SAASxC,EAAQ;EAAS,IAAIA,EAAQ;CAAG,CAAC,GACjG+B;AACT;AAWA,SAAgBU,EAAO,GAAO,GAAG;CAC/B,IAAMC,IAAIC,GAAO;CACjB,AAAKD,KAAyBC,EAAO,aAAa,WAAS3D,EAAK,YAAY,2BAA2BK,EAASsD,CAAK,GAAG;CACxH,IAAMC,IAASF,EAAE,cAAc;CAG/B,OAFA,EAAE,YAAY,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAGF,CAAC,CAAC,IAAII,CAAM,IAAI,GACjE,EAAM,UAAUF,EAAE,YAAY,GACvBC;AACT"}
|
package/dist/particles.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as e, Ct as t, Dt as n, Ft as r,
|
|
1
|
+
import { At as e, Ct as t, Dt as n, Ft as r, Ot as i, Tt as a, _t as o, at as s, ct as c, it as l, tt as u } from "./core.js";
|
|
2
2
|
// src/particles/Emitter.js
|
|
3
3
|
var d = [
|
|
4
4
|
"origin",
|
|
@@ -71,20 +71,20 @@ var d = [
|
|
|
71
71
|
constructor(t = {}) {
|
|
72
72
|
t?.geometry !== void 0 && e("Emitter", "an Emitter makes its own geometry - size it with 'max'");
|
|
73
73
|
let n = t?.max ?? 1e3;
|
|
74
|
-
(!Number.isInteger(n) || n < 1) && e("Emitter", `'max' must be a whole number of 1 or more, got ${
|
|
74
|
+
(!Number.isInteger(n) || n < 1) && e("Emitter", `'max' must be a whole number of 1 or more, got ${i(n)}`);
|
|
75
75
|
let r = t?.material;
|
|
76
|
-
r === void 0 || r instanceof
|
|
77
|
-
let
|
|
76
|
+
r === void 0 || r instanceof s || r && typeof r == "object" && !Array.isArray(r) || e("Emitter", `'material' is a Material or material options such as { size: 0.2 }, got ${i(r)}`);
|
|
77
|
+
let a = r instanceof s ? r : {
|
|
78
78
|
...m,
|
|
79
79
|
...r
|
|
80
|
-
},
|
|
80
|
+
}, o = new c({
|
|
81
81
|
positions: new Float32Array(n * 3),
|
|
82
82
|
colors: new Float32Array(n * 3)
|
|
83
83
|
});
|
|
84
|
-
|
|
84
|
+
o.drawCount = 0, super({
|
|
85
85
|
...t,
|
|
86
|
-
geometry:
|
|
87
|
-
material:
|
|
86
|
+
geometry: o,
|
|
87
|
+
material: a
|
|
88
88
|
}), this.#e = n, this.#r = new Float32Array(n * 3), this.#i = new Float32Array(n), this.#a = new Float32Array(n), this.#c = new Uint8Array(n), t.frustumCulled === void 0 && (this.frustumCulled = !1), this.#v(t), this.#_(t), this.onUpdate((e, t) => this.step(t));
|
|
89
89
|
}
|
|
90
90
|
set(t) {
|
|
@@ -176,7 +176,7 @@ var d = [
|
|
|
176
176
|
velocity: this.velocity.toArray(),
|
|
177
177
|
velocitySpread: typeof this.velocitySpread == "number" ? this.velocitySpread : this.velocitySpread.toArray(),
|
|
178
178
|
lifetime: [...this.lifetime],
|
|
179
|
-
color: this.#o[0].map((e) => new
|
|
179
|
+
color: this.#o[0].map((e) => new o().setSRGB(e[0], e[1], e[2]).toJSON())
|
|
180
180
|
};
|
|
181
181
|
}
|
|
182
182
|
#f(e, t, n) {
|
|
@@ -215,15 +215,15 @@ var d = [
|
|
|
215
215
|
}
|
|
216
216
|
#_(e) {
|
|
217
217
|
let n = "Emitter";
|
|
218
|
-
if (e.origin !== void 0 && this.origin.copy(e.origin, n), e.originSpread !== void 0 && (this.originSpread = Math.max(0,
|
|
218
|
+
if (e.origin !== void 0 && this.origin.copy(e.origin, n), e.originSpread !== void 0 && (this.originSpread = Math.max(0, a(n, "originSpread", e.originSpread))), e.velocity !== void 0 && this.velocity.copy(e.velocity, n), e.velocitySpread !== void 0) {
|
|
219
219
|
let r = e.velocitySpread;
|
|
220
|
-
typeof r == "number" ? this.velocitySpread =
|
|
220
|
+
typeof r == "number" ? this.velocitySpread = a(n, "velocitySpread", r) : this.velocitySpread instanceof t ? this.velocitySpread.copy(r, n) : this.velocitySpread = t.fromInput(r, n);
|
|
221
221
|
}
|
|
222
222
|
e.lifetime !== void 0 && (this.lifetime = v(e.lifetime)), e.color !== void 0 && (this.#o[0] = y(e.color));
|
|
223
223
|
}
|
|
224
224
|
#v(e) {
|
|
225
225
|
let t = "Emitter";
|
|
226
|
-
e.rate !== void 0 && (this.rate = Math.max(0,
|
|
226
|
+
e.rate !== void 0 && (this.rate = Math.max(0, a(t, "rate", e.rate))), e.gravity !== void 0 && this.gravity.copy(e.gravity, t), e.drag !== void 0 && (this.drag = Math.max(0, a(t, "drag", e.drag))), e.follow !== void 0 && (this.follow = _(e.follow)), e.onParticle !== void 0 && (this.onParticle = e.onParticle);
|
|
227
227
|
}
|
|
228
228
|
#y() {
|
|
229
229
|
return {
|
|
@@ -245,15 +245,15 @@ var d = [
|
|
|
245
245
|
}
|
|
246
246
|
};
|
|
247
247
|
function _(t) {
|
|
248
|
-
return t === null || t instanceof l ? t : e("Emitter", `'follow' must be a node, got ${
|
|
248
|
+
return t === null || t instanceof l ? t : e("Emitter", `'follow' must be a node, got ${i(t)}`);
|
|
249
249
|
}
|
|
250
250
|
function v(t) {
|
|
251
251
|
let n = typeof t == "number" ? [t, t] : t;
|
|
252
|
-
return Array.isArray(n) && n.length === 2 && n.every((e) => typeof e == "number" && e > 0) || e("Emitter", `'lifetime' must be seconds above 0, or a [min, max] range, got ${
|
|
252
|
+
return Array.isArray(n) && n.length === 2 && n.every((e) => typeof e == "number" && e > 0) || e("Emitter", `'lifetime' must be seconds above 0, or a [min, max] range, got ${i(t)}`), [Math.min(n[0], n[1]), Math.max(n[0], n[1])];
|
|
253
253
|
}
|
|
254
254
|
function y(t) {
|
|
255
255
|
let n = Array.isArray(t) && !(t.length === 3 && t.every((e) => typeof e == "number")) ? t : [t];
|
|
256
|
-
return n.length || e("Emitter", "'color' needs at least one colour"), n.map((e) =>
|
|
256
|
+
return n.length || e("Emitter", "'color' needs at least one colour"), n.map((e) => o.fromInput(e, "Emitter").toSRGB());
|
|
257
257
|
}
|
|
258
258
|
function b(e) {
|
|
259
259
|
if (!e) return [
|
|
@@ -286,7 +286,7 @@ var x = [
|
|
|
286
286
|
gravity = new t();
|
|
287
287
|
drag = 0;
|
|
288
288
|
constructor(e = {}) {
|
|
289
|
-
n("Body", e, x, S), e.velocity !== void 0 && this.velocity.copy(e.velocity, "Body"), e.gravity !== void 0 && this.gravity.copy(e.gravity, "Body"), e.drag !== void 0 && (this.drag = Math.max(0,
|
|
289
|
+
n("Body", e, x, S), e.velocity !== void 0 && this.velocity.copy(e.velocity, "Body"), e.gravity !== void 0 && this.gravity.copy(e.gravity, "Body"), e.drag !== void 0 && (this.drag = Math.max(0, a("Body", "drag", e.drag)));
|
|
290
290
|
}
|
|
291
291
|
impulse(e) {
|
|
292
292
|
return this.velocity.add(t.fromInput(e, "Body")), this;
|