simple Three.js site
This commit is contained in:
parent
e33031c071
commit
830af4ac9b
11 changed files with 2306 additions and 1 deletions
|
@ -93,6 +93,13 @@ services:
|
|||
secrets:
|
||||
- db_password
|
||||
env_file: .env
|
||||
site:
|
||||
restart: on-failure
|
||||
build:
|
||||
context: ./requirements/bonus/site
|
||||
dockerfile: Dockerfile
|
||||
networks:
|
||||
- inception
|
||||
|
||||
secrets:
|
||||
db_password:
|
||||
|
|
16
srcs/requirements/bonus/site/Dockerfile
Normal file
16
srcs/requirements/bonus/site/Dockerfile
Normal file
|
@ -0,0 +1,16 @@
|
|||
FROM alpine:3.21.2
|
||||
|
||||
LABEL org.opencontainers.image.authors="alier@student.42mulhouse.fr"
|
||||
|
||||
RUN apk add nodejs curl npm
|
||||
|
||||
COPY app/ /app
|
||||
|
||||
RUN cd /app && npm install && npm run build
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
HEALTHCHECK --start-period=5s \
|
||||
CMD curl "http://site:3000/site/index.html" --fail || exit 1
|
||||
|
||||
ENTRYPOINT ["node", "/app/index.mjs"]
|
20
srcs/requirements/bonus/site/app/index.mjs
Normal file
20
srcs/requirements/bonus/site/app/index.mjs
Normal file
|
@ -0,0 +1,20 @@
|
|||
import Fastify from 'fastify';
|
||||
import path from 'node:path';
|
||||
import * as staticPlugin from '@fastify/static';
|
||||
|
||||
const fastify = Fastify({
|
||||
logger: true
|
||||
});
|
||||
|
||||
fastify.register(staticPlugin, {
|
||||
root: path.join(import.meta.dirname, 'dist'),
|
||||
prefix: '/site/',
|
||||
})
|
||||
|
||||
try {
|
||||
await fastify.listen({ port: 3000, host: 'site' });
|
||||
} catch (err) {
|
||||
fastify.log.error(err);
|
||||
process.exit(1);
|
||||
};
|
||||
|
2103
srcs/requirements/bonus/site/app/package-lock.json
generated
Normal file
2103
srcs/requirements/bonus/site/app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
14
srcs/requirements/bonus/site/app/package.json
Normal file
14
srcs/requirements/bonus/site/app/package.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build src --outDir ../dist --emptyOutDir --base /site"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/static": "^8.1.1",
|
||||
"fastify": "^5.2.1",
|
||||
"lil-gui": "^0.20.0",
|
||||
"three": "^0.173.0",
|
||||
"vite": "^6.1.0"
|
||||
}
|
||||
}
|
115
srcs/requirements/bonus/site/app/src/app.mjs
Normal file
115
srcs/requirements/bonus/site/app/src/app.mjs
Normal file
|
@ -0,0 +1,115 @@
|
|||
import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
||||
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
|
||||
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
|
||||
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
||||
import GUI from 'lil-gui';
|
||||
|
||||
const gui = new GUI();
|
||||
|
||||
const sizes = {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
};
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const fontLoader = new FontLoader();
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
const gltfLoader = new GLTFLoader();
|
||||
|
||||
scene.add(new THREE.AmbientLight());
|
||||
|
||||
const light = new THREE.PointLight();
|
||||
light.intensity = 50;
|
||||
light.position.y = 6;
|
||||
scene.add(light);
|
||||
|
||||
const matcapTexture = textureLoader.load('/site/textures/matcaps/gold.png');
|
||||
matcapTexture.colorSpace = THREE.SRGBColorSpace;
|
||||
|
||||
const material = new THREE.MeshMatcapMaterial({ matcap: matcapTexture });
|
||||
|
||||
fontLoader.load('/site/fonts/helvetiker_regular.typeface.json', function (font) {
|
||||
const textGeometry = new TextGeometry('oui oui baguette', {
|
||||
font,
|
||||
size: 1,
|
||||
depth: 0.5
|
||||
});
|
||||
|
||||
textGeometry.center();
|
||||
|
||||
const cubeMesh = new THREE.Mesh(textGeometry, material);
|
||||
scene.add(cubeMesh);
|
||||
|
||||
cubeMesh.position.x = 0;
|
||||
cubeMesh.position.y = 0;
|
||||
|
||||
gui.add(cubeMesh.position, 'y', -3, 3, 0.01);
|
||||
gui.add(cubeMesh, 'visible');
|
||||
gui.add(cubeMat, 'wireframe');
|
||||
gui.addColor(cubeMat, 'color');
|
||||
});
|
||||
|
||||
gltfLoader.load('/site/models/baguette.glb', function (gltf) {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const baguette = gltf.scene.clone();
|
||||
baguette.position.x = (Math.random() - 0.5) * 10;
|
||||
baguette.position.y = (Math.random() - 0.5) * 10;
|
||||
baguette.position.z = (Math.random() - 0.5) * 10;
|
||||
baguette.rotation.x = Math.random() * Math.PI;
|
||||
baguette.rotation.y = Math.random() * Math.PI;
|
||||
const scale = Math.random();
|
||||
baguette.scale.set(scale, scale, scale);
|
||||
scene.add(baguette);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height);
|
||||
camera.position.z = 5;
|
||||
|
||||
//const axesHelper = new THREE.AxesHelper(1);
|
||||
//scene.add(axesHelper);
|
||||
|
||||
const canvas = document.getElementById('three');
|
||||
|
||||
function updateSize() {
|
||||
sizes.width = window.innerWidth;
|
||||
sizes.height = window.innerHeight;
|
||||
|
||||
camera.aspect = sizes.width / sizes.height;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.setSize(sizes.width, sizes.height);
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||
}
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({ canvas });
|
||||
|
||||
updateSize();
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const controls = new OrbitControls(camera, canvas);
|
||||
|
||||
function render() {
|
||||
const elapsedTime = clock.getElapsedTime();
|
||||
|
||||
renderer.render(scene, camera);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
|
||||
requestAnimationFrame(render);
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
updateSize();
|
||||
});
|
||||
|
||||
window.addEventListener('dblclick', () => {
|
||||
if (!document.fullscreenElement) {
|
||||
canvas.requestFullscreen();
|
||||
} else {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
});
|
25
srcs/requirements/bonus/site/app/src/index.html
Normal file
25
srcs/requirements/bonus/site/app/src/index.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Baguette Land</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#three {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<canvas id="three"></canvas>
|
||||
<script src="app.mjs" type="module"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
File diff suppressed because one or more lines are too long
BIN
srcs/requirements/bonus/site/app/src/public/models/baguette.glb
Normal file
BIN
srcs/requirements/bonus/site/app/src/public/models/baguette.glb
Normal file
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
|
@ -31,4 +31,8 @@ server {
|
|||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
}
|
||||
|
||||
location /site {
|
||||
proxy_pass http://site:3000;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue