diff --git a/bedtime-story-generator/.gitignore b/bedtime-story-generator/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/bedtime-story-generator/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/bedtime-story-generator/README.md b/bedtime-story-generator/README.md new file mode 100644 index 00000000..9f0b3c82 --- /dev/null +++ b/bedtime-story-generator/README.md @@ -0,0 +1,19 @@ +--- +title: Bedtime Story Generator +emoji: ✨ +colorFrom: yellow +colorTo: purple +sdk: static +pinned: false +license: apache-2.0 +short_description: Craft magical tales in seconds. +app_build_command: npm run build +app_file: dist/index.html +thumbnail: >- + https://cdn-uploads.huggingface.co/production/uploads/61b253b7ac5ecaae3d1efe0c/Y7gInUdGdF_53fEGfWlbJ.png +header: mini +models: +- onnx-community/gemma-3-270m-it-ONNX +--- + +Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference \ No newline at end of file diff --git a/bedtime-story-generator/eslint.config.js b/bedtime-story-generator/eslint.config.js new file mode 100644 index 00000000..f4616740 --- /dev/null +++ b/bedtime-story-generator/eslint.config.js @@ -0,0 +1,23 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import tseslint from "typescript-eslint"; +import { globalIgnores } from "eslint/config"; + +export default tseslint.config([ + globalIgnores(["dist"]), + { + files: ["**/*.{ts,tsx}"], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs["recommended-latest"], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]); diff --git a/bedtime-story-generator/index.html b/bedtime-story-generator/index.html new file mode 100644 index 00000000..0739f869 --- /dev/null +++ b/bedtime-story-generator/index.html @@ -0,0 +1,16 @@ + + + + + + + Bedtime Story Generator + + +
+ + + diff --git a/bedtime-story-generator/package-lock.json b/bedtime-story-generator/package-lock.json new file mode 100644 index 00000000..827013d0 --- /dev/null +++ b/bedtime-story-generator/package-lock.json @@ -0,0 +1,2985 @@ +{ + "name": "bedtime-story-generator", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bedtime-story-generator", + "version": "0.0.0", + "dependencies": { + "@huggingface/transformers": "^3.7.1", + "@tailwindcss/vite": "^4.1.11", + "kokoro-js": "^1.2.1", + "lucide-react": "^0.539.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "tailwindcss": "^4.1.11" + }, + "devDependencies": { + "@eslint/js": "^9.32.0", + "@types/audioworklet": "^0.0.82", + "@types/react": "^19.1.9", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^4.7.0", + "@webgpu/types": "^0.1.64", + "eslint": "^9.32.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.39.0", + "vite": "^7.1.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.8", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.33.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@huggingface/jinja": { + "version": "0.5.1", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@huggingface/transformers": { + "version": "3.7.1", + "license": "Apache-2.0", + "dependencies": { + "@huggingface/jinja": "^0.5.1", + "onnxruntime-node": "1.21.0", + "onnxruntime-web": "1.22.0-dev.20250409-89f8206ba4", + "sharp": "^0.34.1" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "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", + "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.34.3", + "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.2.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.0", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.46.2", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.11", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.11" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.11", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.11", + "@tailwindcss/oxide-darwin-arm64": "4.1.11", + "@tailwindcss/oxide-darwin-x64": "4.1.11", + "@tailwindcss/oxide-freebsd-x64": "4.1.11", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", + "@tailwindcss/oxide-linux-x64-musl": "4.1.11", + "@tailwindcss/oxide-wasm32-wasi": "4.1.11", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.11", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.11", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.11", + "@tailwindcss/oxide": "4.1.11", + "tailwindcss": "4.1.11" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/audioworklet": { + "version": "0.0.82", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.2.1", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.7", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/type-utils": "8.39.0", + "@typescript-eslint/utils": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.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.39.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "debug": "^4.3.4" + }, + "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", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.39.0", + "@typescript-eslint/types": "^8.39.0", + "debug": "^4.3.4" + }, + "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.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0" + }, + "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.39.0", + "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.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/utils": "8.39.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "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", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.39.0", + "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.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.39.0", + "@typescript-eslint/tsconfig-utils": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "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.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0" + }, + "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", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@webgpu/types": { + "version": "0.1.64", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.64.tgz", + "integrity": "sha512-84kRIAGV46LJTlJZWxShiOrNL30A+9KokD7RB3dRCIqODFjodS5tCD5yyiZ8kIReGVZSDfA3XkkwyyOIF6K62A==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/acorn": { + "version": "8.15.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "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/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/boolean": { + "version": "3.2.0", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.2", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001733", + "electron-to-chromium": "^1.5.199", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001733", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/color": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "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.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.199", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.8", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.33.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.33.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.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", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "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/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatbuffers": { + "version": "25.2.10", + "license": "Apache-2.0" + }, + "node_modules/flatted": { + "version": "3.3.3", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "license": "BSD-3-Clause", + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.7.2", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "16.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/guid-typescript": { + "version": "1.0.9", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.5.1", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kokoro-js": { + "version": "1.2.1", + "license": "Apache-2.0", + "dependencies": { + "@huggingface/transformers": "^3.5.1", + "phonemizer": "^1.2.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "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.30.1", + "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-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.539.0", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "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", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "dev": true, + "license": "MIT" + }, + "node_modules/object-keys": { + "version": "1.1.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/onnxruntime-common": { + "version": "1.21.0", + "license": "MIT" + }, + "node_modules/onnxruntime-node": { + "version": "1.21.0", + "hasInstallScript": true, + "license": "MIT", + "os": [ + "win32", + "darwin", + "linux" + ], + "dependencies": { + "global-agent": "^3.0.0", + "onnxruntime-common": "1.21.0", + "tar": "^7.0.1" + } + }, + "node_modules/onnxruntime-web": { + "version": "1.22.0-dev.20250409-89f8206ba4", + "license": "MIT", + "dependencies": { + "flatbuffers": "^25.1.24", + "guid-typescript": "^1.0.9", + "long": "^5.2.3", + "onnxruntime-common": "1.22.0-dev.20250409-89f8206ba4", + "platform": "^1.3.6", + "protobufjs": "^7.2.4" + } + }, + "node_modules/onnxruntime-web/node_modules/onnxruntime-common": { + "version": "1.22.0-dev.20250409-89f8206ba4", + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/phonemizer": { + "version": "1.2.1", + "license": "Apache-2.0" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/platform": { + "version": "1.3.6", + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.6", + "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/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/protobufjs": { + "version": "7.5.3", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.1", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "license": "BSD-3-Clause", + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/rollup": { + "version": "4.46.2", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.46.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "license": "MIT", + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sharp": { + "version": "0.34.3", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.4", + "semver": "^7.7.2" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.3", + "@img/sharp-darwin-x64": "0.34.3", + "@img/sharp-libvips-darwin-arm64": "1.2.0", + "@img/sharp-libvips-darwin-x64": "1.2.0", + "@img/sharp-libvips-linux-arm": "1.2.0", + "@img/sharp-libvips-linux-arm64": "1.2.0", + "@img/sharp-libvips-linux-ppc64": "1.2.0", + "@img/sharp-libvips-linux-s390x": "1.2.0", + "@img/sharp-libvips-linux-x64": "1.2.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0", + "@img/sharp-linux-arm": "0.34.3", + "@img/sharp-linux-arm64": "0.34.3", + "@img/sharp-linux-ppc64": "0.34.3", + "@img/sharp-linux-s390x": "0.34.3", + "@img/sharp-linux-x64": "0.34.3", + "@img/sharp-linuxmusl-arm64": "0.34.3", + "@img/sharp-linuxmusl-x64": "0.34.3", + "@img/sharp-wasm32": "0.34.3", + "@img/sharp-win32-arm64": "0.34.3", + "@img/sharp-win32-ia32": "0.34.3", + "@img/sharp-win32-x64": "0.34.3" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.7.2", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "license": "BSD-3-Clause" + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.11", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.2", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.13.1", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.39.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.39.0", + "@typescript-eslint/parser": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/utils": "8.39.0" + }, + "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", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/undici-types": { + "version": "7.10.0", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + }, + "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", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.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 + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "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/vite/node_modules/fdir": { + "version": "6.4.6", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/bedtime-story-generator/package.json b/bedtime-story-generator/package.json new file mode 100644 index 00000000..7e87f000 --- /dev/null +++ b/bedtime-story-generator/package.json @@ -0,0 +1,41 @@ +{ + "name": "bedtime-story-generator", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@huggingface/transformers": "^3.7.1", + "@tailwindcss/vite": "^4.1.11", + "kokoro-js": "^1.2.1", + "lucide-react": "^0.539.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "tailwindcss": "^4.1.11" + }, + "devDependencies": { + "@eslint/js": "^9.32.0", + "@types/audioworklet": "^0.0.82", + "@types/react": "^19.1.9", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^4.7.0", + "@webgpu/types": "^0.1.64", + "eslint": "^9.32.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.39.0", + "vite": "^7.1.0" + }, + "overrides": { + "kokoro-js": { + "@huggingface/transformers": "^3.7.1" + } + } +} diff --git a/bedtime-story-generator/public/bubble.mp3 b/bedtime-story-generator/public/bubble.mp3 new file mode 100644 index 00000000..51361694 Binary files /dev/null and b/bedtime-story-generator/public/bubble.mp3 differ diff --git a/bedtime-story-generator/public/hover.mp3 b/bedtime-story-generator/public/hover.mp3 new file mode 100644 index 00000000..d16e1a93 Binary files /dev/null and b/bedtime-story-generator/public/hover.mp3 differ diff --git a/bedtime-story-generator/public/music.mp3 b/bedtime-story-generator/public/music.mp3 new file mode 100644 index 00000000..c6af57be Binary files /dev/null and b/bedtime-story-generator/public/music.mp3 differ diff --git a/bedtime-story-generator/src/App.tsx b/bedtime-story-generator/src/App.tsx new file mode 100644 index 00000000..44436038 --- /dev/null +++ b/bedtime-story-generator/src/App.tsx @@ -0,0 +1,138 @@ +import { useState, useEffect, useRef, useCallback } from "react"; +import { Volume2, VolumeX } from "lucide-react"; + +import { useLLM } from "./hooks/useLLM"; +import { useTTS } from "./hooks/useTTS"; +import useAudioPlayer from "./hooks/useAudioPlayer"; + +import LandingScreen from "./components/LandingScreen"; +import ProgressScreen from "./components/ProgressScreen"; +import ErrorScreen from "./components/ErrorScreen"; + +import WORKLET from "./play-worklet.js?raw"; +import MainApplication from "./components/MainApplication"; + +export default function App() { + const llm = useLLM(); + const tts = useTTS(); + + const { initAudio, playPopSound, playHoverSound, toggleMusic, playMusic, isMusicPlaying, isAudioReady } = + useAudioPlayer(); + const [appState, setAppState] = useState<"landing" | "loading" | "main" | "error">( + navigator.gpu ? "landing" : "error", + ); + const [error, setError] = useState(null); + const audioWorkletNodeRef = useRef(null); + const audioContextRef = useRef(null); + + const audioGlobal = (globalThis as any).__AUDIO__ || { + ctx: null as AudioContext | null, + node: null as AudioWorkletNode | null, + loaded: false as boolean, + }; + (globalThis as any).__AUDIO__ = audioGlobal; + + const allowAutoplayRef = useRef(true); + const handleToggleMusic = useCallback(() => { + if (isMusicPlaying) allowAutoplayRef.current = false; + toggleMusic(); + }, [isMusicPlaying, toggleMusic]); + + const handleLoadApp = async () => { + setAppState("loading"); + initAudio(); + + if (audioGlobal.ctx && audioGlobal.node) { + audioContextRef.current = audioGlobal.ctx; + audioWorkletNodeRef.current = audioGlobal.node; + await audioContextRef.current?.resume(); + } else { + try { + const audioContext = new AudioContext({ sampleRate: 24000 }); + audioContextRef.current = audioContext; + await audioContext.resume(); + + if (!audioGlobal.loaded) { + const blob = new Blob([WORKLET], { type: "application/javascript" }); + const url = URL.createObjectURL(blob); + await audioContext.audioWorklet.addModule(url); + URL.revokeObjectURL(url); + audioGlobal.loaded = true; + } + + const workletNode = new AudioWorkletNode(audioContext, "buffered-audio-worklet-processor"); + workletNode.connect(audioContext.destination); + + audioWorkletNodeRef.current = workletNode; + audioGlobal.ctx = audioContext; + audioGlobal.node = workletNode; + } catch {} + } + + await audioContextRef.current?.resume(); + llm.load(); + tts.load(); + }; + + const handleLoadingComplete = useCallback(() => { + setAppState("main"); + if (allowAutoplayRef.current && !isMusicPlaying) playMusic(); + }, [playMusic, isMusicPlaying]); + + const handleRetry = () => { + setError(null); + handleLoadApp(); + }; + + useEffect(() => { + if (llm.error) { + setError(`LLM Error: ${llm.error}`); + setAppState("error"); + } else if (tts.error) { + setError(`TTS Error: ${tts.error}`); + setAppState("error"); + } else if (llm.isReady && tts.isReady) { + handleLoadingComplete(); + } + }, [llm.isReady, tts.isReady, llm.error, tts.error, handleLoadingComplete]); + + useEffect(() => { + if (!navigator.gpu) { + setError("WebGPU is not supported in this browser."); + setAppState("error"); + return; + } + return () => { + audioWorkletNodeRef.current?.disconnect(); + }; + }, []); + + return ( + <> +
+ {isAudioReady && ( + + )} + + + + +
+ + ); +} diff --git a/bedtime-story-generator/src/components/ErrorScreen.tsx b/bedtime-story-generator/src/components/ErrorScreen.tsx new file mode 100644 index 00000000..ecdf19a6 --- /dev/null +++ b/bedtime-story-generator/src/components/ErrorScreen.tsx @@ -0,0 +1,37 @@ +import type React from "react"; +import { AlertTriangle } from "lucide-react"; +import NeoButton from "./NeoButton"; + +interface ErrorScreenProps { + isVisible: boolean; + error: string | null; + onRetry: () => void; +} + +const ErrorScreen: React.FC = ({ isVisible, error, onRetry }) => { + const transitionClass = isVisible ? "opacity-100" : "opacity-0 -translate-y-10 pointer-events-none"; + return ( +
+
+

+ +
+ An Error Occurred +

+ {error && ( +
+ Details: + {error} +
+ )} + + Try Again + +
+
+ ); +}; + +export default ErrorScreen; diff --git a/bedtime-story-generator/src/components/LandingScreen.tsx b/bedtime-story-generator/src/components/LandingScreen.tsx new file mode 100644 index 00000000..b983c977 --- /dev/null +++ b/bedtime-story-generator/src/components/LandingScreen.tsx @@ -0,0 +1,49 @@ +import type React from "react"; +import { Sparkles } from "lucide-react"; +import NeoButton from "./NeoButton"; + +interface LandingScreenProps { + isVisible: boolean; + onLoad: () => void; + playHoverSound?: () => void; +} + +const LandingScreen: React.FC = ({ isVisible, onLoad, playHoverSound }) => { + const transitionClass = isVisible ? "opacity-100" : "opacity-0 -translate-y-10 pointer-events-none"; + return ( +
+
+

+ ✨ Bedtime Story ✨
+ Generator +

+

Craft magical tales in seconds.

+ + Start Creating + +
+ + +
+ ); +}; + +export default LandingScreen; diff --git a/bedtime-story-generator/src/components/MainApplication.tsx b/bedtime-story-generator/src/components/MainApplication.tsx new file mode 100644 index 00000000..8c82804f --- /dev/null +++ b/bedtime-story-generator/src/components/MainApplication.tsx @@ -0,0 +1,523 @@ +import { useReducer, useState, useRef, useEffect, useCallback } from "react"; +import type React from "react"; +import { Dices, RefreshCw } from "lucide-react"; + +import type { generateFn } from "../hooks/useLLM"; +import NeoButton from "./NeoButton"; +import OptionCard from "./OptionCard"; +import { STORY_DATA } from "../constants"; + +interface MainApplicationProps { + isVisible: boolean; + playPopSound: () => void; + playHoverSound: () => void; + generate: generateFn; + streamTTS: (onAudioChunk: (chunk: { audio: Float32Array; text?: string }) => void) => { + splitter: any; + ttsPromise: Promise; + }; + isTTSReady: boolean; + audioWorkletNode: AudioWorkletNode | null; + toggleMusic: (force?: boolean) => void; + isMusicPlaying: boolean; +} + +type StoryState = { + character: string; + setting: string; + item: string; + theme: string; + length: string; + customCharacter: string; + customSetting: string; + customItem: string; +}; + +type StoryAction = + | { type: "SET_FIELD"; field: keyof StoryState; value: string } + | { + type: "SURPRISE_ME"; + payload: Omit; + } + | { type: "RESET" }; + +const initialState: StoryState = { + character: STORY_DATA.characters[0], + setting: STORY_DATA.settings[0], + item: STORY_DATA.items[0], + theme: STORY_DATA.themes[0], + length: STORY_DATA.length[0], + customCharacter: "", + customSetting: "", + customItem: "", +}; + +const storyReducer = (state: StoryState, action: StoryAction): StoryState => { + switch (action.type) { + case "SET_FIELD": + return { ...state, [action.field]: action.value }; + case "SURPRISE_ME": + return { ...initialState, ...action.payload }; + case "RESET": + return initialState; + default: + return state; + } +}; + +const MainApplication: React.FC = ({ + isVisible, + playPopSound, + playHoverSound, + generate, + streamTTS, + isTTSReady, + audioWorkletNode, + toggleMusic, + isMusicPlaying, +}) => { + const [storyState, dispatch] = useReducer(storyReducer, initialState); + const { character, setting, item, theme, length, customCharacter, customSetting, customItem } = storyState; + + const [generatedStory, setGeneratedStory] = useState(null); + const [isShuffling, setIsShuffling] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [isSpeaking, setIsSpeaking] = useState(false); + const [previewText, setPreviewText] = useState(""); + + const storyPanelRef = useRef(null); + + const [ranges, setRanges] = useState>([]); + const rangesRef = useRef(ranges); + useEffect(() => { + rangesRef.current = ranges; + }, [ranges]); + + const pendingRef = useRef([]); + const rawSearchStartRef = useRef(0); + const normDataRef = useRef<{ norm: string; map: number[] } | null>(null); + + const [currentChunkIdx, setCurrentChunkIdx] = useState(-1); + const finishedIndexRef = useRef(-1); + const textContainerRef = useRef(null); + const chunkRefs = useRef<(HTMLSpanElement | null)[]>([]); + const resumeMusicOnPlaybackEndRef = useRef(false); + const activeSplitterRef = useRef(null); + + const displayedText = previewText || generatedStory || ""; + + const buildNorm = (text: string) => { + const map: number[] = []; + let norm = ""; + for (let i = 0; i < text.length; i++) { + const ch = text[i]; + if (/\s/.test(ch)) continue; + map.push(i); + norm += ch; + } + return { norm, map }; + }; + + const tryResolve = useCallback(() => { + const normData = normDataRef.current; + if (!normData) return; + + const { norm, map } = normData; + const nextRanges = rangesRef.current.slice(); + + const normStartFromRaw = () => { + let i = 0; + while (i < map.length && map[i] < rawSearchStartRef.current) i++; + return i; + }; + + let changed = false; + while (pendingRef.current.length) { + const nextText = pendingRef.current[0]; + const needle = nextText.replace(/\s+/g, ""); + if (!needle) { + pendingRef.current.shift(); + continue; + } + const startNormIdx = normStartFromRaw(); + const idx = norm.indexOf(needle, startNormIdx); + if (idx === -1) break; + + const startRaw = map[idx]; + const endRaw = map[idx + needle.length - 1] + 1; + + nextRanges.push({ start: startRaw, end: endRaw }); + rawSearchStartRef.current = endRaw; + pendingRef.current.shift(); + changed = true; + } + + if (changed) { + setRanges(nextRanges); + setCurrentChunkIdx((prev) => + prev === -1 ? Math.min(finishedIndexRef.current + 1, nextRanges.length - 1) : prev, + ); + } + }, []); + + useEffect(() => { + normDataRef.current = buildNorm(displayedText); + tryResolve(); + }, [displayedText, tryResolve]); + + useEffect(() => { + if (!audioWorkletNode) return; + const handler = (event: MessageEvent) => { + const data = (event as any).data; + if (!data || typeof data !== "object") return; + if (data.type === "next_chunk") { + finishedIndexRef.current += 1; + const nextIdx = finishedIndexRef.current + 1; + setCurrentChunkIdx(nextIdx < rangesRef.current.length ? nextIdx : -1); + } else if (data.type === "playback_ended") { + setIsSpeaking(false); + setCurrentChunkIdx(-1); + if (resumeMusicOnPlaybackEndRef.current) { + toggleMusic(); + } + } + }; + (audioWorkletNode.port as any).onmessage = handler; + return () => { + if (audioWorkletNode?.port) (audioWorkletNode.port as any).onmessage = null; + }; + }, [audioWorkletNode, toggleMusic]); + + useEffect(() => { + if (currentChunkIdx < 0) return; + const container = textContainerRef.current; + const el = chunkRefs.current[currentChunkIdx]; + if (!container || !el) return; + const containerRect = container.getBoundingClientRect(); + const elRect = el.getBoundingClientRect(); + const elTopInContainer = elRect.top - containerRect.top + container.scrollTop; + const targetTop = Math.max(0, elTopInContainer - container.clientHeight * 0.3); + container.scrollTo({ top: targetTop, behavior: "smooth" }); + }, [currentChunkIdx]); + + const getRandomItem = (arr: string[]): string => arr[Math.floor(Math.random() * arr.length)]; + + const handleSurpriseMe = () => { + playPopSound(); + if (isShuffling) return; + setIsShuffling(true); + dispatch({ type: "SET_FIELD", field: "customCharacter", value: "" }); + dispatch({ type: "SET_FIELD", field: "customSetting", value: "" }); + dispatch({ type: "SET_FIELD", field: "customItem", value: "" }); + + let count = 0; + const max = 15; + const interval = setInterval(() => { + dispatch({ + type: "SURPRISE_ME", + payload: { + character: getRandomItem(STORY_DATA.characters), + setting: getRandomItem(STORY_DATA.settings), + item: getRandomItem(STORY_DATA.items), + theme: getRandomItem(STORY_DATA.themes), + length: getRandomItem(STORY_DATA.length), + }, + }); + count++; + if (count >= max) { + clearInterval(interval); + setIsShuffling(false); + } + }, 60); + }; + + const generateStory = async () => { + if (!audioWorkletNode) return; + playPopSound(); + setIsLoading(true); + setPreviewText(""); + setGeneratedStory(null); + + setRanges([]); + rangesRef.current = []; + pendingRef.current = []; + rawSearchStartRef.current = 0; + setCurrentChunkIdx(-1); + finishedIndexRef.current = -1; + chunkRefs.current = []; + + const wasMusicPlaying = isMusicPlaying; + resumeMusicOnPlaybackEndRef.current = wasMusicPlaying; + + storyPanelRef.current?.scrollIntoView({ + behavior: "smooth", + block: "start", + }); + + setIsSpeaking(true); + if (wasMusicPlaying) toggleMusic(); + + const { splitter, ttsPromise } = streamTTS(({ audio, text }) => { + audioWorkletNode.port.postMessage(audio); + if (text) { + pendingRef.current.push(text); + tryResolve(); + } + }); + activeSplitterRef.current = splitter; + + const selectedCharacter = (customCharacter || character).trim(); + const selectedSetting = (customSetting || setting).trim(); + const selectedItem = (customItem || item).trim(); + + const lengthMap: Record = { + Short: "100-200 word", + Medium: "200-300 word", + Long: "300-400 word", + }; + + const userMessage = `Write a ${lengthMap[length]} ${theme.toLowerCase()} story about ${selectedCharacter} ${selectedSetting} that ${selectedItem}.`; + + try { + const llmPromise = generate( + [{ role: "user", content: userMessage }], + (token: string) => setPreviewText((prev) => prev + token), + splitter, + ); + await Promise.all([llmPromise, ttsPromise]); + } catch { + setGeneratedStory(previewText || "Sorry, the story failed to generate."); + } finally { + activeSplitterRef.current = null; + setIsLoading(false); + } + }; + + const handleReset = () => { + playPopSound(); + + activeSplitterRef.current?.close?.(); + activeSplitterRef.current = null; + audioWorkletNode?.port.postMessage("stop"); + setIsSpeaking(false); + + if (!isMusicPlaying && resumeMusicOnPlaybackEndRef.current) { + toggleMusic(); + } + resumeMusicOnPlaybackEndRef.current = false; + + setRanges([]); + rangesRef.current = []; + pendingRef.current = []; + rawSearchStartRef.current = 0; + setCurrentChunkIdx(-1); + finishedIndexRef.current = -1; + chunkRefs.current = []; + + setGeneratedStory(null); + setPreviewText(""); + + dispatch({ type: "RESET" }); + }; + + const transitionClass = isVisible ? "opacity-100" : "opacity-0 translate-y-10 pointer-events-none"; + + return ( +
+
+

Let's Make a Story!

+

+ Runs completely on your device, powered by + + Gemma 3 270M + + ! +

+
+ +
+ dispatch({ type: "SET_FIELD", field: "character", value: val })} + customValue={customCharacter} + onCustomChange={(val) => + dispatch({ + type: "SET_FIELD", + field: "customCharacter", + value: val, + }) + } + isShuffling={isShuffling} + isVisible={isVisible} + playPopSound={playPopSound} + playHoverSound={playHoverSound} + /> + dispatch({ type: "SET_FIELD", field: "setting", value: val })} + customValue={customSetting} + onCustomChange={(val) => dispatch({ type: "SET_FIELD", field: "customSetting", value: val })} + isShuffling={isShuffling} + isVisible={isVisible} + playPopSound={playPopSound} + playHoverSound={playHoverSound} + /> + dispatch({ type: "SET_FIELD", field: "item", value: val })} + customValue={customItem} + onCustomChange={(val) => dispatch({ type: "SET_FIELD", field: "customItem", value: val })} + isShuffling={isShuffling} + isVisible={isVisible} + playPopSound={playPopSound} + playHoverSound={playHoverSound} + /> +
+

4. Select a Theme

+
+ {STORY_DATA.themes.map((t) => ( + + ))} +
+
+
+

5. Story Length

+
+ {STORY_DATA.length.map((l) => ( + + ))} +
+
+
+ + Make My Story + + + + Surprise Me! + + + + Reset + +
+ + {/* Story Panel (covers screen height, no separate story page) */} +
+

Your Story

+
+ {(() => { + const displayed = displayedText; + if (!displayed) { + return "Click “Make My Story” to generate a bedtime story."; + } + const pieces: React.ReactNode[] = []; + let last = 0; + for (let i = 0; i < ranges.length; i++) { + const { start, end } = ranges[i]; + if (start > last) { + pieces.push({displayed.slice(last, start)}); + } + pieces.push( + { + chunkRefs.current[i] = el; + }} + className={i === currentChunkIdx ? "bg-yellow-200" : ""} + > + {displayed.slice(start, end)} + , + ); + last = end; + } + if (last < displayed.length) { + pieces.push({displayed.slice(last)}); + } + return pieces; + })()} +
+ {isLoading && ( +
+ {isSpeaking ? "Generating and speaking..." : "Generating..."} +
+ )} + {generatedStory && !isLoading && isTTSReady && !isSpeaking && ( +
+

Story finished.

+
+ )} +
+
+
+ ); +}; + +export default MainApplication; diff --git a/bedtime-story-generator/src/components/NeoButton.tsx b/bedtime-story-generator/src/components/NeoButton.tsx new file mode 100644 index 00000000..139d5ed1 --- /dev/null +++ b/bedtime-story-generator/src/components/NeoButton.tsx @@ -0,0 +1,47 @@ +import type React from "react"; +import { Loader } from "lucide-react"; + +interface NeoButtonProps { + children: React.ReactNode; + onClick?: (e: React.MouseEvent) => void; + playPopSound?: () => void; + playHoverSound?: () => void; + className?: string; + variant?: "primary" | "secondary" | "accent"; + isLoading?: boolean; + disabled?: boolean; +} + +const NeoButtonComponent: React.FC = ({ + children, + onClick, + playHoverSound, + className = "", + variant = "primary", + isLoading = false, + disabled = false, +}) => { + const colorClasses = { + primary: "bg-yellow-300 hover:bg-yellow-400 border-black", + secondary: "bg-pink-400 hover:bg-pink-500 border-black", + accent: "bg-cyan-400 hover:bg-cyan-500 border-black", + }; + const primaryShine = variant === "primary" ? "animate-shine" : ""; + + return ( + + ); +}; + +export default NeoButtonComponent; diff --git a/bedtime-story-generator/src/components/OptionCard.tsx b/bedtime-story-generator/src/components/OptionCard.tsx new file mode 100644 index 00000000..340ea7e3 --- /dev/null +++ b/bedtime-story-generator/src/components/OptionCard.tsx @@ -0,0 +1,88 @@ +import { useState } from "react"; +import type React from "react"; +import { Pencil } from "lucide-react"; + +interface OptionCardProps { + title: string; + options: string[]; + selected: string; + onSelect: (value: string) => void; + customValue: string; + onCustomChange: (value: string) => void; + isShuffling: boolean; + isVisible: boolean; + playPopSound: () => void; + playHoverSound: () => void; +} + +const OptionCard: React.FC = ({ + title, + options, + selected, + onSelect, + customValue, + onCustomChange, + isShuffling, + isVisible, + playPopSound, + playHoverSound, +}) => { + const [isCustom, setIsCustom] = useState(false); + + const handleSelect = (option: string) => { + playPopSound(); + setIsCustom(false); + onSelect(option); + onCustomChange(""); + }; + const handleCustomClick = () => { + playPopSound(); + setIsCustom(true); + onSelect(""); + }; + + const shuffleClass = isShuffling ? "animate-shake" : ""; + const visibilityClass = isVisible ? "animate-slide-in opacity-100" : "opacity-0 pointer-events-none"; + + return ( +
+

{title}

+
+ {options.map((option) => ( + + ))} + +
+ {isCustom && ( + ) => { + onCustomChange(e.target.value); + onSelect(""); + }} + placeholder="Enter your own option..." + className="mt-4 w-full p-3 border-2 border-black rounded-lg focus:outline-none focus:ring-2 focus:ring-yellow-400" + /> + )} +
+ ); +}; + +export default OptionCard; diff --git a/bedtime-story-generator/src/components/ProgressScreen.tsx b/bedtime-story-generator/src/components/ProgressScreen.tsx new file mode 100644 index 00000000..59c34057 --- /dev/null +++ b/bedtime-story-generator/src/components/ProgressScreen.tsx @@ -0,0 +1,25 @@ +import type React from "react"; + +interface ProgressScreenProps { + progress: number; + isVisible: boolean; +} + +const ProgressScreen: React.FC = ({ progress, isVisible }) => { + const transitionClass = isVisible ? "opacity-100" : "opacity-0 pointer-events-none"; + return ( +
+
+

Warming up the magic...

+
+
+
+

{progress.toFixed(2)}%

+
+
+ ); +}; + +export default ProgressScreen; diff --git a/bedtime-story-generator/src/constants.ts b/bedtime-story-generator/src/constants.ts new file mode 100644 index 00000000..5a1ca0e5 --- /dev/null +++ b/bedtime-story-generator/src/constants.ts @@ -0,0 +1,31 @@ +export const STORY_DATA = { + characters: [ + "a brave squirrel", + "a shy dragon", + "a clever fox", + "a sleepy astronaut", + "a grumpy gnome", + "a cheerful princess", + "a tiny robot", + "a magical cat", + ], + settings: [ + "on the moon", + "in an enchanted forest", + "under the sea", + "in a castle made of clouds", + "inside a giant's boot", + "at a wizard's school", + "on a floating island", + ], + items: [ + "discovers a map to hidden treasure", + "finds a pair of flying shoes", + "stumbles upon an invisible cloak", + "befriends a friendly ghost", + "uncovers a secret door", + "meets a wise old man", + ], + themes: ["Fairy Tale", "Silly", "Adventurous", "Magical", "Bedtime", "Funny"], + length: ["Short", "Medium", "Long"], +}; diff --git a/bedtime-story-generator/src/hooks/useAudioPlayer.ts b/bedtime-story-generator/src/hooks/useAudioPlayer.ts new file mode 100644 index 00000000..53e82575 --- /dev/null +++ b/bedtime-story-generator/src/hooks/useAudioPlayer.ts @@ -0,0 +1,86 @@ +import { useState, useRef, useCallback } from "react"; + +type AudioKeys = "pop" | "hover" | "music"; +interface AudioPlayer { + initAudio: () => boolean; + playPopSound: () => void; + playHoverSound: () => void; + toggleMusic: () => void; + playMusic: () => void; + isMusicPlaying: boolean; + isAudioReady: boolean; +} + +const useAudioPlayer = (): AudioPlayer => { + const audioRefs = useRef>({ + pop: null, + hover: null, + music: null, + }); + const [isReady, setIsReady] = useState(false); + const [isMusicPlaying, setIsMusicPlaying] = useState(false); + + const initAudio = useCallback(() => { + if (isReady) return true; + try { + audioRefs.current.pop = new Audio("/bubble.mp3"); + audioRefs.current.hover = new Audio("/hover.mp3"); + audioRefs.current.music = new Audio("/music.mp3"); + audioRefs.current.music.loop = true; + audioRefs.current.music.volume = 0.1; + setIsReady(true); + return true; + } catch { + return false; + } + }, [isReady]); + + const playMusic = useCallback(() => { + if (isReady && !isMusicPlaying) { + audioRefs.current.music?.play().catch(() => {}); + setIsMusicPlaying(true); + } + }, [isReady, isMusicPlaying]); + + const toggleMusic = useCallback( + (force?: boolean) => { + if (!isReady || !audioRefs.current.music) return; + + const shouldBePlaying = force === undefined ? !isMusicPlaying : force; + + if (shouldBePlaying === isMusicPlaying) return; + + if (shouldBePlaying) { + audioRefs.current.music?.play().catch(() => {}); + } else { + audioRefs.current.music?.pause(); + } + setIsMusicPlaying(shouldBePlaying); + }, + [isReady, isMusicPlaying], + ); + + const playPopSound = useCallback(() => { + if (!isReady || !audioRefs.current.pop) return; + audioRefs.current.pop.currentTime = 0; + audioRefs.current.pop.play().catch(() => {}); + }, [isReady]); + + const playHoverSound = useCallback(() => { + if (!isReady || !audioRefs.current.hover) return; + audioRefs.current.hover.currentTime = 0; + audioRefs.current.hover.play().catch(() => {}); + }, [isReady]); + + return { + initAudio, + playPopSound, + playHoverSound, + toggleMusic, + playMusic, + isMusicPlaying, + isAudioReady: isReady, + }; +}; + +export default useAudioPlayer; diff --git a/bedtime-story-generator/src/hooks/useLLM.ts b/bedtime-story-generator/src/hooks/useLLM.ts new file mode 100644 index 00000000..7fbff4fe --- /dev/null +++ b/bedtime-story-generator/src/hooks/useLLM.ts @@ -0,0 +1,86 @@ +import { useState, useCallback } from "react"; +import { pipeline, TextStreamer } from "@huggingface/transformers"; +import type { TextSplitterStream } from "kokoro-js"; + +interface LLMState { + isLoading: boolean; + isReady: boolean; + error: string | null; + progress: number; +} + +type LLMGlobal = { generator: any | null }; +const g = globalThis as any; +let __LLM: LLMGlobal = g.__LLM || { generator: null }; +g.__LLM = __LLM; + +export type generateFn = ( + messages: Array<{ role: string; content: string }>, + onToken?: (token: string) => void, + splitter?: TextSplitterStream, +) => Promise; + +export const useLLM = () => { + const [state, setState] = useState({ + isLoading: false, + isReady: !!__LLM.generator, + error: null, + progress: __LLM.generator ? 100 : 0, + }); + + const load = async () => { + if (__LLM.generator) return __LLM.generator; + setState((p) => ({ ...p, isLoading: true, error: null, progress: 0 })); + try { + const generator = await pipeline("text-generation", "onnx-community/gemma-3-270m-it-ONNX", { + dtype: "fp32", + device: "webgpu", + progress_callback: (item) => { + if (item.status === "progress" && item.file?.endsWith?.("onnx_data")) { + setState((p) => ({ ...p, progress: item.progress || 0 })); + } + }, + }); + __LLM.generator = generator; + setState((p) => ({ + ...p, + isLoading: false, + isReady: true, + progress: 100, + })); + return generator; + } catch (error) { + setState((p) => ({ + ...p, + isLoading: false, + error: error instanceof Error ? error.message : "Failed to load model", + })); + throw error; + } + }; + + const generate: generateFn = useCallback(async (messages, onToken, splitter) => { + const generator = __LLM.generator; + if (!generator) throw new Error("Model not loaded. Call load() first."); + const streamer = new TextStreamer(generator.tokenizer, { + skip_prompt: true, + skip_special_tokens: true, + callback_function: (token: string) => { + onToken?.(token); + splitter?.push(token); + }, + }); + await generator(messages, { + max_new_tokens: 1024, + do_sample: false, + streamer, + }); + splitter?.close(); + }, []); + + return { + ...state, + load, + generate, + }; +}; diff --git a/bedtime-story-generator/src/hooks/useTTS.ts b/bedtime-story-generator/src/hooks/useTTS.ts new file mode 100644 index 00000000..6181f12f --- /dev/null +++ b/bedtime-story-generator/src/hooks/useTTS.ts @@ -0,0 +1,75 @@ +import { useState, useCallback } from "react"; +import { KokoroTTS, TextSplitterStream } from "kokoro-js"; + +interface TTSState { + isLoading: boolean; + isReady: boolean; + error: string | null; + progress: number; +} + +type TTSGlobal = { model: KokoroTTS | null }; +const g = globalThis as any; +let __TTS: TTSGlobal = g.__TTS || { model: null }; +g.__TTS = __TTS; + +export const useTTS = () => { + const [state, setState] = useState({ + isLoading: false, + isReady: !!__TTS.model, + error: null, + progress: __TTS.model ? 100 : 0, + }); + + const load = async () => { + if (__TTS.model) return __TTS.model; + setState((p) => ({ ...p, isLoading: true, error: null, progress: 0 })); + try { + const tts = await KokoroTTS.from_pretrained("onnx-community/Kokoro-82M-v1.0-ONNX", { + dtype: "fp32", + device: "webgpu", + progress_callback: (item) => { + if (item.status === "progress" && item.file?.endsWith?.("onnx")) { + setState((p) => ({ ...p, progress: item.progress || 0 })); + } + }, + }); + __TTS.model = tts; + setState((p) => ({ + ...p, + isLoading: false, + isReady: true, + progress: 100, + })); + return tts; + } catch (error) { + setState((p) => ({ + ...p, + isLoading: false, + error: error instanceof Error ? error.message : "Failed to load TTS model", + })); + throw error; + } + }; + + const stream = useCallback((onAudioChunk: (chunk: { audio: Float32Array; text?: string }) => void) => { + const tts = __TTS.model as KokoroTTS | null; + if (!tts) throw new Error("TTS model not loaded. Call load() first."); + const splitter = new TextSplitterStream(); + const ttsStream = tts.stream(splitter); + const ttsPromise = (async () => { + for await (const chunk of ttsStream) { + if (chunk.audio) { + onAudioChunk({ audio: chunk.audio.audio, text: chunk.text }); + } + } + })(); + return { splitter, ttsPromise }; + }, []); + + return { + ...state, + load, + stream, + }; +}; diff --git a/bedtime-story-generator/src/index.css b/bedtime-story-generator/src/index.css new file mode 100644 index 00000000..73475a31 --- /dev/null +++ b/bedtime-story-generator/src/index.css @@ -0,0 +1,88 @@ +@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;900&display=swap"); +@import "tailwindcss"; + +body { + font-family: "Nunito", sans-serif; +} +.bg-pattern { + background-color: #fef3c7; + background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23fbbf24' fill-opacity='0.2'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); +} +@keyframes shine { + 0% { + transform: translateX(-100%) skewX(-20deg); + } + 100% { + transform: translateX(200%) skewX(-20deg); + } +} +.animate-shine { + background: linear-gradient( + 90deg, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0.4) 50%, + rgba(255, 255, 255, 0) 100% + ); + animation: shine 4s infinite; +} +@keyframes shake { + 0%, + 100% { + transform: translateX(0); + } + 10%, + 30%, + 50%, + 70%, + 90% { + transform: translateX(-3px); + } + 20%, + 40%, + 60%, + 80% { + transform: translateX(3px); + } +} +.animate-shake { + animation: shake 0.3s linear infinite; +} +@keyframes slide-in { + from { + transform: translateY(20px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} +.animate-slide-in { + animation: slide-in 0.5s ease-out forwards; +} +@keyframes pulse-grow { + 0%, + 100% { + transform: scale(1); + } + 50% { + transform: scale(1.05); + } +} +.animate-pulse-grow { + animation: pulse-grow 3s infinite; +} +@keyframes sway { + 0% { + transform: rotate(-1deg); + } + 50% { + transform: rotate(1deg); + } + 100% { + transform: rotate(-1deg); + } +} +.animate-sway { + animation: sway 8s ease-in-out infinite; +} diff --git a/bedtime-story-generator/src/main.tsx b/bedtime-story-generator/src/main.tsx new file mode 100644 index 00000000..eff7ccc6 --- /dev/null +++ b/bedtime-story-generator/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./index.css"; +import App from "./App.tsx"; + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/bedtime-story-generator/src/play-worklet.js b/bedtime-story-generator/src/play-worklet.js new file mode 100644 index 00000000..07c64e2b --- /dev/null +++ b/bedtime-story-generator/src/play-worklet.js @@ -0,0 +1,63 @@ +class BufferedAudioWorkletProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.bufferQueue = []; + this.currentChunkOffset = 0; + this.hadData = false; + + this.port.onmessage = (event) => { + const data = event.data; + if (data instanceof Float32Array) { + this.hadData = true; + this.bufferQueue.push(data); + } else if (data === "stop") { + this.bufferQueue = []; + this.currentChunkOffset = 0; + } + }; + } + + process(inputs, outputs) { + const channel = outputs[0][0]; + if (!channel) return true; + + const numSamples = channel.length; + let outputIndex = 0; + + if (this.hadData && this.bufferQueue.length === 0) { + this.port.postMessage({ type: "playback_ended" }); + this.hadData = false; + } + + while (outputIndex < numSamples) { + if (this.bufferQueue.length > 0) { + const currentChunk = this.bufferQueue[0]; + const remainingSamples = currentChunk.length - this.currentChunkOffset; + const samplesToCopy = Math.min(remainingSamples, numSamples - outputIndex); + + channel.set( + currentChunk.subarray(this.currentChunkOffset, this.currentChunkOffset + samplesToCopy), + outputIndex, + ); + + this.currentChunkOffset += samplesToCopy; + outputIndex += samplesToCopy; + + // Remove the chunk if fully consumed. + if (this.currentChunkOffset >= currentChunk.length) { + // current chunk finished; advance and signal UI to move highlight + this.bufferQueue.shift(); + this.currentChunkOffset = 0; + this.port.postMessage({ type: "next_chunk" }); + } + } else { + // If no data is available, fill the rest of the buffer with silence. + channel.fill(0, outputIndex); + outputIndex = numSamples; + } + } + return true; + } +} + +registerProcessor("buffered-audio-worklet-processor", BufferedAudioWorkletProcessor); diff --git a/bedtime-story-generator/src/vite-env.d.ts b/bedtime-story-generator/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/bedtime-story-generator/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/bedtime-story-generator/tsconfig.app.json b/bedtime-story-generator/tsconfig.app.json new file mode 100644 index 00000000..d5ff3f90 --- /dev/null +++ b/bedtime-story-generator/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + "types": ["@webgpu/types"] + }, + "include": ["src"] +} diff --git a/bedtime-story-generator/tsconfig.json b/bedtime-story-generator/tsconfig.json new file mode 100644 index 00000000..d32ff682 --- /dev/null +++ b/bedtime-story-generator/tsconfig.json @@ -0,0 +1,4 @@ +{ + "files": [], + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] +} diff --git a/bedtime-story-generator/tsconfig.node.json b/bedtime-story-generator/tsconfig.node.json new file mode 100644 index 00000000..f85a3990 --- /dev/null +++ b/bedtime-story-generator/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/bedtime-story-generator/vite.config.ts b/bedtime-story-generator/vite.config.ts new file mode 100644 index 00000000..d4a9bf6f --- /dev/null +++ b/bedtime-story-generator/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], + + resolve: { + // Only bundle a single instance of Transformers.js + // (shared by `@huggingface/transformers` and `kokoro-js`) + dedupe: ["@huggingface/transformers"], + }, +});