diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 8dadaa612..bbaf538de 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -5,10 +5,6 @@ on: branches: - main -env: - GITEA_MAIL: ${{ secrets.GITEA_MAIL }} - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - jobs: build-deploy: runs-on: ubuntu-latest @@ -16,26 +12,25 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 21 + node-version: 25 ref: main submodules: true fetch-depth: 0 - run: | - yarn install - rm -rf dist/vrma - git clone https://${GITEA_TOKEN}@git.syui.ai/ai/vrma dist/vrma - rm -rf dist/vrma/.git + cd atmosphere/ + npm i - name: Build env: TZ: "Asia/Tokyo" run: | - yarn build + cd atmosphere/ + npm run build - name: Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./dist + publish_dir: ./atmosphere/dist user_name: 'ai[bot]' user_email: '138105980+yui-syui-ai[bot]@users.noreply.github.com' diff --git a/README.md b/README.md index 84db76ca5..7929e73df 100644 --- a/README.md +++ b/README.md @@ -47,4 +47,11 @@ $ yarn install $ yarn dev ``` +## theatre + +```sh +$ cd theatre +$ npm install +$ npm run dev +``` diff --git a/atmosphere/README.md b/atmosphere/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/atmosphere/index.html b/atmosphere/index.html new file mode 100644 index 000000000..a3d638f59 --- /dev/null +++ b/atmosphere/index.html @@ -0,0 +1,15 @@ + + + + + + VRM Animation Preview + + + +
+ + + diff --git a/atmosphere/package.json b/atmosphere/package.json new file mode 100644 index 000000000..1aefc5572 --- /dev/null +++ b/atmosphere/package.json @@ -0,0 +1,26 @@ +{ + "name": "react-vrm-atmosphere", + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@pixiv/three-vrm": "^3.4.4", + "@pixiv/three-vrm-animation": "^3.4.4", + "@react-three/drei": "^10.7.7", + "@react-three/fiber": "^9.4.0", + "@react-three/postprocessing": "^3.0.4", + "@takram/three-atmosphere": "^0.15.1", + "@takram/three-clouds": "^0.5.2", + "react": "^19.0.0-rc.1", + "react-dom": "^19.0.0-rc.1", + "three": "^0.181.2" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.2.1", + "vite": "^5.1.0" + } +} diff --git a/atmosphere/public/ai.vrm b/atmosphere/public/ai.vrm new file mode 100644 index 000000000..d8fb84c00 Binary files /dev/null and b/atmosphere/public/ai.vrm differ diff --git a/min-react-2/public/sky.vrma b/atmosphere/public/fly.vrma similarity index 100% rename from min-react-2/public/sky.vrma rename to atmosphere/public/fly.vrma diff --git a/atmosphere/public/idle.vrma b/atmosphere/public/idle.vrma new file mode 100644 index 000000000..fbb400bb5 Binary files /dev/null and b/atmosphere/public/idle.vrma differ diff --git a/min-react-2/public/run.vrma b/atmosphere/public/run.vrma similarity index 100% rename from min-react-2/public/run.vrma rename to atmosphere/public/run.vrma diff --git a/atmosphere/src/App.jsx b/atmosphere/src/App.jsx new file mode 100644 index 000000000..fc833c678 --- /dev/null +++ b/atmosphere/src/App.jsx @@ -0,0 +1,276 @@ +import React, { useEffect, useRef, Suspense, useState } from 'react'; +import { Canvas, useFrame, useLoader, useThree } from '@react-three/fiber'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; +import { VRMLoaderPlugin, VRMUtils } from '@pixiv/three-vrm'; +import { createVRMAnimationClip, VRMAnimationLoaderPlugin } from '@pixiv/three-vrm-animation'; +import { AnimationMixer, Vector3, MathUtils } from 'three'; +import { OrbitControls, PerspectiveCamera } from '@react-three/drei'; +import { EffectComposer, ToneMapping } from '@react-three/postprocessing'; +import { ToneMappingMode } from 'postprocessing'; +import * as THREE from 'three'; + +// Takram Libraries +import { AerialPerspective, Atmosphere } from '@takram/three-atmosphere/r3f'; +import { Clouds, CloudLayer } from '@takram/three-clouds/r3f'; + +const BASE_URL = import.meta.env.BASE_URL; + +const VRM_URL = `${BASE_URL}ai.vrm`; +const VRMA_URL = `${BASE_URL}fly.vrma`; +const EARTH_RADIUS = 6378137; + +// 天気変更の間隔 (ms) - 5分 +const WEATHER_INTERVAL = 5 * 60 * 1000; + +// 時間の進行速度 (倍率) +const TIME_SCALE = 100; + +// 初期時刻: 正午 (12:00) +const INITIAL_DATE = new Date('2024-06-21T12:00:00'); + +// --- Weather Presets (天候設定) --- +const WEATHER_PRESETS = [ + { + name: 'Clear (快晴)', + coverage: 0.1, + layers: [ + { channel: 'r', altitude: 1500, height: 500, densityScale: 0.0 }, + { channel: 'g', altitude: 2500, height: 800, densityScale: 0.0 }, + { channel: 'b', altitude: 7500, height: 500, densityScale: 0.1 }, + ] + }, + { + name: 'Sunny (晴れ)', + coverage: 0.4, + layers: [ + { channel: 'r', altitude: 1500, height: 500, densityScale: 0.4 }, + { channel: 'g', altitude: 2500, height: 800, densityScale: 0.0 }, + { channel: 'b', altitude: 7500, height: 500, densityScale: 0.2 }, + ] + }, + { + name: 'Cloudy (曇り)', + coverage: 0.75, + layers: [ + { channel: 'r', altitude: 1500, height: 500, densityScale: 0.6 }, + { channel: 'g', altitude: 2000, height: 1000, densityScale: 0.5 }, + { channel: 'b', altitude: 7500, height: 500, densityScale: 0.0 }, + ] + } +]; + +// --------------------------------------------------------- +// Scene Components (Inside Canvas) +// --------------------------------------------------------- + +// Canvasの内側で動作するメインシーンコンポーネント +function AtmosphereScene() { + const { gl } = useThree(); + const sunRef = useRef(); + const atmosphereRef = useRef(); + const dateRef = useRef(new Date(INITIAL_DATE)); + const [weather, setWeather] = useState(WEATHER_PRESETS[1]); + + // 1. 露出設定 (Canvas内なのでuseThreeが使える) + useEffect(() => { + gl.toneMapping = THREE.NoToneMapping; + gl.toneMappingExposure = 10.0; + }, [gl]); + + // 2. 天候の定期変更 + useEffect(() => { + const interval = setInterval(() => { + setWeather(prev => { + const others = WEATHER_PRESETS.filter(w => w.name !== prev.name); + const next = others[Math.floor(Math.random() * others.length)]; + console.log(`[Weather] Changing to: ${next.name}`); + return next; + }); + }, WEATHER_INTERVAL); + return () => clearInterval(interval); + }, []); + + // 3. 時間進行と太陽移動 (Canvas内なのでuseFrameが使える) + useFrame((state, delta) => { + // 時間を進める + const currentDate = dateRef.current; + const elapsedMs = delta * TIME_SCALE * 1000; + currentDate.setTime(currentDate.getTime() + elapsedMs); + + // Atmosphere更新 + if (atmosphereRef.current) { + atmosphereRef.current.updateByDate(currentDate); + } + + // 太陽移動 + if (sunRef.current) { + const hours = currentDate.getHours() + currentDate.getMinutes() / 60 + currentDate.getSeconds() / 3600; + const sunAngle = MathUtils.mapLinear(hours, 6, 18, 0, Math.PI); + const sunX = -Math.cos(sunAngle); + const sunY = Math.sin(sunAngle); + + if (hours < 6 || hours > 18) { + sunRef.current.position.set(0, -1, 0); + sunRef.current.intensity = 0.0; + } else { + sunRef.current.position.set(sunX, sunY, 0.2); + sunRef.current.intensity = MathUtils.lerp(0.5, 3.0, sunY); + } + } + }); + + return ( + <> + + + + + + + + {weather.layers.map((layer, index) => ( + + ))} + + + + + + + + + ); +} + +function FlyOverCamera() { + useFrame((state) => { + const t = state.clock.getElapsedTime() * 0.05; + const altitude = 2000; + const radius = 5000; + + state.camera.position.x = Math.sin(t) * radius; + state.camera.position.z = Math.cos(t) * radius; + state.camera.position.y = EARTH_RADIUS + altitude; + + const lookAtTarget = new Vector3( + Math.sin(t + 0.1) * radius, + EARTH_RADIUS + altitude, + Math.cos(t + 0.1) * radius + ); + state.camera.lookAt(lookAtTarget); + }); + return null; +} + +// --------------------------------------------------------- +// Scene 2: Avatar +// --------------------------------------------------------- +function VrmCharacter() { + const mixerRef = useRef(null); + const vrmRef = useRef(null); + + const gltf = useLoader(GLTFLoader, VRM_URL, (loader) => { + loader.register((parser) => new VRMLoaderPlugin(parser)); + }); + + const vrma = useLoader(GLTFLoader, VRMA_URL, (loader) => { + loader.register((parser) => new VRMAnimationLoaderPlugin(parser)); + }); + + useEffect(() => { + const vrm = gltf.userData.vrm; + vrmRef.current = vrm; + VRMUtils.removeUnnecessaryJoints(vrm.scene); + vrm.humanoid.resetPose(); + vrm.scene.rotation.y = Math.PI; + + if (vrma.userData.vrmAnimations?.[0]) { + const clip = createVRMAnimationClip(vrma.userData.vrmAnimations[0], vrm); + mixerRef.current = new AnimationMixer(vrm.scene); + mixerRef.current.clipAction(clip).play(); + } + }, [gltf, vrma]); + + useFrame((state, delta) => { + mixerRef.current?.update(delta); + vrmRef.current?.update(delta); + }); + + return ; +} + +function AvatarLayer() { + return ( + + + + + + + + + + + + + + ); +} + +// --------------------------------------------------------- +// Main App +// --------------------------------------------------------- +function AtmosphereLayer() { + // Canvasが親となり、その中にロジックコンポーネント(AtmosphereScene)を入れる + return ( + + + + ); +} + +export default function App() { + const layerStyle = { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', + }; + + return ( +
+ + {/* Layer 0: Atmosphere */} +
+ +
+ + {/* Layer 1: Avatar */} +
+
+ +
+
+ +
+ ); +} diff --git a/atmosphere/src/main.jsx b/atmosphere/src/main.jsx new file mode 100644 index 000000000..1943cc824 --- /dev/null +++ b/atmosphere/src/main.jsx @@ -0,0 +1,9 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App' + +ReactDOM.createRoot(document.getElementById('root')).render( + + + , +) diff --git a/atmosphere/vite.config.ts b/atmosphere/vite.config.ts new file mode 100644 index 000000000..84bddafac --- /dev/null +++ b/atmosphere/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + base: '/', +}) diff --git a/dist/vrma b/dist/vrma deleted file mode 160000 index 1eccc36a5..000000000 --- a/dist/vrma +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1eccc36a5113246728ae8b63389c948ce1bd286f diff --git a/package.json b/package.json index 90bccd370..88f358d53 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "@pixiv/three-vrm-animation": "^3.1.0", "@pixiv/three-vrm-springbone": "^3.1.0", "postprocessing": "^6.35.2", + "react": "^19.2.0", + "react-dom": "^18.3.1", "three": "^0.167.1" } } diff --git a/planet/src/index.css b/planet/src/index.css index 110949926..724b909b7 100644 --- a/planet/src/index.css +++ b/planet/src/index.css @@ -5,6 +5,7 @@ html { body { background-color: #fff; background-color: #000; + background-color: #313131; margin: 0; height: 100%; } diff --git a/planet/src/pages/vrm_model.tsx b/planet/src/pages/vrm_model.tsx index 8e67046b6..740164138 100644 --- a/planet/src/pages/vrm_model.tsx +++ b/planet/src/pages/vrm_model.tsx @@ -88,6 +88,8 @@ export function Galaxy(props: JSX.IntrinsicElements['group']) { const galaxyCenterLightRef = useRef(null!) const searchParams = new URLSearchParams(window.location.search); var g = searchParams.get('g') ?? 'galaxy'; + const ms = searchParams.get('ms'); + const vrm_scale = ms ? parseInt(ms, 10) : 1; var model_galaxy = "./models/galaxy.glb" var model_custom = "./models/ai.vrm" var model_scale = 0.01; @@ -158,7 +160,7 @@ export function Galaxy(props: JSX.IntrinsicElements['group']) { return ( - + {g === 'sun' && } {g === 'galaxy' && } diff --git a/theatre/.gitignore b/theatre/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/theatre/.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/theatre/README.md b/theatre/README.md new file mode 100644 index 000000000..74872fd4a --- /dev/null +++ b/theatre/README.md @@ -0,0 +1,50 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default tseslint.config({ + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` +- Optionally add `...tseslint.configs.stylisticTypeChecked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: + +```js +// eslint.config.js +import react from 'eslint-plugin-react' + +export default tseslint.config({ + // Set the react version + settings: { react: { version: '18.3' } }, + plugins: { + // Add the react plugin + react, + }, + rules: { + // other rules... + // Enable its recommended rules + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + }, +}) +``` diff --git a/theatre/eslint.config.js b/theatre/eslint.config.js new file mode 100644 index 000000000..092408a9f --- /dev/null +++ b/theatre/eslint.config.js @@ -0,0 +1,28 @@ +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' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/theatre/index.html b/theatre/index.html new file mode 100644 index 000000000..e4b78eae1 --- /dev/null +++ b/theatre/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/theatre/package.json b/theatre/package.json new file mode 100644 index 000000000..4848a4a67 --- /dev/null +++ b/theatre/package.json @@ -0,0 +1,32 @@ +{ + "name": "vite-react-typescript-starter", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@theatre/core": "^0.6.1", + "@theatre/r3f": "^0.7.2", + "@theatre/studio": "^0.6.1", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@eslint/js": "^9.9.1", + "@types/react": "^18.3.4", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^9.9.1", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.11", + "globals": "^15.9.0", + "typescript": "^5.5.3", + "typescript-eslint": "^8.3.0", + "vite": "^5.4.2" + } +} diff --git a/theatre/public/vite.svg b/theatre/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/theatre/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theatre/src/App.css b/theatre/src/App.css new file mode 100644 index 000000000..b9d355df2 --- /dev/null +++ b/theatre/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/theatre/src/App.tsx b/theatre/src/App.tsx new file mode 100644 index 000000000..afe48ac75 --- /dev/null +++ b/theatre/src/App.tsx @@ -0,0 +1,35 @@ +import { useState } from 'react' +import reactLogo from './assets/react.svg' +import viteLogo from '/vite.svg' +import './App.css' + +function App() { + const [count, setCount] = useState(0) + + return ( + <> + +

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ) +} + +export default App diff --git a/theatre/src/assets/react.svg b/theatre/src/assets/react.svg new file mode 100644 index 000000000..6c87de9bb --- /dev/null +++ b/theatre/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theatre/src/index.css b/theatre/src/index.css new file mode 100644 index 000000000..6119ad9a8 --- /dev/null +++ b/theatre/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/theatre/src/main.tsx b/theatre/src/main.tsx new file mode 100644 index 000000000..b4aa27012 --- /dev/null +++ b/theatre/src/main.tsx @@ -0,0 +1,36 @@ +import './index.css' +import { createRoot } from 'react-dom/client' +import React, { useEffect } from 'react' +import { Canvas } from '@react-three/fiber' +import studio from '@theatre/studio' +import extension from '@theatre/r3f/dist/extension' +import { SheetProvider, editable as e, PerspectiveCamera } from '@theatre/r3f' +import { getProject } from '@theatre/core' +import demoProjectState from './state.json' + +studio.initialize() +studio.extend(extension) + +const demoSheet = getProject('Demo Project', { state: demoProjectState }).sheet('Demo Sheet') +//const demoSheet = getProject('Demo Project').sheet('Demo Sheet') +const App = () => { + useEffect(() => { + demoSheet.project.ready.then(() => demoSheet.sequence.play({ iterationCount: Infinity, range: [0, 1] })) + }, []) + + return ( + + + + + + + + + + + + ) +} + +createRoot(document.getElementById('root')!).render() diff --git a/theatre/src/state.json b/theatre/src/state.json new file mode 100644 index 000000000..468cea8d8 --- /dev/null +++ b/theatre/src/state.json @@ -0,0 +1,7 @@ +{ + "sheetsById": {}, + "definitionVersion": "0.4.0", + "revisionHistory": [ + "jbMA2kSJZuOGYgr9" + ] +} \ No newline at end of file diff --git a/theatre/src/vite-env.d.ts b/theatre/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/theatre/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/theatre/tsconfig.app.json b/theatre/tsconfig.app.json new file mode 100644 index 000000000..f0a235055 --- /dev/null +++ b/theatre/tsconfig.app.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/theatre/tsconfig.json b/theatre/tsconfig.json new file mode 100644 index 000000000..1ffef600d --- /dev/null +++ b/theatre/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/theatre/tsconfig.node.json b/theatre/tsconfig.node.json new file mode 100644 index 000000000..0d3d71446 --- /dev/null +++ b/theatre/tsconfig.node.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/theatre/vite.config.ts b/theatre/vite.config.ts new file mode 100644 index 000000000..5a33944a9 --- /dev/null +++ b/theatre/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +})