├── src
├── index.css
├── App.css
├── Experience.jsx
├── main.jsx
├── mesh
│ ├── Mesh.jsx
│ └── useMaterial.jsx
├── App.jsx
├── ResizeHandler.js
├── LightEnvironment.jsx
└── WebGPUCanvas.jsx
├── bun.lockb
├── vite.config.js
├── .gitignore
├── index.html
├── README.md
├── package.json
├── LICENSE
├── eslint.config.js
└── public
└── vite.svg
/src/index.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mustache-dev/R3F-WebGPU-template/HEAD/bun.lockb
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vite.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/src/Experience.jsx:
--------------------------------------------------------------------------------
1 | import { LightEnvironment } from "./LightEnvironment";
2 |
3 | import { Mesh } from "./mesh/Mesh";
4 |
5 | export const Experience = () => {
6 | return (
7 | <>
8 |
9 |
10 | >
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react'
2 | import { createRoot } from 'react-dom/client'
3 | import './index.css'
4 | import App from './App.jsx'
5 |
6 | createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/src/mesh/Mesh.jsx:
--------------------------------------------------------------------------------
1 | import { useMaterial } from './useMaterial';
2 |
3 | export const Mesh = () => {
4 | const { colorNode, key } = useMaterial();
5 | return (
6 |
7 |
8 |
9 |
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import './App.css'
2 | import { WebGPUCanvas } from './WebGPUCanvas';
3 | import { Experience } from './Experience';
4 |
5 | function App() {
6 |
7 | return (
8 | <>
9 |
10 |
11 |
12 |
13 | >
14 | )
15 | }
16 |
17 | export default App
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # R3F WebGPU + TSL Template
2 |
3 | This is a template for creating Three.js WebGPU projects with React Three Fiber and TSL.
4 |
5 | ## Getting Started
6 |
7 | To get started, run the following commands:
8 |
9 | ```bash
10 | bun install
11 | bun run dev
12 | ```
13 |
14 | ## Features
15 |
16 | - React Three Fiber
17 | - WebGPU
18 | - TSL
19 | - ESLint
20 | - Prettier
21 | - Bun
22 | - Vite
23 |
24 | ## License
25 |
26 | MIT
27 |
28 |
--------------------------------------------------------------------------------
/src/mesh/useMaterial.jsx:
--------------------------------------------------------------------------------
1 | import { useFrame } from "@react-three/fiber";
2 | import {
3 | uniform,
4 | float,
5 | vec4,
6 | } from "three/tsl";
7 |
8 | export const useMaterial = () => {
9 | const uTime = uniform(float(0.0));
10 |
11 | const finalColor = vec4(1.0, 1.0, 1.0, 1.0);
12 |
13 | useFrame((state, delta) => {
14 | uTime.value -= delta * 0.2;
15 | });
16 |
17 | return {
18 | key: uTime.id,
19 | colorNode: finalColor,
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/src/ResizeHandler.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 |
3 | export function ResizeHandler({ quality, rendererRef }) {
4 | useEffect(() => {
5 | const handleResize = () => {
6 | if (rendererRef.current) {
7 | rendererRef.current.setSize(window.innerWidth, window.innerHeight);
8 | }
9 | };
10 |
11 | window.addEventListener("resize", handleResize);
12 |
13 | // Cleanup
14 | return () => window.removeEventListener("resize", handleResize);
15 | }, [quality]);
16 |
17 | return null;
18 | }
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gpu",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@react-three/drei": "^9.121.3",
14 | "@react-three/fiber": "^8.17.12",
15 | "react": "^18.3.1",
16 | "react-dom": "^18.3.1",
17 | "three": "^0.172.0"
18 | },
19 | "devDependencies": {
20 | "@eslint/js": "^9.17.0",
21 | "@types/react": "^18.3.18",
22 | "@types/react-dom": "^18.3.5",
23 | "@vitejs/plugin-react-swc": "^3.5.0",
24 | "eslint": "^9.17.0",
25 | "eslint-plugin-react": "^7.37.2",
26 | "eslint-plugin-react-hooks": "^5.0.0",
27 | "eslint-plugin-react-refresh": "^0.4.16",
28 | "globals": "^15.14.0",
29 | "vite": "^6.0.5"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/LightEnvironment.jsx:
--------------------------------------------------------------------------------
1 | import { Environment } from "@react-three/drei";
2 | import { OrbitControls } from "@react-three/drei";
3 |
4 | export const LightEnvironment = () => {
5 | return (
6 | <>
7 |
20 |
24 |
29 | >
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Lunakepio
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js'
2 | import globals from 'globals'
3 | import react from 'eslint-plugin-react'
4 | import reactHooks from 'eslint-plugin-react-hooks'
5 | import reactRefresh from 'eslint-plugin-react-refresh'
6 |
7 | export default [
8 | { ignores: ['dist'] },
9 | {
10 | files: ['**/*.{js,jsx}'],
11 | languageOptions: {
12 | ecmaVersion: 2020,
13 | globals: globals.browser,
14 | parserOptions: {
15 | ecmaVersion: 'latest',
16 | ecmaFeatures: { jsx: true },
17 | sourceType: 'module',
18 | },
19 | },
20 | settings: { react: { version: '18.3' } },
21 | plugins: {
22 | react,
23 | 'react-hooks': reactHooks,
24 | 'react-refresh': reactRefresh,
25 | },
26 | rules: {
27 | ...js.configs.recommended.rules,
28 | ...react.configs.recommended.rules,
29 | ...react.configs['jsx-runtime'].rules,
30 | ...reactHooks.configs.recommended.rules,
31 | 'react/jsx-no-target-blank': 'off',
32 | 'react-refresh/only-export-components': [
33 | 'warn',
34 | { allowConstantExport: true },
35 | ],
36 | 'react/no-unknown-property': 'off',
37 | 'react/prop-types': 'off',
38 | },
39 | },
40 | ]
41 |
--------------------------------------------------------------------------------
/src/WebGPUCanvas.jsx:
--------------------------------------------------------------------------------
1 | import { Canvas, extend } from "@react-three/fiber";
2 | import { useRef, useState } from "react";
3 | import * as THREE from "three/webgpu";
4 | import { ResizeHandler } from "./ResizeHandler";
5 |
6 | extend(THREE);
7 |
8 | export const WebGPUCanvas = ({ quality, children }) => {
9 | const rendererRef = useRef();
10 | const [frameloop, setFrameloop] = useState("never");
11 | return (
12 |
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------