diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..af289c005 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +build/ +node_modules/ +src/build/ +static/ \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..949de408b --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "printWidth": 120, + "tabWidth": 4, + "trailingComma": "es5" +} \ No newline at end of file diff --git a/azure-pipelines.compiled-demos.yml b/azure-pipelines.compiled-demos.yml new file mode 100644 index 000000000..c4d54f374 --- /dev/null +++ b/azure-pipelines.compiled-demos.yml @@ -0,0 +1,60 @@ +trigger: + branches: + include: + - master + paths: + include: + - azure-pipelines.compiled-demos.yml + - .prettierignore + - .prettierrc.json + - docs/compiled-demos.md + - eslint.config.mjs + - package.json + - package-lock.json + - scripts/demos/** + - src/compiledDemos/** + - static/Demos/** + - static/Scenes/** + - tsconfig.demos.json + - vite.demos.config.mjs + +pr: + branches: + include: + - master + paths: + include: + - azure-pipelines.compiled-demos.yml + - .prettierignore + - .prettierrc.json + - docs/compiled-demos.md + - eslint.config.mjs + - package.json + - package-lock.json + - scripts/demos/** + - src/compiledDemos/** + - static/Demos/** + - static/Scenes/** + - tsconfig.demos.json + - vite.demos.config.mjs + +pool: + vmImage: ubuntu-latest + +steps: + - task: NodeTool@0 + displayName: Use Node.js 20 + inputs: + versionSpec: 20.x + + - script: npm ci + displayName: Install dependencies + + - script: npx playwright install --with-deps chromium + displayName: Install Playwright Chromium + + - script: npm run build + displayName: Build site and compiled demos + + - script: npm run demos:ci + displayName: Lint, typecheck, and render-check compiled demos diff --git a/docs/compiled-demo-migration.md b/docs/compiled-demo-migration.md new file mode 100644 index 000000000..d63a9d61f --- /dev/null +++ b/docs/compiled-demo-migration.md @@ -0,0 +1,61 @@ +# Compiled Demo Migration Inventory + +This tracks the move from legacy static demos under `static/Demos/` to compiled demos under `src/compiledDemos/`. Each migration should keep the public URL stable at `/Demos//`, expose source with `/Demos//source/`, and pass the compiled demo CI checks. + +## Status Key + +- `done`: Ported to `src/compiledDemos`, registered in `manifest.json`, and covered by render checks. +- `covered`: Scenario is already exercised by another compiled demo and should not consume a current migration wave slot. +- `unusable`: The legacy/online demo no longer renders correctly and should not be ported until the source demo is repaired or replaced. +- `wave-1`: Simple single-canvas demo selected for the current migration wave. +- `candidate`: Not migrated yet, likely suitable for a later wave after inspection. +- `special`: Needs extra handling such as workers, vendored bundles, service workers, generated app bundles, WebGPU, physics, GUI, or complex external assets. + +## Current Status + +| Demo | Status | Notes | +| --- | --- | --- | +| AssetsManager | done | AssetsManager mesh, text, and binary tasks using local legacy demo assets. | +| Boom | done | First compiled demo; includes click interaction render check. | +| Lines | done | Thin animated line rendering; custom low colored-sample threshold. | +| Heightmap | done | Texture and heightmap asset loading. | +| Offscreen | done | Custom worker bootstrap; render check validates both canvases. | +| Fog | done | Animated simple geometry and exponential fog. | +| Bump | done | Simple texture material using an existing shared normal map asset. | +| FlightHelmet | covered | Flight Helmet asset loading is already exercised by the compiled Offscreen demo; standalone legacy page is left out of this wave. | +| GLTF | done | glTF binary asset loading from the deployed legacy `/assets/` path. | +| GLTF1CesiumMan | unusable | Legacy and online demo do not render; excluded from the compiled registry until the source demo is repaired or replaced. | +| GLTFMeshPrimitiveAttributeTest | done | Multiple remote glTF assets plus generated normal attribute coverage. | +| GLTFNormals | done | Multiple remote glTF assets covering normals/tangents variants. | +| Lights | done | Multiple dynamic lights and shared skybox assets. | +| Particles | done | CPU particle systems plus mirror render target texture. | +| Fresnel | done | Fresnel material parameters, shared skybox assets, and lens flares. | +| Shadows | done | Directional lights, shadow generators, and legacy grass texture. | +| PointLightShadowMap | done | Point light shadow generator with torus knot scene. | +| Refraction | done | Reflection probe refraction with built-in bump/fresnel/IOR controls. | +| Ribbons | done | Dynamic ribbon geometry with volumetric light scattering post-process coverage. | +| VolumetricLightScattering | done | Local skull scene asset with volumetric light scattering billboard and texture coverage. | +| Yeti | done | Remote animated glTF asset with loader animation options, default environment, and textured snow particles. | + +## Next Waves + +| Wave | Demos | Main Risk To Prove | +| --- | --- | --- | +| Asset and loader follow-up | Mansion, Sponza, TheCar | Larger model load times, local scene payloads, animation/UI dependencies, service workers, shadows, and optimizer behavior. TheCar currently needs investigation because its scene readiness can stall render validation. | +| Render/effects follow-up | Polygon | Polygon needs an explicit `earcut` dependency decision before porting. | +| Materials and render pipeline demos | CellShading, FireMaterial, Fur, GlowLayer, PBR, PBRGlossy, PBRGlossyBloom, PBRRough, WaterMaterial, DOF, DefaultRenderingPipeline, MotionBlur, PPBloom, PPConvolution, PPRef, SSAO, SSAO2, StandardRenderingPipeline | Extra Babylon packages, shader/material side effects, post-process scene components. | +| Interaction and tooling demos | ActionBuilder, Actions, Charting, CustomShader, Decals, DragNDrop, Facets, Highlights, Lens, LookAt, Octree, Procedural, Simplification, VertexData, Views | Picking, pointer events, custom shaders, scene tools, and user interaction checks. | +| Animation, skeleton, and morph demos | Bones, Dancers, Dancing CSG, HillValley, HillValleyVR, InstancedBones, Instances, Instances2, LOD, MorphTargets, V8 | Skeletons, animation loops, instancing, LOD behavior, and render-check stability. | +| Physics and advanced systems | AdvancedShadows, CSG, Cloth, CustomRenderTarget, DisplacementMap, ExtrudePolygon, Multimaterial, Particles2, Physics, Planet, Ruins, SelfShadowing, SoftShadows, SPS, SPSCollisions, Starfield, Tunnel, Viper | Physics engines, generated geometry, custom render targets, particles, and advanced scene components. | +| Special app-style demos | Amp360Video, AnimatedGif, AudioAnalyser, AudioAnalyzer, ChibiRex, Distraction, Espilit, FatObjects, Flat2009, GlowingEspilit, Heart, Ink, MansionVR, ProductPage, RefProbe, Retail, SpaceDeK, Spaceship, SponzaDynamicShadows, Train, UTD, VideoProcessing, WCafe, WebGPU | Vendored bundles, multi-page apps, workers/service workers, audio/video, VR, WebGPU, or nonstandard build/runtime flows. | + +## Per-Demo Checklist + +1. Inspect the legacy `index.html`, `demo.js`, scene file, and local assets. +2. Create `src/compiledDemos//index.html`, `main.ts`, and `scene.ts` unless the demo needs a custom bootstrap. +3. Prefer `shared/demoRunner.ts` for single-canvas demos. +4. Replace `BABYLON.*` globals with named ESM imports and add side-effect imports for prototype-augmented APIs. +5. Keep asset URLs rooted at stable public paths such as `/Scenes/...` when possible. +6. Register the demo in `src/compiledDemos/manifest.json` with source files and render-check thresholds. +7. Run `npm run demos:format:write`, `npm run build`, and `npm run demos:ci`. +8. Commit one demo or small coherent batch at a time. \ No newline at end of file diff --git a/docs/compiled-demos.md b/docs/compiled-demos.md new file mode 100644 index 000000000..41d936cec --- /dev/null +++ b/docs/compiled-demos.md @@ -0,0 +1,171 @@ +# Compiled Demos Architecture + +The legacy demos under `static/Demos/` are copied directly into `build/` and load Babylon from the UMD CDN. Compiled demos live under `src/compiledDemos/`, import `@babylonjs/core` and sibling packages as ES modules, and are bundled with Vite. + +The migration tracker lives in `docs/compiled-demo-migration.md`. + +## Goals + +- Keep existing demo URLs stable, for example `/Demos/Boom/`. +- Migrate one demo at a time without disturbing demos that still live in `static/Demos/`. +- Make new demos easy to add with a small source folder and one manifest entry. +- Check that compiled demos typecheck, bundle, load in a browser, create a scene, and render a nonblank canvas. + +## Build Flow + +1. `npm run site:build` runs the existing Eleventy build and copies `static/` to `build/`. +2. `npm run demos:build` runs Vite with `vite.demos.config.mjs` and generates source pages. +3. `npm run build` runs both steps in order, producing the full deployable site output. +4. Vite writes compiled demo pages into `build/Demos//`, overlaying only the migrated demos listed in `src/compiledDemos/manifest.json`. +5. Unmigrated demos continue to come from `static/Demos/`. + +This keeps the site and demo build steps available separately while making the default `build` script produce the final combined output. + +For local preview, run `npm run demos:serve`. This builds the site, overlays the compiled demos, and serves the final `build/` output with Vite preview. + +## Source Layout + +```text +src/compiledDemos/ + manifest.json + shared/ + demoRunner.ts + AssetsManager/ + index.html + main.ts + scene.ts + Boom/ + index.html + main.ts + scene.ts + Bump/ + index.html + main.ts + scene.ts + Fog/ + index.html + main.ts + scene.ts + Fresnel/ + index.html + main.ts + scene.ts + GLTF/ + index.html + main.ts + scene.ts + GLTFMeshPrimitiveAttributeTest/ + index.html + main.ts + scene.ts + GLTFNormals/ + index.html + main.ts + scene.ts + Lines/ + index.html + main.ts + scene.ts + Lights/ + index.html + main.ts + scene.ts + Ribbons/ + index.html + main.ts + scene.ts + VolumetricLightScattering/ + index.html + main.ts + scene.ts + Yeti/ + index.html + main.ts + scene.ts + Heightmap/ + index.html + main.ts + scene.ts + Offscreen/ + index.html + main.ts + scene.ts + worker.ts + PointLightShadowMap/ + index.html + main.ts + scene.ts + Particles/ + index.html + main.ts + scene.ts + Refraction/ + index.html + main.ts + scene.ts + Shadows/ + index.html + main.ts + scene.ts +``` + +Each demo folder owns its HTML shell and TypeScript entry. Shared browser bootstrapping lives in `shared/demoRunner.ts`, which creates the engine, starts the render loop, wires common controls, and exposes `window.__babylonDemoReady` for CI. + +Each demo page should include a small source link at the bottom of the viewport: + +```html +Source +``` + +`npm run demos:build` generates `/Demos//source/` from the files listed in `manifest.json`, so the site can show the exact TypeScript source for each compiled demo. + +## Adding A Demo + +1. Create `src/compiledDemos//index.html`, `main.ts`, and `scene.ts`. +2. Export a scene factory from `scene.ts`: + + ```ts + export function createScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + // create and return a Babylon scene + } + ``` + +3. Call the shared runner from `main.ts`: + + ```ts + import { runDemo } from "../shared/demoRunner"; + import { createScene } from "./scene"; + + runDemo({ createScene }); + ``` + +4. Add the demo to `src/compiledDemos/manifest.json`. +5. Add `sourceFiles` for the files that should appear on the source page. +6. Run `npm run demos:format:write` if needed, then `npm run build && npm run demos:ci`. + +## Render Checks + +`npm run demos:check` serves the `build/` directory locally, opens each compiled demo with Playwright Chromium, waits for `window.__babylonDemoReady`, screenshots the canvas, samples pixels with Sharp, and fails if the canvas is blank or browser errors were reported. + +The initial check is intentionally a health check. It proves the demo compiles and renders. Individual demos can add `renderCheck.interaction` entries for important first-screen behavior; Boom uses this to click the canvas and verify the rendered output changes after the sign explodes. Screenshot baselines can be added later once the migration has enough coverage to justify the extra maintenance. + +Demos with more than one canvas can set `renderCheck.minimumCanvasCount` and `renderCheck.canvasSelector`. The Offscreen demo uses this to verify both the main-thread canvas and worker OffscreenCanvas render nonblank frames. + +## Linting And Formatting + +Compiled demo source is linted with ESLint and formatted with Prettier. The checks are intentionally scoped to the new compiled demo pipeline, not the legacy `static/` demo tree. + +- `npm run demos:lint` checks TypeScript demo source and demo build scripts. +- `npm run demos:format` verifies formatting for compiled demo source, config, and docs. +- `npm run demos:format:write` applies the configured formatting. + +## CI + +`azure-pipelines.compiled-demos.yml` is intentionally separate from the existing build CI. It runs `npm run build` first, which produces the site with compiled demos, and then runs `npm run demos:ci` to lint, format-check, typecheck, and render-check the compiled demos. If the main build pipeline can publish a build artifact later, this pipeline can be changed to consume that artifact instead of rebuilding the site. + +## Migration Notes + +- Custom scene-factory demos usually map cleanly from `BABYLON.*` globals to named ES module imports from `@babylonjs/core`. +- Demos that currently load `.babylon`, `.glb`, GUI, materials, loaders, or inspector packages should import the matching side-effect modules in their compiled entry. +- Keep asset URLs rooted at existing public paths such as `/Scenes/...` when assets are already served from `static/`. +- Once a compiled demo is stable, the old `static/Demos//` sources can be removed in a separate cleanup PR. diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..86204decb --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,38 @@ +import js from "@eslint/js"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +export default [ + { + ignores: ["build/**", "node_modules/**", "src/build/**", "static/**"], + }, + js.configs.recommended, + ...tseslint.configs.recommended, + { + files: ["scripts/demos/**/*.mjs", "vite.demos.config.mjs", "eslint.config.mjs"], + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { ...globals.node, ...globals.browser }, + }, + }, + { + files: ["src/compiledDemos/**/*.ts"], + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: globals.browser, + }, + rules: { + "no-undef": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + }, + }, +]; diff --git a/package-lock.json b/package-lock.json index a3cb1984d..dbf97ac22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,21 @@ "dependencies": { "@11ty/eleventy": "^3.1.5", "sharp": "^0.33.5" + }, + "devDependencies": { + "@babylonjs/core": "^9.5.2", + "@babylonjs/gui": "^9.5.2", + "@babylonjs/inspector": "^9.5.2", + "@babylonjs/loaders": "^9.5.2", + "@babylonjs/materials": "^9.5.2", + "@eslint/js": "^10.0.1", + "eslint": "^10.3.0", + "globals": "^17.6.0", + "playwright": "^1.59.1", + "prettier": "^3.8.3", + "typescript": "^6.0.3", + "typescript-eslint": "^8.59.2", + "vite": "^8.0.10" } }, "node_modules/@11ty/dependency-tree": { @@ -189,406 +204,3226 @@ "node": ">=18" } }, - "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "peer": true, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" - ], + "node_modules/@babylonjs/addons": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@babylonjs/addons/-/addons-9.5.2.tgz", + "integrity": "sha512-vIk4EZqSfSiJHTDz1KXF/oqzFNmAYhbfALgQ4P8WBiwojvO66L54A5VISNuP6JSOn5cTqtRli/VLTXxCn5hK5Q==", + "dev": true, "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" + "peer": true, + "peerDependencies": { + "@babylonjs/core": "^9.0.0" } }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", - "cpu": [ - "x64" - ], + "node_modules/@babylonjs/core": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-9.5.2.tgz", + "integrity": "sha512-rh/ahhlEc8QQqmXx/ZZjuz36zoRbYvd0pUw3O2NFGtnamKCI4P/RuitSypn9KivvzfqMasNDwUJQrx5te3LXWg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@babylonjs/gui": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-9.5.2.tgz", + "integrity": "sha512-LP0eb+VZSaK0PUOtyoQkX5B7OprQU/UodwSLkoNCuSFcuUQvPVW6+K7NgDQWF/6RgINujFFCI2nBYUrLpLJ+DA==", + "dev": true, "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" + "peerDependencies": { + "@babylonjs/core": "^9.0.0" } }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babylonjs/gui-editor": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@babylonjs/gui-editor/-/gui-editor-9.5.2.tgz", + "integrity": "sha512-D78CO6aDEjbzTYyu14gcGTP4CBpDDMu0DJ9yen1lPCsjOo9o5M3r6ilUbZmFGqzH4LitT0ZbY6LQD/BHxrZeGQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@babylonjs/core": "^9.0.0", + "@babylonjs/gui": "^9.0.0", + "@types/react": ">=16.7.3", + "@types/react-dom": ">=16.0.9" } }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babylonjs/inspector": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-9.5.2.tgz", + "integrity": "sha512-dfLoetibow78e6dFA3LfsnmXNQXWa3XPwz1UEZvBm0jnruDHIPhgF8Ko8U0eau2MZ01jpGHwCdyAD6ztNuWVcQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "babylon-inspector": "bin/inspector-cli.mjs" + }, + "peerDependencies": { + "@babylonjs/addons": "^9.0.0", + "@babylonjs/core": "^9.0.0", + "@babylonjs/gui": "^9.0.0", + "@babylonjs/gui-editor": "^9.0.0", + "@babylonjs/loaders": "^9.0.0", + "@babylonjs/materials": "^9.0.0", + "@babylonjs/serializers": "^9.0.0", + "@fluentui-contrib/react-resize-handle": "^0.8.4", + "@fluentui-contrib/react-virtualizer": "^1.0.0", + "@fluentui/react-components": "^9.70.0", + "@fluentui/react-icons": "^2.0.310", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0", + "usehooks-ts": "^3.1.1" + } + }, + "node_modules/@babylonjs/loaders": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-9.5.2.tgz", + "integrity": "sha512-JAewBFzYfTUnSPyTboIz+NjQq4r+ki1ASdFrcj8a10N3+8Vn1xhAzUOr8HjVjyrWDYk7iIVGcbr2qtAu+nQ6/w==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "@babylonjs/core": "^9.0.0", + "babylonjs-gltf2interface": "^9.0.0" } }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babylonjs/materials": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-9.5.2.tgz", + "integrity": "sha512-ufWYFfNlbrLjZF7e9pmSWgKfqT8Gp5WwQDBweGE9bAjrU0oY+z95aWL/fV2eZeGG9rIYxFf07LcCWsrAF+R/1Q==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "@babylonjs/core": "^9.0.0" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babylonjs/serializers": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-9.5.2.tgz", + "integrity": "sha512-jU6JMPVSgTC0Q/GaukhtoBmij78yDNqRFC5DVxVlxYLO4MNwvC29IPMxu2KbMpUE1vyxlNxUce5e9dWziwWdCA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@babylonjs/core": "^9.0.0", + "babylonjs-gltf2interface": "^9.0.0" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "license": "MIT", "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/libvips" + "url": "https://opencollective.com/eslint" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" }, - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/devtools": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.3.tgz", + "integrity": "sha512-ZTcxTvgo9CRlP7vJV62yCxdqmahHTGpSTi5QaTDgGoyQq0OyjaVZhUhXv/qdkQFOI3Sxlfmz0XGG4HaZMsDf8Q==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@fluentui-contrib/react-resize-handle": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@fluentui-contrib/react-resize-handle/-/react-resize-handle-0.8.4.tgz", + "integrity": "sha512-g3cJ3q+nn32BB5b5mEtuSh6sGNYOGcKvRxQljvfg+UAhStceCPZYRM8gF+HswPPhQ0LUR6h780WMe072ndR6Lw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-utilities": "^9.16.0", + "@swc/helpers": "~0.5.11" + }, + "peerDependencies": { + "@fluentui/react-components": ">=9.70.0 <10.0.0", + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.8.0 <20.0.0", + "react": ">=16.8.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui-contrib/react-virtualizer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@fluentui-contrib/react-virtualizer/-/react-virtualizer-1.0.0.tgz", + "integrity": "sha512-z1KE+OyCTICkOeyCmFI0nlNRTPAhCv2ZhCIDjebnlkNQMIcMtTrI/ogy4Fu8UgbFP+WReE50JeduLtM+Sst+1A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.29", + "@fluentui/react-utilities": "^9.16.0", + "@griffel/react": "^1.5.14", + "@swc/helpers": "~0.5.11" + }, + "peerDependencies": { + "@fluentui/react-shared-contexts": ">=9.7.2 <10.0.0", + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.8.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/keyboard-keys": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-keys/-/keyboard-keys-9.0.8.tgz", + "integrity": "sha512-iUSJUUHAyTosnXK8O2Ilbfxma+ZyZPMua5vB028Ys96z80v+LFwntoehlFsdH3rMuPsA8GaC1RE7LMezwPBPdw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/priority-overflow": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@fluentui/priority-overflow/-/priority-overflow-9.3.0.tgz", + "integrity": "sha512-yaBC0R4e+4ZlCWDulB5S+xBrlnLwfzdg68GaarCqQO8OHjLg7Ah05xTj7PsAYcoHeEg/9vYeBwGXBpRO8+Tjqw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-accordion": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.11.0.tgz", + "integrity": "sha512-mEy73hbJM53tMj3MWqm3ajbBxj48uubnJjumVKI8Z/eXHS8L3GzUy5rf/gUH26xSR2Tl+edpFhYB8PFbJDIKKw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-alert": { + "version": "9.0.0-beta.139", + "resolved": "https://registry.npmjs.org/@fluentui/react-alert/-/react-alert-9.0.0-beta.139.tgz", + "integrity": "sha512-R9r4dwwpWpgFmB8wVeWqipjUh/e6lyacnerX39HtVdgcG/PE+kpdHjKGiy8MAD+BGYCzrUxKNhXTQDlpXasJ1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-avatar": "^9.11.1", + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-icons": "^2.0.239", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-aria": { + "version": "9.17.11", + "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.17.11.tgz", + "integrity": "sha512-K9nz+Wn5JliCpG6bIYYPXvKmpOql+w9uyzmYNYkYQ6QHgoCpph7XUFx1HCtsJm2PPNi8WO8g0ZV9jojdGKl1Tg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-utilities": "^9.26.3", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-avatar": { + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.11.1.tgz", + "integrity": "sha512-y1T67rVQQ/D4FAod8F4crXo9funaptscRIiW81LAsbN82fFVexMPQ9GmXooQQvn6ILvjJtf9IyvSJ195qDsyag==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-badge": "^9.5.2", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-popover": "^9.14.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-tooltip": "^9.10.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-badge": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.5.2.tgz", + "integrity": "sha512-+UPAK9dCD6Gx+LWr6vqKMIbYOPf7oXX+GXRtCJ5fekCTHD0VgIWuIMuEtxVrHpJQdb2VNaZadY8/dMomk2JaXw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-breadcrumb": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.4.1.tgz", + "integrity": "sha512-XgUB1yv04GdcL/6kUo6kh+BaN4df1A/Ds/fL1QxNrm5E26Vmvvlc0LN0WV/qb5qhKx0NwhtIXgOZHjfzyt7iCA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-link": "^9.8.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-button": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.9.1.tgz", + "integrity": "sha512-WNzpseiVbqEKKevTkAnyHNoK/8ktYPE6rvf31gGvSDnBBclqfrn4PSYG2ppi+Z7abmClnaNFxpp1OHuOoVQ8Bg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-card": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.6.1.tgz", + "integrity": "sha512-KBijjAxi0mBDSgnA1OCglqAVWc+Q0L7A2wCokszX/53oqfJPSvWxWFma7esz9b5MF/kdRrAR0vmy7MiosepNLQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-text": "^9.6.16", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-carousel": { + "version": "9.9.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-carousel/-/react-carousel-9.9.7.tgz", + "integrity": "sha512-lummYk+tASL/rM/SXWruoqhUAyJjTiOMgiCz55ncE3q2pSZe/EbsV5WfRw5B3y7pHX8xLusN831TBgUthj/sUw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-tooltip": "^9.10.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1", + "embla-carousel": "^8.5.1", + "embla-carousel-autoplay": "^8.5.1", + "embla-carousel-fade": "^8.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-checkbox": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.6.1.tgz", + "integrity": "sha512-Rsf3TmcNrzLuHan9lyUFUmMZnNyvS7DV8C4Vc9lZnZTFRBo94GRMGzu0BcWKFbr3cCDT/r5RmIyQYz0kc7Jd2w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-label": "^9.4.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-color-picker": { + "version": "9.2.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-color-picker/-/react-color-picker-9.2.16.tgz", + "integrity": "sha512-+H8Ea8dwoSeUCTLRpUiGLrRsNvBnlHplnwJPU0isp8jdAfrIM/savZTLj6o4rqNFpNHQqAXxGwNuUV9YfHoJuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ctrl/tinycolor": "^3.3.4", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-combobox": { + "version": "9.17.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.17.1.tgz", + "integrity": "sha512-ezgt6tfOKd3wlG6IHvWl0TPNPpfHRtnEwC2kuqHYH/r1nMNp9edFi8Ya3+1eM7oxai19XW0swt69GPwRu51FVQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-positioning": "^9.22.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-components": { + "version": "9.73.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.73.8.tgz", + "integrity": "sha512-JG4KQjEvRRfPlh4yt6Rv1/k87ydM2y49r5XPNCnuYHahA7kEM+dY8JdOI7n7FW8bdcvZ7qt4smDrQ2XcPfmxlA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-accordion": "^9.11.0", + "@fluentui/react-alert": "9.0.0-beta.139", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-avatar": "^9.11.1", + "@fluentui/react-badge": "^9.5.2", + "@fluentui/react-breadcrumb": "^9.4.1", + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-card": "^9.6.1", + "@fluentui/react-carousel": "^9.9.7", + "@fluentui/react-checkbox": "^9.6.1", + "@fluentui/react-color-picker": "^9.2.16", + "@fluentui/react-combobox": "^9.17.1", + "@fluentui/react-dialog": "^9.18.0", + "@fluentui/react-divider": "^9.7.1", + "@fluentui/react-drawer": "^9.12.0", + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-image": "^9.4.1", + "@fluentui/react-infobutton": "9.0.0-beta.115", + "@fluentui/react-infolabel": "^9.4.20", + "@fluentui/react-input": "^9.8.2", + "@fluentui/react-label": "^9.4.1", + "@fluentui/react-link": "^9.8.1", + "@fluentui/react-list": "^9.6.14", + "@fluentui/react-menu": "^9.24.1", + "@fluentui/react-message-bar": "^9.7.0", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-nav": "^9.3.24", + "@fluentui/react-overflow": "^9.7.2", + "@fluentui/react-persona": "^9.7.3", + "@fluentui/react-popover": "^9.14.2", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-positioning": "^9.22.1", + "@fluentui/react-progress": "^9.5.1", + "@fluentui/react-provider": "^9.22.16", + "@fluentui/react-radio": "^9.6.2", + "@fluentui/react-rating": "^9.4.1", + "@fluentui/react-search": "^9.4.2", + "@fluentui/react-select": "^9.5.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-skeleton": "^9.7.2", + "@fluentui/react-slider": "^9.6.2", + "@fluentui/react-spinbutton": "^9.6.2", + "@fluentui/react-spinner": "^9.8.2", + "@fluentui/react-swatch-picker": "^9.5.2", + "@fluentui/react-switch": "^9.7.2", + "@fluentui/react-table": "^9.19.15", + "@fluentui/react-tabs": "^9.12.1", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-tag-picker": "^9.8.6", + "@fluentui/react-tags": "^9.8.1", + "@fluentui/react-teaching-popover": "^9.6.21", + "@fluentui/react-text": "^9.6.16", + "@fluentui/react-textarea": "^9.7.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-toast": "^9.7.17", + "@fluentui/react-toolbar": "^9.8.0", + "@fluentui/react-tooltip": "^9.10.1", + "@fluentui/react-tree": "^9.16.0", + "@fluentui/react-utilities": "^9.26.3", + "@fluentui/react-virtualizer": "9.0.0-alpha.112", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-context-selector": { + "version": "9.2.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.2.16.tgz", + "integrity": "sha512-D+/X2liT+eZe0rzXbwddPH333ml2SXz71biR13aeyGJQr8+W+icMAIsYhpwk0CC3KtJ3f1/CLTm7vcIrvqsJ4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-utilities": "^9.26.3", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0", + "scheduler": ">=0.19.0" + } + }, + "node_modules/@fluentui/react-dialog": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.18.0.tgz", + "integrity": "sha512-i+V2o0NJ1itjVADJFov5AR/JetpD2hCMiLye0vfi3/XsFMgEPZnGzILVxPCO/ovULTiCyThcL1UvY0d/PYrZfA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-divider": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.7.1.tgz", + "integrity": "sha512-ptymE6iADb/ugezulaMeoAfGxKSwOjHEHBh8N1ydOR3AoOxsSUPkvoPC0mReO/yV5Nas7pz5s5VuJTspmFz0hA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-drawer": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.12.0.tgz", + "integrity": "sha512-PUXeXUH6JqwpjqYphHesHl75UAFSvxQJQqrevMFHE78ZF0Cqn59Xpa+8hGwRSuoRcYa90jjfHzJOOjN0iNM2iA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-dialog": "^9.18.0", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-field": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.5.1.tgz", + "integrity": "sha512-u8J2d3AWb4yZXvy/mQd95y2lTon890RfybBTCbeBUzApGMI/77WqT5pRJ+zTM3lOMToPHVKylchNFusMpJaX9w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-label": "^9.4.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-icons": { + "version": "2.0.325", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.325.tgz", + "integrity": "sha512-dbmpGMwyCFfkFdMSTEFnbNMXKDomPpqbzXVKRKM0EEQrcwOoQvm08d+SV+WWH11kni26SrgEtB9ycldD+fr92w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@griffel/react": "^1.6.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-image": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.4.1.tgz", + "integrity": "sha512-yNd2Wq2xq952UUEVBkWeEmM7bTKdWx6BnsHPYRf0kdTADox2PquApYXsI1xw2pnAh3GSjARrGi9Eto0qxouLqA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-infobutton": { + "version": "9.0.0-beta.115", + "resolved": "https://registry.npmjs.org/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.115.tgz", + "integrity": "sha512-b+4B0ODzPEb4jNaW9HdT6VVt3CL5FgPL2yuKzALBsYVl3udJdFpyxHsZEPf3JrVTBL/rgF2fRI1iAioX6Fl7DA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-icons": "^2.0.237", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-label": "^9.4.1", + "@fluentui/react-popover": "^9.14.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-infolabel": { + "version": "9.4.20", + "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.4.20.tgz", + "integrity": "sha512-w4FOnNP+CtbVdKBEO6wXAcmOuPZWvmB/BJj+7J/8cLAQm7+4kQgitFHncU6rtFhPdGbikVoBf707/0R1mA4aIg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-label": "^9.4.1", + "@fluentui/react-popover": "^9.14.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.8.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-input": { + "version": "9.8.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.8.2.tgz", + "integrity": "sha512-t9zmqZR4bqeRjpWuCGfI4yrtPoCXFiK2XO4BoV5nNwAesglgz4+Vtso4YXst9QYEAazHtKI73YFJf1mn55hCuA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-jsx-runtime": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.4.2.tgz", + "integrity": "sha512-y3o0PBg2qzSdvgxDm7rH9BWq7E1h/eUWS+IhjQhd9dRpme6Py01+OLOglHojM5Tc9QjIp2Rjy2mFWBHXOR+8mw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-utilities": "^9.26.3", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "react": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-label": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.4.1.tgz", + "integrity": "sha512-4O3cPX6dSJVBKlIEbznjJ08utEc98lKbZz/6MZTTQfFgYl0TxAhxEDsIIIyNjj0Xy9eJpqubJsaswucWXTG/qg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-link": { + "version": "9.8.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.8.1.tgz", + "integrity": "sha512-ZxrCeX4pMWHujdmYV8b0QW0ztLtu0rHHvRNx67Y3WqSijVyij8QtNNiZ/nab+UDNlz9t8QIXKdWQgYj1uKDpMg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-list": { + "version": "9.6.14", + "resolved": "https://registry.npmjs.org/@fluentui/react-list/-/react-list-9.6.14.tgz", + "integrity": "sha512-B1mUQFvJOUlZysSduVnATNZggrGpgEWnW9ZSJAZ17LM0+9nWEQRi40jpUGI/d3PGKHt5O2df78s+1nEPAk0L6A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-checkbox": "^9.6.1", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.8.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-menu": { + "version": "9.24.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.24.1.tgz", + "integrity": "sha512-NLB5EhzKFiwax3O5JTRTtsqdEFDGEXzEuP/suyxNAaaQsIuXygo//Rmdq6dSn7GybTpEOZHKxYDyyG7dj+a4YA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-positioning": "^9.22.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-message-bar": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.7.0.tgz", + "integrity": "sha512-ICFDxZ62r5OG97/FcfK1EfJPxGlyDNyFixLD/a3gOREvEcT/hyZgnlUM9Y30u92HjxChx2SwGWnv3iaQPsvToQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-link": "^9.8.1", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.8.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-motion": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion/-/react-motion-9.15.0.tgz", + "integrity": "sha512-ZNQHYzE6MRbLQFT08/mrcqQ9k7F5niktRP93X1v/kmwKfPjvdDofySfbhQXQs3zQw600690C9rfJTKUd3h+zlg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-utilities": "^9.26.3", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.8.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-motion-components-preview": { + "version": "0.15.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion-components-preview/-/react-motion-components-preview-0.15.4.tgz", + "integrity": "sha512-gAHPlyEYylZzUSGwc68VaB+vO8CTX6tgIA3d2+jFrpcwvXZjsdCpF1w1zK1+hTuiipmEaZLZyBz0e0CKH2+3XQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-motion": "*", + "@fluentui/react-utilities": "*", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-nav": { + "version": "9.3.24", + "resolved": "https://registry.npmjs.org/@fluentui/react-nav/-/react-nav-9.3.24.tgz", + "integrity": "sha512-OlB5k5Zev5VNjSRfJvJLO09Hjcv2UHAjLpSVa6gKHx+1NqqSJWZeDLSF7r+/nyZ4CWP5jWZYq7whEu3WvzdVZw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-divider": "^9.7.1", + "@fluentui/react-drawer": "^9.12.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-tooltip": "^9.10.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-overflow": { + "version": "9.7.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.7.2.tgz", + "integrity": "sha512-5PA67LgnVmbbOzBN2H5gH3OvSVy1373VJfsHq2+6TLCfm+LXAkWBoFwvBuFI7HsMYae9A0FVlgX7gTsKVfMddw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/priority-overflow": "^9.3.0", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-persona": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.7.3.tgz", + "integrity": "sha512-OY3xpSD6l4NDdeKihriC+H0q6P1CA2xyZ+pe/WwfKPnatxs2BALoRFtDQduMO7AK/j0w7UAxnaZrvEeftLen2g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-avatar": "^9.11.1", + "@fluentui/react-badge": "^9.5.2", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-popover": { + "version": "9.14.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.14.2.tgz", + "integrity": "sha512-EDvzLkT98/vcCSGrcZWUACGsvLjrHin0Xf9eowMQKiiHFWbu8HNRmr7W2XB9Eja1W5HSIK6+mV8ro9zrLibG4w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-positioning": "^9.22.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-portal": { + "version": "9.8.12", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.8.12.tgz", + "integrity": "sha512-+WH0wH/5lsodGP6Mam1alHXpkMCYA5uMcnF98RVOs7/GR69KiFcza1mCnvPJUaJ55AfwLuz/xLxuWdWgQnUdMQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-positioning": { + "version": "9.22.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.22.1.tgz", + "integrity": "sha512-/r1BHQKr/WCjEM8UGloiq7bWWBSYB/Uqt7D1sAF9EHd968VH07cAN3RMVKmWWjeJO31rstOZHdgcz0WHhFF+2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/devtools": "^0.2.3", + "@floating-ui/dom": "^1.6.12", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-progress": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.5.1.tgz", + "integrity": "sha512-EXJ/Bp67d5+bXPNpPabxdtXUgCMTtvYrBoKtIS6wE5KeUzaek/rgQ3v5wnGfbuLnJ4J/kj+n7XQEc9fhoFPy9w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-provider": { + "version": "9.22.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.22.16.tgz", + "integrity": "sha512-S77n5ASUWE/V1I6lX09CrHm4TAKSGENhIrKz9qMKDv2Vrq44/j3eGBLz12k8IW4TJVu9nwGwst9kBpCT+3WHpA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/core": "^1.16.0", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-radio": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.6.2.tgz", + "integrity": "sha512-Sp2us4eWRopUKOMCQw5/iks7euPKY6FeesBCCUIVGBg5VKZf2/CfEtbCa9hMjn4D4PCHGivnUTf23t238mvvnw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-label": "^9.4.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-rating": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-rating/-/react-rating-9.4.1.tgz", + "integrity": "sha512-DfWipzrT44j+yaShtfHz96/vHEa5ut5IR1kobrO0bSqAcpetOn327gFeY+sG/W6xzork/STcy/T836yK8A2+DQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.8.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-search": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-search/-/react-search-9.4.2.tgz", + "integrity": "sha512-PIb50euHoMsKWLqFymf8wo/+z1jrx1MB7uNuhjNT5DvwTP4VYAy5EtRCSwVRyxWNSaWSL6iy6dDy517EQE96mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-input": "^9.8.2", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-select": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.5.1.tgz", + "integrity": "sha512-8GocQKiUHEUlAks6zA0HbGGSF2lpjuSZuxPzIBqTyuWof8vFiK6eFAcSXb0hTYIVH3RsTihhfc6G3NRnHoBrzg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-shared-contexts": { + "version": "9.26.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.26.2.tgz", + "integrity": "sha512-upKXkwlIp5oIhELr4clAZXQkuCd4GDXM6GZEz8BOmRO+PnxyqmycCXvxDxsmi6XN+0vkGM4joiIgkB14o/FctQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-theme": "^9.2.1", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "react": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-skeleton": { + "version": "9.7.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.7.2.tgz", + "integrity": "sha512-PrUgdSGDAZw9FIP5NyvPoPfHDe2N9VxMyBfyTwWfZVg03dzRfnE3vEqr7N5xyfv4JsRs6u1xSqVn/0jdS0IEMQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-slider": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.6.2.tgz", + "integrity": "sha512-lVavtTg8eqovfRokeYDk4popwCi8nuicacJ/HZdF3ni5e3y/2WT/bVP0eErS/GvC7+90ACQQ8uxdr4sjjY/HWA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-spinbutton": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.6.2.tgz", + "integrity": "sha512-P4vvJH7P5yHPFAv6aSo3dZxtErN62DiRJN+nEKS+/XBoRGsOGQdqyyx5Q/PQKOmyQrtwuZdXNHUjcyv8b50T2w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-spinner": { + "version": "9.8.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.8.2.tgz", + "integrity": "sha512-0LxykLJGUD/I3XEeIXAWznwdg9XRe0piaByR0nLFOOV3UPwkVc2w5UdPhy2Y0NZDvtPHbNaMCuQAq82+bxg/0w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-label": "^9.4.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-swatch-picker": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-swatch-picker/-/react-swatch-picker-9.5.2.tgz", + "integrity": "sha512-DK6UU9OJY9XaGBPU2ROx+B5/7XdwVtHBdVthOAptyKSsYGOdQt5AQqg3ZOXH6r5WYbMRQDuP2OZ2iKtwidFCVQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.8.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-switch": { + "version": "9.7.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.7.2.tgz", + "integrity": "sha512-j3e5se+3d+befV9MytkxxvJ9nHZOeZ7thKDTF4YVSYf6kcNx9eOlLvPgDjhGO08gzngO4B7aaprhDN7DJc3W1g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-label": "^9.4.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-table": { + "version": "9.19.15", + "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.19.15.tgz", + "integrity": "sha512-OdQ2Nwx2nAlPMlJeyAFrKa3Zy5Ya/H87OU8MvtFJhabM/FkHiZoli/DO1mavVI+jqavOlJuQWmJ55D6jjuGa7g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-avatar": "^9.11.1", + "@fluentui/react-checkbox": "^9.6.1", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-radio": "^9.6.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-tabs": { + "version": "9.12.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.12.1.tgz", + "integrity": "sha512-WvzOtpC6C/7Mo5X+xmE+3stpCbx2iH9BqrEN5KuGrsHJ78DjMDeabYeL90vlrHBdP4VlTpwdORBui/jtWkxnmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-tabster": { + "version": "9.26.14", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.26.14.tgz", + "integrity": "sha512-WibgoF67hl6BXfmsY6RSIWSHadeMP/6EDG9gAacfHlwKvK0+FiHp5ernwuXTPAmu2kiHicn2qUZ8EteCFiFryg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1", + "keyborg": "^2.6.0", + "tabster": "^8.5.5" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-tag-picker": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-tag-picker/-/react-tag-picker-9.8.6.tgz", + "integrity": "sha512-sOZ+wBA3hgGhKrOP7wbjB2yRvAxjcRXtcj1jDTrtSkaDPXb3K0nGmjiqp2mve995ps3wvCGnNKK4EurX842ZbA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-combobox": "^9.17.1", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-positioning": "^9.22.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-tags": "^9.8.1", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-tags": { + "version": "9.8.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.8.1.tgz", + "integrity": "sha512-6ZTW78fu5eWByKHIM3i+raDrX3hwfZ67ONfZ8wEUXfZHowskxqpMHI8Gw7IAMWkC1scgLqEnht8TnHvZgjo7Ug==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-avatar": "^9.11.1", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-teaching-popover": { + "version": "9.6.21", + "resolved": "https://registry.npmjs.org/@fluentui/react-teaching-popover/-/react-teaching-popover-9.6.21.tgz", + "integrity": "sha512-V86zLB1B8xu3U/02FvvMdsJP+ZC9l3vT9bQ2Gr7hZHxJ4/0NLpVcrYSBFHpON9e/WK3p+A5b5V96p86b5Pavlg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-popover": "^9.14.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <20.0.0", + "@types/react-dom": ">=16.8.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-text": { + "version": "9.6.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.6.16.tgz", + "integrity": "sha512-ZzCSJWQ6LrVuPqA6sqNEZaXbLvhi2NxBOtlMudWlqYzidLQp038d7mMGSzNnhyeblg+gj+bOVE2eOgWFuVHGYw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-textarea": { + "version": "9.7.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.7.2.tgz", + "integrity": "sha512-awlkZoW81WaOqSoXTT9rZs3mTAzCCHnC9eAm6J8ZxI5+ASX07BTolBfZ82it5wxOHI5GMDfbFOl+xIy8uAMdzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-field": "^9.5.1", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-theme": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.2.1.tgz", + "integrity": "sha512-lJxfz7LmmglFz+c9C41qmMqaRRZZUPtPPl9DWQ79vH+JwZd4dkN7eA78OTRwcGCOTPEKoLTX72R+EFaWEDlX+w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/tokens": "1.0.0-alpha.23", + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-toast": { + "version": "9.7.17", + "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.7.17.tgz", + "integrity": "sha512-DWA5EARWSo1k19iWAulLpKrcUHT+Dq/Bw9zfdpoQEWWybrAZwyN7WiYFkBjKCQRxSp10OjLASSQK91CXfb1wJA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-toolbar": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.8.0.tgz", + "integrity": "sha512-EIe+QWOaFR1pZzENefsFTmjxGa2yJb4A/by3kGuGqSjx7isqPUllPq0/kFQzfoUYgPDJbJtQ+KyuRDekTL0QpQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-divider": "^9.7.1", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-radio": "^9.6.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-tooltip": { + "version": "9.10.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.10.1.tgz", + "integrity": "sha512-IPHBFjqGhaaMDhLt5NSNOE9LEpDOpT7qgEqNz+Mlflo0A4qI2LW/EnkNop7IRmX/bC88A+wUtEONTjjR87dNBw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-portal": "^9.8.12", + "@fluentui/react-positioning": "^9.22.1", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-tree": { + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.16.0.tgz", + "integrity": "sha512-c+Q4AVaYk9U69aGDgmJVNne+CtWKS75YIfGoxs6+9+wE2Wqz4T0E+gE1ng7ARCQQgI7E2NEJlot6DuI6nYYrRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.17.11", + "@fluentui/react-avatar": "^9.11.1", + "@fluentui/react-button": "^9.9.1", + "@fluentui/react-checkbox": "^9.6.1", + "@fluentui/react-context-selector": "^9.2.16", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-motion": "^9.15.0", + "@fluentui/react-motion-components-preview": "^0.15.4", + "@fluentui/react-radio": "^9.6.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-tabster": "^9.26.14", + "@fluentui/react-theme": "^9.2.1", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-utilities": { + "version": "9.26.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.26.3.tgz", + "integrity": "sha512-bXB3jMm/RroT8c5eGZkijkPbLd4MqMI6biBHjavo0e7OkZHv9IPfH2nDkGhSn5Sh8e6kRcX0IjYhbM10WUK2iQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-shared-contexts": "^9.26.2", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "react": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/react-virtualizer": { + "version": "9.0.0-alpha.112", + "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.112.tgz", + "integrity": "sha512-dao/mQssaPFxCXMx7K+G/DrRoZg28kXcE1NGbJ1RPtbkVCzJgwrEEeDhM5/wyOXO/Z5EZ31FIerDDVOyr6FAaw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.4.2", + "@fluentui/react-shared-contexts": "^9.26.2", + "@fluentui/react-utilities": "^9.26.3", + "@griffel/react": "^1.5.32", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <20.0.0", + "@types/react-dom": ">=16.9.0 <20.0.0", + "react": ">=16.14.0 <20.0.0", + "react-dom": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@fluentui/tokens": { + "version": "1.0.0-alpha.23", + "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.23.tgz", + "integrity": "sha512-uxrzF9Z+J10naP0pGS7zPmzSkspSS+3OJDmYIK3o1nkntQrgBXq3dBob4xSlTDm5aOQ0kw6EvB9wQgtlyy4eKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@griffel/core": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.21.0.tgz", + "integrity": "sha512-QqMoewiNTT0DmLM7OY607c7yhg18SuKfzovTO3hPXGQvtdu/StnjvuBAs+1B1kYSVGReAo6s/dJVeLnPuHjE7Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@emotion/hash": "^0.9.0", + "@griffel/style-types": "^1.4.0", + "csstype": "^3.1.3", + "rtl-css-js": "^1.16.1", + "stylis": "^4.4.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@griffel/react": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.7.2.tgz", + "integrity": "sha512-/+N+81e9ibNsh2wNlhGf2PcimEFrx8VbtWiLCmI6lsrTV5eBcQrIIDVQq737KPIJFtD4v6Txu9n0PXbN3hedNg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@griffel/core": "^1.21.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.14.0 <20.0.0" + } + }, + "node_modules/@griffel/style-types": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@griffel/style-types/-/style-types-1.4.0.tgz", + "integrity": "sha512-vNDfOGV7RN/XkA7vxgf7Z5HgW8eiBm5cHT9wQPhsKB4pxWom5u6eQ9CkYE5mCCTSPl9H6Nd1NBai04d4P6BD7Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.1.3" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "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/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "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.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "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.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "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.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "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.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "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.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "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.0.4" } }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "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/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "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/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", "cpu": [ "arm64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "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.0.4" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", "cpu": [ "x64" ], - "license": "Apache-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/slugify": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz", + "integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==", + "license": "MIT", + "dependencies": { + "@sindresorhus/transliterate": "^1.0.0", + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/transliterate": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz", + "integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.21.tgz", + "integrity": "sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.2.tgz", + "integrity": "sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/type-utils": "8.59.2", + "@typescript-eslint/utils": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.59.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.2.tgz", + "integrity": "sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.2.tgz", + "integrity": "sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.59.2", + "@typescript-eslint/types": "^8.59.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.2.tgz", + "integrity": "sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.2.tgz", + "integrity": "sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.2.tgz", + "integrity": "sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/utils": "8.59.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/libvips" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, + "node_modules/@typescript-eslint/types": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.2.tgz", + "integrity": "sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.2.tgz", + "integrity": "sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==", + "dev": true, + "license": "MIT", "dependencies": { - "@emnapi/runtime": "^1.2.0" + "@typescript-eslint/project-service": "8.59.2", + "@typescript-eslint/tsconfig-utils": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/libvips" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" }, - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://opencollective.com/libvips" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@sindresorhus/slugify": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz", - "integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==", + "node_modules/@typescript-eslint/utils": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.2.tgz", + "integrity": "sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==", + "dev": true, "license": "MIT", "dependencies": { - "@sindresorhus/transliterate": "^1.0.0", - "escape-string-regexp": "^5.0.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2" }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@sindresorhus/transliterate": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz", - "integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.2.tgz", + "integrity": "sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==", + "dev": true, "license": "MIT", "dependencies": { - "escape-string-regexp": "^5.0.0" + "@typescript-eslint/types": "8.59.2", + "eslint-visitor-keys": "^5.0.0" }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/a-sync-waterfall": { @@ -609,6 +3444,16 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-walk": { "version": "8.3.5", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", @@ -621,6 +3466,23 @@ "node": ">=0.4.0" } }, + "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/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -658,6 +3520,14 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "license": "MIT" }, + "node_modules/babylonjs-gltf2interface": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-9.5.2.tgz", + "integrity": "sha512-ICFeKhRDruVXezoQVdjQCjjnxYWNAiRFcLRvw+e6FrHyuhjB621EgAzTijDqE7y8E3OZ53vaHKR9T4ADZ9lEnQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -817,6 +3687,29 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -834,6 +3727,13 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -931,6 +3831,36 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, + "node_modules/embla-carousel": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", + "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/embla-carousel-autoplay": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-autoplay/-/embla-carousel-autoplay-8.6.0.tgz", + "integrity": "sha512-OBu5G3nwaSXkZCo1A6LTaFMZ8EpkYbwIaH+bPqdBnDGQ2fh4+NbzjXjs2SktoPNKCtflfVMc75njaDHOYXcrsA==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "embla-carousel": "8.6.0" + } + }, + "node_modules/embla-carousel-fade": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-fade/-/embla-carousel-fade-8.6.0.tgz", + "integrity": "sha512-qaYsx5mwCz72ZrjlsXgs1nKejSrW+UhkbOMwLgfRT7w2LtdEB03nPRI06GHuHv5ac2USvbEiX2/nAHctcDwvpg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "embla-carousel": "8.6.0" + } + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -982,6 +3912,159 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.3.0.tgz", + "integrity": "sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/esm-import-transformer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/esm-import-transformer/-/esm-import-transformer-3.0.5.tgz", @@ -991,6 +4074,24 @@ "acorn": "^8.15.0" } }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1004,6 +4105,52 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1034,6 +4181,27 @@ "node": ">=0.10.0" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -1051,6 +4219,19 @@ } } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/filesize": { "version": "10.1.6", "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz", @@ -1086,24 +4267,62 @@ "statuses": "~2.0.2", "unpipe": "~1.0.0" }, - "engines": { - "node": ">= 0.8" + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" }, "node_modules/fresh": { "version": "2.0.0", @@ -1140,6 +4359,19 @@ "node": ">= 6" } }, + "node_modules/globals": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gray-matter": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", @@ -1237,6 +4469,26 @@ "url": "https://opencollective.com/express" } }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -1340,6 +4592,13 @@ "node": ">=0.12.0" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, "node_modules/iso-639-1": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/iso-639-1/-/iso-639-1-3.1.5.tgz", @@ -1361,6 +4620,27 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "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/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/junk": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", @@ -1370,6 +4650,24 @@ "node": ">=8" } }, + "node_modules/keyborg": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/keyborg/-/keyborg-2.14.1.tgz", + "integrity": "sha512-/WmmVBa6Me3hIKAOIyIq1sql+6oydQZzGMBDLNfOcJ8710byMsq3KSLS8GQhBJHOMtvnXnUBrDAIbABcZVipcg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "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", @@ -1388,6 +4686,281 @@ "node": ">=6" } }, + "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/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -1423,6 +4996,30 @@ "integrity": "sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g==", "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/luxon": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", @@ -1552,6 +5149,32 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/node-retrieve-globals": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/node-retrieve-globals/-/node-retrieve-globals-6.0.1.tgz", @@ -1603,19 +5226,69 @@ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "license": "MIT", "engines": { - "node": ">= 6" + "node": ">= 6" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "license": "MIT", "dependencies": { - "ee-first": "1.1.1" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 0.8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/parse-srcset": { @@ -1633,6 +5306,33 @@ "node": ">= 0.8" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, "node_modules/picomatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", @@ -1645,6 +5345,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", + "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.59.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", + "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/please-upgrade-node": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", @@ -1654,6 +5401,35 @@ "semver-compare": "^1.0.0" } }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/posthtml": { "version": "0.16.7", "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.7.tgz", @@ -1703,12 +5479,48 @@ "node": ">=12" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "license": "MIT" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/punycode.js": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", @@ -1727,6 +5539,31 @@ "node": ">= 0.6" } }, + "node_modules/react": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.5" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1751,6 +5588,59 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/rolldown": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + } + }, + "node_modules/rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -1853,6 +5743,29 @@ "@img/sharp-win32-x64": "0.33.5" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/simple-swizzle": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", @@ -1880,6 +5793,16 @@ "node": ">=8.0.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1916,6 +5839,26 @@ "node": ">=0.10.0" } }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/tabster": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/tabster/-/tabster-8.8.0.tgz", + "integrity": "sha512-eGFXgtvKOQP5BywDI9Ngs+Atm6TRj45epAAqWKyVoi+HmOmdamEB//1H/FttLdNly/+Cz+GJ4RN8TnXTw0KwfA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "keyborg": "^2.14.0", + "tslib": "^2.8.1" + } + }, "node_modules/tinyglobby": { "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", @@ -1953,12 +5896,76 @@ "node": ">=0.6" } }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true + "devOptional": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.2.tgz", + "integrity": "sha512-pJw051uomb3ZeCzGTpRb8RbEqB5Y4WWet8gl/GcTlU35BSx0PVdZ86/bqkQCyKKuraVQEK7r6kBHQXF+fBhkoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/utils": "8.59.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } }, "node_modules/uc.micro": { "version": "2.1.0", @@ -1975,12 +5982,154 @@ "node": ">= 0.8" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/urlpattern-polyfill": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz", "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==", "license": "MIT" }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/usehooks-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.1.tgz", + "integrity": "sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lodash.debounce": "^4.0.8" + }, + "engines": { + "node": ">=16.15.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/vite": { + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ws": { "version": "8.20.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", @@ -2001,6 +6150,19 @@ "optional": true } } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 3205e2cc4..9c70328ea 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,16 @@ "main": "eleventy.config.js", "scripts": { "start": "npx @11ty/eleventy --serve", - "build": "npx @11ty/eleventy", + "site:build": "npx @11ty/eleventy", + "build": "npm run site:build && npm run demos:build", + "demos:lint": "eslint \"vite.demos.config.mjs\" \"scripts/demos/**/*.mjs\" \"src/compiledDemos/**/*.ts\"", + "demos:format": "prettier --check \"azure-pipelines.compiled-demos.yml\" \"docs/compiled-demos.md\" \"eslint.config.mjs\" \"package.json\" \"scripts/demos/**/*.mjs\" \"src/compiledDemos/**/*.{html,json,ts}\" \"tsconfig.demos.json\" \"vite.demos.config.mjs\"", + "demos:format:write": "prettier --write \"azure-pipelines.compiled-demos.yml\" \"docs/compiled-demos.md\" \"eslint.config.mjs\" \"package.json\" \"scripts/demos/**/*.mjs\" \"src/compiledDemos/**/*.{html,json,ts}\" \"tsconfig.demos.json\" \"vite.demos.config.mjs\"", + "demos:build": "vite build --config vite.demos.config.mjs --logLevel silent && node scripts/demos/generate-source-pages.mjs", + "demos:serve": "npm run build && vite preview --host 127.0.0.1 --port 4173 --outDir build", + "demos:typecheck": "tsc -p tsconfig.demos.json --noEmit", + "demos:check": "node scripts/demos/check-render.mjs", + "demos:ci": "npm run demos:lint && npm run demos:format && npm run demos:typecheck && npm run demos:check", "process-images": "node .github/scripts/process-images.js", "update-image": "node .github/scripts/update-image.js", "test": "echo \"Error: no test specified\" && exit 1" @@ -15,5 +24,20 @@ "dependencies": { "@11ty/eleventy": "^3.1.5", "sharp": "^0.33.5" + }, + "devDependencies": { + "@babylonjs/core": "^9.5.2", + "@babylonjs/gui": "^9.5.2", + "@babylonjs/inspector": "^9.5.2", + "@babylonjs/loaders": "^9.5.2", + "@babylonjs/materials": "^9.5.2", + "@eslint/js": "^10.0.1", + "eslint": "^10.3.0", + "globals": "^17.6.0", + "playwright": "^1.59.1", + "prettier": "^3.8.3", + "typescript": "^6.0.3", + "typescript-eslint": "^8.59.2", + "vite": "^8.0.10" } } diff --git a/scripts/demos/check-render.mjs b/scripts/demos/check-render.mjs new file mode 100644 index 000000000..086c228d8 --- /dev/null +++ b/scripts/demos/check-render.mjs @@ -0,0 +1,270 @@ +import fs from "node:fs/promises"; +import http from "node:http"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { chromium } from "playwright"; +import sharp from "sharp"; + +const repoRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url)))); +const buildRoot = path.join(repoRoot, "build"); +const manifestPath = path.join(repoRoot, "src/compiledDemos/manifest.json"); +const manifest = JSON.parse(await fs.readFile(manifestPath, "utf8")); +const selectedDemos = new Set( + (process.env.DEMOS || "") + .split(",") + .map((value) => value.trim()) + .filter(Boolean) +); + +const contentTypes = new Map([ + [".html", "text/html; charset=utf-8"], + [".js", "text/javascript; charset=utf-8"], + [".css", "text/css; charset=utf-8"], + [".json", "application/json; charset=utf-8"], + [".png", "image/png"], + [".jpg", "image/jpeg"], + [".jpeg", "image/jpeg"], + [".webp", "image/webp"], + [".wasm", "application/wasm"], +]); + +const demos = manifest.demos.filter( + (demo) => !demo.renderCheck?.disabled && (selectedDemos.size === 0 || selectedDemos.has(demo.slug)) +); + +if (demos.length === 0) { + console.log("No compiled demos selected for render checks."); + process.exit(0); +} + +const server = http.createServer(async (request, response) => { + try { + const requestUrl = new URL(request.url || "/", "http://127.0.0.1"); + let relativePath = decodeURIComponent(requestUrl.pathname).replace(/^\/+/, ""); + if (!relativePath || relativePath.endsWith("/")) { + relativePath = path.join(relativePath, "index.html"); + } + + const filePath = path.normalize(path.join(buildRoot, relativePath)); + if (!filePath.startsWith(buildRoot)) { + response.writeHead(403); + response.end("Forbidden"); + return; + } + + const body = await fs.readFile(filePath); + response.writeHead(200, { + "content-type": contentTypes.get(path.extname(filePath).toLowerCase()) || "application/octet-stream", + }); + response.end(body); + } catch { + response.writeHead(404); + response.end("Not found"); + } +}); + +await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); +const address = server.address(); +const baseUrl = `http://127.0.0.1:${address.port}`; + +const browser = await chromium.launch({ + args: ["--ignore-gpu-blocklist", "--use-gl=swiftshader"], +}); + +const failures = []; + +async function sampleCanvas(canvas, timeoutMs) { + const screenshot = await canvas.screenshot({ timeout: timeoutMs }); + const image = sharp(screenshot).ensureAlpha(); + const metadata = await image.metadata(); + const pixels = await image.raw().toBuffer(); + let coloredSamples = 0; + let transparentSamples = 0; + const step = 12; + + for (let y = 0; y < metadata.height; y += step) { + for (let x = 0; x < metadata.width; x += step) { + const index = (y * metadata.width + x) * 4; + const red = pixels[index]; + const green = pixels[index + 1]; + const blue = pixels[index + 2]; + const alpha = pixels[index + 3]; + + if (alpha === 0) { + transparentSamples++; + } + + if (alpha > 0 && (red > 8 || green > 8 || blue > 8)) { + coloredSamples++; + } + } + } + + return { + stats: { + exists: true, + readable: true, + width: metadata.width, + height: metadata.height, + coloredSamples, + transparentSamples, + }, + pixels, + }; +} + +function countChangedSamples(before, after, width, height) { + let changedSamples = 0; + const step = 12; + const threshold = 18; + + for (let y = 0; y < height; y += step) { + for (let x = 0; x < width; x += step) { + const index = (y * width + x) * 4; + const delta = + Math.abs(before[index] - after[index]) + + Math.abs(before[index + 1] - after[index + 1]) + + Math.abs(before[index + 2] - after[index + 2]) + + Math.abs(before[index + 3] - after[index + 3]); + + if (delta > threshold) { + changedSamples++; + } + } + } + + return changedSamples; +} + +async function waitForAnimationFramePair(page) { + await page.evaluate( + () => + new Promise((resolve) => { + requestAnimationFrame(() => requestAnimationFrame(resolve)); + }) + ); +} + +async function waitForDemoReady(page, timeoutMs) { + await page.evaluate((timeout) => { + const ready = window.__babylonDemoReady; + return Promise.race([ + ready, + new Promise((_, reject) => { + window.setTimeout(() => reject(new Error(`Demo readiness timed out after ${timeout}ms`)), timeout); + }), + ]); + }, timeoutMs); +} + +async function checkCanvas(locator, demo, timeoutMs, label) { + const sample = await sampleCanvas(locator, timeoutMs); + const minimumColoredSamples = demo.renderCheck?.minimumColoredSamples || 50; + + if (sample.stats.coloredSamples < minimumColoredSamples) { + failures.push( + `${demo.slug}: ${label} canvas check failed (${JSON.stringify(sample.stats)}, expected at least ${minimumColoredSamples} colored samples)` + ); + } + + return sample; +} + +try { + for (const demo of demos) { + const page = await browser.newPage({ viewport: { width: 960, height: 540 } }); + const consoleErrors = []; + const pageErrors = []; + page.on("console", (message) => { + if (message.type() === "error") { + consoleErrors.push(message.text()); + } + }); + page.on("pageerror", (error) => pageErrors.push(error.message)); + + const timeoutMs = demo.renderCheck?.timeoutMs || 15000; + const url = `${baseUrl}/Demos/${encodeURIComponent(demo.slug)}/`; + + try { + await page.goto(url, { waitUntil: "domcontentloaded", timeout: timeoutMs }); + await page.waitForFunction(() => Boolean(window.__babylonDemoReady), null, { timeout: timeoutMs }); + await waitForDemoReady(page, timeoutMs); + await waitForAnimationFramePair(page); + + const canvasSelector = demo.renderCheck?.canvasSelector || "canvas"; + const canvases = page.locator(canvasSelector); + const canvasCount = await canvases.count(); + const minimumCanvasCount = demo.renderCheck?.minimumCanvasCount || 1; + const canvas = canvases.first(); + let canvasStats = { exists: false }; + let canvasPixels = null; + + if (canvasCount < minimumCanvasCount) { + failures.push( + `${demo.slug}: expected at least ${minimumCanvasCount} canvas element${minimumCanvasCount === 1 ? "" : "s"}, found ${canvasCount}` + ); + } + + if (canvasCount > 0) { + const sample = await checkCanvas(canvas, demo, timeoutMs, "primary"); + canvasStats = sample.stats; + canvasPixels = sample.pixels; + } + + for (let canvasIndex = 1; canvasIndex < Math.min(canvasCount, minimumCanvasCount); canvasIndex++) { + await checkCanvas(canvases.nth(canvasIndex), demo, timeoutMs, `canvas ${canvasIndex + 1}`); + } + + const interaction = demo.renderCheck?.interaction; + if (interaction?.type === "clickCanvas" && canvasStats.readable) { + const box = await canvas.boundingBox(); + if (!box) { + failures.push(`${demo.slug}: interaction check failed (canvas has no bounding box)`); + } else { + await canvas.click({ + position: { + x: box.width * (interaction.x ?? 0.5), + y: box.height * (interaction.y ?? 0.5), + }, + timeout: timeoutMs, + }); + await page.waitForTimeout(interaction.waitMs || 750); + await waitForAnimationFramePair(page); + + const afterInteraction = await sampleCanvas(canvas, timeoutMs); + const changedSamples = countChangedSamples( + canvasPixels, + afterInteraction.pixels, + canvasStats.width, + canvasStats.height + ); + const minimumChangedSamples = interaction.minimumChangedSamples || 25; + + if (changedSamples < minimumChangedSamples) { + failures.push( + `${demo.slug}: interaction check failed (${changedSamples} changed samples, expected at least ${minimumChangedSamples})` + ); + } + } + } + + if (consoleErrors.length > 0 || pageErrors.length > 0) { + failures.push(`${demo.slug}: browser errors: ${[...consoleErrors, ...pageErrors].join(" | ")}`); + } + } catch (error) { + failures.push(`${demo.slug}: ${error.message}`); + } finally { + await page.close(); + } + } +} finally { + await browser.close(); + server.close(); +} + +if (failures.length > 0) { + console.error(failures.join("\n")); + process.exit(1); +} + +console.log(`Checked ${demos.length} compiled demo${demos.length === 1 ? "" : "s"}.`); diff --git a/scripts/demos/generate-source-pages.mjs b/scripts/demos/generate-source-pages.mjs new file mode 100644 index 000000000..00f24b757 --- /dev/null +++ b/scripts/demos/generate-source-pages.mjs @@ -0,0 +1,139 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const repoRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url)))); +const sourceRoot = path.join(repoRoot, "src/compiledDemos"); +const buildRoot = path.join(repoRoot, "build/Demos"); +const manifest = JSON.parse(await fs.readFile(path.join(sourceRoot, "manifest.json"), "utf8")); + +const escapeHtml = (value) => + value + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); + +const renderSourcePage = (demo, files) => ` + + + + + ${escapeHtml(demo.title)} source + + + +
+

${escapeHtml(demo.title)} source

+ Back to demo +
+ ${files + .map( + (file) => `
+

${escapeHtml(file.path)}

+
${escapeHtml(file.contents)}
+
` + ) + .join("\n")} + + +`; + +for (const demo of manifest.demos) { + const sourceFiles = demo.sourceFiles || ["main.ts", "scene.ts"]; + const files = []; + + for (const sourceFile of sourceFiles) { + const filePath = path.normalize(path.join(sourceRoot, demo.slug, sourceFile)); + const demoRoot = path.join(sourceRoot, demo.slug); + + if (!filePath.startsWith(demoRoot)) { + throw new Error(`Source file ${sourceFile} escapes ${demo.slug}.`); + } + + files.push({ + path: sourceFile, + contents: await fs.readFile(filePath, "utf8"), + }); + } + + const sourceOutDir = path.join(buildRoot, demo.slug, "source"); + await fs.mkdir(sourceOutDir, { recursive: true }); + await fs.writeFile(path.join(sourceOutDir, "index.html"), renderSourcePage(demo, files)); +} + +console.log( + `Generated source pages for ${manifest.demos.length} compiled demo${manifest.demos.length === 1 ? "" : "s"}.` +); diff --git a/src/compiledDemos/AssetsManager/index.html b/src/compiledDemos/AssetsManager/index.html new file mode 100644 index 000000000..84e1510d1 --- /dev/null +++ b/src/compiledDemos/AssetsManager/index.html @@ -0,0 +1,112 @@ + + + + + + Babylon.js - Assets manager demo + + + + +
+ + +
+ Source +
+
+
+ + + + diff --git a/src/compiledDemos/AssetsManager/main.ts b/src/compiledDemos/AssetsManager/main.ts new file mode 100644 index 000000000..e6a7c67ba --- /dev/null +++ b/src/compiledDemos/AssetsManager/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createAssetsManagerScene } from "./scene"; + +runDemo({ + createScene: createAssetsManagerScene, +}); diff --git a/src/compiledDemos/AssetsManager/scene.ts b/src/compiledDemos/AssetsManager/scene.ts new file mode 100644 index 000000000..d09430644 --- /dev/null +++ b/src/compiledDemos/AssetsManager/scene.ts @@ -0,0 +1,48 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import type { Engine } from "@babylonjs/core/Engines/engine"; +import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { AssetsManager } from "@babylonjs/core/Misc/assetsManager"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Loading/Plugins/babylonFileLoader"; + +export async function createAssetsManagerScene(engine: Engine, canvas: HTMLCanvasElement): Promise { + const scene = new Scene(engine); + const status = document.getElementById("assetStatus"); + const camera = new ArcRotateCamera("Camera", 0, Math.PI / 2, 80, Vector3.Zero(), scene); + new HemisphericLight("light", new Vector3(0, 1, 0), scene); + + camera.attachControl(canvas, true); + + const assetsManager = new AssetsManager(scene); + assetsManager.useDefaultLoadingScreen = false; + + const meshTask = assetsManager.addMeshTask("skull task", "", "./", "skull.babylon"); + meshTask.onSuccess = (task) => { + const rootMesh = task.loadedMeshes[0]; + if (rootMesh) { + rootMesh.position = Vector3.Zero(); + } + }; + + const textTask = assetsManager.addTextFileTask("text task", "msg.txt"); + textTask.onSuccess = (task) => { + if (status) { + status.textContent = task.text.trim(); + } + }; + + assetsManager.addBinaryFileTask("binary task", "grass.jpg"); + + await new Promise((resolve, reject) => { + assetsManager.onTaskError = (task) => { + reject(new Error(`Unable to complete asset task: ${task.name}`)); + }; + assetsManager.onFinish = () => { + resolve(); + }; + assetsManager.load(); + }); + + return scene; +} diff --git a/src/compiledDemos/Boom/index.html b/src/compiledDemos/Boom/index.html new file mode 100644 index 000000000..911ee325b --- /dev/null +++ b/src/compiledDemos/Boom/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Boom demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Boom/main.ts b/src/compiledDemos/Boom/main.ts new file mode 100644 index 000000000..d93bfd623 --- /dev/null +++ b/src/compiledDemos/Boom/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createBoomScene } from "./scene"; + +runDemo({ + createScene: createBoomScene, +}); diff --git a/src/compiledDemos/Boom/scene.ts b/src/compiledDemos/Boom/scene.ts new file mode 100644 index 000000000..ff229c507 --- /dev/null +++ b/src/compiledDemos/Boom/scene.ts @@ -0,0 +1,258 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; +import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"; +import { PointLight } from "@babylonjs/core/Lights/pointLight"; +import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { DynamicTexture } from "@babylonjs/core/Materials/Textures/dynamicTexture"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"; +import { CreateDisc } from "@babylonjs/core/Meshes/Builders/discBuilder"; +import { CreateGroundFromHeightMap } from "@babylonjs/core/Meshes/Builders/groundBuilder"; +import { SolidParticleSystem } from "@babylonjs/core/Particles/solidParticleSystem"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Culling/ray"; +import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent"; + +export function createBoomScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const size = 10; + const widthCount = 30; + const heightCount = 20; + const gravity = -0.07; + const restitution = 0.9; + const friction = 0.995; + const radius = (size * heightCount) / 12; + const speed = radius * 1.2; + + const subdivisions = 50; + const width = 1000; + const height = 1000; + const groundHeight = width / 6; + + const scene = new Scene(engine); + scene.clearColor = new Color3(0.4, 0.6, 0.8).toColor4(1); + + const camera = new ArcRotateCamera("camera1", 0, 0, 0, Vector3.Zero(), scene); + camera.setPosition(new Vector3(0, 0, -800)); + camera.attachControl(canvas, true); + + const hemisphericLight = new HemisphericLight("light1", new Vector3(0, 1, 0), scene); + hemisphericLight.groundColor = new Color3(0.5, 0.5, 0.5); + hemisphericLight.intensity = 0.2; + + const lightDirection = new Vector3(0, -1, 1); + const directionalLight = new DirectionalLight("dl", lightDirection, scene); + directionalLight.position = new Vector3(0, 200, -1000); + directionalLight.diffuse = Color3.White(); + directionalLight.intensity = 0.8; + directionalLight.specular = new Color3(0.5, 0.5, 0.2); + + const pointLight = new PointLight("pl", Vector3.Zero(), scene); + pointLight.diffuse = Color3.White(); + pointLight.specular = Color3.Black(); + pointLight.intensity = 0.4; + + const texture = new DynamicTexture("dt", { width: 500, height: 65 }, scene); + texture.hasAlpha = true; + texture.drawText("BabylonJS Roxxx", null, 45, "bold 56px Arial", "blue", "red", true, false); + texture.drawText("CLICK = BOOM", null, 60, "bold 20px Arial", "yellow", null, true, true); + + const particleMaterial = new StandardMaterial("mat1", scene); + particleMaterial.diffuseTexture = texture; + particleMaterial.freeze(); + + const ground = CreateGroundFromHeightMap( + "ground", + "/Scenes/Customs/heightMap.png", + { + width, + height, + subdivisions, + minHeight: 0, + maxHeight: groundHeight, + onReady: (mesh) => { + mesh.getHeightAtCoordinates(mesh.position.x, mesh.position.z); + }, + }, + scene + ); + + const groundMaterial = new StandardMaterial("ground", scene); + const groundTexture = new Texture("/Scenes/Customs/Ground.jpg", scene); + groundTexture.uScale = 6; + groundTexture.vScale = 6; + groundMaterial.diffuseTexture = groundTexture; + groundMaterial.specularColor = Color3.Black(); + ground.material = groundMaterial; + ground.isPickable = false; + ground.position.y = -heightCount * size; + ground.position.z = heightCount * size; + groundMaterial.freeze(); + ground.freezeWorldMatrix(); + + const disc = CreateDisc("d", { radius: width * 4 }, scene); + disc.position.copyFrom(ground.position); + disc.position.y -= 0.1; + disc.rotation.x = Math.PI / 2; + + const discMaterial = new StandardMaterial("groundDisc", scene); + const discTexture = new Texture("/Scenes/Customs/Ground.jpg", scene); + discTexture.uScale = 50; + discTexture.vScale = 50; + discMaterial.diffuseTexture = discTexture; + discMaterial.specularColor = Color3.Black(); + discMaterial.zOffset = 1; + discMaterial.freeze(); + disc.material = discMaterial; + disc.isPickable = false; + disc.freezeWorldMatrix(); + + const model = CreateBox("m", { size }, scene); + const solidParticles = new SolidParticleSystem("sps", scene, { isPickable: true }); + solidParticles.addShape(model, widthCount * heightCount); + model.dispose(); + + const particleMesh = solidParticles.buildMesh(); + particleMesh.material = particleMaterial; + particleMesh.freezeWorldMatrix(); + + const particleVars = solidParticles.vars as Record; + particleVars.target = Vector3.Zero(); + particleVars.temp = Vector3.Zero(); + particleVars.totalWidth = size * widthCount; + particleVars.totalHeight = size * heightCount; + particleVars.shiftX = -particleVars.totalWidth / 2; + particleVars.shiftY = -particleVars.totalHeight / 2; + particleVars.radius = radius; + particleVars.minY = 0; + particleVars.normal = Vector3.Zero(); + particleVars.symmetry = 0; + particleVars.loss = 0; + particleVars.justClicked = false; + + const shadowGenerator = new ShadowGenerator(1024, directionalLight); + shadowGenerator.getShadowMap()?.renderList?.push(particleMesh); + shadowGenerator.setDarkness(0.2); + shadowGenerator.usePoissonSampling = true; + ground.receiveShadows = true; + disc.receiveShadows = true; + + solidParticles.initParticles = () => { + let particleIndex = 0; + for (let heightIndex = 0; heightIndex < heightCount; heightIndex++) { + for (let widthIndex = 0; widthIndex < widthCount; widthIndex++) { + const particle = solidParticles.particles[particleIndex] as any; + particle.position.x = widthIndex * size + particleVars.shiftX; + particle.position.y = heightIndex * size + particleVars.shiftY; + particle.position.z = 0; + particle.uvs.x = (widthIndex * size) / particleVars.totalWidth; + particle.uvs.y = (heightIndex * size) / particleVars.totalHeight; + particle.uvs.z = ((widthIndex + 1) * size) / particleVars.totalWidth; + particle.uvs.w = ((heightIndex + 1) * size) / particleVars.totalHeight; + particle.randomFactor = 1 / (1 + Math.random()) / 10; + particleIndex++; + } + } + }; + + let exploded = false; + + solidParticles.updateParticle = (particle) => { + const activeParticle = particle as any; + + if (particleVars.justClicked) { + activeParticle.position.subtractToRef(particleVars.target, particleVars.temp); + const distance = particleVars.temp.length(); + const scale = distance < 0.001 ? 1 : particleVars.radius / distance; + particleVars.temp.normalize(); + activeParticle.velocity.x += particleVars.temp.x * scale * speed * (1 + Math.random() * 0.3); + activeParticle.velocity.y += particleVars.temp.y * scale * speed * (1 + Math.random() * 0.3); + activeParticle.velocity.z += particleVars.temp.z * scale * speed * (1 + Math.random() * 0.3); + if (activeParticle.idx === solidParticles.nbParticles - 1) { + particleVars.justClicked = false; + } + } + + if (exploded && !particleVars.justClicked) { + particleVars.minY = + ground.getHeightAtCoordinates(activeParticle.position.x, activeParticle.position.z) + size; + particleVars.loss = -restitution * activeParticle.randomFactor * 10; + + if (activeParticle.position.y < particleVars.minY) { + ground.getNormalAtCoordinatesToRef( + activeParticle.position.x, + activeParticle.position.z, + particleVars.normal + ); + particleVars.symmetry = + (2 * + (particleVars.normal.x * activeParticle.velocity.x + + particleVars.normal.y * activeParticle.velocity.y + + particleVars.normal.z * activeParticle.velocity.z)) / + particleVars.normal.lengthSquared(); + + activeParticle.velocity.x = particleVars.symmetry * particleVars.normal.x - activeParticle.velocity.x; + activeParticle.velocity.z = particleVars.symmetry * particleVars.normal.z - activeParticle.velocity.z; + activeParticle.velocity.y = particleVars.symmetry * particleVars.normal.y - activeParticle.velocity.y; + activeParticle.velocity.x *= particleVars.loss; + activeParticle.velocity.y *= particleVars.loss; + activeParticle.velocity.z *= particleVars.loss; + } + + activeParticle.velocity.y += gravity; + activeParticle.position.x += activeParticle.velocity.x; + activeParticle.position.y += activeParticle.velocity.y; + activeParticle.position.z += activeParticle.velocity.z; + activeParticle.rotation.x += activeParticle.velocity.z * activeParticle.randomFactor; + activeParticle.rotation.y += activeParticle.velocity.x * activeParticle.randomFactor; + activeParticle.rotation.z += activeParticle.velocity.y * activeParticle.randomFactor; + + if (activeParticle.position.y < particleVars.minY && Math.abs(activeParticle.velocity.y) < 0.1 - gravity) { + activeParticle.velocity.x *= friction; + activeParticle.velocity.z *= friction; + activeParticle.position.y = particleVars.minY; + activeParticle.velocity.y = 0; + } + } + return particle; + }; + + solidParticles.afterUpdateParticles = function () { + this.refreshVisibleSize(); + }; + + solidParticles.initParticles(); + solidParticles.setParticles(); + solidParticles.computeParticleColor = false; + solidParticles.computeParticleTexture = false; + + scene.onPointerDown = (_event, pickResult) => { + const faceId = pickResult.faceId; + if (faceId === -1 || faceId === undefined) { + return; + } + + const pickedParticle = solidParticles.pickedParticles[faceId]; + if (!pickedParticle) { + return; + } + + const particle = solidParticles.particles[pickedParticle.idx] as any; + exploded = true; + camera.position.subtractToRef(particle.position, particleVars.target); + particleVars.target.normalize(); + particleVars.target.scaleInPlace(radius); + particleVars.target.addInPlace(particle.position); + particleVars.justClicked = true; + }; + + scene.registerBeforeRender(() => { + solidParticles.setParticles(); + pointLight.position.copyFrom(camera.position); + }); + + return scene; +} diff --git a/src/compiledDemos/Bump/index.html b/src/compiledDemos/Bump/index.html new file mode 100644 index 000000000..388b8514e --- /dev/null +++ b/src/compiledDemos/Bump/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Bump demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Bump/main.ts b/src/compiledDemos/Bump/main.ts new file mode 100644 index 000000000..3758165a5 --- /dev/null +++ b/src/compiledDemos/Bump/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createBumpScene } from "./scene"; + +runDemo({ + createScene: createBumpScene, +}); diff --git a/src/compiledDemos/Bump/scene.ts b/src/compiledDemos/Bump/scene.ts new file mode 100644 index 000000000..1e019c17c --- /dev/null +++ b/src/compiledDemos/Bump/scene.ts @@ -0,0 +1,32 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { PointLight } from "@babylonjs/core/Lights/pointLight"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder"; +import { Scene } from "@babylonjs/core/scene"; + +export function createBumpScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("Camera", 0, 0, 10, Vector3.Zero(), scene); + new PointLight("Omni", new Vector3(20, 100, 2), scene); + + const sphere = CreateSphere("Sphere", { segments: 16, diameter: 3 }, scene); + const material = new StandardMaterial("kosh", scene); + const bumpTexture = new Texture("/Scenes/Customs/normalMap.jpg", scene); + bumpTexture.level = 1; + material.bumpTexture = bumpTexture; + material.diffuseColor = new Color3(1, 0, 0); + sphere.material = material; + + camera.setPosition(new Vector3(-5, 5, 0)); + camera.attachControl(canvas, true); + + scene.registerBeforeRender(() => { + sphere.rotation.y += 0.02; + }); + + return scene; +} diff --git a/src/compiledDemos/Fog/index.html b/src/compiledDemos/Fog/index.html new file mode 100644 index 000000000..590fa8127 --- /dev/null +++ b/src/compiledDemos/Fog/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Fog demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Fog/main.ts b/src/compiledDemos/Fog/main.ts new file mode 100644 index 000000000..fde490891 --- /dev/null +++ b/src/compiledDemos/Fog/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createFogScene } from "./scene"; + +runDemo({ + createScene: createFogScene, +}); diff --git a/src/compiledDemos/Fog/scene.ts b/src/compiledDemos/Fog/scene.ts new file mode 100644 index 000000000..8e5b39aea --- /dev/null +++ b/src/compiledDemos/Fog/scene.ts @@ -0,0 +1,48 @@ +import { FreeCamera } from "@babylonjs/core/Cameras/freeCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { PointLight } from "@babylonjs/core/Lights/pointLight"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder"; +import { Scene } from "@babylonjs/core/scene"; + +export function createFogScene(engine: Engine): Scene { + const scene = new Scene(engine); + const camera = new FreeCamera("Camera", new Vector3(0, 0, -20), scene); + new PointLight("Omni", new Vector3(20, 100, 2), scene); + + const sphere0 = CreateSphere("Sphere0", { segments: 16, diameter: 3 }, scene); + const sphere1 = CreateSphere("Sphere1", { segments: 16, diameter: 3 }, scene); + const sphere2 = CreateSphere("Sphere2", { segments: 16, diameter: 3 }, scene); + + const material0 = new StandardMaterial("mat0", scene); + material0.diffuseColor = new Color3(1, 0, 0); + sphere0.material = material0; + sphere0.position.x = -10; + + const material1 = new StandardMaterial("mat1", scene); + material1.diffuseColor = new Color3(1, 1, 0); + sphere1.material = material1; + + const material2 = new StandardMaterial("mat2", scene); + material2.diffuseColor = new Color3(1, 0, 1); + sphere2.material = material2; + sphere2.position.x = 10; + + sphere1.convertToFlatShadedMesh(); + camera.setTarget(Vector3.Zero()); + + scene.fogMode = Scene.FOGMODE_EXP; + scene.fogDensity = 0.1; + + let alpha = 0; + scene.registerBeforeRender(() => { + sphere0.position.z = 4 * Math.cos(alpha); + sphere1.position.z = 4 * Math.sin(alpha); + sphere2.position.z = sphere0.position.z; + alpha += 0.1; + }); + + return scene; +} diff --git a/src/compiledDemos/Fresnel/index.html b/src/compiledDemos/Fresnel/index.html new file mode 100644 index 000000000..bd5bfbbed --- /dev/null +++ b/src/compiledDemos/Fresnel/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Fresnel demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Fresnel/main.ts b/src/compiledDemos/Fresnel/main.ts new file mode 100644 index 000000000..611320c6b --- /dev/null +++ b/src/compiledDemos/Fresnel/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createFresnelScene } from "./scene"; + +runDemo({ + createScene: createFresnelScene, +}); diff --git a/src/compiledDemos/Fresnel/scene.ts b/src/compiledDemos/Fresnel/scene.ts new file mode 100644 index 000000000..1a70a73eb --- /dev/null +++ b/src/compiledDemos/Fresnel/scene.ts @@ -0,0 +1,153 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { LensFlare } from "@babylonjs/core/LensFlares/lensFlare"; +import { LensFlareSystem } from "@babylonjs/core/LensFlares/lensFlareSystem"; +import { PointLight } from "@babylonjs/core/Lights/pointLight"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { FresnelParameters } from "@babylonjs/core/Materials/fresnelParameters"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"; +import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder"; +import { Mesh } from "@babylonjs/core/Meshes/mesh"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/LensFlares/lensFlareSystemSceneComponent"; + +const skyboxTextureUrl = "/Scenes/Customs/skybox/TropicalSunnyDay"; +const flareTextureUrl = "/Scenes/WorldMonger/Assets/Flare.png"; + +export function createFresnelScene(engine: Engine): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("Camera", 0, 0, 10, Vector3.Zero(), scene); + const light = new PointLight("Omni0", new Vector3(-17.6, 18.8, -49.9), scene); + + camera.setPosition(new Vector3(-15, 3, 0)); + + const sphere1 = CreateSphere("Sphere1", { segments: 32, diameter: 3 }, scene); + const sphere2 = CreateSphere("Sphere2", { segments: 32, diameter: 3 }, scene); + const sphere3 = CreateSphere("Sphere3", { segments: 32, diameter: 3 }, scene); + const sphere4 = CreateSphere("Sphere4", { segments: 32, diameter: 3 }, scene); + const sphere5 = CreateSphere("Sphere5", { segments: 32, diameter: 3 }, scene); + + sphere2.position.z -= 5; + sphere3.position.z += 5; + sphere4.position.x += 5; + sphere5.position.x -= 5; + + sphere1.material = createReflectiveMaterial("kosh", scene); + sphere2.material = createBrightReflectiveMaterial(scene); + sphere3.material = createTransparentWhiteMaterial("kosh3", 0.2, scene); + sphere4.material = createOpaqueWhiteMaterial(scene); + sphere5.material = createDarkReflectiveMaterial(scene); + + markAsLensFlareBlocker(sphere2); + markAsLensFlareBlocker(sphere3); + markAsLensFlareBlocker(sphere4); + markAsLensFlareBlocker(sphere5); + + const skybox = CreateBox("skyBox", { size: 100 }, scene); + const skyboxMaterial = new StandardMaterial("skyBox", scene); + const skyboxTexture = new CubeTexture(skyboxTextureUrl, scene); + skyboxTexture.coordinatesMode = Texture.SKYBOX_MODE; + skyboxMaterial.backFaceCulling = false; + skyboxMaterial.reflectionTexture = skyboxTexture; + skyboxMaterial.diffuseColor = Color3.Black(); + skyboxMaterial.specularColor = Color3.Black(); + skyboxMaterial.disableLighting = true; + skybox.material = skyboxMaterial; + + const lensFlareSystem = new LensFlareSystem("lensFlareSystem", light, scene); + new LensFlare(0.2, 0, Color3.White(), flareTextureUrl, lensFlareSystem); + new LensFlare(0.5, 0.2, new Color3(0.5, 0.5, 1), flareTextureUrl, lensFlareSystem); + new LensFlare(0.2, 1, Color3.White(), flareTextureUrl, lensFlareSystem); + new LensFlare(0.4, 0.4, new Color3(1, 0.5, 1), flareTextureUrl, lensFlareSystem); + new LensFlare(0.1, 0.6, Color3.White(), flareTextureUrl, lensFlareSystem); + new LensFlare(0.3, 0.8, Color3.White(), flareTextureUrl, lensFlareSystem); + + scene.registerBeforeRender(() => { + camera.alpha += 0.01 * scene.getAnimationRatio(); + }); + + return scene; +} + +function createReflectiveMaterial(name: string, scene: Scene): StandardMaterial { + const material = new StandardMaterial(name, scene); + material.reflectionTexture = new CubeTexture(skyboxTextureUrl, scene); + material.diffuseColor = Color3.Black(); + material.emissiveColor = new Color3(0.5, 0.5, 0.5); + material.alpha = 0.2; + material.specularPower = 16; + material.reflectionFresnelParameters = new FresnelParameters(); + material.reflectionFresnelParameters.bias = 0.1; + material.emissiveFresnelParameters = createEmissiveFresnel(0.6, 4, Color3.White(), Color3.Black()); + material.opacityFresnelParameters = createOpacityFresnel(1, Color3.White(), Color3.Black()); + return material; +} + +function createBrightReflectiveMaterial(scene: Scene): StandardMaterial { + const material = new StandardMaterial("kosh2", scene); + material.reflectionTexture = new CubeTexture(skyboxTextureUrl, scene); + material.diffuseColor = Color3.Black(); + material.emissiveColor = new Color3(0.5, 0.5, 0.5); + material.specularPower = 32; + material.reflectionFresnelParameters = new FresnelParameters(); + material.reflectionFresnelParameters.bias = 0.1; + material.emissiveFresnelParameters = createEmissiveFresnel(0.5, 4, Color3.White(), Color3.Black()); + return material; +} + +function createTransparentWhiteMaterial(name: string, alpha: number, scene: Scene): StandardMaterial { + const material = new StandardMaterial(name, scene); + material.diffuseColor = Color3.Black(); + material.emissiveColor = Color3.White(); + material.specularPower = 64; + material.alpha = alpha; + material.emissiveFresnelParameters = createEmissiveFresnel(0.2, 1, Color3.White(), Color3.Black()); + material.opacityFresnelParameters = createOpacityFresnel(4, Color3.White(), Color3.Black()); + return material; +} + +function createOpaqueWhiteMaterial(scene: Scene): StandardMaterial { + const material = new StandardMaterial("kosh4", scene); + material.diffuseColor = Color3.Black(); + material.emissiveColor = Color3.White(); + material.specularPower = 64; + material.emissiveFresnelParameters = createEmissiveFresnel(0.5, 4, Color3.White(), Color3.Black()); + return material; +} + +function createDarkReflectiveMaterial(scene: Scene): StandardMaterial { + const material = new StandardMaterial("kosh5", scene); + const reflectionTexture = new CubeTexture(skyboxTextureUrl, scene); + reflectionTexture.level = 0.5; + material.diffuseColor = Color3.Black(); + material.reflectionTexture = reflectionTexture; + material.specularPower = 64; + material.emissiveColor = new Color3(0.2, 0.2, 0.2); + material.emissiveFresnelParameters = createEmissiveFresnel(0.4, 2, Color3.Black(), Color3.White()); + return material; +} + +function createEmissiveFresnel(bias: number, power: number, leftColor: Color3, rightColor: Color3): FresnelParameters { + const fresnel = new FresnelParameters(); + fresnel.bias = bias; + fresnel.power = power; + fresnel.leftColor = leftColor; + fresnel.rightColor = rightColor; + return fresnel; +} + +function createOpacityFresnel(power: number, leftColor: Color3, rightColor: Color3): FresnelParameters { + const fresnel = new FresnelParameters(); + fresnel.power = power; + fresnel.leftColor = leftColor; + fresnel.rightColor = rightColor; + return fresnel; +} + +function markAsLensFlareBlocker(mesh: Mesh & { isBlocker?: boolean }): void { + mesh.isBlocker = true; +} diff --git a/src/compiledDemos/GLTF/index.html b/src/compiledDemos/GLTF/index.html new file mode 100644 index 000000000..ec3f9b1f5 --- /dev/null +++ b/src/compiledDemos/GLTF/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - GLTF demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/GLTF/main.ts b/src/compiledDemos/GLTF/main.ts new file mode 100644 index 000000000..e40c9f9e2 --- /dev/null +++ b/src/compiledDemos/GLTF/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createGltfScene } from "./scene"; + +runDemo({ + createScene: createGltfScene, +}); diff --git a/src/compiledDemos/GLTF/scene.ts b/src/compiledDemos/GLTF/scene.ts new file mode 100644 index 000000000..340736c2a --- /dev/null +++ b/src/compiledDemos/GLTF/scene.ts @@ -0,0 +1,34 @@ +import type { Engine } from "@babylonjs/core/Engines/engine"; +import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"; +import { AppendSceneAsync } from "@babylonjs/core/Loading/sceneLoader"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Helpers/sceneHelpers"; +import "@babylonjs/core/Loading/loadingScreen"; +import "@babylonjs/loaders/glTF"; + +export async function createGltfScene(engine: Engine): Promise { + const scene = new Scene(engine); + scene.clearColor.set(0, 0, 0, 1); + + const light = new HemisphericLight("light", new Vector3(0, 1, 0), scene); + light.diffuse = Color3.White(); + + await AppendSceneAsync("Alien.glb", scene, { + rootUrl: "https://www.babylonjs.com/assets/", + }); + + scene.activeCamera = null; + scene.createDefaultCameraOrLight(true, true, true); + + const rootMesh = scene.meshes[0]; + if (rootMesh) { + rootMesh.rotationQuaternion = null; + scene.registerBeforeRender(() => { + rootMesh.rotation.y += 0.003 * scene.getAnimationRatio(); + }); + } + + return scene; +} diff --git a/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/index.html b/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/index.html new file mode 100644 index 000000000..7671e45d7 --- /dev/null +++ b/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Mesh primitive attribute test + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/main.ts b/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/main.ts new file mode 100644 index 000000000..49c90bcb4 --- /dev/null +++ b/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createGltfMeshPrimitiveAttributeTestScene } from "./scene"; + +runDemo({ + createScene: createGltfMeshPrimitiveAttributeTestScene, +}); diff --git a/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/scene.ts b/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/scene.ts new file mode 100644 index 000000000..dfb6c73e1 --- /dev/null +++ b/src/compiledDemos/GLTFMeshPrimitiveAttributeTest/scene.ts @@ -0,0 +1,75 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import type { Engine } from "@babylonjs/core/Engines/engine"; +import { ImportMeshAsync } from "@babylonjs/core/Loading/sceneLoader"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture"; +import { DynamicTexture } from "@babylonjs/core/Materials/Textures/dynamicTexture"; +import { CreatePlane } from "@babylonjs/core/Meshes/Builders/planeBuilder"; +import { Mesh } from "@babylonjs/core/Meshes/mesh"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Helpers/sceneHelpers"; +import "@babylonjs/core/Loading/loadingScreen"; +import "@babylonjs/loaders/glTF"; + +const rootUrl = "https://www.babylonjs.com/Assets/glTFMeshPrimitiveAttributeTest/"; + +export async function createGltfMeshPrimitiveAttributeTestScene( + engine: Engine, + canvas: HTMLCanvasElement +): Promise { + const scene = new Scene(engine); + const hdrTexture = CubeTexture.CreateFromPrefilteredData("https://www.babylonjs.com/Assets/environment.dds", scene); + hdrTexture.gammaSpace = false; + scene.createDefaultSkybox(hdrTexture, true, 100, 0.3); + + const camera = new ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2, 5, Vector3.Zero(), scene); + camera.wheelPrecision = 100; + camera.attachControl(canvas, true); + + const title = createLabel(scene, "Generated Normal Attribute"); + title.position = new Vector3(0, 1.7, 0); + + await Promise.all([ + loadModel(scene, "NoNormalsBottom.gltf", new Vector3(-1.5, 0.7, 0), "Bottom Primitive"), + loadModel(scene, "NoNormalsMiddle.gltf", new Vector3(0, 0.7, 0), "Middle Primitive"), + loadModel(scene, "NoNormalsTop.gltf", new Vector3(1.5, 0.7, 0), "Top Primitive"), + ]); + + return scene; +} + +async function loadModel(scene: Scene, name: string, center: Vector3, caption: string): Promise { + const result = await ImportMeshAsync(name, scene, { rootUrl }); + const root = new Mesh(`${name} root`, scene); + + result.meshes.forEach((mesh) => { + if (!mesh.parent) { + mesh.setParent(root); + } + }); + + root.position = center; + root.rotation = new Vector3(0, Math.PI, 0); + + const label = createLabel(scene, caption); + label.position = center.clone(); + label.position.y -= 2; +} + +function createLabel(scene: Scene, text: string): Mesh { + const dynamicTexture = new DynamicTexture("DynamicTexture", 512, scene, true); + dynamicTexture.hasAlpha = true; + dynamicTexture.drawText(text, null, null, "36px Arial", "white", "transparent"); + + const plane = CreatePlane("TextPlane", { size: 2 }, scene); + const material = new StandardMaterial("TextPlaneMaterial", scene); + material.backFaceCulling = false; + material.specularColor = Color3.Black(); + material.diffuseTexture = dynamicTexture; + material.useAlphaFromDiffuseTexture = true; + plane.material = material; + + return plane; +} diff --git a/src/compiledDemos/GLTFNormals/index.html b/src/compiledDemos/GLTFNormals/index.html new file mode 100644 index 000000000..4a177171d --- /dev/null +++ b/src/compiledDemos/GLTFNormals/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Normals Test + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/GLTFNormals/main.ts b/src/compiledDemos/GLTFNormals/main.ts new file mode 100644 index 000000000..8c81176e0 --- /dev/null +++ b/src/compiledDemos/GLTFNormals/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createGltfNormalsScene } from "./scene"; + +runDemo({ + createScene: createGltfNormalsScene, +}); diff --git a/src/compiledDemos/GLTFNormals/scene.ts b/src/compiledDemos/GLTFNormals/scene.ts new file mode 100644 index 000000000..11acd58e0 --- /dev/null +++ b/src/compiledDemos/GLTFNormals/scene.ts @@ -0,0 +1,74 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import type { Engine } from "@babylonjs/core/Engines/engine"; +import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; +import { ImportMeshAsync } from "@babylonjs/core/Loading/sceneLoader"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { PBRMaterial } from "@babylonjs/core/Materials/PBR/pbrMaterial"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { DynamicTexture } from "@babylonjs/core/Materials/Textures/dynamicTexture"; +import { CreatePlane } from "@babylonjs/core/Meshes/Builders/planeBuilder"; +import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder"; +import { Mesh } from "@babylonjs/core/Meshes/mesh"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Loading/loadingScreen"; +import "@babylonjs/loaders/glTF"; + +const rootUrl = "https://www.babylonjs.com/Assets/TestCube/"; + +export async function createGltfNormalsScene(engine: Engine, canvas: HTMLCanvasElement): Promise { + const scene = new Scene(engine); + new DirectionalLight("light", new Vector3(1, -1, 1), scene); + + const sphere = CreateSphere("sphere", { segments: 16, diameter: 0.5 }, scene); + const sphereMaterial = new PBRMaterial("sphereMaterial", scene); + sphere.position.y = 1; + sphereMaterial.metallic = 0; + sphere.material = sphereMaterial; + + const camera = new ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2, 6, Vector3.Zero(), scene); + camera.wheelPrecision = 100; + camera.attachControl(canvas, true); + + await Promise.all([ + loadModel(scene, "TestCube1.gltf", new Vector3(-2, -0.5, 0), "Normals + Tangents"), + loadModel(scene, "TestCube2.gltf", new Vector3(0, -0.5, 0), "Normals Only"), + loadModel(scene, "TestCube3.gltf", new Vector3(2, -0.5, 0), "No Normals/Tangents"), + ]); + + return scene; +} + +async function loadModel(scene: Scene, name: string, center: Vector3, caption: string): Promise { + const result = await ImportMeshAsync(name, scene, { rootUrl }); + const root = new Mesh(`${name} root`, scene); + + result.meshes.forEach((mesh) => { + if (!mesh.parent) { + mesh.setParent(root); + } + }); + + root.position = center; + root.rotation = new Vector3(Math.PI / 4, Math.PI / 4, 0); + + const label = createLabel(scene, caption); + label.position = center.clone(); + label.position.y -= 1; +} + +function createLabel(scene: Scene, text: string): Mesh { + const dynamicTexture = new DynamicTexture("DynamicTexture", 512, scene, true); + dynamicTexture.hasAlpha = true; + dynamicTexture.drawText(text, null, null, "36px Arial", "white", "transparent"); + + const plane = CreatePlane("TextPlane", { size: 2 }, scene); + const material = new StandardMaterial("TextPlaneMaterial", scene); + material.backFaceCulling = false; + material.specularColor = Color3.Black(); + material.diffuseTexture = dynamicTexture; + material.useAlphaFromDiffuseTexture = true; + plane.material = material; + + return plane; +} diff --git a/src/compiledDemos/Heightmap/index.html b/src/compiledDemos/Heightmap/index.html new file mode 100644 index 000000000..d00e71963 --- /dev/null +++ b/src/compiledDemos/Heightmap/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Heightmap demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Heightmap/main.ts b/src/compiledDemos/Heightmap/main.ts new file mode 100644 index 000000000..128386a5f --- /dev/null +++ b/src/compiledDemos/Heightmap/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createHeightmapScene } from "./scene"; + +runDemo({ + createScene: createHeightmapScene, +}); diff --git a/src/compiledDemos/Heightmap/scene.ts b/src/compiledDemos/Heightmap/scene.ts new file mode 100644 index 000000000..e13e614f6 --- /dev/null +++ b/src/compiledDemos/Heightmap/scene.ts @@ -0,0 +1,72 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { PointLight } from "@babylonjs/core/Lights/pointLight"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"; +import { CreateGroundFromHeightMap } from "@babylonjs/core/Meshes/Builders/groundBuilder"; +import { Scene } from "@babylonjs/core/scene"; + +export function createHeightmapScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("Camera", 0, 0, 10, Vector3.Zero(), scene); + new PointLight("Omni0", new Vector3(60, 100, 10), scene); + + camera.setPosition(new Vector3(-20, 20, 0)); + camera.attachControl(canvas, true); + + const skybox = CreateBox("skyBox", { size: 100 }, scene); + const skyboxMaterial = new StandardMaterial("skyBox", scene); + const skyboxTexture = new CubeTexture("/Scenes/Customs/skybox/skybox", scene); + skyboxTexture.coordinatesMode = Texture.SKYBOX_MODE; + skyboxMaterial.backFaceCulling = false; + skyboxMaterial.reflectionTexture = skyboxTexture; + skyboxMaterial.diffuseColor = Color3.Black(); + skyboxMaterial.specularColor = Color3.Black(); + skyboxMaterial.disableLighting = true; + skybox.material = skyboxMaterial; + + const ground = CreateGroundFromHeightMap( + "ground", + "./heightMap.png", + { + width: 100, + height: 100, + subdivisions: 100, + minHeight: 0, + maxHeight: 10, + updatable: false, + }, + scene + ); + + const groundMaterial = new StandardMaterial("ground", scene); + const groundTexture = new Texture("./Ground.jpg", scene); + groundTexture.uScale = 6; + groundTexture.vScale = 6; + groundMaterial.diffuseTexture = groundTexture; + groundMaterial.specularColor = Color3.Black(); + ground.position.y = -2.05; + ground.material = groundMaterial; + + scene.registerBeforeRender(() => { + if (camera.beta < 0.1) { + camera.beta = 0.1; + } else if (camera.beta > (Math.PI / 2) * 0.9) { + camera.beta = (Math.PI / 2) * 0.9; + } + + if (camera.radius > 50) { + camera.radius = 50; + } + + if (camera.radius < 5) { + camera.radius = 5; + } + }); + + return scene; +} diff --git a/src/compiledDemos/Lights/index.html b/src/compiledDemos/Lights/index.html new file mode 100644 index 000000000..1b478eb23 --- /dev/null +++ b/src/compiledDemos/Lights/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Lights demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Lights/main.ts b/src/compiledDemos/Lights/main.ts new file mode 100644 index 000000000..1dafa7975 --- /dev/null +++ b/src/compiledDemos/Lights/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createLightsScene } from "./scene"; + +runDemo({ + createScene: createLightsScene, +}); diff --git a/src/compiledDemos/Lights/scene.ts b/src/compiledDemos/Lights/scene.ts new file mode 100644 index 000000000..be6db11ea --- /dev/null +++ b/src/compiledDemos/Lights/scene.ts @@ -0,0 +1,82 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; +import { PointLight } from "@babylonjs/core/Lights/pointLight"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"; +import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder"; +import { Scene } from "@babylonjs/core/scene"; + +export function createLightsScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("Camera", 0, 0, 10, Vector3.Zero(), scene); + const light0 = new PointLight("Omni0", new Vector3(0, 10, 0), scene); + const light1 = new PointLight("Omni1", new Vector3(0, -10, 0), scene); + const light2 = new PointLight("Omni2", new Vector3(10, 0, 0), scene); + const light3 = new DirectionalLight("Dir0", new Vector3(1, -1, 0), scene); + const material = new StandardMaterial("kosh", scene); + const sphere = CreateSphere("Sphere", { segments: 16, diameter: 3 }, scene); + + camera.setPosition(new Vector3(-10, 10, 0)); + camera.attachControl(canvas, true); + light3.parent = camera; + + const lightSphere0 = CreateSphere("Sphere0", { segments: 16, diameter: 0.5 }, scene); + const lightSphere1 = CreateSphere("Sphere1", { segments: 16, diameter: 0.5 }, scene); + const lightSphere2 = CreateSphere("Sphere2", { segments: 16, diameter: 0.5 }, scene); + + lightSphere0.material = createEmissiveMaterial("red", new Color3(1, 0, 0), scene); + lightSphere1.material = createEmissiveMaterial("green", new Color3(0, 1, 0), scene); + lightSphere2.material = createEmissiveMaterial("blue", new Color3(0, 0, 1), scene); + + material.diffuseColor = Color3.White(); + sphere.material = material; + + light0.diffuse = new Color3(1, 0, 0); + light0.specular = new Color3(1, 0, 0); + light1.diffuse = new Color3(0, 1, 0); + light1.specular = new Color3(0, 1, 0); + light2.diffuse = new Color3(0, 0, 1); + light2.specular = new Color3(0, 0, 1); + light3.diffuse = Color3.White(); + light3.specular = Color3.White(); + + const skybox = CreateBox("skyBox", { size: 100 }, scene); + const skyboxMaterial = new StandardMaterial("skyBox", scene); + const skyboxTexture = new CubeTexture("/Scenes/Customs/skybox/skybox", scene); + skyboxTexture.coordinatesMode = Texture.SKYBOX_MODE; + skyboxMaterial.backFaceCulling = false; + skyboxMaterial.reflectionTexture = skyboxTexture; + skyboxMaterial.diffuseColor = Color3.Black(); + skyboxMaterial.specularColor = Color3.Black(); + skyboxMaterial.disableLighting = true; + skybox.material = skyboxMaterial; + skybox.infiniteDistance = true; + + let alpha = 0; + scene.registerBeforeRender(() => { + light0.position.set(10 * Math.sin(alpha), 0, 10 * Math.cos(alpha)); + light1.position.set(10 * Math.sin(alpha), 0, -10 * Math.cos(alpha)); + light2.position.set(10 * Math.cos(alpha), 0, 10 * Math.sin(alpha)); + + lightSphere0.position.copyFrom(light0.position); + lightSphere1.position.copyFrom(light1.position); + lightSphere2.position.copyFrom(light2.position); + + alpha += 0.01; + }); + + return scene; +} + +function createEmissiveMaterial(name: string, color: Color3, scene: Scene): StandardMaterial { + const material = new StandardMaterial(name, scene); + material.diffuseColor = Color3.Black(); + material.specularColor = Color3.Black(); + material.emissiveColor = color; + return material; +} diff --git a/src/compiledDemos/Lines/index.html b/src/compiledDemos/Lines/index.html new file mode 100644 index 000000000..0c7e0366c --- /dev/null +++ b/src/compiledDemos/Lines/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Lines demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Lines/main.ts b/src/compiledDemos/Lines/main.ts new file mode 100644 index 000000000..0afda6640 --- /dev/null +++ b/src/compiledDemos/Lines/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createLinesScene } from "./scene"; + +runDemo({ + createScene: createLinesScene, +}); diff --git a/src/compiledDemos/Lines/scene.ts b/src/compiledDemos/Lines/scene.ts new file mode 100644 index 000000000..cfce88e4d --- /dev/null +++ b/src/compiledDemos/Lines/scene.ts @@ -0,0 +1,50 @@ +import { VertexBuffer } from "@babylonjs/core/Buffers/buffer"; +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { CreateLines } from "@babylonjs/core/Meshes/Builders/linesBuilder"; +import { Scene } from "@babylonjs/core/scene"; + +export function createLinesScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("Camera", 0, 0, 10, Vector3.Zero(), scene); + camera.setPosition(new Vector3(20, 200, 400)); + camera.maxZ = 20000; + camera.lowerRadiusLimit = 150; + camera.attachControl(canvas, true); + + scene.clearColor = Color3.Black().toColor4(1); + + const points: Vector3[] = []; + let radius = 0.5; + let angle = 0; + + for (let index = 0; index < 1000; index++) { + points.push(new Vector3(radius * Math.cos(angle), 0, radius * Math.sin(angle))); + radius += 0.3; + angle += 0.1; + } + + const whirlpool = CreateLines("whirlpool", { points, updatable: true }, scene); + whirlpool.color = Color3.White(); + + const positionData = whirlpool.getVerticesData(VertexBuffer.PositionKind); + if (!positionData) { + throw new Error("Lines demo could not read whirlpool vertex positions."); + } + + const heightRange = 10; + let alpha = 0; + + scene.registerBeforeRender(() => { + for (let index = 0; index < 1000; index++) { + positionData[index * 3 + 1] = heightRange * Math.sin(alpha + index * 0.1); + } + + whirlpool.updateVerticesData(VertexBuffer.PositionKind, positionData); + alpha += 0.05 * scene.getAnimationRatio(); + }); + + return scene; +} diff --git a/src/compiledDemos/Offscreen/index.html b/src/compiledDemos/Offscreen/index.html new file mode 100644 index 000000000..77083b056 --- /dev/null +++ b/src/compiledDemos/Offscreen/index.html @@ -0,0 +1,187 @@ + + + + + + Babylon.js - Worker mode + + + +
+

Babylon.js Offscreen Canvas demo

+
+ This page demonstrates Babylon.js rendering in a worker thread. The left canvas renders on the main + thread. The right canvas renders with an OffscreenCanvas in a worker thread. The button simulates heavy + main-thread work to make the difference visible. +
+ Click + here + for more documentation. +
+ + + +
UI thread
+
Worker thread
+
Please wait loading...
+ +
+ Source + + + diff --git a/src/compiledDemos/Offscreen/main.ts b/src/compiledDemos/Offscreen/main.ts new file mode 100644 index 000000000..3db3dbc1d --- /dev/null +++ b/src/compiledDemos/Offscreen/main.ts @@ -0,0 +1,137 @@ +import { Engine } from "@babylonjs/core/Engines/engine"; +import type { Scene } from "@babylonjs/core/scene"; +import { createOffscreenScene } from "./scene"; + +declare global { + interface Window { + __babylonDemoReady?: Promise; + __babylonDemo?: { + engine: Engine; + scene?: Scene; + }; + } +} + +type WorkerMessage = + | { + type: "ready"; + } + | { + type: "error"; + message: string; + }; + +const mainCanvas = document.getElementById("renderCanvas") as HTMLCanvasElement | null; +const workerCanvas = document.getElementById("workerRenderCanvas") as HTMLCanvasElement | null; +const loading = document.getElementById("loading"); +const notSupported = document.getElementById("notSupported"); +const labelWorker = document.getElementById("labelWorker"); +const slowButton = document.getElementById("slowButton"); + +if (!mainCanvas || !workerCanvas) { + throw new Error("Offscreen demo requires renderCanvas and workerRenderCanvas elements."); +} + +function fitCanvasToDisplaySize(canvas: HTMLCanvasElement): void { + canvas.width = Math.max(1, Math.floor(canvas.clientWidth)); + canvas.height = Math.max(1, Math.floor(canvas.clientHeight)); +} + +function slowDownMainThread(): void { + let count = 0; + window.setInterval(() => { + for (let index = 0; index < 10_000_000; index++) { + count += Math.cos(Math.sin(Math.random())); + } + + if (count > Number.MAX_SAFE_INTEGER) { + count = 0; + } + }, 1); +} + +async function waitForSceneReady(scene: Scene): Promise { + await new Promise((resolve) => { + scene.executeWhenReady(resolve); + }); +} + +function startMainThreadDemo(): Promise { + const engine = new Engine(mainCanvas, true, { + preserveDrawingBuffer: true, + stencil: true, + }); + window.__babylonDemo = { engine }; + + return createOffscreenScene(engine, true).then(async (scene) => { + window.__babylonDemo = { engine, scene }; + await waitForSceneReady(scene); + mainCanvas.style.opacity = "1"; + + engine.runRenderLoop(() => { + engine.resize(); + if (scene.activeCamera) { + scene.render(); + } + }); + + window.addEventListener("resize", () => { + engine.resize(); + }); + }); +} + +function startWorkerDemo(): Promise { + if (!("OffscreenCanvas" in window) || typeof workerCanvas.transferControlToOffscreen !== "function") { + notSupported?.classList.remove("hidden"); + if (labelWorker) { + labelWorker.textContent = "OffscreenCanvas is not supported"; + } + return Promise.reject(new Error("OffscreenCanvas is not supported by this browser.")); + } + + fitCanvasToDisplaySize(workerCanvas); + const offscreenCanvas = workerCanvas.transferControlToOffscreen(); + const worker = new Worker(new URL("./worker.ts", import.meta.url), { type: "module" }); + + const ready = new Promise((resolve, reject) => { + worker.addEventListener("message", (event: MessageEvent) => { + if (event.data.type === "ready") { + workerCanvas.style.opacity = "1"; + resolve(); + } else if (event.data.type === "error") { + reject(new Error(event.data.message)); + } + }); + + worker.addEventListener("error", (event) => { + reject(new Error(event.message)); + }); + }); + + worker.postMessage( + { + type: "init", + canvas: offscreenCanvas, + width: workerCanvas.width, + height: workerCanvas.height, + }, + [offscreenCanvas] + ); + + window.addEventListener("resize", () => { + worker.postMessage({ + type: "resize", + width: Math.max(1, Math.floor(workerCanvas.clientWidth)), + height: Math.max(1, Math.floor(workerCanvas.clientHeight)), + }); + }); + + return ready; +} + +slowButton?.addEventListener("click", slowDownMainThread); + +window.__babylonDemoReady = Promise.all([startMainThreadDemo(), startWorkerDemo()]).then(() => { + loading?.classList.add("hidden"); +}); diff --git a/src/compiledDemos/Offscreen/scene.ts b/src/compiledDemos/Offscreen/scene.ts new file mode 100644 index 000000000..8e8323f15 --- /dev/null +++ b/src/compiledDemos/Offscreen/scene.ts @@ -0,0 +1,24 @@ +import { Animation } from "@babylonjs/core/Animations/animation"; +import type { Engine } from "@babylonjs/core/Engines/engine"; +import { ImportMeshAsync } from "@babylonjs/core/Loading/sceneLoader"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Helpers/sceneHelpers"; +import "@babylonjs/loaders/glTF"; + +export async function createOffscreenScene(engine: Engine, attachCameraControls: boolean): Promise { + const scene = new Scene(engine); + const result = await ImportMeshAsync("flightHelmet.glb", scene, { + rootUrl: "https://models.babylonjs.com/", + }); + + scene.createDefaultCameraOrLight(true, true, attachCameraControls); + scene.createDefaultEnvironment(); + + const rootMesh = result.meshes[0]; + if (rootMesh) { + rootMesh.rotationQuaternion = null; + Animation.CreateAndStartAnimation("turnTable", rootMesh, "rotation.y", 60, 480, 0, Math.PI * 2); + } + + return scene; +} diff --git a/src/compiledDemos/Offscreen/worker.ts b/src/compiledDemos/Offscreen/worker.ts new file mode 100644 index 000000000..6c0064af5 --- /dev/null +++ b/src/compiledDemos/Offscreen/worker.ts @@ -0,0 +1,69 @@ +import { Engine } from "@babylonjs/core/Engines/engine"; +import { createOffscreenScene } from "./scene"; + +type InitMessage = { + type: "init"; + canvas: OffscreenCanvas; + width: number; + height: number; +}; + +type ResizeMessage = { + type: "resize"; + width: number; + height: number; +}; + +type WorkerMessage = InitMessage | ResizeMessage; + +let canvas: OffscreenCanvas | undefined; +let engine: Engine | undefined; + +async function waitForSceneReady(scene: Awaited>): Promise { + await new Promise((resolve) => { + scene.executeWhenReady(resolve); + }); +} + +async function startWorkerRender(message: InitMessage): Promise { + canvas = message.canvas; + canvas.width = message.width; + canvas.height = message.height; + + engine = new Engine(canvas, true, { + preserveDrawingBuffer: true, + stencil: true, + }); + + const scene = await createOffscreenScene(engine, false); + await waitForSceneReady(scene); + + engine.runRenderLoop(() => { + engine?.resize(); + if (scene.activeCamera) { + scene.render(); + } + }); + + self.postMessage({ type: "ready" }); +} + +self.onmessage = (event: MessageEvent) => { + const message = event.data; + + if (message.type === "init") { + startWorkerRender(message).catch((error: unknown) => { + self.postMessage({ + type: "error", + message: error instanceof Error ? error.message : String(error), + }); + }); + return; + } + + if (canvas) { + canvas.width = message.width; + canvas.height = message.height; + engine?.resize(); + } +}; diff --git a/src/compiledDemos/Particles/index.html b/src/compiledDemos/Particles/index.html new file mode 100644 index 000000000..c8f662911 --- /dev/null +++ b/src/compiledDemos/Particles/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Particles demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Particles/main.ts b/src/compiledDemos/Particles/main.ts new file mode 100644 index 000000000..eb80c392a --- /dev/null +++ b/src/compiledDemos/Particles/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createParticlesScene } from "./scene"; + +runDemo({ + createScene: createParticlesScene, +}); diff --git a/src/compiledDemos/Particles/scene.ts b/src/compiledDemos/Particles/scene.ts new file mode 100644 index 000000000..df2d6253d --- /dev/null +++ b/src/compiledDemos/Particles/scene.ts @@ -0,0 +1,92 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; +import { Plane } from "@babylonjs/core/Maths/math.plane"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { MirrorTexture } from "@babylonjs/core/Materials/Textures/mirrorTexture"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"; +import { ParticleSystem } from "@babylonjs/core/Particles/particleSystem"; +import { Scene } from "@babylonjs/core/scene"; + +const particleTextureUrl = "/Scenes/WorldMonger/Assets/Flare.png"; + +export function createParticlesScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("Camera", 0, 0, 10, Vector3.Zero(), scene); + camera.setPosition(new Vector3(-5, 5, 0)); + camera.lowerBetaLimit = 0.1; + camera.upperBetaLimit = (Math.PI / 2) * 0.99; + camera.lowerRadiusLimit = 5; + camera.attachControl(canvas, true); + + const mirror = CreateBox("Mirror", { size: 1 }, scene); + mirror.scaling = new Vector3(100, 0.01, 100); + mirror.position.set(0, 0, 0); + + const mirrorMaterial = new StandardMaterial("mirror", scene); + const mirrorTexture = new MirrorTexture("mirror", 512, scene, true); + mirrorTexture.mirrorPlane = new Plane(0, -1, 0, 0); + mirrorTexture.level = 0.2; + mirrorMaterial.diffuseColor = new Color3(0.4, 0.4, 0.4); + mirrorMaterial.specularColor = Color3.Black(); + mirrorMaterial.reflectionTexture = mirrorTexture; + mirror.material = mirrorMaterial; + + const emitter0 = CreateBox("emitter0", { size: 0.1 }, scene); + emitter0.isVisible = false; + const emitter1 = CreateBox("emitter1", { size: 0.1 }, scene); + emitter1.isVisible = false; + mirrorTexture.renderList = [emitter0, emitter1]; + + const particleSystem = new ParticleSystem("particles", 4000, scene); + particleSystem.particleTexture = new Texture(particleTextureUrl, scene); + particleSystem.minAngularSpeed = -0.5; + particleSystem.maxAngularSpeed = 0.5; + particleSystem.minSize = 0.1; + particleSystem.maxSize = 0.5; + particleSystem.minLifeTime = 0.5; + particleSystem.maxLifeTime = 2; + particleSystem.minEmitPower = 0.5; + particleSystem.maxEmitPower = 4; + particleSystem.emitter = emitter0; + particleSystem.emitRate = 400; + particleSystem.blendMode = ParticleSystem.BLENDMODE_ONEONE; + particleSystem.minEmitBox = new Vector3(-0.5, 0, -0.5); + particleSystem.maxEmitBox = new Vector3(0.5, 0, 0.5); + particleSystem.direction1 = new Vector3(-1, 1, -1); + particleSystem.direction2 = new Vector3(1, 1, 1); + particleSystem.color1 = new Color4(1, 0, 0, 1); + particleSystem.color2 = new Color4(0, 1, 1, 1); + particleSystem.gravity = new Vector3(0, -2, 0); + particleSystem.start(); + + const particleSystem2 = new ParticleSystem("particles2", 4000, scene); + particleSystem2.particleTexture = new Texture(particleTextureUrl, scene); + particleSystem2.minSize = 0.1; + particleSystem2.maxSize = 0.3; + particleSystem2.minEmitPower = 1; + particleSystem2.maxEmitPower = 2; + particleSystem2.minLifeTime = 0.5; + particleSystem2.maxLifeTime = 1; + particleSystem2.emitter = emitter1; + particleSystem2.emitRate = 500; + particleSystem2.blendMode = ParticleSystem.BLENDMODE_ONEONE; + particleSystem2.minEmitBox = Vector3.Zero(); + particleSystem2.maxEmitBox = Vector3.Zero(); + particleSystem2.gravity = new Vector3(0, -0.5, 0); + particleSystem2.direction1 = Vector3.Zero(); + particleSystem2.direction2 = Vector3.Zero(); + particleSystem2.start(); + + let alpha = 0; + scene.registerBeforeRender(() => { + emitter1.position.x = 3 * Math.cos(alpha); + emitter1.position.y = 1; + emitter1.position.z = 3 * Math.sin(alpha); + alpha += 0.05 * scene.getAnimationRatio(); + }); + + return scene; +} diff --git a/src/compiledDemos/PointLightShadowMap/index.html b/src/compiledDemos/PointLightShadowMap/index.html new file mode 100644 index 000000000..3134bfc05 --- /dev/null +++ b/src/compiledDemos/PointLightShadowMap/index.html @@ -0,0 +1,96 @@ + + + + + + Babylon.js - Point light shadow map demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/PointLightShadowMap/main.ts b/src/compiledDemos/PointLightShadowMap/main.ts new file mode 100644 index 000000000..98d8a8366 --- /dev/null +++ b/src/compiledDemos/PointLightShadowMap/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createPointLightShadowMapScene } from "./scene"; + +runDemo({ + createScene: createPointLightShadowMapScene, +}); diff --git a/src/compiledDemos/PointLightShadowMap/scene.ts b/src/compiledDemos/PointLightShadowMap/scene.ts new file mode 100644 index 000000000..1ea2d8608 --- /dev/null +++ b/src/compiledDemos/PointLightShadowMap/scene.ts @@ -0,0 +1,74 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { PointLight } from "@babylonjs/core/Lights/pointLight"; +import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder"; +import { CreateTorus } from "@babylonjs/core/Meshes/Builders/torusBuilder"; +import { CreateTorusKnot } from "@babylonjs/core/Meshes/Builders/torusKnotBuilder"; +import { Mesh } from "@babylonjs/core/Meshes/mesh"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent"; + +export function createPointLightShadowMapScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("Camera", (3 * Math.PI) / 2, Math.PI / 8, 30, Vector3.Zero(), scene); + camera.lowerRadiusLimit = 5; + camera.upperRadiusLimit = 40; + camera.minZ = 0; + camera.attachControl(canvas, true); + + const light = new PointLight("light1", Vector3.Zero(), scene); + light.intensity = 0.7; + + const lightImpostor = CreateSphere("sphere1", { segments: 16, diameter: 1 }, scene); + const lightImpostorMaterial = new StandardMaterial("lightImpostor", scene); + lightImpostorMaterial.emissiveColor = Color3.Yellow(); + lightImpostorMaterial.linkEmissiveWithDiffuse = true; + lightImpostor.material = lightImpostorMaterial; + lightImpostor.parent = light; + + const knot = CreateTorusKnot( + "knot", + { radius: 2, tube: 0.2, radialSegments: 128, tubularSegments: 64, p: 4, q: 1 }, + scene + ); + const torus = CreateTorus("torus", { diameter: 8, thickness: 1, tessellation: 32 }, scene); + + const torusMaterial = new StandardMaterial("torus", scene); + torusMaterial.diffuseColor = Color3.Red(); + torus.material = torusMaterial; + + const knotMaterial = new StandardMaterial("knot", scene); + knotMaterial.diffuseColor = Color3.White(); + knot.material = knotMaterial; + + const container = CreateSphere("sphere2", { segments: 16, diameter: 50, sideOrientation: Mesh.BACKSIDE }, scene); + const containerMaterial = new StandardMaterial("container", scene); + const containerTexture = new Texture("/Scenes/Customs/grass.jpg", scene); + containerTexture.uScale = 10; + containerTexture.vScale = 10; + containerMaterial.diffuseTexture = containerTexture; + container.material = containerMaterial; + + const shadowGenerator = new ShadowGenerator(1024, light); + shadowGenerator.getShadowMap()?.renderList?.push(knot, torus); + shadowGenerator.setDarkness(0.5); + shadowGenerator.usePoissonSampling = true; + shadowGenerator.bias = 0; + + container.receiveShadows = true; + torus.receiveShadows = true; + + scene.registerBeforeRender(() => { + knot.rotation.y += 0.01; + knot.rotation.x += 0.01; + torus.rotation.y += 0.05; + torus.rotation.z += 0.03; + }); + + return scene; +} diff --git a/src/compiledDemos/Refraction/index.html b/src/compiledDemos/Refraction/index.html new file mode 100644 index 000000000..6a8ab7b71 --- /dev/null +++ b/src/compiledDemos/Refraction/index.html @@ -0,0 +1,126 @@ + + + + + + Babylon.js - Refraction demo + + + + +
+ + +
+
+ + + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Refraction/main.ts b/src/compiledDemos/Refraction/main.ts new file mode 100644 index 000000000..488e28bab --- /dev/null +++ b/src/compiledDemos/Refraction/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createRefractionScene } from "./scene"; + +runDemo({ + createScene: createRefractionScene, +}); diff --git a/src/compiledDemos/Refraction/scene.ts b/src/compiledDemos/Refraction/scene.ts new file mode 100644 index 000000000..ed7b5b577 --- /dev/null +++ b/src/compiledDemos/Refraction/scene.ts @@ -0,0 +1,108 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Matrix, Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { FresnelParameters } from "@babylonjs/core/Materials/fresnelParameters"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"; +import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder"; +import { CreateTorusKnot } from "@babylonjs/core/Meshes/Builders/torusKnotBuilder"; +import { ReflectionProbe } from "@babylonjs/core/Probes/reflectionProbe"; +import { Scene } from "@babylonjs/core/scene"; + +export function createRefractionScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("camera1", 0, 0, 10, Vector3.Zero(), scene); + camera.setPosition(new Vector3(0, 5, -10)); + camera.attachControl(canvas, true); + camera.upperBetaLimit = Math.PI / 2; + camera.lowerRadiusLimit = 4; + + const light = new HemisphericLight("light1", new Vector3(0, 1, 0), scene); + light.intensity = 0.7; + + const knot = CreateTorusKnot( + "knot", + { radius: 1, tube: 0.4, radialSegments: 128, tubularSegments: 64, p: 2, q: 3 }, + scene + ); + const yellowSphere = CreateSphere("yellowSphere", { segments: 16, diameter: 1.5 }, scene); + const greenSphere = CreateSphere("greenSphere", { segments: 16, diameter: 1.5 }, scene); + + yellowSphere.setPivotMatrix(Matrix.Translation(3, 0, 0)); + greenSphere.setPivotMatrix(Matrix.Translation(0, 0, 3)); + yellowSphere.material = createDiffuseMaterial("yellowMaterial", Color3.Yellow(), scene); + greenSphere.material = createDiffuseMaterial("greenMaterial", Color3.Green(), scene); + + const ground = CreateBox("Mirror", { size: 1 }, scene); + const groundMaterial = new StandardMaterial("ground", scene); + ground.scaling = new Vector3(100, 0.01, 100); + const groundTexture = new Texture("./refraction.jpg", scene); + groundTexture.uScale = 10; + groundTexture.vScale = 10; + groundMaterial.diffuseTexture = groundTexture; + ground.position = new Vector3(0, -2, 0); + ground.material = groundMaterial; + + const mainMaterial = new StandardMaterial("main", scene); + const probe = new ReflectionProbe("main", 512, scene); + probe.renderList?.push(yellowSphere, greenSphere, ground); + mainMaterial.diffuseColor = new Color3(1, 0.5, 0.5); + mainMaterial.refractionTexture = probe.cubeTexture; + mainMaterial.refractionFresnelParameters = new FresnelParameters(); + mainMaterial.refractionFresnelParameters.bias = 0.5; + mainMaterial.refractionFresnelParameters.power = 16; + mainMaterial.refractionFresnelParameters.leftColor = Color3.Black(); + mainMaterial.refractionFresnelParameters.rightColor = Color3.White(); + mainMaterial.refractionFresnelParameters.isEnabled = false; + mainMaterial.indexOfRefraction = 1.05; + knot.material = mainMaterial; + + scene.fogMode = Scene.FOGMODE_LINEAR; + scene.fogColor = new Color3(scene.clearColor.r, scene.clearColor.g, scene.clearColor.b); + scene.fogStart = 20; + scene.fogEnd = 50; + + wireControls(mainMaterial, scene); + + scene.registerBeforeRender(() => { + yellowSphere.rotation.y += 0.01; + greenSphere.rotation.y += 0.01; + }); + + return scene; +} + +function createDiffuseMaterial(name: string, color: Color3, scene: Scene): StandardMaterial { + const material = new StandardMaterial(name, scene); + material.diffuseColor = color; + return material; +} + +function wireControls(mainMaterial: StandardMaterial, scene: Scene): void { + const bumpToggle = document.getElementById("bumpToggle") as HTMLInputElement | null; + const fresnelToggle = document.getElementById("fresnelToggle") as HTMLInputElement | null; + const indexOfRefraction = document.getElementById("indexOfRefraction") as HTMLInputElement | null; + + bumpToggle?.addEventListener("change", () => { + if (!bumpToggle.checked) { + mainMaterial.bumpTexture?.dispose(); + mainMaterial.bumpTexture = null; + return; + } + + mainMaterial.bumpTexture = new Texture("/Scenes/Customs/normalMap.jpg", scene); + }); + + fresnelToggle?.addEventListener("change", () => { + if (mainMaterial.refractionFresnelParameters) { + mainMaterial.refractionFresnelParameters.isEnabled = fresnelToggle.checked; + } + }); + + indexOfRefraction?.addEventListener("input", () => { + mainMaterial.indexOfRefraction = Number(indexOfRefraction.value); + }); +} diff --git a/src/compiledDemos/Ribbons/index.html b/src/compiledDemos/Ribbons/index.html new file mode 100644 index 000000000..f80af69b8 --- /dev/null +++ b/src/compiledDemos/Ribbons/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Ribbons demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Ribbons/main.ts b/src/compiledDemos/Ribbons/main.ts new file mode 100644 index 000000000..6ef7210f6 --- /dev/null +++ b/src/compiledDemos/Ribbons/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createRibbonsScene } from "./scene"; + +runDemo({ + createScene: createRibbonsScene, +}); diff --git a/src/compiledDemos/Ribbons/scene.ts b/src/compiledDemos/Ribbons/scene.ts new file mode 100644 index 000000000..3f7427960 --- /dev/null +++ b/src/compiledDemos/Ribbons/scene.ts @@ -0,0 +1,209 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import type { Engine } from "@babylonjs/core/Engines/engine"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateRibbon } from "@babylonjs/core/Meshes/Builders/ribbonBuilder"; +import type { Mesh } from "@babylonjs/core/Meshes/mesh"; +import { VolumetricLightScatteringPostProcess } from "@babylonjs/core/PostProcesses/volumetricLightScatteringPostProcess"; +import { Scene } from "@babylonjs/core/scene"; + +const latitude = 50; +const longitude = 50; +const morphDelayMs = 4000; +const morphSteps = Math.floor(morphDelayMs / 80); + +function randomHalfColor(): Color3 { + return new Color3(Math.random() / 2, Math.random() / 2, Math.random() / 2); +} + +function harmonic(multipliers: number[], paths: Vector3[][]): void { + const stepLatitude = Math.PI / latitude; + const stepLongitude = (Math.PI * 2) / longitude; + let index = 0; + + for (let theta = 0; theta <= Math.PI * 2; theta += stepLongitude) { + const path: Vector3[] = []; + + for (let phi = 0; phi <= Math.PI; phi += stepLatitude) { + let radius = 0; + radius += Math.pow(Math.sin(Math.floor(multipliers[0]) * phi), Math.floor(multipliers[1])); + radius += Math.pow(Math.cos(Math.floor(multipliers[2]) * phi), Math.floor(multipliers[3])); + radius += Math.pow(Math.sin(Math.floor(multipliers[4]) * theta), Math.floor(multipliers[5])); + radius += Math.pow(Math.cos(Math.floor(multipliers[6]) * theta), Math.floor(multipliers[7])); + + path.push( + new Vector3( + radius * Math.sin(phi) * Math.cos(theta), + radius * Math.cos(phi), + radius * Math.sin(phi) * Math.sin(theta) + ) + ); + } + + paths[index] = path; + index++; + } +} + +function setNextTarget( + multipliers: number[], + paths: Vector3[][], + targetPaths: Vector3[][], + deltas: Vector3[], + colors: Color3[], + deltaColors: Color3[] +): void { + const scale = 1 / morphSteps; + + for (let index = 0; index < multipliers.length; index++) { + multipliers[index] = Math.floor(Math.random() * 10); + } + + harmonic(multipliers, targetPaths); + + let deltaIndex = 0; + for (let pathIndex = 0; pathIndex < targetPaths.length; pathIndex++) { + const targetPath = targetPaths[pathIndex]; + const path = paths[pathIndex]; + + for (let pointIndex = 0; pointIndex < targetPath.length; pointIndex++) { + deltas[deltaIndex] = targetPath[pointIndex].subtract(path[pointIndex]).scale(scale); + deltaIndex++; + } + } + + for (let colorIndex = 0; colorIndex < colors.length; colorIndex++) { + deltaColors[colorIndex] = randomHalfColor().subtract(colors[colorIndex]).scale(scale); + } +} + +function morphRibbon( + scene: Scene, + mesh: Mesh, + paths: Vector3[][], + targetPaths: Vector3[][], + deltas: Vector3[], + colors: Color3[], + deltaColors: Color3[], + counter: number +): Mesh { + if (counter === morphSteps) { + paths.length = 0; + targetPaths.forEach((path) => paths.push(path)); + return mesh; + } + + let deltaIndex = 0; + for (const path of paths) { + for (let pointIndex = 0; pointIndex < path.length; pointIndex++) { + path[pointIndex] = path[pointIndex].add(deltas[deltaIndex]); + deltaIndex++; + } + } + + const updatedMesh = CreateRibbon("ribbon", { pathArray: paths, instance: mesh }, scene); + + for (let colorIndex = 0; colorIndex < colors.length; colorIndex++) { + colors[colorIndex] = colors[colorIndex].add(deltaColors[colorIndex]); + } + + return updatedMesh; +} + +export function createRibbonsScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + scene.clearColor.set(0, 0, 0.2, 1); + + const camera = new ArcRotateCamera("Camera", Math.PI / 2 - 0.5, 0.5, 6, Vector3.Zero(), scene); + camera.wheelPrecision = 100; + camera.attachControl(canvas, true); + + const colors = [ + randomHalfColor(), + randomHalfColor(), + randomHalfColor(), + randomHalfColor(), + randomHalfColor(), + randomHalfColor(), + ]; + const material = new StandardMaterial("ribbonMaterial", scene); + material.diffuseColor = colors[0]; + material.emissiveColor = colors[1]; + material.specularColor = colors[2]; + material.specularPower = 4; + material.backFaceCulling = false; + + const multipliers = [1, 3, 1, 5, 1, 7, 1, 9]; + const paths: Vector3[][] = []; + const targetPaths: Vector3[][] = []; + const deltas: Vector3[] = []; + const deltaColors: Color3[] = []; + harmonic(multipliers, paths); + + let mesh = CreateRibbon( + "ribbon", + { pathArray: paths, closeArray: true, closePath: false, offset: 0, updatable: true }, + scene + ); + mesh.freezeNormals(); + mesh.material = material; + + const volumetricLight = new VolumetricLightScatteringPostProcess( + "vl", + 1, + camera, + mesh, + 50, + Texture.BILINEAR_SAMPLINGMODE, + engine, + false + ); + volumetricLight.exposure = 0.15; + volumetricLight.decay = 0.95; + volumetricLight.weight = 0.5; + + let morphing = true; + let counter = 0; + let rotationX = 0; + let rotationY = 0; + let deltaRotationX = Math.random() / 200; + let deltaRotationY = Math.random() / 400; + + const beginMorph = () => { + morphing = true; + counter = 0; + setNextTarget(multipliers, paths, targetPaths, deltas, colors, deltaColors); + deltaRotationX = Math.random() / 200; + deltaRotationY = Math.random() / 400; + }; + + const interval = window.setInterval(beginMorph, morphDelayMs); + beginMorph(); + + scene.registerBeforeRender(() => { + if (morphing) { + mesh = morphRibbon(scene, mesh, paths, targetPaths, deltas, colors, deltaColors, counter); + material.diffuseColor = colors[0]; + material.emissiveColor = colors[1]; + material.specularColor = colors[2]; + counter++; + + if (counter > morphSteps) { + morphing = false; + } + } + + rotationX += deltaRotationX; + rotationY -= deltaRotationY; + mesh.rotation.y = rotationY; + mesh.rotation.z = rotationX; + }); + + scene.onDisposeObservable.add(() => { + window.clearInterval(interval); + }); + + return scene; +} diff --git a/src/compiledDemos/Shadows/index.html b/src/compiledDemos/Shadows/index.html new file mode 100644 index 000000000..db902c93d --- /dev/null +++ b/src/compiledDemos/Shadows/index.html @@ -0,0 +1,96 @@ + + + + + + Babylon.js - Shadows demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/Shadows/main.ts b/src/compiledDemos/Shadows/main.ts new file mode 100644 index 000000000..d7b44c04e --- /dev/null +++ b/src/compiledDemos/Shadows/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createShadowsScene } from "./scene"; + +runDemo({ + createScene: createShadowsScene, +}); diff --git a/src/compiledDemos/Shadows/scene.ts b/src/compiledDemos/Shadows/scene.ts new file mode 100644 index 000000000..fe995f471 --- /dev/null +++ b/src/compiledDemos/Shadows/scene.ts @@ -0,0 +1,82 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { Engine } from "@babylonjs/core/Engines/engine"; +import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; +import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"; +import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder"; +import { CreateTorus } from "@babylonjs/core/Meshes/Builders/torusBuilder"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent"; + +export function createShadowsScene(engine: Engine, canvas: HTMLCanvasElement): Scene { + const scene = new Scene(engine); + const camera = new ArcRotateCamera("Camera", 0, 0, 10, Vector3.Zero(), scene); + const light = new DirectionalLight("dir01", new Vector3(0, -1, -0.2), scene); + const light2 = new DirectionalLight("dir02", new Vector3(-1, -2, -1), scene); + + light.position = new Vector3(0, 30, 0); + light2.position = new Vector3(10, 20, 10); + light.intensity = 0.6; + light2.intensity = 0.6; + + camera.setPosition(new Vector3(-20, 20, 0)); + camera.attachControl(canvas, true); + + const skybox = CreateBox("skyBox", { size: 1000 }, scene); + const skyboxMaterial = new StandardMaterial("skyBox", scene); + const skyboxTexture = new CubeTexture("/Scenes/Customs/skybox/night", scene); + skyboxTexture.coordinatesMode = Texture.SKYBOX_MODE; + skyboxMaterial.backFaceCulling = false; + skyboxMaterial.reflectionTexture = skyboxTexture; + skyboxMaterial.diffuseColor = Color3.Black(); + skyboxMaterial.specularColor = Color3.Black(); + skyboxMaterial.disableLighting = true; + skybox.material = skyboxMaterial; + + const ground = CreateGround("ground", { width: 1000, height: 1000, subdivisions: 1 }, scene); + const groundMaterial = new StandardMaterial("ground", scene); + const grassTexture = new Texture("./grass.jpg", scene); + grassTexture.uScale = 60; + grassTexture.vScale = 60; + groundMaterial.diffuseTexture = grassTexture; + groundMaterial.specularColor = Color3.Black(); + ground.position.y = -2.05; + ground.material = groundMaterial; + + const torus = CreateTorus("torus", { diameter: 8, thickness: 2, tessellation: 32 }, scene); + torus.position.y = 6; + const torus2 = CreateTorus("torus2", { diameter: 4, thickness: 1, tessellation: 32 }, scene); + torus2.position.y = 6; + + const torusMaterial = new StandardMaterial("torus", scene); + torusMaterial.diffuseColor = new Color3(0.5, 0.5, 0.5); + torusMaterial.specularColor = new Color3(0.5, 0.5, 0.5); + torus.material = torusMaterial; + torus2.material = torusMaterial; + + const shadowGenerator = new ShadowGenerator(512, light); + shadowGenerator.getShadowMap()?.renderList?.push(torus, torus2); + shadowGenerator.useExponentialShadowMap = true; + + const shadowGenerator2 = new ShadowGenerator(512, light2); + shadowGenerator2.getShadowMap()?.renderList?.push(torus, torus2); + shadowGenerator2.useExponentialShadowMap = true; + + ground.receiveShadows = true; + + scene.registerBeforeRender(() => { + camera.beta = Math.min(Math.max(camera.beta, 0.1), (Math.PI / 2) * 0.99); + camera.radius = Math.min(Math.max(camera.radius, 5), 150); + torus.rotation.x += 0.01; + torus.rotation.z += 0.02; + torus2.rotation.x += 0.02; + torus2.rotation.y += 0.01; + }); + + return scene; +} diff --git a/src/compiledDemos/VolumetricLightScattering/index.html b/src/compiledDemos/VolumetricLightScattering/index.html new file mode 100644 index 000000000..140e4712a --- /dev/null +++ b/src/compiledDemos/VolumetricLightScattering/index.html @@ -0,0 +1,105 @@ + + + + + + Babylon.js - Volumetric Light Scattering demo + + + + +
+ + +
+ Source +
+
+ + + + diff --git a/src/compiledDemos/VolumetricLightScattering/main.ts b/src/compiledDemos/VolumetricLightScattering/main.ts new file mode 100644 index 000000000..d188c147d --- /dev/null +++ b/src/compiledDemos/VolumetricLightScattering/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createVolumetricLightScatteringScene } from "./scene"; + +runDemo({ + createScene: createVolumetricLightScatteringScene, +}); diff --git a/src/compiledDemos/VolumetricLightScattering/scene.ts b/src/compiledDemos/VolumetricLightScattering/scene.ts new file mode 100644 index 000000000..d71586f59 --- /dev/null +++ b/src/compiledDemos/VolumetricLightScattering/scene.ts @@ -0,0 +1,62 @@ +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import type { Engine } from "@babylonjs/core/Engines/engine"; +import { PointLight } from "@babylonjs/core/Lights/pointLight"; +import { ImportMeshAsync } from "@babylonjs/core/Loading/sceneLoader"; +import { Color3 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { VolumetricLightScatteringPostProcess } from "@babylonjs/core/PostProcesses/volumetricLightScatteringPostProcess"; +import { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Loading/Plugins/babylonFileLoader"; + +export async function createVolumetricLightScatteringScene(engine: Engine, canvas: HTMLCanvasElement): Promise { + const scene = new Scene(engine); + scene.clearColor.set(0.02, 0.02, 0.08, 1); + + const light = new PointLight("Omni", new Vector3(20, 20, 100), scene); + const camera = new ArcRotateCamera("Camera", -0.5, 2.2, 100, Vector3.Zero(), scene); + camera.attachControl(canvas, true); + + const result = await ImportMeshAsync("skull.babylon", scene, { + rootUrl: "/Scenes/Assets/", + meshNames: "", + }); + + const skull = result.meshes[0]; + if (skull) { + camera.target = skull.position; + const material = new StandardMaterial("skull", scene); + material.emissiveColor = new Color3(0.2, 0.2, 0.2); + skull.material = material; + } + + const godRays = new VolumetricLightScatteringPostProcess( + "godrays", + 1, + camera, + null, + 100, + Texture.BILINEAR_SAMPLINGMODE, + engine, + false + ); + + if (godRays.mesh.material instanceof StandardMaterial) { + const sunTexture = new Texture("/Scenes/Assets/sun.png", scene, true, false, Texture.BILINEAR_SAMPLINGMODE); + sunTexture.hasAlpha = true; + godRays.mesh.material.diffuseTexture = sunTexture; + } + + godRays.mesh.position = new Vector3(-150, 150, 150); + godRays.mesh.scaling = new Vector3(350, 350, 350); + light.position = godRays.mesh.position; + + scene.registerBeforeRender(() => { + if (skull) { + skull.rotation.y += 0.002 * scene.getAnimationRatio(); + } + }); + + return scene; +} diff --git a/src/compiledDemos/Yeti/index.html b/src/compiledDemos/Yeti/index.html new file mode 100644 index 000000000..eba8a71e5 --- /dev/null +++ b/src/compiledDemos/Yeti/index.html @@ -0,0 +1,113 @@ + + + + + + Babylon.js - Yeti demo + + + + +
+ + +
+ Source +
+
Yeti by Patrick Ryan
+
+ + + + diff --git a/src/compiledDemos/Yeti/main.ts b/src/compiledDemos/Yeti/main.ts new file mode 100644 index 000000000..b7b367877 --- /dev/null +++ b/src/compiledDemos/Yeti/main.ts @@ -0,0 +1,6 @@ +import { runDemo } from "../shared/demoRunner"; +import { createYetiScene } from "./scene"; + +runDemo({ + createScene: createYetiScene, +}); diff --git a/src/compiledDemos/Yeti/scene.ts b/src/compiledDemos/Yeti/scene.ts new file mode 100644 index 000000000..bc21db093 --- /dev/null +++ b/src/compiledDemos/Yeti/scene.ts @@ -0,0 +1,90 @@ +import type { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import type { Engine } from "@babylonjs/core/Engines/engine"; +import { AppendSceneAsync } from "@babylonjs/core/Loading/sceneLoader"; +import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; +import { Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"; +import { ParticleSystem } from "@babylonjs/core/Particles/particleSystem"; +import { Scene } from "@babylonjs/core/scene"; +import { GLTFLoaderAnimationStartMode } from "@babylonjs/loaders/glTF"; +import "@babylonjs/core/Helpers/sceneHelpers"; +import "@babylonjs/core/Loading/loadingScreen"; + +export async function createYetiScene(engine: Engine): Promise { + const scene = new Scene(engine); + scene.clearColor = new Color4(0.02, 0.02, 0.02, 1); + scene.imageProcessingConfiguration.contrast = 1.6; + scene.imageProcessingConfiguration.exposure = 0.6; + scene.imageProcessingConfiguration.toneMappingEnabled = true; + engine.setHardwareScalingLevel(0.75); + + await AppendSceneAsync("Yeti_Idle.gltf", scene, { + rootUrl: "https://www.babylonjs.com/Assets/Yeti/glTF/", + pluginOptions: { + gltf: { + animationStartMode: GLTFLoaderAnimationStartMode.ALL, + compileMaterials: true, + }, + }, + }); + + scene.activeCamera = null; + scene.createDefaultCameraOrLight(true, true, true); + + const camera = scene.activeCamera as ArcRotateCamera | null; + if (camera) { + camera.alpha = 2; + camera.beta = 1.5; + camera.lowerRadiusLimit = 20; + camera.upperRadiusLimit = 200; + camera.useAutoRotationBehavior = true; + } + + scene.meshes.forEach((mesh) => { + mesh.alwaysSelectAsActiveMesh = true; + }); + + const helper = scene.createDefaultEnvironment({ + skyboxSize: 1000, + groundShadowLevel: 0.6, + }); + helper?.setMainColor(Color3.White()); + + const fountain = CreateBox("fountain", { size: 0.1 }, scene); + fountain.position.y = 100; + fountain.isVisible = false; + + const particleSystem = new ParticleSystem("particles", 1500, scene, undefined, true); + particleSystem.particleTexture = new Texture("https://www.babylonjs.com/Assets/Yeti/snowflake.png", scene); + particleSystem.startSpriteCellID = 0; + particleSystem.endSpriteCellID = 0; + particleSystem.spriteCellHeight = 512; + particleSystem.spriteCellWidth = 512; + particleSystem.emitter = fountain; + particleSystem.minEmitBox = new Vector3(-100, 0, -100); + particleSystem.maxEmitBox = new Vector3(100, 0, 100); + particleSystem.minSize = 0.5; + particleSystem.maxSize = 4; + particleSystem.minLifeTime = 1.2; + particleSystem.maxLifeTime = 1.6; + particleSystem.emitRate = 150; + particleSystem.blendMode = ParticleSystem.BLENDMODE_ONEONE; + particleSystem.gravity = new Vector3(0, -98, 0); + particleSystem.direction1 = new Vector3(5.5, -1, 5.5); + particleSystem.direction2 = new Vector3(-5.5, -1, -5.5); + particleSystem.minAngularSpeed = 0; + particleSystem.maxAngularSpeed = Math.PI; + particleSystem.minEmitPower = 1; + particleSystem.maxEmitPower = 10; + particleSystem.updateSpeed = 0.005; + + scene.registerBeforeRender(() => { + particleSystem.startSpriteCellID = Math.round(Math.random() * 3 - 1); + particleSystem.endSpriteCellID = particleSystem.startSpriteCellID; + }); + + particleSystem.start(); + + return scene; +} diff --git a/src/compiledDemos/manifest.json b/src/compiledDemos/manifest.json new file mode 100644 index 000000000..afb931a3a --- /dev/null +++ b/src/compiledDemos/manifest.json @@ -0,0 +1,203 @@ +{ + "demos": [ + { + "slug": "AssetsManager", + "title": "Babylon.js - Assets manager demo", + "legacyPath": "static/Demos/AssetsManager", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 80 + } + }, + { + "slug": "Boom", + "title": "Babylon.js - Boom demo", + "legacyPath": "static/Demos/Boom", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 200, + "interaction": { + "type": "clickCanvas", + "x": 0.5, + "y": 0.5, + "waitMs": 1000, + "minimumChangedSamples": 400 + } + } + }, + { + "slug": "Bump", + "title": "Babylon.js - Bump demo", + "legacyPath": "static/Demos/Bump", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 15000, + "minimumColoredSamples": 120 + } + }, + { + "slug": "Fog", + "title": "Babylon.js - Fog demo", + "legacyPath": "static/Demos/Fog", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 15000, + "minimumColoredSamples": 120 + } + }, + { + "slug": "Fresnel", + "title": "Babylon.js - Fresnel demo", + "legacyPath": "static/Demos/Fresnel", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 160 + } + }, + { + "slug": "Lines", + "title": "Babylon.js - Lines demo", + "legacyPath": "static/Demos/Lines", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 15000, + "minimumColoredSamples": 10 + } + }, + { + "slug": "Lights", + "title": "Babylon.js - Lights demo", + "legacyPath": "static/Demos/Lights", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 120 + } + }, + { + "slug": "GLTF", + "title": "Babylon.js - GLTF demo", + "legacyPath": "static/Demos/GLTF", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 60000, + "minimumColoredSamples": 160 + } + }, + { + "slug": "GLTFMeshPrimitiveAttributeTest", + "title": "Babylon.js - Mesh primitive attribute test", + "legacyPath": "static/Demos/GLTFMeshPrimitiveAttributeTest", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 30000, + "minimumColoredSamples": 100 + } + }, + { + "slug": "GLTFNormals", + "title": "Babylon.js - Normals Test", + "legacyPath": "static/Demos/GLTFNormals", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 30000, + "minimumColoredSamples": 100 + } + }, + { + "slug": "Heightmap", + "title": "Babylon.js - Heightmap demo", + "legacyPath": "static/Demos/Heightmap", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 200 + } + }, + { + "slug": "Offscreen", + "title": "Babylon.js - Worker mode", + "legacyPath": "static/Demos/Offscreen", + "sourceFiles": ["main.ts", "scene.ts", "worker.ts"], + "renderCheck": { + "timeoutMs": 45000, + "canvasSelector": "canvas", + "minimumCanvasCount": 2, + "minimumColoredSamples": 150 + } + }, + { + "slug": "PointLightShadowMap", + "title": "Babylon.js - Point light shadow map demo", + "legacyPath": "static/Demos/PointLightShadowMap", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 120 + } + }, + { + "slug": "Particles", + "title": "Babylon.js - Particles demo", + "legacyPath": "static/Demos/Particles", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 80 + } + }, + { + "slug": "Refraction", + "title": "Babylon.js - Refraction demo", + "legacyPath": "static/Demos/Refraction", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 120 + } + }, + { + "slug": "Shadows", + "title": "Babylon.js - Shadows demo", + "legacyPath": "static/Demos/Shadows", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 120 + } + }, + { + "slug": "Ribbons", + "title": "Babylon.js - Ribbons demo", + "legacyPath": "static/Demos/Ribbons", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 120 + } + }, + { + "slug": "VolumetricLightScattering", + "title": "Babylon.js - Volumetric Light Scattering demo", + "legacyPath": "static/Demos/VolumetricLightScattering", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 20000, + "minimumColoredSamples": 120 + } + }, + { + "slug": "Yeti", + "title": "Babylon.js - Yeti demo", + "legacyPath": "static/Demos/Yeti", + "sourceFiles": ["main.ts", "scene.ts"], + "renderCheck": { + "timeoutMs": 60000, + "minimumColoredSamples": 160 + } + } + ] +} diff --git a/src/compiledDemos/shared/demoRunner.ts b/src/compiledDemos/shared/demoRunner.ts new file mode 100644 index 000000000..267dce6dd --- /dev/null +++ b/src/compiledDemos/shared/demoRunner.ts @@ -0,0 +1,106 @@ +import { Engine } from "@babylonjs/core/Engines/engine"; +import type { Scene } from "@babylonjs/core/scene"; +import "@babylonjs/core/Engines/Extensions/engine.dynamicTexture"; +import "@babylonjs/core/Engines/Extensions/engine.readTexture"; +import "@babylonjs/core/Materials/standardMaterial"; +import "@babylonjs/core/Rendering/depthRendererSceneComponent"; +import "@babylonjs/core/Rendering/outlineRenderer"; + +export interface DemoDefinition { + createScene: (engine: Engine, canvas: HTMLCanvasElement) => Scene | Promise; + onReady?: (scene: Scene, engine: Engine) => void | Promise; +} + +declare global { + interface Window { + __babylonDemoReady?: Promise; + __babylonDemo?: { + engine: Engine; + scene?: Scene; + }; + } +} + +export function runDemo(definition: DemoDefinition): void { + const canvas = document.getElementById("renderCanvas") as HTMLCanvasElement | null; + const fps = document.getElementById("fps"); + const status = document.getElementById("status"); + const debugButton = document.getElementById("enableDebug"); + const fullscreenButton = document.getElementById("fullscreen"); + const notSupported = document.getElementById("notSupported"); + + if (!canvas) { + throw new Error("Compiled demo requires a canvas with id renderCanvas."); + } + + if (!Engine.isSupported()) { + notSupported?.classList.remove("hidden"); + return; + } + + const engine = new Engine(canvas, true, { + preserveDrawingBuffer: true, + stencil: true, + }); + + let scene: Scene | undefined; + window.__babylonDemo = { engine }; + + const ready = Promise.resolve(definition.createScene(engine, canvas)).then( + (createdScene) => + new Promise((resolve) => { + scene = createdScene; + window.__babylonDemo = { engine, scene }; + + if (status) { + status.textContent = "Loading..."; + } + + scene.executeWhenReady(async () => { + if (scene?.activeCamera) { + scene.activeCamera.attachControl(canvas, true); + } + + await definition.onReady?.(scene, engine); + + canvas.style.opacity = "1"; + if (status) { + status.textContent = ""; + } + resolve(); + }); + }) + ); + + window.__babylonDemoReady = ready; + + engine.runRenderLoop(() => { + if (fps) { + fps.textContent = `${engine.getFps().toFixed()} fps`; + } + + scene?.render(); + }); + + window.addEventListener("resize", () => { + engine.resize(); + }); + + fullscreenButton?.addEventListener("click", () => { + engine.switchFullscreen(true); + }); + + debugButton?.addEventListener("click", async () => { + if (!scene) { + return; + } + + await import("@babylonjs/inspector"); + + if (scene.debugLayer.isVisible()) { + scene.debugLayer.hide(); + } else { + scene.debugLayer.show(); + } + }); +} diff --git a/tsconfig.demos.json b/tsconfig.demos.json new file mode 100644 index 000000000..d0336672d --- /dev/null +++ b/tsconfig.demos.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": false, + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": [], + "allowJs": false, + "checkJs": false, + "strict": false, + "isolatedModules": true, + "noEmit": true, + "skipLibCheck": true + }, + "include": ["src/compiledDemos/**/*.ts"] +} diff --git a/vite.demos.config.mjs b/vite.demos.config.mjs new file mode 100644 index 000000000..939ac93b4 --- /dev/null +++ b/vite.demos.config.mjs @@ -0,0 +1,32 @@ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { defineConfig } from "vite"; + +const repoRoot = path.dirname(fileURLToPath(import.meta.url)); +const demosRoot = path.join(repoRoot, "src/compiledDemos"); +const manifestPath = path.join(demosRoot, "manifest.json"); +const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); + +const input = Object.fromEntries( + manifest.demos.map((demo) => [`${demo.slug}/index`, path.join(demosRoot, demo.slug, "index.html")]) +); + +export default defineConfig({ + root: demosRoot, + base: "/Demos/", + publicDir: false, + build: { + outDir: path.join(repoRoot, "build/Demos"), + emptyOutDir: false, + sourcemap: true, + rollupOptions: { + input, + output: { + entryFileNames: "_compiled/[name]-[hash].js", + chunkFileNames: "_compiled/[name]-[hash].js", + assetFileNames: "_compiled/[name]-[hash][extname]", + }, + }, + }, +});