├── .gitignore ├── src ├── Materials │ ├── Materials.jsx │ ├── shaders │ │ ├── shockWave │ │ │ ├── vertex.glsl │ │ │ └── fragment.glsl │ │ └── beams │ │ │ ├── vertex.glsl │ │ │ └── fragment.glsl │ ├── BeamsMaterial.jsx │ └── ShockWaveMaterial.jsx ├── index.jsx ├── Effects │ ├── Overlay.jsx │ ├── OverlayEffect.jsx │ └── Effects.jsx ├── Experience.jsx ├── Levels │ ├── Beams.jsx │ ├── ShockWave.jsx │ ├── FloorText.jsx │ ├── Blocks.jsx │ ├── Block.jsx │ └── Levels.jsx ├── Application.jsx ├── TouchControls.jsx ├── Lights.jsx ├── index.html ├── stores │ └── useGame.jsx ├── Player.jsx ├── Interface.jsx ├── Sounds.jsx └── style.css ├── public ├── levels │ ├── 0.glb │ ├── 1.glb │ ├── 10.glb │ ├── 11.glb │ ├── 2.glb │ ├── 3.glb │ ├── 4.glb │ ├── 5.glb │ ├── 6.glb │ ├── 7.glb │ ├── 8.glb │ └── 9.glb ├── sounds │ ├── Clock.mp3 │ ├── punches │ │ ├── Water Punch 1.mp3 │ │ ├── Water Punch 2.mp3 │ │ ├── Water Punch 3.mp3 │ │ ├── Water Punch 4.mp3 │ │ ├── Water Punch 5.mp3 │ │ ├── Water Punch 6.mp3 │ │ ├── Magic Game Pack a Punch.wav │ │ ├── Magic Game Pack a Punch 2.wav │ │ ├── Magic Game Pack a Punch 3.wav │ │ ├── Magic Game Pack a Punch 4.wav │ │ └── Quest_Game_Magic_Hit_Jewel_Collect_3.wav │ ├── swooshes │ │ ├── Magic Swoosh 1.mp3 │ │ ├── Magic Swoosh 2.mp3 │ │ ├── Magic Swoosh 3.mp3 │ │ ├── Magic Swoosh 4.mp3 │ │ └── Magic Swoosh 5.mp3 │ ├── Ghostly Whisper Background Loop 9.mp3 │ ├── Mountain Audio - Small Chimes - Loop.mp3 │ └── Frost Magic Ice Bolt Spell Flying Loop 2.mp3 ├── icons │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── mstile-150x150.png │ ├── android-chrome-192x192.png │ ├── android-chrome-256x256.png │ ├── browserconfig.xml │ ├── site.webmanifest │ └── safari-pinned-tab.svg ├── social │ └── share-1200x630.png ├── videos │ └── button-preview.mp4 └── fonts │ └── saira-stencil-one-v16-latin-regular.woff ├── resources ├── levels.blend └── levels.blend1 ├── readme.md ├── package.json └── vite.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist -------------------------------------------------------------------------------- /src/Materials/Materials.jsx: -------------------------------------------------------------------------------- 1 | import './BeamsMaterial.jsx' 2 | import './ShockWaveMaterial.jsx' -------------------------------------------------------------------------------- /public/levels/0.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/0.glb -------------------------------------------------------------------------------- /public/levels/1.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/1.glb -------------------------------------------------------------------------------- /public/levels/10.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/10.glb -------------------------------------------------------------------------------- /public/levels/11.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/11.glb -------------------------------------------------------------------------------- /public/levels/2.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/2.glb -------------------------------------------------------------------------------- /public/levels/3.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/3.glb -------------------------------------------------------------------------------- /public/levels/4.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/4.glb -------------------------------------------------------------------------------- /public/levels/5.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/5.glb -------------------------------------------------------------------------------- /public/levels/6.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/6.glb -------------------------------------------------------------------------------- /public/levels/7.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/7.glb -------------------------------------------------------------------------------- /public/levels/8.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/8.glb -------------------------------------------------------------------------------- /public/levels/9.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/levels/9.glb -------------------------------------------------------------------------------- /public/sounds/Clock.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/Clock.mp3 -------------------------------------------------------------------------------- /resources/levels.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/resources/levels.blend -------------------------------------------------------------------------------- /resources/levels.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/resources/levels.blend1 -------------------------------------------------------------------------------- /public/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/icons/favicon.ico -------------------------------------------------------------------------------- /public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /public/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /public/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/icons/mstile-150x150.png -------------------------------------------------------------------------------- /public/social/share-1200x630.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/social/share-1200x630.png -------------------------------------------------------------------------------- /public/videos/button-preview.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/videos/button-preview.mp4 -------------------------------------------------------------------------------- /public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/icons/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/icons/android-chrome-256x256.png -------------------------------------------------------------------------------- /public/sounds/punches/Water Punch 1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Water Punch 1.mp3 -------------------------------------------------------------------------------- /public/sounds/punches/Water Punch 2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Water Punch 2.mp3 -------------------------------------------------------------------------------- /public/sounds/punches/Water Punch 3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Water Punch 3.mp3 -------------------------------------------------------------------------------- /public/sounds/punches/Water Punch 4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Water Punch 4.mp3 -------------------------------------------------------------------------------- /public/sounds/punches/Water Punch 5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Water Punch 5.mp3 -------------------------------------------------------------------------------- /public/sounds/punches/Water Punch 6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Water Punch 6.mp3 -------------------------------------------------------------------------------- /public/sounds/swooshes/Magic Swoosh 1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/swooshes/Magic Swoosh 1.mp3 -------------------------------------------------------------------------------- /public/sounds/swooshes/Magic Swoosh 2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/swooshes/Magic Swoosh 2.mp3 -------------------------------------------------------------------------------- /public/sounds/swooshes/Magic Swoosh 3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/swooshes/Magic Swoosh 3.mp3 -------------------------------------------------------------------------------- /public/sounds/swooshes/Magic Swoosh 4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/swooshes/Magic Swoosh 4.mp3 -------------------------------------------------------------------------------- /public/sounds/swooshes/Magic Swoosh 5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/swooshes/Magic Swoosh 5.mp3 -------------------------------------------------------------------------------- /public/sounds/punches/Magic Game Pack a Punch.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Magic Game Pack a Punch.wav -------------------------------------------------------------------------------- /public/fonts/saira-stencil-one-v16-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/fonts/saira-stencil-one-v16-latin-regular.woff -------------------------------------------------------------------------------- /public/sounds/Ghostly Whisper Background Loop 9.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/Ghostly Whisper Background Loop 9.mp3 -------------------------------------------------------------------------------- /public/sounds/punches/Magic Game Pack a Punch 2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Magic Game Pack a Punch 2.wav -------------------------------------------------------------------------------- /public/sounds/punches/Magic Game Pack a Punch 3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Magic Game Pack a Punch 3.wav -------------------------------------------------------------------------------- /public/sounds/punches/Magic Game Pack a Punch 4.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Magic Game Pack a Punch 4.wav -------------------------------------------------------------------------------- /public/sounds/Mountain Audio - Small Chimes - Loop.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/Mountain Audio - Small Chimes - Loop.mp3 -------------------------------------------------------------------------------- /public/sounds/Frost Magic Ice Bolt Spell Flying Loop 2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/Frost Magic Ice Bolt Spell Flying Loop 2.mp3 -------------------------------------------------------------------------------- /public/sounds/punches/Quest_Game_Magic_Hit_Jewel_Collect_3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/three.js-journey-bounce-friday/HEAD/public/sounds/punches/Quest_Game_Magic_Hit_Jewel_Collect_3.wav -------------------------------------------------------------------------------- /src/Materials/shaders/shockWave/vertex.glsl: -------------------------------------------------------------------------------- 1 | attribute float random; 2 | 3 | varying vec2 vUv; 4 | 5 | void main() 6 | { 7 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 8 | vUv = uv; 9 | } -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | import './style.css' 2 | import ReactDOM from 'react-dom/client' 3 | import Application from './Application.jsx' 4 | 5 | const root = ReactDOM.createRoot(document.querySelector('#root')) 6 | 7 | root.render() -------------------------------------------------------------------------------- /src/Materials/shaders/beams/vertex.glsl: -------------------------------------------------------------------------------- 1 | attribute float random; 2 | 3 | varying float vRandom; 4 | varying vec2 vUv; 5 | 6 | void main() 7 | { 8 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 9 | vRandom = random; 10 | vUv = uv; 11 | } -------------------------------------------------------------------------------- /src/Effects/Overlay.jsx: -------------------------------------------------------------------------------- 1 | import OverlayEffect from './OverlayEffect.jsx' 2 | import { forwardRef, useState } from 'react' 3 | 4 | export default forwardRef(function Overlay(props, ref) 5 | { 6 | const [ effect ] = useState(() => new OverlayEffect(props)) 7 | 8 | return 9 | }) -------------------------------------------------------------------------------- /public/icons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #ffffff 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Materials/shaders/beams/fragment.glsl: -------------------------------------------------------------------------------- 1 | uniform vec3 color; 2 | uniform float time; 3 | 4 | varying float vRandom; 5 | varying vec2 vUv; 6 | 7 | void main() 8 | { 9 | float progress = mod(time * 0.2 * (1.0 + vRandom) + vRandom, 1.0); 10 | float strength = abs((vUv.y * 0.8 + 0.1) - progress); 11 | strength = step(strength, 0.1); 12 | 13 | if(strength < 0.5) 14 | discard; 15 | 16 | gl_FragColor = vec4(color, 1.0); 17 | 18 | // gl_FragColor = vec4(vUv, 1.0, 1.0); 19 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Bounce Friday 2 | 3 | A [Three.js Journey](https://threejs-journey.com/apps/bounce-friday/) game by [Bruno Simon](https://bruno-simon.com/) for Black Friday 4 | 5 | ## Setup 6 | Download [Node.js](https://nodejs.org/en/download/). 7 | Run this followed commands: 8 | 9 | ``` bash 10 | # Install dependencies (only the first time) 11 | npm install --force 12 | 13 | # Run the local server at localhost:8080 14 | npm run dev 15 | 16 | # Build for production in the dist/ directory 17 | npm run build 18 | ``` 19 | -------------------------------------------------------------------------------- /src/Materials/BeamsMaterial.jsx: -------------------------------------------------------------------------------- 1 | import vertexShader from './shaders/beams/vertex.glsl' 2 | import fragmentShader from './shaders/beams/fragment.glsl' 3 | import { shaderMaterial } from '@react-three/drei' 4 | import { extend } from '@react-three/fiber' 5 | import { Color } from 'three' 6 | 7 | const BeamsMaterial = shaderMaterial( 8 | { 9 | color: new Color(0xffffff), 10 | time: 0 11 | }, 12 | vertexShader, 13 | fragmentShader 14 | ) 15 | 16 | extend({ BeamsMaterial }) 17 | 18 | export default BeamsMaterial -------------------------------------------------------------------------------- /src/Materials/ShockWaveMaterial.jsx: -------------------------------------------------------------------------------- 1 | import vertexShader from './shaders/shockWave/vertex.glsl' 2 | import fragmentShader from './shaders/shockWave/fragment.glsl' 3 | import { shaderMaterial } from '@react-three/drei' 4 | import { extend } from '@react-three/fiber' 5 | import { Color } from 'three' 6 | 7 | const ShockWaveMaterial = shaderMaterial( 8 | { 9 | color: new Color(0xffffff), 10 | outerProgress: 0, 11 | radialProgress: 0, 12 | }, 13 | vertexShader, 14 | fragmentShader 15 | ) 16 | 17 | extend({ ShockWaveMaterial }) 18 | 19 | export default ShockWaveMaterial -------------------------------------------------------------------------------- /public/icons/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Black Friday 2023", 3 | "short_name": "Black Friday 2023", 4 | "icons": [ 5 | { 6 | "src": "https://threejs-journey.com/apps/black-friday-2023/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "https://threejs-journey.com/apps/black-friday-2023/icons/android-chrome-256x256.png", 12 | "sizes": "256x256", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /public/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Effects/OverlayEffect.jsx: -------------------------------------------------------------------------------- 1 | import { Effect } from 'postprocessing' 2 | import { Uniform } from 'three' 3 | 4 | const fragmentShader = /* glsl */` 5 | uniform float alpha; 6 | 7 | void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) 8 | { 9 | outputColor = vec4(vec3(inputColor * (1.0 - alpha)), 1.0); 10 | } 11 | ` 12 | 13 | export default class OverlayEffect extends Effect 14 | { 15 | constructor() 16 | { 17 | super( 18 | 'OverlayEffect', 19 | fragmentShader, 20 | { 21 | uniforms: new Map([ 22 | [ 'alpha', new Uniform(1) ] 23 | ]) 24 | } 25 | ) 26 | } 27 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "threejs-journey-bounce-friday", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build" 9 | }, 10 | "devDependencies": { 11 | "@vitejs/plugin-react": "4.2", 12 | "vite": "^5.0.0" 13 | }, 14 | "dependencies": { 15 | "@react-three/drei": "^9.88.16", 16 | "@react-three/fiber": "^8.15.11", 17 | "@react-three/postprocessing": "^2.15.11", 18 | "@react-three/rapier": "^1.1.2", 19 | "animejs": "^3.2.1", 20 | "ecctrl": "^1.0.45", 21 | "howler": "^2.2.4", 22 | "leva": "^0.9.35", 23 | "r3f-perf": "^7.1.2", 24 | "react": "18.2", 25 | "react-dom": "18.2", 26 | "three": "^0.158.0", 27 | "vite-plugin-glsl": "^1.1.2", 28 | "zustand": "4.4" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Experience.jsx: -------------------------------------------------------------------------------- 1 | import { Physics } from '@react-three/rapier' 2 | import Lights from './Lights.jsx' 3 | import Effects from './Effects/Effects.jsx' 4 | import Player from './Player.jsx' 5 | import { useControls } from 'leva' 6 | import Levels from './Levels/Levels.jsx' 7 | import './Materials/Materials.jsx' 8 | 9 | export default function Experience() 10 | { 11 | const physicsSettings = useControls('physics', { 12 | debug: { value: false }, 13 | }) 14 | 15 | return <> 16 | 17 | 18 | 19 | 20 | 21 | {/* */} 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | } -------------------------------------------------------------------------------- /src/Materials/shaders/shockWave/fragment.glsl: -------------------------------------------------------------------------------- 1 | #define M_PI 3.1415926535897932384626433832795 2 | 3 | uniform vec3 color; 4 | uniform float outerProgress; 5 | uniform float radialProgress; 6 | 7 | varying vec2 vUv; 8 | 9 | float inverseLerp(float v, float minValue, float maxValue) 10 | { 11 | return (v - minValue) / (maxValue - minValue); 12 | } 13 | 14 | float remap(float v, float inMin, float inMax, float outMin, float outMax) 15 | { 16 | float t = inverseLerp(v, inMin, inMax); 17 | return mix(outMin, outMax, t); 18 | } 19 | 20 | void main() 21 | { 22 | float outerStrength = max(abs((vUv.x - 0.5) * 2.0), abs((vUv.y - 0.5) * 2.0)); 23 | 24 | float angle = atan(vUv.y - 0.5, vUv.x - 0.5); 25 | float radialStrength = sin(angle * 6.0) * 0.5 + 0.5; 26 | radialStrength += sin(angle * 10.0) * 0.5 + 0.5; 27 | radialStrength += sin(angle * 15.0) * 0.5 + 0.5; 28 | radialStrength /= 3.0; 29 | 30 | if(outerStrength < outerProgress || radialStrength < radialProgress) 31 | discard; 32 | 33 | gl_FragColor = vec4(color, 1.0); 34 | } -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react' 2 | import { transformWithEsbuild } from 'vite' 3 | import glsl from 'vite-plugin-glsl' 4 | 5 | export default { 6 | root: 'src/', 7 | publicDir: '../public/', 8 | base: './', 9 | plugins: 10 | [ 11 | // React support 12 | react(), 13 | 14 | // GLSL 15 | glsl(), 16 | 17 | // .js file support as if it was JSX 18 | { 19 | name: 'load+transform-js-files-as-jsx', 20 | async transform(code, id) 21 | { 22 | if (!id.match(/src\/.*\.js$/)) 23 | return null 24 | 25 | return transformWithEsbuild(code, id, { 26 | loader: 'jsx', 27 | jsx: 'automatic', 28 | }); 29 | }, 30 | }, 31 | ], 32 | server: 33 | { 34 | host: true, // Open to local network and display URL 35 | open: !('SANDBOX_URL' in process.env || 'CODESANDBOX_HOST' in process.env) // Open if it's not a CodeSandbox 36 | }, 37 | build: 38 | { 39 | outDir: '../dist', // Output in the dist/ folder 40 | emptyOutDir: true, // Empty the folder first 41 | sourcemap: true // Add sourcemap 42 | }, 43 | } -------------------------------------------------------------------------------- /src/Levels/Beams.jsx: -------------------------------------------------------------------------------- 1 | import { useFrame } from '@react-three/fiber' 2 | import { forwardRef, useRef } from 'react' 3 | import { BufferAttribute, DoubleSide, PlaneGeometry } from 'three' 4 | import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js' 5 | 6 | const geometries = [] 7 | 8 | for(let i = 0; i < 15; i++) 9 | { 10 | const height = 1 + Math.random() * 2 11 | const geometry = new PlaneGeometry(0.1, height) 12 | geometry.rotateY(Math.random() * Math.PI) 13 | 14 | const randomArray = new Float32Array(4) 15 | const randomValue = Math.random() 16 | 17 | for(let i = 0; i < 4; i++) 18 | randomArray[i] = randomValue 19 | 20 | geometry.setAttribute('random', new BufferAttribute(randomArray, 1)) 21 | 22 | geometry.translate( 23 | (Math.random() - 0.5) * 1, 24 | height * 0.5, 25 | (Math.random() - 0.5) * 1 26 | ) 27 | 28 | geometries.push(geometry) 29 | } 30 | const beamsGeometry = BufferGeometryUtils.mergeGeometries(geometries) 31 | 32 | export default forwardRef(function Beams({ color = 'red' }, ref) 33 | { 34 | const material = useRef() 35 | 36 | useFrame((_, delta) => 37 | { 38 | material.current.uniforms.time.value += delta 39 | }) 40 | 41 | return 42 | 43 | 44 | }) -------------------------------------------------------------------------------- /src/Effects/Effects.jsx: -------------------------------------------------------------------------------- 1 | import { Bloom, EffectComposer, ToneMapping } from '@react-three/postprocessing' 2 | import { useControls } from 'leva' 3 | import { useEffect, useRef } from 'react' 4 | import useGame from '../stores/useGame' 5 | import anime from 'animejs' 6 | import Overlay from './Overlay.jsx' 7 | 8 | export default function Effects() 9 | { 10 | const [ status ] = useGame(state => [ state.status ]) 11 | const bloomSettings = useControls('effects.bloom', { 12 | luminanceThreshold: { value: 1.4, min: 0, max: 3, step: 0.01 }, 13 | }) 14 | const overlay = useRef() 15 | 16 | useEffect(() => 17 | { 18 | if(status === 'finished') 19 | { 20 | anime({ 21 | targets: overlay.current.uniforms.get('alpha'), 22 | value: 1, 23 | duration: 300, 24 | easing: 'easeOutQuad', 25 | }) 26 | } 27 | else if(status === 'playing') 28 | { 29 | anime({ 30 | targets: overlay.current.uniforms.get('alpha'), 31 | value: 0, 32 | duration: 600, 33 | easing: 'easeInQuad', 34 | }) 35 | } 36 | }, [ status ]) 37 | 38 | return <> 39 | 40 | 41 | 42 | 43 | 44 | 45 | } -------------------------------------------------------------------------------- /src/Levels/ShockWave.jsx: -------------------------------------------------------------------------------- 1 | import anime from 'animejs' 2 | import { forwardRef, useEffect, useRef } from 'react' 3 | import { PlaneGeometry } from 'three' 4 | 5 | const shockWaveGeometry = new PlaneGeometry() 6 | shockWaveGeometry.rotateX(- Math.PI * 0.5) 7 | 8 | export default forwardRef(function ShockWave({ animateKey = false, color = 'red' }, ref) 9 | { 10 | const material = useRef() 11 | 12 | useEffect(() => 13 | { 14 | if(animateKey) 15 | { 16 | material.current.uniforms.outerProgress.value = 0 17 | material.current.uniforms.radialProgress.value = 0 18 | ref.current.scale.set(1, 1, 1) 19 | 20 | anime({ 21 | targets: material.current.uniforms.outerProgress, 22 | value: 0.98, 23 | duration: 200, 24 | easing: 'easeOutCirc', 25 | update: (anim) => 26 | { 27 | const scale = 1 + anim.progress / 100 28 | ref.current.scale.set(scale, scale, scale) 29 | } 30 | }) 31 | anime({ 32 | targets: material.current.uniforms.radialProgress, 33 | value: 1, 34 | duration: 1000, 35 | delay: 150, 36 | easing: 'easeOutSine' 37 | }) 38 | } 39 | }, [ animateKey ]) 40 | 41 | return 42 | 43 | 44 | }) -------------------------------------------------------------------------------- /src/Application.jsx: -------------------------------------------------------------------------------- 1 | import './style.css' 2 | import { Canvas } from '@react-three/fiber' 3 | import Experience from './Experience.jsx' 4 | import { KeyboardControls } from '@react-three/drei' 5 | import Interface from './Interface.jsx' 6 | import TouchControls from './TouchControls.jsx' 7 | import { Leva } from 'leva' 8 | import useGame from './stores/useGame.jsx' 9 | import Sounds from './Sounds.jsx' 10 | 11 | export default function Application() 12 | { 13 | const [ status ] = useGame(state => [ state.status ]) 14 | 15 | return <> 16 |