diff --git a/ASSETS.md b/ASSETS.md index 083fce4..be2ed2e 100644 --- a/ASSETS.md +++ b/ASSETS.md @@ -46,10 +46,10 @@ The Babylon comparison path now has a formal package pipeline rather than scene- | Storefront depth and background massing | Original procedural geometry plus existing generated facade WebP | Awnings, columns, sills, roof depth, and skyline enclosure around the existing facade | Consolidate into `block.1208-las-olas.v1` source scene and GLB | | FPS weapon presentation | Original procedural assembly in `OpsWorld.ts` | Visible first-person weapon and local recoil only | Replace with the possessed member package's `firstPersonArmsGlb` and weapon socket contract | -The Quaternius Universal Base Characters pack was evaluated as a permissive cross-engine reference and its primary page/license were checked, but no archive was committed or used in the runtime. The official free-download endpoint rate-limited automated access, and the pack's visual style is not the final benchmark. No marketplace or third-party model is represented as project-owned content. +The Quaternius Universal Base Characters and Universal Animation Library free standard packages were acquired through their official zero-price itch pages. Their creator-provided archive licenses dedicate the included assets to CC0 1.0. One male base and 12 gameplay clips are now combined into the optimized runtime package at `/assets/packages/characters/universal-male/universal-male.v1.glb`; the exact license and strict package manifest ship beside it. This model proves the portable rig pipeline but its superhero costume is explicitly not the final benchmark. No marketplace asset or third-party model is represented as project-owned content. All procedural fallbacks are code, not claimed production art. They exist to remove player-facing capsules/spheres, exercise semantic hit zones, and let the gameplay and package pipeline be verified before licensed source models arrive. ### Evaluated External Character Reference -Quaternius's **Universal Base Characters** page describes six game-ready base characters, 20 hairstyles, an average 13,000-triangle model, humanoid retargeting, FBX/glTF exports, and compatibility claims for Unreal, Unity, and Godot: https://quaternius.com/packs/universalbasecharacters.html. The current Quaternius Asset License permits use and modification in commercial products without attribution but prohibits redistributing the assets themselves as an asset pack: https://quaternius.com/license.html. These links document evaluation only; the files are not part of this repository. +Quaternius's **Universal Base Characters** page describes six game-ready base characters, 20 hairstyles, an average 13,000-triangle model, humanoid retargeting, FBX/glTF exports, and compatibility with Unreal, Unity, and Godot: https://quaternius.com/packs/universalbasecharacters.html. The selected free standard archive includes `CC0 1.0 Universal (CC0 1.0) Public Domain Dedication` and identifies Quaternius as the model creator; that exact license is preserved at `frontend/public/assets/packages/characters/universal-male/LICENSE-QUATERNIUS-CC0.txt`. Acquisition and transformation details are recorded in `docs/PRODUCTION_ART_SOURCES.md` and `docs/PRODUCTION_ART_PACKAGE_V1.md`. diff --git a/docs/PRODUCTION_ART_PACKAGE_V1.md b/docs/PRODUCTION_ART_PACKAGE_V1.md new file mode 100644 index 0000000..15ea00e --- /dev/null +++ b/docs/PRODUCTION_ART_PACKAGE_V1.md @@ -0,0 +1,85 @@ +# Production Art Package V1 + +**Status:** Implemented on `feat/production-art-package-v1` +**Scope:** One legally portable rigged-character pipeline plus CC0 PBR surfaces for the 1208 Las Olas Babylon comparison client. + +## Outcome + +The Modern Ops renderer now loads a strict character package before the scene becomes ready. The package contains a real 65-joint humanoid rig and 12 selected gameplay animation groups in one optimized GLB. Every deployed combatant receives an independently animated rig, physical hit proxies attached to named bones, a visible weapon attached to the right-hand bone, shadows, and the existing selection marker. If any manifest, GLB, skeleton, or animation requirement fails, the scene keeps the previously verified articulated fallback and records a diagnostic instead of crashing. + +The 1208 street now uses compact CC0 asphalt, concrete, and brick color, OpenGL-normal, and roughness maps. These replace flat colors while preserving the authoritative grid, cover metadata, vehicle metadata, line-of-sight, cameras, and result boundary. + +| Package component | Runtime result | +|---|---:| +| Optimized rigged character GLB | 1,358,092 bytes | +| Character skeleton | 65 joints | +| Included animation groups | 12 | +| CC0 PBR maps | 9 WebP files, approximately 278 KB | +| Total package directory | 13 files, 1.57 MB | +| Global shipped asset total | 7.38 MB of 20 MB | +| Package schemas validated | 5 packages across 4 schemas | + +## Included Character States + +| Semantic state | Packaged animation | +|---|---| +| Idle | `Idle_Loop` | +| Walk | `Walk_Loop` | +| Sprint | `Sprint_Loop` | +| Crouch | `Crouch_Idle_Loop` | +| Aim | `Pistol_Aim_Neutral` | +| Fire | `Pistol_Shoot` | +| Reload | `Pistol_Reload` | +| Hit | `Hit_Chest` | +| Downed | `Death01` | + +The package contract also supplies controlled fallbacks for strafe, aim-walk, and cover transitions until an authored final rig includes dedicated clips. + +## Runtime Architecture + +`build-character-package.mjs` verifies that the base model and animation source have identical joint-name sets, copies only required animation channels, deduplicates and prunes data, and emits one intermediate GLB. The documented optimization pass converts textures to 512-pixel WebP while disabling mesh compression, simplification, joining, flattening, instancing, and palette operations that could disturb the rig or named bones. + +`loadPackagedCharacterTemplate()` loads the GLB once into a Babylon `AssetContainer`. It validates every animation required by the package, then clones the skeleton and animation groups for each combatant. Renderer-visible meshes are non-pickable; invisible boxes attached to the authored head, torso, arm, and leg bones provide stable renderer-neutral hit-zone candidates. This prevents texture or mesh changes from altering the shared damage contract. + +The canvas exposes only the active package ID as a diagnostic. The browser gauntlet requires `character.universal-male.pipeline-v1` before accepting the TPS, FPS, tactical, possession, firing, result, and return evidence. + +## Provenance and Reproducibility + +The character and animations are from Quaternius CC0 standard packages. The runtime package includes the creator-provided CC0 license. The road, concrete, and brick maps are from ambientCG CC0 archives, with per-source archive and runtime-file checksums in `pbr-sources.json`. Acquisition references and source checksums are recorded in `PRODUCTION_ART_SOURCES.md`. + +No marketplace, ripped GTA/FiveM content, login-bound Mixamo asset, or unverified mirror is included. The source archives are deliberately excluded from Git; the repository contains the deterministic build tools, optimized runtime package, exact license, package manifest, and provenance locks. + +## Verification + +The isolated live-browser gauntlet proved all of the following in WebGL2: + +| Gate | Result | +|---|---| +| Production package active | Passed | +| Third-person possession | Passed | +| Switch from Lil Dre to Kilo | Passed | +| First-person camera and firing | Passed | +| Tactical commander view | Passed | +| Result produced and applied once | Passed | +| Return to strategy block | Passed | +| Fatal local runtime exceptions | 0 | + +The focused unit test verifies the shipped manifest, CC0 license, engine portability, named skeleton hit zones, fire/reload/downed clips, and a GLB smaller than 1.5 MB. Package validation and global asset-budget auditing are part of the existing quality gate. + +## Visual Limitation and Decision + +The free standard character is a pipeline stand-in, **not final art**. Its only male full-body option is a bare-torso superhero model. Two procedural streetwear overlay experiments were rejected after live TPS review because their bone-local orientation produced inferior silhouettes. Those overlays are not included. + +This milestone proves that a commissioned or licensed clothed member can drop into the game without rewriting combat, possession, hit resolution, animation dispatch, FPS/TPS/tactical cameras, or persistence. The next paid or commissioned deliverable should target this exact contract: + +| Required final deliverable | Acceptance gate | +|---|---| +| One recognizable clothed hero | Matches Contacts identity in face, hair, silhouette, and palette | +| One visually distinct rival | Reads correctly at tactical and TPS distances | +| Same 65-bone-compatible or mapped rig | Imports through package validation without gameplay changes | +| Dedicated locomotion and gun set | Idle, walk, sprint, aim, aim-walk, fire, reload, hit, downed, crouch, and cover | +| Named hit bones and right-hand weapon socket | Passes existing physical-ray browser test | +| Source and cross-engine rights | Editable source, FBX/GLB, no engine restriction, commercial redistribution in compiled game | +| Web LOD0 | Under 65,000 triangles, 120 bones, 2–4K source textures with a 512–1024 web export | + +The user should approve a final character source only after it is tested against this package, not on screenshots alone. diff --git a/docs/PRODUCTION_ART_SOURCES.md b/docs/PRODUCTION_ART_SOURCES.md new file mode 100644 index 0000000..17deb33 --- /dev/null +++ b/docs/PRODUCTION_ART_SOURCES.md @@ -0,0 +1,29 @@ +# Production Art Sources — Portable Package V1 + +**Author:** Manus AI +**Date:** 2026-08-29 + +This milestone uses only primary-source assets that can be incorporated into a commercial cross-engine pipeline without an additional purchase. The assets remain visually provisional; their purpose is to exercise the real rig, animation, GLB, PBR, provenance, and optimization path that final commissioned assets must follow. + +| Source | Selected content | License and portability | Acquisition evidence | +|---|---|---|---| +| Quaternius Universal Base Characters | Free standard package; selected `Superhero_Male_FullBody` humanoid base; glTF/FBX and textures | CC0; commercial use allowed; humanoid rig intended for retargeting in Babylon/web, Unreal, Unity, and Godot [1] | Official itch product ID `3822259`; free upload ID `15861669`; archive 128,968,391 bytes; SHA-256 `fdbf1804c90dfc1ea03e992bff7da2dfd1a79318e13270a660180f9308455f40` | +| Quaternius Universal Animation Library | Free standard package; 43 animation groups including idle, walk, jog, sprint, pistol aim/fire/reload, hit, crouch, driving, and death | CC0; commercial use allowed; current library documents compatibility with the Universal Base Characters rig and Unreal/Godot/Unity exports [2] | Free upload ID `17958403`; archive 15,904,933 bytes; SHA-256 `cc73fc4e495b82958207316596317a3f40b9fa38065bde1027937452da537724` | +| ambientCG | `Asphalt033`, `Concrete034`, and `Bricks097` 1K JPG PBR packages | CC0; downloadable maps may be modified, distributed, and included in a commercial game [3] | Official API archives; SHA-256: Asphalt `c71801b342dbea594dbdd0bd2ddc0a6d13f813c923fca408b9f5b9ee5e58aba2`; Concrete `5839d284d94ffb8d2a56df742ec522b13dd311c52dbd42b8fd33f0409ceedb81`; Bricks `97b5df360161e48bcfed609aef361e8115b680ddc0aea4ad9321d4b00e222ad0`. Runtime-map checksums ship in `pbr-sources.json`. | +| Kenney City Kit Roads | Modular road, sidewalk, signs, traffic lights, utility poles, wires, construction props, and dumpster GLB/FBX models | CC0; personal and commercial use; no attribution required [4] [5] | Official archive SHA-256 `22058af3d68173a7cf9bda9f0e243a8cef6bd68168c302ebc76327063849674e`; evaluated but not imported in V1 because the PBR procedural block retained the existing semantic anchors. | + +The Quaternius base character and Universal Animation Library contain matching 65-joint skeleton name sets. The selected base model has 69 total nodes and no embedded animations. The animation GLB has 67 nodes and 43 animation groups. This exact-name compatibility permits deterministic transfer or runtime retargeting rather than manual per-clip remapping. + +The emitted runtime character GLB has SHA-256 `f800a143bec5241cf21090c0921eedaaf6f2bc9c73261462b197668b2037f06b`. + +The Quaternius source glTF references `T_Hair_1_Normal_png.png` and `T_Eye_Normal_png.png`, while the standard archive contains `T_Hair_1_Normal.png` and `T_Eye_Normal.png`. The packaging step must normalize those two URIs or provide deterministic aliases. This source mismatch must remain documented rather than silently repaired by hand. + +The free character is a **real rigged asset but not the target hero design**. It is suitable for proving animation, possession, hit-zone, LOD, and cross-engine import contracts. It must not be presented as the final recognizable member. The no-purchase road kit is similarly useful for semantic props and modular validation but is not a substitute for the commissioned high-fidelity 1208 block. + +## References + +[1]: https://quaternius.com/packs/universalbasecharacters.html "Quaternius — Universal Base Characters" +[2]: https://quaternius.itch.io/universal-animation-library "Quaternius — Universal Animation Library" +[3]: https://docs.ambientcg.com/license/ "ambientCG License" +[4]: https://kenney.nl/assets/city-kit-roads "Kenney — City Kit Roads" +[5]: https://kenney.nl/support "Kenney Support — Commercial Use and Attribution" diff --git a/docs/PRODUCTION_ART_V1_VERIFICATION.md b/docs/PRODUCTION_ART_V1_VERIFICATION.md new file mode 100644 index 0000000..881fd41 --- /dev/null +++ b/docs/PRODUCTION_ART_V1_VERIFICATION.md @@ -0,0 +1,53 @@ +# Production Art V1 — Verification + +**Branch:** `feat/production-art-package-v1` +**Date:** 2026-08-29 + +## Automated Gates + +| Gate | Result | +|---|---| +| ESLint | 0 errors; 194 pre-existing warnings | +| TypeScript | Passed | +| Vitest | 48 files, 708 tests passed | +| Runtime image and package budget | 110 manifest assets plus 13 package files; 7.38 MB / 20 MB; 0 errors; 0 warnings | +| Package schema validation | 5 packages against 4 schemas passed | +| Production build | Passed in 23.63 seconds after browser/acquisition process cleanup; passed again after automated-review fixes | +| Backend offline pytest | 42 passed; 93 existing `datetime.utcnow()` warnings | + +The first production-build attempt terminated during chunk rendering under sandbox memory pressure after all frontend tests and asset gates had passed. No code change was made to conceal it. The temporary development server and completed acquisition browsers were stopped; the identical production source then built successfully with 2.8 GB available. + +## Live WebGL2 Gauntlet + +The reusable `scripts/verify-showdown.mjs` gate now resolves its output directory relative to the repository and requires the loaded canvas package ID to equal `character.universal-male.pipeline-v1`. + +| Interaction | Result | +|---|---| +| Real strategy shell to 1208 Strip and OPS 3D launch | Passed | +| Production character package active | Passed | +| Third-person possession | Passed | +| Possession transfer: Lil Dre → Kilo | Passed | +| First-person camera and physical fire | Passed | +| Tactical commander camera | Passed | +| Retreat result generated | Passed | +| Result applied once to block | Passed | +| Return to strategy view | Passed | +| Fatal local runtime exceptions | 0 | + +Final screenshots are stored in `docs/evidence/production-art-v1/`. + +## Asset Pipeline Gates + +The runtime package is 1,358,092 bytes and contains 65 named joints plus 12 animation groups. A unit test enforces a GLB smaller than 1.5 MB, CC0 provenance, zero engine restrictions, named head/arm hit-zone mapping, and required fire, reload, and downed clips. The package validator verifies the runtime JSON against `character-package.schema.json` and confirms the referenced GLB exists. + +The asset audit now counts all files under `public/assets/packages` in the global shipping budget without treating package manifests, licenses, PBR maps, or GLBs as unregistered image orphans. + +## Automated Review Remediation + +Cursor Bugbot identified two valid lifecycle issues on PR #121. First, an interrupted transient animation could finish later and restart idle over a newer clip. The completion callback now returns unless its animation group is still the active group. Second, invisible physical hit proxies could remain pickable after an actor was downed or while the possessed body was hidden in first person. Snapshot and camera synchronization now toggle both rendered meshes and hit proxies together. + +After both fixes, TypeScript, all 708 tests, both asset gates, the production build, and the complete WebGL2 gauntlet passed again. The final browser evidence reports the production package active, TPS/FPS/tactical continuity, member transfer, result application and strategy return, with zero fatal local runtime exceptions. + +## Honest Visual Gate + +The final captures prove the rigged-character and PBR pipeline but do not meet the cinematic visual target. The free source character’s superhero costume is unsuitable for recognizable street members. Two bone-attached primitive-clothing experiments were tested and removed after live TPS review because they degraded silhouette. The next character must be licensed or commissioned against the package contract and judged in all three cameras. diff --git a/docs/PRODUCTION_ART_VISUAL_REVIEW.md b/docs/PRODUCTION_ART_VISUAL_REVIEW.md new file mode 100644 index 0000000..a5200e0 --- /dev/null +++ b/docs/PRODUCTION_ART_VISUAL_REVIEW.md @@ -0,0 +1,14 @@ +# Production Art V1 — Visual Review + +**Evidence date:** 2026-08-29 +**Final captures:** `docs/evidence/production-art-v1/` + +The runtime conclusively loads `character.universal-male.pipeline-v1` and renders independently animated rigs in tactical, first-person, and third-person modes. Scale, ground placement, physical bone hit zones, right-hand weapon attachment, camera possession, member switching, PBR road/concrete/brick response, and the exactly-once result return are functional. This is a production-pipeline improvement over capsules and renderer-owned character assumptions. + +The selected free standard Quaternius asset is not suitable as final member art. Its only male full-body option is a bare-torso superhero wearing briefs. The underlying UV and final TPS capture confirm that the asset demonstrates the rig and animation path but does not represent the game’s character-driven streetwear vision. + +Two bone-attached procedural clothing experiments were tested in the live TPS view. Although both followed the skeleton and preserved the browser gauntlet, their local bone orientation produced oversized torsos and disconnected shoes, degrading silhouette and member identity. Both experiments were removed. This confirms that procedural clothing cannot rescue an unsuitable source body at target quality. + +The environment’s imported asphalt, concrete, and brick maps create denser surfaces and preserve the invisible gameplay grid. The block still remains below the visual target in modeled storefront depth, background-city density, wet reflections, vegetation, vehicle fidelity, lighting complexity, and authored human detail. + +The approved next visual gate is therefore one authored clothed hero and one distinct rival that satisfy `character-package.schema.json`. They must be evaluated live in tactical, FPS, and TPS—not as standalone renders—before the roster is scaled. diff --git a/docs/PROJECT_LOG.md b/docs/PROJECT_LOG.md index 5e83333..915eb1f 100644 --- a/docs/PROJECT_LOG.md +++ b/docs/PROJECT_LOG.md @@ -68,6 +68,38 @@ Payments/monetization P0s are separately listed in `docs/MVP_STATUS_AND_DEV_PLAN ## Log +### 2026-08-29 — Portable production-art package v1 + +- Merged PRs #119 and #120 in order, then created `feat/production-art-package-v1` + from the updated protected default branch. The Modern Ops contracts, aimed fire, + tactical/FPS/TPS possession, and exactly-once result boundary remain unchanged. +- Acquired the free Quaternius Universal Base Characters and Universal Animation + Library packages through their official zero-price itch paths. Their included + creator license is CC0 1.0. A deterministic build script verifies the matching + 65-joint rigs and copies 12 selected locomotion, pistol, hit, crouch, and death + clips into one optimized 1,358,092-byte GLB. +- Modern Ops now loads the strict runtime package before scene readiness, parses the + GLB once into an `AssetContainer`, clones a rig and animation groups per combatant, + attaches physical head/torso/arm/leg hit proxies to named bones, attaches the + presentation weapon to `hand_r`, and drives animation from existing combat events. + Any package failure keeps the verified articulated fallback instead of crashing. +- Added ambientCG CC0 asphalt, concrete, and brick color/normal/roughness maps to the + 1208 block. Nine 512px WebP maps replace flat street materials. Package files now + count against the global asset gate: 13 files / 1.57 MB, total shipped assets + 7.38 MB / 20 MB, zero audit warnings. +- The live isolated WebGL2 gauntlet verified the production package ID, TPS, FPS, + tactical commander view, possession transfer from Lil Dre to Kilo, firing, result + application, and return to strategy with zero local runtime exceptions. A + procedural bone-attached streetwear experiment was rejected and removed after + TPS review; the free superhero model proves the pipeline but is not final art. + Final character procurement must now satisfy the package specification in + `docs/PRODUCTION_ART_PACKAGE_V1.md` rather than being selected from screenshots. +- PR #121 review found and resolved two lifecycle defects before merge: interrupted + transient clips can no longer restart idle over a newer animation, and downed or + first-person-hidden member hit proxies now become non-pickable with their rendered + meshes. TypeScript, 708 tests, both asset gates, the production build, and the full + WebGL2 gauntlet passed again after the fixes. + ### 2026-08-29 — 1208 Las Olas visual showdown foundation and multiview verification - Stacked the showdown branch on PR #119 rather than rewriting its verified Modern Ops diff --git a/docs/evidence/production-art-v1/fps-rigged-character-pbr.jpg b/docs/evidence/production-art-v1/fps-rigged-character-pbr.jpg new file mode 100644 index 0000000..210c963 Binary files /dev/null and b/docs/evidence/production-art-v1/fps-rigged-character-pbr.jpg differ diff --git a/docs/evidence/production-art-v1/result-boundary.jpg b/docs/evidence/production-art-v1/result-boundary.jpg new file mode 100644 index 0000000..e9b7068 Binary files /dev/null and b/docs/evidence/production-art-v1/result-boundary.jpg differ diff --git a/docs/evidence/production-art-v1/strategy-return.jpg b/docs/evidence/production-art-v1/strategy-return.jpg new file mode 100644 index 0000000..bb91b5d Binary files /dev/null and b/docs/evidence/production-art-v1/strategy-return.jpg differ diff --git a/docs/evidence/production-art-v1/tactical-rigged-character-pbr.jpg b/docs/evidence/production-art-v1/tactical-rigged-character-pbr.jpg new file mode 100644 index 0000000..8579e7a Binary files /dev/null and b/docs/evidence/production-art-v1/tactical-rigged-character-pbr.jpg differ diff --git a/docs/evidence/production-art-v1/tps-rigged-character-pbr.jpg b/docs/evidence/production-art-v1/tps-rigged-character-pbr.jpg new file mode 100644 index 0000000..604938d Binary files /dev/null and b/docs/evidence/production-art-v1/tps-rigged-character-pbr.jpg differ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d56c7a3..8f589e3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -26,6 +26,9 @@ "zustand": "^4.4.7" }, "devDependencies": { + "@gltf-transform/cli": "^4.4.2", + "@gltf-transform/core": "^4.4.2", + "@gltf-transform/functions": "^4.4.2", "@testing-library/jest-dom": "^7.0.0", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", @@ -467,6 +470,16 @@ "specificity": "bin/cli.js" } }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@csstools/color-helpers": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", @@ -607,6 +620,198 @@ "node": ">=20.19.0" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", + "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@so-ric/colorspace": "^1.1.6", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@donmccurdy/caporal": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/@donmccurdy/caporal/-/caporal-0.0.10.tgz", + "integrity": "sha512-VdaJjOqYFYcDTM5We2x8cL+B+U9UFQvq0iW2ypqEGX31SDf2oYFjEg7INEJorBwJJnFNXV8jXoYGzJyLeYl1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/glob": "^8.1.0", + "@types/lodash": "^4.14.197", + "@types/node": "20.5.6", + "@types/table": "5.0.0", + "@types/wrap-ansi": "^8.0.1", + "chalk": "3.0.0", + "glob": "^10.3.3", + "lodash": "^4.17.21", + "table": "5.4.6", + "winston": "3.10.0", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/@types/node": { + "version": "20.5.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.6.tgz", + "integrity": "sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@donmccurdy/caporal/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@donmccurdy/caporal/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@donmccurdy/caporal/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/@emnapi/runtime": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", @@ -1206,82 +1411,53 @@ } } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "node_modules/@gltf-transform/cli": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@gltf-transform/cli/-/cli-4.4.2.tgz", + "integrity": "sha512-DBez2yawK9uXjefRBOJfFxkeTl2Jr4BZG8oOtHZd8if5KQaIdGN99ombzjf2ugjC7Lms9QSpY2pTBANE3H+kGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@donmccurdy/caporal": "~0.0.10", + "@gltf-transform/core": "^4.4.2", + "@gltf-transform/extensions": "^4.4.2", + "@gltf-transform/functions": "^4.4.2", + "@types/language-tags": "~1.0.4", + "@types/micromatch": "~4.0.10", + "@types/node-fetch": "~2.6.13", + "@types/prompts": "^2.4.9", + "@types/tmp": "~0.2.6", + "cli-table3": "~0.6.5", + "csv-stringify": "~6.6.0", + "draco3dgltf": "~1.5.7", + "gltf-validator": "~2.0.0-dev.3.10", + "keyframe-resample": "~0.1.0", + "ktx-parse": "^1.1.0", + "language-tags": "^2.1.0", + "listr2": "~8.3.3", + "meshoptimizer": "~1.0.1", + "micromatch": "~4.0.8", + "mikktspace": "~1.1.1", + "node-fetch": "~3.3.2", + "prompts": "^2.4.2", + "sharp": "~0.34.5", + "tmp": "~0.2.5", + "watlas": "^1.0.1" }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" + "bin": { + "gltf-transform": "bin/cli.js" }, "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" + "node": ">=20" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" + "url": "https://github.com/sponsors/donmccurdy" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", - "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", "cpu": [ "arm64" ], @@ -1292,19 +1468,19 @@ "darwin" ], "engines": { - "node": ">=20.9.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", - "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", "cpu": [ "x64" ], @@ -1315,39 +1491,19 @@ "darwin" ], "engines": { - "node": ">=20.9.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", - "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", - "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", "cpu": [ "arm64" ], @@ -1361,10 +1517,10 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", - "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", "cpu": [ "x64" ], @@ -1378,10 +1534,10 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", - "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", "cpu": [ "arm" ], @@ -1395,10 +1551,10 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", - "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", "cpu": [ "arm64" ], @@ -1412,10 +1568,10 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", - "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", "cpu": [ "ppc64" ], @@ -1429,10 +1585,10 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", - "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", "cpu": [ "riscv64" ], @@ -1446,10 +1602,672 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", - "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@gltf-transform/cli/node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@gltf-transform/cli/node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/@gltf-transform/core": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@gltf-transform/core/-/core-4.4.2.tgz", + "integrity": "sha512-qsWKwNSwK+2s834Mt4xbYcyHqCrgNFP7hIv5s487JxebngRfDgelpghNF+kSswGb2/NuapasfK3UViFoSJJoMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "property-graph": "^4.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/donmccurdy" + } + }, + "node_modules/@gltf-transform/extensions": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@gltf-transform/extensions/-/extensions-4.4.2.tgz", + "integrity": "sha512-HJH1FM+edC5eNvl6xO0SOXJ/j/3oDoIpSu150OTdJaLBoM3TgCCGIfh4wyhgWAqZrkvgHKVGiZKxcKV5LkgPCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@gltf-transform/core": "^4.4.2", + "ktx-parse": "^1.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/donmccurdy" + } + }, + "node_modules/@gltf-transform/functions": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@gltf-transform/functions/-/functions-4.4.2.tgz", + "integrity": "sha512-dclXgv9TshMaWBqPDUYd4xTwBQ2PpuR8p0Y9pokrRzGQDUPXRP6lTDzbqT0UmEmxFSvRyPJjvOWUmzeiRafpvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@gltf-transform/core": "^4.4.2", + "@gltf-transform/extensions": "^4.4.2", + "ktx-parse": "^1.1.0", + "ndarray": "^1.0.19", + "ndarray-lanczos": "^0.3.0", + "ndarray-pixels": "^5.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/donmccurdy" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", + "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", + "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", + "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", + "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", + "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", + "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", + "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", + "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", + "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", + "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", "cpu": [ "s390x" ], @@ -1795,6 +2613,109 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -2064,6 +2985,17 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@remix-run/router": { "version": "1.23.3", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz", @@ -2442,6 +3374,17 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@so-ric/colorspace": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", + "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "color": "^5.0.2", + "text-hex": "1.0.x" + } + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", @@ -2698,6 +3641,13 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/braces": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.5.tgz", + "integrity": "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -2723,6 +3673,17 @@ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, "node_modules/@types/http-cache-semantics": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", @@ -2745,12 +3706,50 @@ "@types/node": "*" } }, + "node_modules/@types/language-tags": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/language-tags/-/language-tags-1.0.4.tgz", + "integrity": "sha512-20PQbifv3v/djCT+KlXybv0KqO5ofoR1qD1wkinN59kfggTPVTWGmPFgL/1yWuDyRcsQP/POvkqK+fnl5nOwTg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.25.tgz", + "integrity": "sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/micromatch": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.10.tgz", + "integrity": "sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/braces": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "license": "MIT" }, + "node_modules/@types/ndarray": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/ndarray/-/ndarray-1.1.0.tgz", + "integrity": "sha512-go+C6vHBUuO9jH6Tj6qEZ63JEGoMSxFdmd+6QAtthGD6xumBfIz3RbNDDs2aoRVLf9naH8lk5jnWy2UHHKgYQQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.19.43", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", @@ -2760,12 +3759,51 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "license": "MIT" }, + "node_modules/@types/prompts": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.9.tgz", + "integrity": "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "kleur": "^3.0.3" + } + }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -2810,6 +3848,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/table": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/table/-/table-5.0.0.tgz", + "integrity": "sha512-fQLtGLZXor264zUPWI95WNDsZ3QV43/c0lJpR/h1hhLJumXRmHNsrvBfEzW2YMhb0EWCsn4U6h82IgwsajAuTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tmp": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz", + "integrity": "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/uuid": { "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", @@ -2817,6 +3876,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/wrap-ansi": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-8.0.2.tgz", + "integrity": "sha512-mdaFibQzYYqJF8Sc9By84eBLtDQD9Hnko0yXuezHBU5f5KdtQk+j5hPRQc1j4ayzdqGddKON6PjeuzxD5U1hPg==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", @@ -3208,6 +4274,22 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3308,6 +4390,23 @@ "node": ">=12" } }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3719,6 +4818,109 @@ "node": ">= 6" } }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3746,6 +4948,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/color": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", + "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^3.1.3", + "color-string": "^2.1.3" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3766,6 +4982,59 @@ "dev": true, "license": "MIT" }, + "node_modules/color-string": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", + "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-string/node_modules/color-name": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.1.tgz", + "integrity": "sha512-p2FdgwVx1a9yWBHP2wI0VgShkDpgN4kZISkxdNipGBJWpa5G6b04OINlVWCyJj0JmfvcPrgqt95E9k8yvaOJFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", + "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=14.6" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.1.tgz", + "integrity": "sha512-p2FdgwVx1a9yWBHP2wI0VgShkDpgN4kZISkxdNipGBJWpa5G6b04OINlVWCyJj0JmfvcPrgqt95E9k8yvaOJFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3886,6 +5155,33 @@ "devOptional": true, "license": "MIT" }, + "node_modules/csv-stringify": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.6.0.tgz", + "integrity": "sha512-YW32lKOmIBgbxtu3g5SaiqWNwa/9ISQt2EcgOq0+RAIFufFp9is6tqNnKahqE5kuKvrnYAzs28r+s6pXJR8Vcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cwise-compiler": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cwise-compiler/-/cwise-compiler-1.1.3.tgz", + "integrity": "sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uniq": "^1.0.0" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/data-urls": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", @@ -4118,6 +5414,13 @@ "url": "https://dotenvx.com" } }, + "node_modules/draco3dgltf": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/draco3dgltf/-/draco3dgltf-1.5.7.tgz", + "integrity": "sha512-LeqcpmoHIyYUi0z70/H3tMkGj8QhqVxq6FJGPjlzR24BNkQ6jyMheMvFKJBI0dzGZrEOUyQEmZ8axM1xRrbRiw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4138,6 +5441,13 @@ "integrity": "sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==", "license": "ISC" }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.402", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.402.tgz", @@ -4152,6 +5462,13 @@ "dev": true, "license": "MIT" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "dev": true, + "license": "MIT" + }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -4196,6 +5513,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -4657,6 +5987,37 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4722,6 +6083,13 @@ "dev": true, "license": "ISC" }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "dev": true, + "license": "MIT" + }, "node_modules/follow-redirects": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", @@ -4742,6 +6110,23 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.5.tgz", @@ -4755,7 +6140,20 @@ "mime-types": "^2.1.35" }, "engines": { - "node": ">= 6" + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" } }, "node_modules/fraction.js": { @@ -4855,6 +6253,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -5009,6 +6420,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gltf-validator": { + "version": "2.0.0-dev.3.10", + "resolved": "https://registry.npmjs.org/gltf-validator/-/gltf-validator-2.0.0-dev.3.10.tgz", + "integrity": "sha512-odJ4k0tRkGXiDGn78yDBg+fBbAIvBnXxh3RwAta0emSxGtyagFE8B4xELB1oYe3S5RD8Ci3uZAsZaascH2LAEQ==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -5260,6 +6678,13 @@ "dev": true, "license": "ISC" }, + "node_modules/iota-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz", + "integrity": "sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==", + "dev": true, + "license": "MIT" + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -5279,6 +6704,13 @@ "node": ">=8" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, "node_modules/is-core-module": { "version": "2.16.2", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", @@ -5363,6 +6795,19 @@ "dev": true, "license": "MIT" }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5370,6 +6815,22 @@ "dev": true, "license": "ISC" }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jiti": { "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", @@ -5524,92 +6985,419 @@ "integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==", "license": "ISC" }, + "node_modules/keyframe-resample": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/keyframe-resample/-/keyframe-resample-0.1.0.tgz", + "integrity": "sha512-z1au6Q6qCWP734q44t/5SyGwNydC7MvOWo2ZETAz7ZqAgtcyb5EGO7jwgk3DEH7CaDtb0DkGec9iwVpeDWX5dA==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ktx-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-1.1.0.tgz", + "integrity": "sha512-mKp3y+FaYgR7mXWAbyyzpa/r1zDWeaunH+INJO4fou3hb45XuNSwar+7llrRyvpMWafxSIi99RNFJ05MHedaJQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-2.1.0.tgz", + "integrity": "sha512-D4CgpyCt+61f6z2jHjJS1OmZPviAWM57iJ9OKdFFWSNgS7Udj9QVWqyGs/cveVNF57XpZmhSvMdVIV5mjLA7Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, "engines": { - "node": ">=14" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/antonk52" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", "dev": true, - "license": "MIT" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "license": "MIT" + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "node_modules/logform/node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } }, "node_modules/loose-envify": { "version": "1.4.0", @@ -5799,6 +7587,13 @@ "node": ">= 8" } }, + "node_modules/meshoptimizer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz", + "integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==", + "dev": true, + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -5813,6 +7608,13 @@ "node": ">=8.6" } }, + "node_modules/mikktspace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/mikktspace/-/mikktspace-1.1.1.tgz", + "integrity": "sha512-w+n5O2YLFsv/aRi3QUF0jxR+mEsl2J08ZkRItJHE08MWqiDIy8amyZN9vetBfbLhlWGMb8G3mzSPwtKHvBF7hQ==", + "dev": true, + "license": "MIT" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -5834,6 +7636,19 @@ "node": ">= 0.6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -5891,6 +7706,16 @@ "node": ">= 6" } }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5940,6 +7765,91 @@ "dev": true, "license": "MIT" }, + "node_modules/ndarray": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.1.1.tgz", + "integrity": "sha512-AsE8w/M2MS+0pD3nP5qbRRtJFeJJJaJ+qXZaZr0XjVGXhy6LIj2TERTlkpdK2AI3WufoOP+pwPk3q2ilAJcZ9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "iota-array": "^1.0.0", + "is-buffer": "^1.0.2" + } + }, + "node_modules/ndarray-lanczos": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/ndarray-lanczos/-/ndarray-lanczos-0.3.0.tgz", + "integrity": "sha512-5kBmmG3Zvyj77qxIAC4QFLKuYdDIBJwCG+DukT6jQHNa1Ft74/hPH1z5mbQXeHBt8yvGPBGVrr3wEOdJPYYZYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ndarray": "^1.0.11", + "ndarray": "^1.0.19" + } + }, + "node_modules/ndarray-ops": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ndarray-ops/-/ndarray-ops-1.2.2.tgz", + "integrity": "sha512-BppWAFRjMYF7N/r6Ie51q6D4fs0iiGmeXIACKY66fLpnwIui3Wc3CXiD/30mgLbDjPpSLrsqcp3Z62+IcHZsDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cwise-compiler": "^1.0.0" + } + }, + "node_modules/ndarray-pixels": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ndarray-pixels/-/ndarray-pixels-5.2.0.tgz", + "integrity": "sha512-lTh4tFKziAatVTa9crIsidUyn+lqujVOQpzfdBWvdFu2wo9Uo6z261lVX7SgMyP89xGmj3TMTPbbxl9YDnV4SA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ndarray": "^1.0.14", + "ndarray": "^1.0.19", + "ndarray-ops": "^1.2.2", + "sharp": "^0.35.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/node-releases": { "version": "2.0.53", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", @@ -6016,6 +7926,32 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -6084,6 +8020,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6163,6 +8106,30 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -6465,6 +8432,27 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/property-graph": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/property-graph/-/property-graph-4.1.0.tgz", + "integrity": "sha512-AvPcP7XECNWy4LGmFQ77k7un4lSKM4eS29PTvW4ck95uYeLxXPWJM7hLuBqK91FaHqCcgJvIUCuNJjjxKE7VKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/protocol-buffers-schema": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz", @@ -6753,6 +8741,21 @@ "node": ">=8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -6857,6 +8860,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -6868,6 +8888,13 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -6931,10 +8958,44 @@ "fsevents": "~2.3.2" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ { @@ -6950,19 +9011,16 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } + "license": "MIT" }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" + "license": "MIT", + "engines": { + "node": ">=10" } }, "node_modules/saxes": { @@ -7092,6 +9150,26 @@ "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -7102,6 +9180,49 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/socket.io-client": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", @@ -7199,6 +9320,16 @@ "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "license": "CC0-1.0" }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -7213,6 +9344,16 @@ "dev": true, "license": "MIT" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -7228,6 +9369,22 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -7241,6 +9398,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -7340,6 +9511,146 @@ "dev": true, "license": "MIT" }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/table/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tailwindcss": { "version": "3.4.19", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", @@ -7404,6 +9715,13 @@ "dev": true, "license": "MIT" }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true, + "license": "MIT" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -7552,6 +9870,16 @@ "dev": true, "license": "MIT" }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7610,6 +9938,16 @@ "node": ">=8" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ts-api-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", @@ -7711,6 +10049,13 @@ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, + "node_modules/uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==", + "dev": true, + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -8384,6 +10729,23 @@ "node": ">=18" } }, + "node_modules/watlas": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/watlas/-/watlas-1.0.1.tgz", + "integrity": "sha512-TmB++BFqEQY19cPNby5iszACZd8t6uauB7YdObkqhWarhed79OMPS8wufoDSo0p85A/8QW/aqZwEJf+nD4emSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", @@ -8452,6 +10814,44 @@ "node": ">=8" } }, + "node_modules/winston": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.10.0.tgz", + "integrity": "sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -8480,6 +10880,25 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index f2e764e..6562592 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -41,6 +41,9 @@ "zustand": "^4.4.7" }, "devDependencies": { + "@gltf-transform/cli": "^4.4.2", + "@gltf-transform/core": "^4.4.2", + "@gltf-transform/functions": "^4.4.2", "@testing-library/jest-dom": "^7.0.0", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-color.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-color.webp new file mode 100644 index 0000000..493cdcd Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-color.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-normal.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-normal.webp new file mode 100644 index 0000000..b5a523f Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-normal.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-roughness.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-roughness.webp new file mode 100644 index 0000000..a7a3d6f Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/asphalt033-roughness.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-color.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-color.webp new file mode 100644 index 0000000..d42dd7f Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-color.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-normal.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-normal.webp new file mode 100644 index 0000000..1573cb2 Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-normal.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-roughness.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-roughness.webp new file mode 100644 index 0000000..a89c5c3 Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/bricks097-roughness.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-color.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-color.webp new file mode 100644 index 0000000..a10f37e Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-color.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-normal.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-normal.webp new file mode 100644 index 0000000..8a105ca Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-normal.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-roughness.webp b/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-roughness.webp new file mode 100644 index 0000000..bd63da2 Binary files /dev/null and b/frontend/public/assets/packages/blocks/las-olas-1208/materials/concrete034-roughness.webp differ diff --git a/frontend/public/assets/packages/blocks/las-olas-1208/materials/pbr-sources.json b/frontend/public/assets/packages/blocks/las-olas-1208/materials/pbr-sources.json new file mode 100644 index 0000000..60a9a97 --- /dev/null +++ b/frontend/public/assets/packages/blocks/las-olas-1208/materials/pbr-sources.json @@ -0,0 +1,114 @@ +{ + "schemaVersion": 1, + "generator": "frontend/scripts/assets/prepare-pbr-textures.py", + "assets": [ + { + "assetId": "Asphalt033", + "sourceArchive": "Asphalt033_1K-JPG.zip", + "sourceSha256": "c71801b342dbea594dbdd0bd2ddc0a6d13f813c923fca408b9f5b9ee5e58aba2", + "license": "CC0-1.0", + "sourceUrl": "https://ambientcg.com/a/Asphalt033", + "maps": [ + { + "map": "color", + "sourceFile": "Asphalt033_1K-JPG_Color.jpg", + "runtimeFile": "asphalt033-color.webp", + "width": 512, + "height": 512, + "bytes": 17566, + "sha256": "b26fb79701b95061400dc92a72c86009dfe7e68264e7931c0b0c498ee9542875" + }, + { + "map": "normal", + "sourceFile": "Asphalt033_1K-JPG_NormalGL.jpg", + "runtimeFile": "asphalt033-normal.webp", + "width": 512, + "height": 512, + "bytes": 71870, + "sha256": "ac3862f5eb29b26aaa303bfda1678fd10551d0eed91681f77fa5e80803e2cf39" + }, + { + "map": "roughness", + "sourceFile": "Asphalt033_1K-JPG_Roughness.jpg", + "runtimeFile": "asphalt033-roughness.webp", + "width": 512, + "height": 512, + "bytes": 46458, + "sha256": "d65ddbab9f86a9bee19aaed58256ef7db341a802d93064d7388b5fa0b0b8000c" + } + ] + }, + { + "assetId": "Concrete034", + "sourceArchive": "Concrete034_1K-JPG.zip", + "sourceSha256": "5839d284d94ffb8d2a56df742ec522b13dd311c52dbd42b8fd33f0409ceedb81", + "license": "CC0-1.0", + "sourceUrl": "https://ambientcg.com/a/Concrete034", + "maps": [ + { + "map": "color", + "sourceFile": "Concrete034_1K-JPG_Color.jpg", + "runtimeFile": "concrete034-color.webp", + "width": 512, + "height": 256, + "bytes": 7814, + "sha256": "09399e857ac48047d95d9d1023b6cc756726a94edcaa27d6ce17718c4dcba39c" + }, + { + "map": "normal", + "sourceFile": "Concrete034_1K-JPG_NormalGL.jpg", + "runtimeFile": "concrete034-normal.webp", + "width": 512, + "height": 256, + "bytes": 17534, + "sha256": "111af614841a597e7d767506208b6b710fbfae756aae81d331d5d5c65fffb32c" + }, + { + "map": "roughness", + "sourceFile": "Concrete034_1K-JPG_Roughness.jpg", + "runtimeFile": "concrete034-roughness.webp", + "width": 512, + "height": 256, + "bytes": 10072, + "sha256": "7fa4e905894fd98539e3d83ee88e7dc7c4ee2317cd96b660a417a464645cf34f" + } + ] + }, + { + "assetId": "Bricks097", + "sourceArchive": "Bricks097_1K-JPG.zip", + "sourceSha256": "97b5df360161e48bcfed609aef361e8115b680ddc0aea4ad9321d4b00e222ad0", + "license": "CC0-1.0", + "sourceUrl": "https://ambientcg.com/a/Bricks097", + "maps": [ + { + "map": "color", + "sourceFile": "Bricks097_1K-JPG_Color.jpg", + "runtimeFile": "bricks097-color.webp", + "width": 512, + "height": 256, + "bytes": 41352, + "sha256": "37203da23d0c3a4af18293246e1cbe9cf809f7755100dc11873281e40047c676" + }, + { + "map": "normal", + "sourceFile": "Bricks097_1K-JPG_NormalGL.jpg", + "runtimeFile": "bricks097-normal.webp", + "width": 512, + "height": 256, + "bytes": 29292, + "sha256": "d6e25eec6d928e34da65613ebc8f29b4cfb92d53c1846e7d1f4c40e6e61ebe1f" + }, + { + "map": "roughness", + "sourceFile": "Bricks097_1K-JPG_Roughness.jpg", + "runtimeFile": "bricks097-roughness.webp", + "width": 512, + "height": 256, + "bytes": 35868, + "sha256": "afb8fc4a1a52246a4d7e1fbc6e9189c350f3d2cc7b6da169111c7bdc526dbbec" + } + ] + } + ] +} diff --git a/frontend/public/assets/packages/characters/universal-male/LICENSE-QUATERNIUS-CC0.txt b/frontend/public/assets/packages/characters/universal-male/LICENSE-QUATERNIUS-CC0.txt new file mode 100644 index 0000000..26189f4 --- /dev/null +++ b/frontend/public/assets/packages/characters/universal-male/LICENSE-QUATERNIUS-CC0.txt @@ -0,0 +1,22 @@ +This is the standard FREE version of the Universal Base Characters Kit, which only contains +a portion of the models . You can buy the SOURCE version which has all the models with rigged .blends, +and Unity(URP), Unreal Engine and Godot projects +with custom shaders already set up. + +You can get the other version from the website https://quaternius.com + +------------------------------------------------------- +License: +CC0 1.0 Universal (CC0 1.0) +Public Domain Dedication +https://creativecommons.org/publicdomain/zero/1.0/ + +------------------------------------------------------ +Models by @Quaternius +Consider supporting me on Patreon! + +https://www.patreon.com/quaternius + +------------------------------------------------------- +Join the Discord Server: +https://discord.gg/vJqnRUYRfT diff --git a/frontend/public/assets/packages/characters/universal-male/package.v1.json b/frontend/public/assets/packages/characters/universal-male/package.v1.json new file mode 100644 index 0000000..a5340bb --- /dev/null +++ b/frontend/public/assets/packages/characters/universal-male/package.v1.json @@ -0,0 +1,69 @@ +{ + "schemaVersion": 1, + "packageId": "character.universal-male.pipeline-v1", + "memberId": "shared-male-production-base", + "displayName": "Universal Male Production Base", + "role": "shooter", + "wardrobeIds": ["quaternius.superhero-male.dark"], + "materialVariantIds": ["skin.deep", "outfit.dark"], + "portraitAssetId": "generated.characters.portraits.character_shooter_male_portrait_v001", + "source": { + "editableFiles": [ + "external/quaternius/Universal Base Characters[Standard].zip", + "external/quaternius/Universal Animation Library[Standard].zip" + ], + "exportFbx": "external/quaternius/Universal Base Characters[Standard]/Base Characters/Unity/Superhero_Male_FullBody.fbx" + }, + "runtime": { + "babylonGlb": "/assets/packages/characters/universal-male/universal-male.v1.glb", + "unrealSkeletalMesh": "/Game/Dealt/Characters/UniversalMale/SK_UniversalMale" + }, + "skeleton": { + "profileId": "quaternius.universal-humanoid.v3", + "rootBone": "root", + "forwardAxis": "+Z", + "upAxis": "+Y", + "metersPerUnit": 1 + }, + "hitZones": { + "head": "Head", + "torso": "spine_03", + "leftArm": "upperarm_l", + "rightArm": "upperarm_r", + "leftLeg": "thigh_l", + "rightLeg": "thigh_r" + }, + "animations": { + "idle": "Idle_Loop", + "walk": "Walk_Loop", + "sprint": "Sprint_Loop", + "strafe": "Walk_Loop", + "aim": "Pistol_Aim_Neutral", + "aimWalk": "Jog_Fwd_Loop", + "fire": "Pistol_Shoot", + "reload": "Pistol_Reload", + "crouch": "Crouch_Idle_Loop", + "hit": "Hit_Chest", + "downed": "Death01", + "coverEnter": "Crouch_Fwd_Loop", + "coverIdle": "Crouch_Idle_Loop", + "coverExit": "Crouch_Fwd_Loop" + }, + "weaponSockets": { + "rightHand": "hand_r", + "leftHandIk": "hand_l", + "holster": "pelvis" + }, + "lods": [ + { "level": 0, "maxTriangles": 15000, "maxBones": 65, "screenCoverage": 0.35 } + ], + "provenance": { + "creator": "Quaternius", + "sourceUrl": "https://quaternius.com/packs/universalbasecharacters.html", + "licenseId": "CC0-1.0", + "commercialUse": true, + "engineRestrictions": [], + "aiInvolvement": "none", + "modificationNotes": "Free standard Universal Base Characters male model combined with selected free Universal Animation Library clips by the deterministic build-character-package.mjs pipeline. Textures were resized to 512px WebP; mesh compression and geometry simplification were disabled. Runtime SHA-256: f800a143bec5241cf21090c0921eedaaf6f2bc9c73261462b197668b2037f06b. This is a legal rigged pipeline stand-in, not the final recognizable Lil Dre art." + } +} diff --git a/frontend/public/assets/packages/characters/universal-male/universal-male.v1.glb b/frontend/public/assets/packages/characters/universal-male/universal-male.v1.glb new file mode 100644 index 0000000..9b24d0a Binary files /dev/null and b/frontend/public/assets/packages/characters/universal-male/universal-male.v1.glb differ diff --git a/frontend/scripts/assets/audit.mjs b/frontend/scripts/assets/audit.mjs index 2c9ecf0..090a846 100644 --- a/frontend/scripts/assets/audit.mjs +++ b/frontend/scripts/assets/audit.mjs @@ -25,6 +25,7 @@ import { ASSET_CLASSES, RUNTIME_BUDGET_MB, FRINGE_THRESHOLD, analysePixels } fro const JSON_OUT = process.argv.includes('--json'); const FRONTEND = path.resolve(path.dirname(new URL(import.meta.url).pathname), '../..'); const RUNTIME_DIR = path.join(FRONTEND, 'public/assets/runtime'); +const PACKAGE_DIR = path.join(FRONTEND, 'public/assets/packages'); const MANIFEST = path.join(FRONTEND, 'src/assets/runtimeManifest.json'); const EXCEPTIONS = path.join(FRONTEND, 'scripts/assets/exceptions.json'); @@ -61,6 +62,7 @@ async function main() { let totalBytes = 0; let orphanBytes = 0; + let packageBytes = 0; let checked = 0; for (const entry of manifest.entries) { @@ -115,17 +117,22 @@ async function main() { } } await walk(RUNTIME_DIR); + const runtimeFileCount = onDisk.length; + await walk(PACKAGE_DIR); const manifestPaths = new Set(manifest.entries.map((e) => path.join(FRONTEND, 'public', e.runtimePath.replace(/^\//, '')))); for (const p of onDisk) { if (!manifestPaths.has(p)) { - warn('W_ORPHAN', `Runtime file not in manifest: ${path.relative(FRONTEND, p)}`); - // Orphans SHIP to the browser, so they must count against the - // budget. Excluding them let ~31 MB of raw PNG land on main while - // the gate still reported 5.35/20 MB. + const isPackageFile = p.startsWith(PACKAGE_DIR + path.sep); + if (!isPackageFile) warn('W_ORPHAN', `Runtime file not in manifest: ${path.relative(FRONTEND, p)}`); + // Unregistered runtime files and production-package files SHIP to + // the browser, so both must count against the global budget. Package + // contents are validated by validate-packages.mjs rather than the + // image-only runtime manifest. try { const oStat = await fs.stat(p); totalBytes += oStat.size; - orphanBytes += oStat.size; + if (isPackageFile) packageBytes += oStat.size; + else orphanBytes += oStat.size; } catch { /* unreadable file already reported elsewhere */ } } } @@ -137,7 +144,14 @@ async function main() { fail('E_BUDGET', `Runtime assets ${totalMB.toFixed(2)} MB exceed the ${budgetMB} MB budget.`); } - report({ checked, totalMB, budgetMB, orphanMB: orphanBytes / 1048576 }); + report({ + checked, + packageFiles: onDisk.length - runtimeFileCount, + packageMB: packageBytes / 1048576, + totalMB, + budgetMB, + orphanMB: orphanBytes / 1048576, + }); } function report(summary = {}) { @@ -148,6 +162,7 @@ function report(summary = {}) { console.log('─'.repeat(70)); if (summary.checked !== undefined) { console.log(`Assets checked : ${summary.checked}`); + if (summary.packageFiles) console.log(`Package files : ${summary.packageFiles} (${summary.packageMB.toFixed(2)} MB)`); console.log(`Runtime total : ${summary.totalMB.toFixed(2)} MB / ${summary.budgetMB} MB budget`); if (summary.orphanMB > 0.01) { console.log(` ...of which unregistered (orphan): ${summary.orphanMB.toFixed(2)} MB`); diff --git a/frontend/scripts/assets/build-character-package.mjs b/frontend/scripts/assets/build-character-package.mjs new file mode 100644 index 0000000..d1b63c0 --- /dev/null +++ b/frontend/scripts/assets/build-character-package.mjs @@ -0,0 +1,108 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { NodeIO } from '@gltf-transform/core'; +import { dedup, prune, resample } from '@gltf-transform/functions'; + +const [baseModelPath, animationLibraryPath, outputPath] = process.argv.slice(2); +if (!baseModelPath || !animationLibraryPath || !outputPath) { + throw new Error('Usage: node build-character-package.mjs '); +} + +const REQUIRED_ANIMATIONS = [ + 'Idle_Loop', + 'Walk_Loop', + 'Jog_Fwd_Loop', + 'Sprint_Loop', + 'Crouch_Idle_Loop', + 'Crouch_Fwd_Loop', + 'Pistol_Aim_Neutral', + 'Pistol_Shoot', + 'Pistol_Reload', + 'Hit_Chest', + 'Hit_Head', + 'Death01', +]; + +const io = new NodeIO(); +const targetDocument = await io.read(baseModelPath); +const animationDocument = await io.read(animationLibraryPath); +const targetRoot = targetDocument.getRoot(); +const animationRoot = animationDocument.getRoot(); +const targetBuffer = targetRoot.listBuffers()[0] ?? targetDocument.createBuffer('runtime-buffer'); +const targetNodes = new Map(targetRoot.listNodes().map((node) => [node.getName(), node])); +const sourceJointNames = new Set(animationRoot.listSkins().flatMap((skin) => skin.listJoints().map((joint) => joint.getName()))); +const targetJointNames = new Set(targetRoot.listSkins().flatMap((skin) => skin.listJoints().map((joint) => joint.getName()))); +const missingTargetJoints = [...sourceJointNames].filter((name) => !targetJointNames.has(name)); +const missingSourceJoints = [...targetJointNames].filter((name) => !sourceJointNames.has(name)); +if (missingTargetJoints.length || missingSourceJoints.length) { + throw new Error(`Skeleton mismatch. Missing in target: ${missingTargetJoints.join(', ')}; missing in animation source: ${missingSourceJoints.join(', ')}`); +} + +function copyAccessor(sourceAccessor, suffix) { + const sourceArray = sourceAccessor.getArray(); + if (!sourceArray) throw new Error(`Animation accessor ${sourceAccessor.getName() || suffix} has no array.`); + const targetAccessor = targetDocument + .createAccessor(`${sourceAccessor.getName() || 'animation-accessor'}-${suffix}`) + .setArray(sourceArray.slice()) + .setType(sourceAccessor.getType()) + .setNormalized(sourceAccessor.getNormalized()) + .setBuffer(targetBuffer); + return targetAccessor; +} + +const sourceAnimations = new Map(animationRoot.listAnimations().map((animation) => [animation.getName(), animation])); +const missingAnimations = REQUIRED_ANIMATIONS.filter((name) => !sourceAnimations.has(name)); +if (missingAnimations.length) throw new Error(`Animation library is missing required clips: ${missingAnimations.join(', ')}`); + +for (const animationName of REQUIRED_ANIMATIONS) { + const sourceAnimation = sourceAnimations.get(animationName); + const targetAnimation = targetDocument.createAnimation(animationName); + const samplerMap = new Map(); + const accessorMap = new Map(); + + for (const [samplerIndex, sourceSampler] of sourceAnimation.listSamplers().entries()) { + const sourceInput = sourceSampler.getInput(); + const sourceOutput = sourceSampler.getOutput(); + if (!sourceInput || !sourceOutput) throw new Error(`${animationName} contains an incomplete sampler.`); + const input = accessorMap.get(sourceInput) ?? copyAccessor(sourceInput, `${animationName}-input-${samplerIndex}`); + const output = accessorMap.get(sourceOutput) ?? copyAccessor(sourceOutput, `${animationName}-output-${samplerIndex}`); + accessorMap.set(sourceInput, input); + accessorMap.set(sourceOutput, output); + const targetSampler = targetDocument + .createAnimationSampler(`${animationName}-sampler-${samplerIndex}`) + .setInput(input) + .setOutput(output) + .setInterpolation(sourceSampler.getInterpolation()); + targetAnimation.addSampler(targetSampler); + samplerMap.set(sourceSampler, targetSampler); + } + + for (const [channelIndex, sourceChannel] of sourceAnimation.listChannels().entries()) { + const sourceTarget = sourceChannel.getTargetNode(); + const sourceSampler = sourceChannel.getSampler(); + const targetNode = sourceTarget ? targetNodes.get(sourceTarget.getName()) : null; + const targetSampler = sourceSampler ? samplerMap.get(sourceSampler) : null; + if (!sourceTarget || !targetNode || !targetSampler) { + throw new Error(`${animationName} channel ${channelIndex} cannot be mapped to the base skeleton.`); + } + targetAnimation.addChannel( + targetDocument + .createAnimationChannel(`${animationName}-channel-${channelIndex}`) + .setSampler(targetSampler) + .setTargetNode(targetNode) + .setTargetPath(sourceChannel.getTargetPath()), + ); + } +} + +await targetDocument.transform(resample(), dedup(), prune()); +await fs.mkdir(path.dirname(outputPath), { recursive: true }); +await io.write(outputPath, targetDocument); + +console.log(JSON.stringify({ + outputPath, + animationCount: targetDocument.getRoot().listAnimations().length, + animationNames: targetDocument.getRoot().listAnimations().map((animation) => animation.getName()), + jointCount: targetJointNames.size, + nodeCount: targetDocument.getRoot().listNodes().length, +})); diff --git a/frontend/scripts/assets/inspect-skeleton.mjs b/frontend/scripts/assets/inspect-skeleton.mjs new file mode 100644 index 0000000..65adae5 --- /dev/null +++ b/frontend/scripts/assets/inspect-skeleton.mjs @@ -0,0 +1,18 @@ +import { NodeIO } from '@gltf-transform/core'; + +const input = process.argv[2]; +if (!input) throw new Error('Usage: node inspect-skeleton.mjs '); +const io = new NodeIO(); +const document = await io.read(input); +const root = document.getRoot(); +const nodes = root.listNodes().map((node) => node.getName()).filter(Boolean); +const skins = root.listSkins().map((skin) => ({ + name: skin.getName(), + joints: skin.listJoints().map((joint) => joint.getName()), +})); +const animations = root.listAnimations().map((animation) => ({ + name: animation.getName(), + targets: [...new Set(animation.listChannels().map((channel) => channel.getTargetNode()?.getName()).filter(Boolean))], + paths: [...new Set(animation.listChannels().map((channel) => channel.getTargetPath()))], +})); +console.log(JSON.stringify({ input, nodes, skins, animations }, null, 2)); diff --git a/frontend/scripts/assets/prepare-pbr-textures.py b/frontend/scripts/assets/prepare-pbr-textures.py new file mode 100644 index 0000000..c42721e --- /dev/null +++ b/frontend/scripts/assets/prepare-pbr-textures.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +"""Prepare compact runtime PBR maps from ambientCG 1K-JPG archives.""" + +from __future__ import annotations + +import hashlib +import json +import sys +import zipfile +from io import BytesIO +from pathlib import Path + +from PIL import Image + +MAP_SUFFIXES = { + "color": "_Color.jpg", + "normal": "_NormalGL.jpg", + "roughness": "_Roughness.jpg", +} + + +def digest(data: bytes) -> str: + return hashlib.sha256(data).hexdigest() + + +def prepare_archive(archive_path: Path, output_dir: Path) -> dict[str, object]: + asset_id = archive_path.name.split("_1K-JPG.zip", 1)[0] + output_stem = asset_id.lower() + written: list[dict[str, object]] = [] + + with zipfile.ZipFile(archive_path) as archive: + names = archive.namelist() + for map_name, suffix in MAP_SUFFIXES.items(): + matches = [name for name in names if name.endswith(suffix)] + if len(matches) != 1: + raise RuntimeError(f"{archive_path}: expected one {suffix} map, found {matches}") + source_name = matches[0] + source_bytes = archive.read(source_name) + with Image.open(BytesIO(source_bytes)) as image: + image = image.convert("RGB") + image.thumbnail((512, 512), Image.Resampling.LANCZOS) + output_path = output_dir / f"{output_stem}-{map_name}.webp" + output_dir.mkdir(parents=True, exist_ok=True) + image.save(output_path, "WEBP", quality=86, method=6) + output_bytes = output_path.read_bytes() + written.append( + { + "map": map_name, + "sourceFile": source_name, + "runtimeFile": output_path.name, + "width": image.width, + "height": image.height, + "bytes": len(output_bytes), + "sha256": digest(output_bytes), + } + ) + + return { + "assetId": asset_id, + "sourceArchive": archive_path.name, + "sourceSha256": digest(archive_path.read_bytes()), + "license": "CC0-1.0", + "sourceUrl": f"https://ambientcg.com/a/{asset_id}", + "maps": written, + } + + +def main() -> None: + if len(sys.argv) < 3: + raise SystemExit("Usage: prepare-pbr-textures.py [...]") + output_dir = Path(sys.argv[1]).resolve() + archives = [Path(value).resolve() for value in sys.argv[2:]] + manifest = { + "schemaVersion": 1, + "generator": "frontend/scripts/assets/prepare-pbr-textures.py", + "assets": [prepare_archive(archive, output_dir) for archive in archives], + } + (output_dir / "pbr-sources.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8") + print(json.dumps(manifest, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/frontend/scripts/assets/validate-packages.mjs b/frontend/scripts/assets/validate-packages.mjs index a875d70..763ede5 100644 --- a/frontend/scripts/assets/validate-packages.mjs +++ b/frontend/scripts/assets/validate-packages.mjs @@ -46,8 +46,12 @@ const targets = [ kind: path.basename(filePath).split('.')[0], runtime: false, })), - ...collectJsonFiles(path.join(publicRoot, 'assets/packages/characters')).map((filePath) => ({ filePath, kind: 'character', runtime: true })), - ...collectJsonFiles(path.join(publicRoot, 'assets/packages/blocks')).map((filePath) => ({ filePath, kind: 'block', runtime: true })), + ...collectJsonFiles(path.join(publicRoot, 'assets/packages/characters')) + .filter((filePath) => path.basename(filePath).startsWith('package.')) + .map((filePath) => ({ filePath, kind: 'character', runtime: true })), + ...collectJsonFiles(path.join(publicRoot, 'assets/packages/blocks')) + .filter((filePath) => path.basename(filePath).startsWith('package.')) + .map((filePath) => ({ filePath, kind: 'block', runtime: true })), ]; const failures = []; diff --git a/frontend/src/game/assets/__tests__/assetPackages.test.ts b/frontend/src/game/assets/__tests__/assetPackages.test.ts index 76c51f2..8463ca9 100644 --- a/frontend/src/game/assets/__tests__/assetPackages.test.ts +++ b/frontend/src/game/assets/__tests__/assetPackages.test.ts @@ -1,3 +1,5 @@ +import fs from 'node:fs'; +import path from 'node:path'; import { describe, expect, it } from 'vitest'; import { anchorsForZone, @@ -109,6 +111,23 @@ describe('production asset packages', () => { expect(isBlockPackageV1({ schemaVersion: 1, packageId: 'broken' })).toBe(false); }); + it('ships a validated CC0 rig with real gameplay clips and a web-budgeted GLB', () => { + const packagePath = path.resolve(process.cwd(), 'public/assets/packages/characters/universal-male/package.v1.json'); + const runtimePackage = JSON.parse(fs.readFileSync(packagePath, 'utf8')) as CharacterPackageV1; + const glbPath = path.resolve(process.cwd(), 'public', runtimePackage.runtime.babylonGlb.replace(/^\//, '')); + + expect(isCharacterPackageV1(runtimePackage)).toBe(true); + expect(runtimePackage.provenance.licenseId).toBe('CC0-1.0'); + expect(runtimePackage.provenance.engineRestrictions).toEqual([]); + expect(runtimePackage.skeleton.rootBone).toBe('root'); + expect(hitZoneForNode(runtimePackage, 'Head')).toBe('head'); + expect(hitZoneForNode(runtimePackage, 'upperarm_r')).toBe('arm'); + expect(runtimePackage.animations.fire).toBe('Pistol_Shoot'); + expect(runtimePackage.animations.reload).toBe('Pistol_Reload'); + expect(runtimePackage.animations.downed).toBe('Death01'); + expect(fs.statSync(glbPath).size).toBeLessThan(1_500_000); + }); + it('maps authored character nodes to renderer-neutral hit zones', () => { expect(hitZoneForNode(character, 'hit_head')).toBe('head'); expect(hitZoneForNode(character, 'hit_arm_r')).toBe('arm'); diff --git a/frontend/src/game/ops/OpsCharacterFactory.ts b/frontend/src/game/ops/OpsCharacterFactory.ts index 68b9c53..9a76772 100644 --- a/frontend/src/game/ops/OpsCharacterFactory.ts +++ b/frontend/src/game/ops/OpsCharacterFactory.ts @@ -15,13 +15,32 @@ export interface OpsImpactMetadata { hitZone?: CombatHitZone; } +export type OpsActorAnimationState = + | 'idle' + | 'walk' + | 'sprint' + | 'strafe' + | 'aim' + | 'aimWalk' + | 'fire' + | 'reload' + | 'crouch' + | 'hit' + | 'downed' + | 'coverEnter' + | 'coverIdle' + | 'coverExit'; + export interface OpsActorVisual { root: TransformNode; meshes: AbstractMesh[]; + hitMeshes?: AbstractMesh[]; marker: Mesh; target: Vector3; weapon: TransformNode; presentation: 'articulated-fallback' | 'production-glb'; + playAnimation(state: OpsActorAnimationState): void; + dispose(): void; } export type RegisterOpsMaterial = (material: StandardMaterial) => void; @@ -189,6 +208,8 @@ export function createArticulatedActorFallback( target: root.position.clone(), weapon, presentation: 'articulated-fallback', + playAnimation: () => undefined, + dispose: () => root.dispose(false, false), }; } diff --git a/frontend/src/game/ops/OpsPackagedAssetLoader.ts b/frontend/src/game/ops/OpsPackagedAssetLoader.ts index c6dc7e9..917a936 100644 --- a/frontend/src/game/ops/OpsPackagedAssetLoader.ts +++ b/frontend/src/game/ops/OpsPackagedAssetLoader.ts @@ -1,16 +1,24 @@ import '@babylonjs/loaders/glTF'; +import type { AnimationGroup } from '@babylonjs/core/Animations/animationGroup'; +import type { AssetContainer, InstantiatedEntries } from '@babylonjs/core/assetContainer'; +import type { Bone } from '@babylonjs/core/Bones/bone'; import { Color3 } from '@babylonjs/core/Maths/math.color'; import { Vector3 } from '@babylonjs/core/Maths/math.vector'; import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial'; import type { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh'; +import type { Mesh } from '@babylonjs/core/Meshes/mesh'; import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder'; import { TransformNode } from '@babylonjs/core/Meshes/transformNode'; import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader'; import type { Scene } from '@babylonjs/core/scene'; import type { BlockPackageV1, CharacterPackageV1 } from '../assets/assetPackages'; -import { hitZoneForNode } from '../assets/assetPackages'; -import type { Combatant } from '../combat/types'; -import type { OpsActorVisual, OpsImpactMetadata, RegisterOpsMaterial } from './OpsCharacterFactory'; +import type { CombatHitZone, Combatant } from '../combat/types'; +import type { + OpsActorAnimationState, + OpsActorVisual, + OpsImpactMetadata, + RegisterOpsMaterial, +} from './OpsCharacterFactory'; function splitAssetUrl(url: string): { rootUrl: string; fileName: string } { const separator = url.lastIndexOf('/'); @@ -21,42 +29,46 @@ function splitAssetUrl(url: string): { rootUrl: string; fileName: string } { }; } -function setActorMetadata(mesh: AbstractMesh, actor: Combatant, packageDefinition: CharacterPackageV1): void { - mesh.metadata = { - impactKind: 'actor', - entityId: actor.id, - hitZone: hitZoneForNode(packageDefinition, mesh.name) ?? 'torso', - } satisfies OpsImpactMetadata; - mesh.isPickable = true; - mesh.receiveShadows = true; +function uniqueMeshes(nodes: InstantiatedEntries['rootNodes']): AbstractMesh[] { + const meshes = new Set(); + nodes.forEach((node) => { + if ('getBoundingInfo' in node) meshes.add(node as AbstractMesh); + node.getChildMeshes(false).forEach((mesh) => meshes.add(mesh)); + }); + return [...meshes]; } -export async function loadPackagedCharacter( - scene: Scene, - packageDefinition: CharacterPackageV1, - actor: Combatant, - position: Vector3, - registerMaterial: RegisterOpsMaterial, -): Promise { - const root = new TransformNode(`ops-actor-${actor.id}`, scene); - root.position.copyFrom(position); - root.scaling.setAll(1 / packageDefinition.skeleton.metersPerUnit); +function findAnimation(groups: AnimationGroup[], expectedName: string): AnimationGroup | undefined { + return groups.find((group) => group.name === expectedName) + ?? groups.find((group) => group.name.startsWith(`${expectedName}-`)) + ?? groups.find((group) => group.name.includes(expectedName)); +} - const { rootUrl, fileName } = splitAssetUrl(packageDefinition.runtime.babylonGlb); - const imported = await SceneLoader.ImportMeshAsync(null, rootUrl, fileName, scene); - imported.meshes.forEach((mesh) => { - if (!mesh.parent) mesh.parent = root; - setActorMetadata(mesh, actor, packageDefinition); - }); +const HIT_PROXY_SPECS: Array<{ + packageKey: keyof CharacterPackageV1['hitZones']; + zone: CombatHitZone; + dimensions: { width: number; height: number; depth: number }; + offset: Vector3; +}> = [ + { packageKey: 'head', zone: 'head', dimensions: { width: 0.38, height: 0.44, depth: 0.38 }, offset: new Vector3(0, 0.1, 0) }, + { packageKey: 'torso', zone: 'torso', dimensions: { width: 0.7, height: 0.82, depth: 0.36 }, offset: new Vector3(0, -0.12, 0) }, + { packageKey: 'leftArm', zone: 'arm', dimensions: { width: 0.22, height: 0.62, depth: 0.22 }, offset: new Vector3(0, -0.23, 0) }, + { packageKey: 'rightArm', zone: 'arm', dimensions: { width: 0.22, height: 0.62, depth: 0.22 }, offset: new Vector3(0, -0.23, 0) }, + { packageKey: 'leftLeg', zone: 'leg', dimensions: { width: 0.28, height: 0.78, depth: 0.3 }, offset: new Vector3(0, -0.34, 0) }, + { packageKey: 'rightLeg', zone: 'leg', dimensions: { width: 0.28, height: 0.78, depth: 0.3 }, offset: new Vector3(0, -0.34, 0) }, +]; - const weapon = new TransformNode(`ops-weapon-root-${actor.id}`, scene); - weapon.parent = root; - const weaponSocket = packageDefinition.weaponSockets?.rightHand; - const socketNode = weaponSocket - ? imported.transformNodes.find((node) => node.name === weaponSocket) - : undefined; - if (socketNode) weapon.parent = socketNode; +function findBone(entries: InstantiatedEntries, name: string): Bone | undefined { + return entries.skeletons.flatMap((skeleton) => skeleton.bones).find((bone) => bone.name === name); +} +function createMarker( + scene: Scene, + actor: Combatant, + root: TransformNode, + localGroundY: number, + registerMaterial: RegisterOpsMaterial, +): Mesh { const markerMaterial = new StandardMaterial(`ops-marker-material-${actor.id}`, scene); markerMaterial.diffuseColor = Color3.Black(); markerMaterial.specularColor = Color3.Black(); @@ -67,21 +79,208 @@ export async function loadPackagedCharacter( const marker = MeshBuilder.CreateTorus(`ops-marker-${actor.id}`, { diameter: 1.2, thickness: 0.045, tessellation: 32 }, scene); marker.parent = root; marker.rotation.x = Math.PI / 2; - marker.position.y = -0.67; + marker.position.y = localGroundY + 0.025; marker.material = markerMaterial; marker.isPickable = false; + return marker; +} + +function createHitProxies( + scene: Scene, + packageDefinition: CharacterPackageV1, + actor: Combatant, + entries: InstantiatedEntries, + renderMeshes: AbstractMesh[], + registerMaterial: RegisterOpsMaterial, +): AbstractMesh[] { + const skinnedMesh = renderMeshes.find((mesh) => 'skeleton' in mesh && Boolean((mesh as Mesh).skeleton)) as Mesh | undefined; + if (!skinnedMesh) return []; - const idleGroup = imported.animationGroups.find((group) => group.name === packageDefinition.animations.idle); - idleGroup?.start(true); + const proxyMaterial = new StandardMaterial(`ops-hit-proxy-material-${actor.id}`, scene); + proxyMaterial.alpha = 0; + proxyMaterial.disableColorWrite = true; + proxyMaterial.disableDepthWrite = true; + registerMaterial(proxyMaterial); + + return HIT_PROXY_SPECS.flatMap((spec) => { + const bone = findBone(entries, packageDefinition.hitZones[spec.packageKey]); + if (!bone) return []; + const proxy = MeshBuilder.CreateBox(`ops-hit-${spec.zone}-${spec.packageKey}-${actor.id}`, spec.dimensions, scene); + proxy.material = proxyMaterial; + proxy.position.copyFrom(spec.offset); + proxy.attachToBone(bone, skinnedMesh); + proxy.metadata = { + impactKind: 'actor', + entityId: actor.id, + hitZone: spec.zone, + } satisfies OpsImpactMetadata; + proxy.isPickable = true; + return [proxy]; + }); +} + +function createWeapon( + scene: Scene, + packageDefinition: CharacterPackageV1, + actor: Combatant, + entries: InstantiatedEntries, + renderMeshes: AbstractMesh[], + root: TransformNode, + registerMaterial: RegisterOpsMaterial, +): TransformNode { + const metal = new StandardMaterial(`ops-package-weapon-${actor.id}`, scene); + metal.diffuseColor = new Color3(0.035, 0.04, 0.045); + metal.specularColor = new Color3(0.62, 0.64, 0.68); + registerMaterial(metal); + + const receiver = MeshBuilder.CreateBox(`ops-package-weapon-receiver-${actor.id}`, { + width: 0.13, + height: 0.17, + depth: 0.58, + }, scene); + receiver.material = metal; + receiver.isPickable = false; + const barrel = MeshBuilder.CreateBox(`ops-package-weapon-barrel-${actor.id}`, { + width: 0.052, + height: 0.052, + depth: 0.42, + }, scene); + barrel.parent = receiver; + barrel.position.z = 0.43; + barrel.material = metal; + barrel.isPickable = false; + + const socketName = packageDefinition.weaponSockets?.rightHand; + const socket = socketName ? findBone(entries, socketName) : undefined; + const skinnedMesh = renderMeshes.find((mesh) => 'skeleton' in mesh && Boolean((mesh as Mesh).skeleton)) as Mesh | undefined; + if (socket && skinnedMesh) { + receiver.attachToBone(socket, skinnedMesh); + receiver.position.set(0.02, 0.03, 0.2); + receiver.rotation.set(Math.PI / 2, 0, 0); + } else { + receiver.parent = root; + receiver.position.set(0.27, 1.05, 0.35); + } + return receiver; +} + +export interface OpsCharacterTemplate { + instantiate(actor: Combatant, position: Vector3): OpsActorVisual; + dispose(): void; +} + +export async function loadPackagedCharacterTemplate( + scene: Scene, + packageDefinition: CharacterPackageV1, + registerMaterial: RegisterOpsMaterial, +): Promise { + const { rootUrl, fileName } = splitAssetUrl(packageDefinition.runtime.babylonGlb); + const container: AssetContainer = await SceneLoader.LoadAssetContainerAsync(rootUrl, fileName, scene); + const requiredClips = new Set(Object.values(packageDefinition.animations)); + const availableClips = new Set(container.animationGroups.map((group) => group.name)); + const missingClips = [...requiredClips].filter((clip) => !availableClips.has(clip)); + if (missingClips.length > 0) { + container.dispose(); + throw new Error(`Character package ${packageDefinition.packageId} is missing animations: ${missingClips.join(', ')}`); + } return { - root, - meshes: imported.meshes, - marker, - target: root.position.clone(), - weapon, - presentation: 'production-glb', + instantiate(actor, position) { + const entries = container.instantiateModelsToScene( + (sourceName) => `${sourceName}-${actor.id}`, + false, + { doNotInstantiate: true }, + ); + const root = new TransformNode(`ops-actor-${actor.id}`, scene); + root.position.copyFrom(position); + root.scaling.setAll(1 / packageDefinition.skeleton.metersPerUnit); + const modelRoot = new TransformNode(`ops-model-${actor.id}`, scene); + modelRoot.parent = root; + entries.rootNodes.forEach((node) => { + if (!node.parent) node.parent = modelRoot; + }); + + const renderMeshes = uniqueMeshes(entries.rootNodes); + renderMeshes.forEach((mesh) => { + mesh.isPickable = false; + mesh.receiveShadows = true; + }); + root.computeWorldMatrix(true); + renderMeshes.forEach((mesh) => mesh.computeWorldMatrix(true)); + const minimumY = Math.min(...renderMeshes.map((mesh) => mesh.getBoundingInfo().boundingBox.minimumWorld.y)); + const localGroundY = 0.06 - root.position.y; + if (Number.isFinite(minimumY)) modelRoot.position.y += 0.06 - minimumY; + + const hitMeshes = createHitProxies(scene, packageDefinition, actor, entries, renderMeshes, registerMaterial); + const marker = createMarker(scene, actor, root, localGroundY, registerMaterial); + const weapon = createWeapon(scene, packageDefinition, actor, entries, renderMeshes, root, registerMaterial); + const groups = entries.animationGroups; + let activeGroup: AnimationGroup | undefined; + let activeState: OpsActorAnimationState | undefined; + let transient = false; + + const playAnimation = (state: OpsActorAnimationState): void => { + if (transient && !['fire', 'reload', 'hit', 'downed'].includes(state)) return; + if (state === activeState && (activeGroup?.isPlaying || state === 'downed')) return; + const clipName = packageDefinition.animations[state]; + const nextGroup = findAnimation(groups, clipName); + if (!nextGroup) return; + activeGroup?.stop(); + activeGroup = nextGroup; + activeState = state; + const loop = ['idle', 'walk', 'sprint', 'strafe', 'aim', 'aimWalk', 'crouch', 'coverIdle'].includes(state); + transient = ['fire', 'reload', 'hit'].includes(state); + nextGroup.start(loop); + if (transient) { + nextGroup.onAnimationGroupEndObservable.addOnce(() => { + if (activeGroup !== nextGroup) return; + transient = false; + activeState = undefined; + playAnimation('idle'); + }); + } + }; + playAnimation('idle'); + + return { + root, + meshes: renderMeshes, + hitMeshes, + marker, + target: root.position.clone(), + weapon, + presentation: 'production-glb', + playAnimation, + dispose() { + activeGroup?.stop(); + groups.forEach((group) => group.stop()); + hitMeshes.forEach((mesh) => mesh.dispose(false, false)); + entries.dispose(); + root.dispose(false, false); + }, + }; + }, + dispose() { + container.dispose(); + }, + }; +} + +export async function loadPackagedCharacter( + scene: Scene, + packageDefinition: CharacterPackageV1, + actor: Combatant, + position: Vector3, + registerMaterial: RegisterOpsMaterial, +): Promise { + const template = await loadPackagedCharacterTemplate(scene, packageDefinition, registerMaterial); + const visual = template.instantiate(actor, position); + const disposeVisual = visual.dispose; + visual.dispose = () => { + disposeVisual(); + template.dispose(); }; + return visual; } export interface OpsBlockVisual { diff --git a/frontend/src/game/ops/OpsPbrMaterials.ts b/frontend/src/game/ops/OpsPbrMaterials.ts new file mode 100644 index 0000000..f6e1470 --- /dev/null +++ b/frontend/src/game/ops/OpsPbrMaterials.ts @@ -0,0 +1,40 @@ +import { Color3 } from '@babylonjs/core/Maths/math.color'; +import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial'; +import { Texture } from '@babylonjs/core/Materials/Textures/texture'; +import type { Scene } from '@babylonjs/core/scene'; + +export type OpsPbrSurfaceId = 'asphalt033' | 'concrete034' | 'bricks097'; + +const PBR_ROOT = '/assets/packages/blocks/las-olas-1208/materials'; + +export function createOpsPbrMaterial( + scene: Scene, + surfaceId: OpsPbrSurfaceId, + name: string, + tiling: { u: number; v: number }, +): PBRMaterial { + const material = new PBRMaterial(name, scene); + const albedo = new Texture(`${PBR_ROOT}/${surfaceId}-color.webp`, scene, true, false); + const normal = new Texture(`${PBR_ROOT}/${surfaceId}-normal.webp`, scene, true, false); + const roughness = new Texture(`${PBR_ROOT}/${surfaceId}-roughness.webp`, scene, true, false); + [albedo, normal, roughness].forEach((texture) => { + texture.uScale = tiling.u; + texture.vScale = tiling.v; + }); + + material.albedoTexture = albedo; + material.bumpTexture = normal; + material.metallicTexture = roughness; + material.metallic = 0; + material.roughness = 0.88; + material.useRoughnessFromMetallicTextureGreen = true; + material.useMetallnessFromMetallicTextureBlue = false; + material.useAmbientOcclusionFromMetallicTextureRed = false; + material.invertNormalMapX = false; + material.invertNormalMapY = false; + material.environmentIntensity = surfaceId === 'asphalt033' ? 0.72 : 0.42; + material.albedoColor = surfaceId === 'asphalt033' + ? new Color3(0.2, 0.23, 0.27) + : Color3.White(); + return material; +} diff --git a/frontend/src/game/ops/OpsWorld.ts b/frontend/src/game/ops/OpsWorld.ts index 87357d8..3384e32 100644 --- a/frontend/src/game/ops/OpsWorld.ts +++ b/frontend/src/game/ops/OpsWorld.ts @@ -9,6 +9,7 @@ import '@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent'; import { ShadowGenerator } from '@babylonjs/core/Lights/Shadows/shadowGenerator'; import { Color3 } from '@babylonjs/core/Maths/math.color'; import { Matrix, Vector3 } from '@babylonjs/core/Maths/math.vector'; +import type { Material } from '@babylonjs/core/Materials/material'; import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial'; import { Texture } from '@babylonjs/core/Materials/Textures/texture'; import type { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh'; @@ -18,6 +19,7 @@ import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder'; import { TransformNode } from '@babylonjs/core/Meshes/transformNode'; import type { Observer } from '@babylonjs/core/Misc/observable'; import type { Scene } from '@babylonjs/core/scene'; +import { loadCharacterPackage } from '../assets/assetPackages'; import type { CombatEvent, CombatImpactCandidate, @@ -39,9 +41,12 @@ import { createWetPuddle, } from './OpsEnvironmentFactory'; import { OpsInput } from './OpsInput'; +import { loadPackagedCharacterTemplate, type OpsCharacterTemplate } from './OpsPackagedAssetLoader'; +import { createOpsPbrMaterial } from './OpsPbrMaterials'; import { gridToWorld, movementToGridStep, OPS_CELL_SIZE } from './opsCoordinates'; const FACADE_URL = '/assets/runtime/generated/environments/street/block_modern_ops_storefront_v001.webp'; +const PRODUCTION_CHARACTER_PACKAGE_URL = '/assets/packages/characters/universal-male/package.v1.json'; const MOVE_INTERVAL_MS = 155; const SIM_TICK_MS = 100; const OPS_FIRE_RANGE = 40; @@ -78,8 +83,9 @@ export class OpsWorld { private readonly input: OpsInput; private readonly actorVisuals = new Map(); private readonly effects: TimedEffect[] = []; - private readonly materials: StandardMaterial[] = []; + private readonly materials: Material[] = []; private readonly observers: Observer[] = []; + private characterTemplate?: OpsCharacterTemplate; private readonly shadowGenerator: ShadowGenerator; private readonly tacticalCamera: ArcRotateCamera; private readonly firstPersonCamera: UniversalCamera; @@ -101,7 +107,7 @@ export class OpsWorld { constructor( private readonly scene: Scene, - canvas: HTMLCanvasElement, + private readonly canvas: HTMLCanvasElement, private readonly controller: CombatSessionController, private readonly preparation: EncounterPreparation, private readonly options: OpsWorldOptions = {}, @@ -136,6 +142,32 @@ export class OpsWorld { })); } + async initializeProductionAssets( + packageUrl = PRODUCTION_CHARACTER_PACKAGE_URL, + ): Promise { + try { + const packageDefinition = await loadCharacterPackage(packageUrl); + const template = await loadPackagedCharacterTemplate( + this.scene, + packageDefinition, + (actorMaterial) => this.materials.push(actorMaterial), + ); + if (this.disposed) { + template.dispose(); + return; + } + this.characterTemplate?.dispose(); + this.characterTemplate = template; + this.canvas.dataset.characterPackage = packageDefinition.packageId; + this.actorVisuals.forEach((visual) => visual.dispose()); + this.actorVisuals.clear(); + this.syncSnapshot(this.snapshot); + } catch (error) { + delete this.canvas.dataset.characterPackage; + console.warn('Modern Ops production character package could not load; keeping articulated fallbacks.', error); + } + } + dispose(): void { if (this.disposed) return; this.disposed = true; @@ -143,6 +175,11 @@ export class OpsWorld { this.input.dispose(); this.observers.forEach((observer) => this.scene.onBeforeRenderObservable.remove(observer)); this.effects.forEach((effect) => effect.mesh.dispose()); + this.actorVisuals.forEach((visual) => visual.dispose()); + this.actorVisuals.clear(); + this.characterTemplate?.dispose(); + this.characterTemplate = undefined; + delete this.canvas.dataset.characterPackage; this.materials.forEach((item) => item.dispose()); if (document.pointerLockElement) void document.exitPointerLock?.(); } @@ -170,15 +207,18 @@ export class OpsWorld { this.scene.clearColor.set(0.012, 0.025, 0.045, 1); this.scene.ambientColor = new Color3(0.08, 0.11, 0.16); + const asphalt = createOpsPbrMaterial(this.scene, 'asphalt033', 'ops-road-pbr', { u: 10, v: 10 }); + const concrete = createOpsPbrMaterial(this.scene, 'concrete034', 'ops-concrete-pbr', { u: 5, v: 5 }); + const brick = createOpsPbrMaterial(this.scene, 'bricks097', 'ops-brick-pbr', { u: 4, v: 3 }); const palette = { - street: material(this.scene, 'ops-road', new Color3(0.035, 0.055, 0.075), new Color3(0.95, 0.95, 1)), - curb: material(this.scene, 'ops-curb', new Color3(0.19, 0.21, 0.23), new Color3(0.4, 0.4, 0.44)), - sidewalk: material(this.scene, 'ops-sidewalk', new Color3(0.13, 0.18, 0.2), new Color3(0.5, 0.54, 0.58)), - storefront: material(this.scene, 'ops-storefront-ground', new Color3(0.11, 0.09, 0.14)), - alley: material(this.scene, 'ops-alley', new Color3(0.035, 0.08, 0.085)), - parking: material(this.scene, 'ops-parking', new Color3(0.095, 0.09, 0.085), new Color3(0.38, 0.35, 0.34)), - rooftop: material(this.scene, 'ops-rooftop', new Color3(0.105, 0.08, 0.13)), - building: material(this.scene, 'ops-building', new Color3(0.055, 0.045, 0.075)), + street: asphalt, + curb: concrete, + sidewalk: concrete, + storefront: brick, + alley: asphalt, + parking: asphalt, + rooftop: concrete, + building: brick, }; this.materials.push(...Object.values(palette)); @@ -466,7 +506,7 @@ export class OpsWorld { const activeIds = new Set(snapshot.combatants.map((actor) => actor.id)); this.actorVisuals.forEach((visual, id) => { if (activeIds.has(id)) return; - visual.root.dispose(false, true); + visual.dispose(); this.actorVisuals.delete(id); }); @@ -479,21 +519,27 @@ export class OpsWorld { visual.target.copyFrom(actorPosition(actor)); const selected = actor.id === this.controller.getHudState().selectedId; visual.marker.setEnabled(selected && !actor.isDown); - visual.root.rotation.z = actor.isDown ? Math.PI / 2 : 0; + visual.root.rotation.z = visual.presentation === 'articulated-fallback' && actor.isDown ? Math.PI / 2 : 0; + if (actor.isDown) visual.playAnimation('downed'); visual.meshes.forEach((mesh) => { mesh.visibility = actor.isDown ? 0.42 : 1; mesh.isPickable = !actor.isDown; }); + visual.hitMeshes?.forEach((mesh) => { + mesh.isPickable = !actor.isDown; + }); }); } private createActorVisual(actor: Combatant): OpsActorVisual { - const visual = createArticulatedActorFallback( - this.scene, - actor, - actorPosition(actor), - (actorMaterial) => this.materials.push(actorMaterial), - ); + const visual = this.characterTemplate + ? this.characterTemplate.instantiate(actor, actorPosition(actor)) + : createArticulatedActorFallback( + this.scene, + actor, + actorPosition(actor), + (actorMaterial) => this.materials.push(actorMaterial), + ); visual.meshes.forEach((mesh) => this.shadowGenerator.addShadowCaster(mesh)); return visual; } @@ -509,6 +555,7 @@ export class OpsWorld { private renderEvent(event: CombatEvent): void { if (event.type === 'weapon-fired' && event.actorId) { + this.actorVisuals.get(event.actorId)?.playAnimation('fire'); if (event.actorId === this.controller.getControlledCrewId()) this.weaponKick = 0.13; const source = this.actorVisuals.get(event.actorId)?.root.position; const impactPoint = event.impact @@ -527,6 +574,10 @@ export class OpsWorld { } } + if (event.type === 'reload-start' && event.actorId) this.actorVisuals.get(event.actorId)?.playAnimation('reload'); + if (event.type === 'impact-actor' && event.targetId) this.actorVisuals.get(event.targetId)?.playAnimation('hit'); + if (event.type === 'actor-downed' && event.targetId) this.actorVisuals.get(event.targetId)?.playAnimation('downed'); + const visibleImpactTypes = new Set([ 'impact-actor', 'impact-cover', @@ -611,9 +662,10 @@ export class OpsWorld { this.actorVisuals.forEach((visual, actorId) => { const movement = visual.target.subtract(visual.root.position); const actor = this.snapshot.combatants.find((candidate) => candidate.id === actorId); - if (!actor?.isDown && movement.lengthSquared() > 0.0025) { - visual.root.rotation.y = Math.atan2(movement.x, movement.z); - } + const moving = !actor?.isDown && movement.lengthSquared() > 0.0025; + if (moving) visual.root.rotation.y = Math.atan2(movement.x, movement.z); + if (actor?.isDown) visual.playAnimation('downed'); + else visual.playAnimation(moving ? 'walk' : 'idle'); visual.root.position.copyFrom(Vector3.Lerp(visual.root.position, visual.target, Math.min(1, boundedDelta * 11))); }); this.updateCamera(); @@ -731,6 +783,9 @@ export class OpsWorld { mesh.visibility = selected.isDown ? 0.42 : 1; mesh.isPickable = !selected.isDown; }); + actor.hitMeshes?.forEach((mesh) => { + mesh.isPickable = !selected.isDown; + }); return; } @@ -741,6 +796,9 @@ export class OpsWorld { mesh.visibility = 0; mesh.isPickable = false; }); + actor.hitMeshes?.forEach((mesh) => { + mesh.isPickable = false; + }); return; } @@ -754,6 +812,9 @@ export class OpsWorld { mesh.visibility = selected.isDown ? 0.42 : 1; mesh.isPickable = !selected.isDown; }); + actor.hitMeshes?.forEach((mesh) => { + mesh.isPickable = !selected.isDown; + }); } private updateEffects(delta: number): void { diff --git a/frontend/src/game/ops/createModernOpsScene.ts b/frontend/src/game/ops/createModernOpsScene.ts index f1395f1..91bc806 100644 --- a/frontend/src/game/ops/createModernOpsScene.ts +++ b/frontend/src/game/ops/createModernOpsScene.ts @@ -34,6 +34,7 @@ export async function createModernOpsScene( glow.intensity = 0.52; const world = new OpsWorld(scene, canvas, controller, preparation, options); + await world.initializeProductionAssets(); await scene.whenReadyAsync(); let disposed = false; diff --git a/scripts/verify-showdown.mjs b/scripts/verify-showdown.mjs index 152460d..5f751d0 100644 --- a/scripts/verify-showdown.mjs +++ b/scripts/verify-showdown.mjs @@ -1,6 +1,9 @@ import { mkdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; -const outputDir = '/home/ubuntu/work/slide-live/verification'; +const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const outputDir = path.join(repositoryRoot, 'verification'); await mkdir(outputDir, { recursive: true }); const targets = await fetch('http://127.0.0.1:9222/json/list').then((response) => response.json()); const target = targets.find((item) => item.type === 'page' && item.url === 'about:blank') @@ -95,7 +98,7 @@ async function opsState() { status: document.querySelector('.ops-status')?.textContent?.trim() ?? null, result: document.querySelector('.ops-result')?.textContent?.replace(/\\s+/g, ' ').trim() ?? null, canvases: document.querySelectorAll('canvas').length, - opsCanvas: (() => { const canvas = document.querySelector('.modern-ops-canvas'); return canvas ? { width: canvas.width, height: canvas.height, clientWidth: canvas.clientWidth, clientHeight: canvas.clientHeight, webgl2: Boolean(canvas.getContext('webgl2')), webgl: Boolean(canvas.getContext('webgl')) } : null; })() + opsCanvas: (() => { const canvas = document.querySelector('.modern-ops-canvas'); return canvas ? { width: canvas.width, height: canvas.height, clientWidth: canvas.clientWidth, clientHeight: canvas.clientHeight, webgl2: Boolean(canvas.getContext('webgl2')), webgl: Boolean(canvas.getContext('webgl')), characterPackage: canvas.dataset.characterPackage ?? null } : null; })() })`); return JSON.parse(raw ?? '{}'); } @@ -183,6 +186,7 @@ console.log(JSON.stringify(report, null, 2)); socket.close(); if (!thirdPersonBefore.modernOps || thirdPersonBefore.error) process.exitCode = 1; +if (thirdPersonBefore.opsCanvas?.characterPackage !== 'character.universal-male.pipeline-v1') process.exitCode = 1; if (thirdPersonBefore.camera !== 'TPS' || firstPerson.camera !== 'FPS' || tactical.camera !== 'TAC') process.exitCode = 1; if (!switchedMember || thirdPersonBefore.selected === thirdPersonAfterSwitch.selected) process.exitCode = 1; if (!firstPerson.status || firstPerson.status === thirdPersonAfterSwitch.status) process.exitCode = 1;