├── README.md ├── package.json ├── pages ├── _app.js ├── birds.js ├── boxes.js ├── index.css └── index.js └── public └── glb ├── flamingo.glb ├── parrot.glb └── stork.glb /README.md: -------------------------------------------------------------------------------- 1 | # With Three js 2 | 3 | This example uses: 4 | 5 | `threejs`: A lightweight, 3D library with a default WebGL renderer. The library also provides Canvas 2D, SVG and CSS3D renderers in the examples. 6 | `react-three-fiber`: A React renderer for Threejs on the web and react-native. 7 | 8 | ## Deploy your own 9 | 10 | Deploy the example using [ZEIT Now](https://zeit.co/now): 11 | 12 | [![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/next.js/tree/canary/examples/with-three-js) 13 | 14 | ## How to use 15 | 16 | ### Using `create-next-app` 17 | 18 | Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: 19 | 20 | ```bash 21 | npx create-next-app --example with-three-js 22 | # or 23 | yarn create next-app --example with-three-js 24 | ``` 25 | 26 | ### Download manually 27 | 28 | Download the example: 29 | 30 | ```bash 31 | curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-three-js 32 | cd with-three-js 33 | ``` 34 | 35 | Install it and run: 36 | 37 | ```bash 38 | npm install 39 | npm run dev 40 | # or 41 | yarn 42 | yarn dev 43 | ``` 44 | 45 | Deploy it to the cloud with [ZEIT Now](https://zeit.co/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-three-js", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "next": "9.3.3", 12 | "react": "16.12.0", 13 | "react-dom": "16.12.0", 14 | "react-three-fiber": "4.0.12", 15 | "three": "0.112.1" 16 | }, 17 | "devDependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './index.css' 3 | 4 | function MyApp({ Component, pageProps }) { 5 | return 6 | } 7 | 8 | export default MyApp 9 | -------------------------------------------------------------------------------- /pages/birds.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState, useEffect, Suspense } from 'react' 2 | import * as THREE from 'three' 3 | import { Canvas, useFrame, useLoader } from 'react-three-fiber' 4 | 5 | let GLTFLoader 6 | 7 | const Bird = ({ speed, factor, url, ...props }) => { 8 | const gltf = useLoader(GLTFLoader, url) 9 | const group = useRef() 10 | const [mixer] = useState(() => new THREE.AnimationMixer()) 11 | useEffect( 12 | () => void mixer.clipAction(gltf.animations[0], group.current).play(), 13 | [gltf.animations, mixer] 14 | ) 15 | useFrame((state, delta) => { 16 | group.current.rotation.y += 17 | Math.sin((delta * factor) / 2) * Math.cos((delta * factor) / 2) * 1.5 18 | mixer.update(delta * speed) 19 | }) 20 | return ( 21 | 22 | 23 | 29 | 30 | 35 | 36 | 37 | 38 | ) 39 | } 40 | 41 | const Birds = () => { 42 | return new Array(5).fill().map((_, i) => { 43 | const x = (15 + Math.random() * 30) * (Math.round(Math.random()) ? -1 : 1) 44 | const y = -10 + Math.random() * 20 45 | const z = -5 + Math.random() * 10 46 | const bird = ['stork', 'parrot', 'flamingo'][Math.round(Math.random() * 2)] 47 | let speed = bird === 'stork' ? 0.5 : bird === 'flamingo' ? 2 : 5 48 | let factor = 49 | bird === 'stork' 50 | ? 0.5 + Math.random() 51 | : bird === 'flamingo' 52 | ? 0.25 + Math.random() 53 | : 1 + Math.random() - 0.5 54 | return ( 55 | 0 ? Math.PI : 0, 0]} 59 | speed={speed} 60 | factor={factor} 61 | url={`/glb/${bird}.glb`} 62 | /> 63 | ) 64 | }) 65 | } 66 | 67 | const BirdsPage = props => { 68 | useEffect(() => { 69 | GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader').GLTFLoader 70 | }, []) 71 | return ( 72 | <> 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | ) 82 | } 83 | 84 | export default BirdsPage 85 | -------------------------------------------------------------------------------- /pages/boxes.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState, Suspense } from 'react' 2 | import { Canvas, useFrame } from 'react-three-fiber' 3 | 4 | const Box = props => { 5 | const mesh = useRef() 6 | 7 | const [hovered, setHover] = useState(false) 8 | const [active, setActive] = useState(false) 9 | 10 | useFrame(() => (mesh.current.rotation.x = mesh.current.rotation.y += 0.01)) 11 | 12 | return ( 13 | setActive(!active)} 18 | onPointerOver={e => setHover(true)} 19 | onPointerOut={e => setHover(false)} 20 | > 21 | 22 | 26 | 27 | ) 28 | } 29 | 30 | const BirdsPage = () => { 31 | return [ 32 |

Click on me - Hover me :)

, 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | , 43 | ] 44 | } 45 | 46 | export default BirdsPage 47 | -------------------------------------------------------------------------------- /pages/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | width: 100%; 5 | height: 100vh; 6 | background: lavender; 7 | } 8 | 9 | canvas { 10 | width: 100%; 11 | height: 100vh; 12 | } 13 | 14 | h1 { 15 | display: flex; 16 | justify-content: center; 17 | align-content: center; 18 | color: hotpink; 19 | } 20 | 21 | .main { 22 | background: hotpink; 23 | padding: 50px; 24 | border-radius: 4px; 25 | display: flex; 26 | margin: 200px; 27 | flex-direction: column; 28 | justify-content: center; 29 | align-items: center; 30 | color: white; 31 | } 32 | 33 | a { 34 | color: white; 35 | display: block; 36 | text-decoration: unset; 37 | font-size: 20px; 38 | margin: 5px 0; 39 | } 40 | 41 | a:hover { 42 | color: #3f51b5; 43 | } 44 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Link from 'next/link' 3 | 4 | const Index = () => { 5 | return ( 6 |
7 | 8 | Birds Example 9 | 10 | 11 | Boxes Example 12 | 13 |
14 | ) 15 | } 16 | 17 | export default Index 18 | -------------------------------------------------------------------------------- /public/glb/flamingo.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjcero/next-js-with-threejs/75475c5da099acafd7aba5c1c2ca804dc2b46b1c/public/glb/flamingo.glb -------------------------------------------------------------------------------- /public/glb/parrot.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjcero/next-js-with-threejs/75475c5da099acafd7aba5c1c2ca804dc2b46b1c/public/glb/parrot.glb -------------------------------------------------------------------------------- /public/glb/stork.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjcero/next-js-with-threejs/75475c5da099acafd7aba5c1c2ca804dc2b46b1c/public/glb/stork.glb --------------------------------------------------------------------------------