mirror of
https://github.com/bartvdbraak/hellob.art.git
synced 2025-04-26 17:11:21 +00:00
feat: added threlte & threejs implementations
This commit is contained in:
parent
908499271c
commit
d199ec5305
10 changed files with 198 additions and 109 deletions
|
@ -34,7 +34,9 @@
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@threlte/core": "6.0.0-next.11",
|
||||||
|
"@threlte/extras": "5.0.0-next.16",
|
||||||
"@types/three": "^0.154.0",
|
"@types/three": "^0.154.0",
|
||||||
"three": "^0.154.0"
|
"three": "^0.155.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,18 @@ settings:
|
||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@threlte/core':
|
||||||
|
specifier: 6.0.0-next.11
|
||||||
|
version: 6.0.0-next.11
|
||||||
|
'@threlte/extras':
|
||||||
|
specifier: 5.0.0-next.16
|
||||||
|
version: 5.0.0-next.16(three@0.155.0)
|
||||||
'@types/three':
|
'@types/three':
|
||||||
specifier: ^0.154.0
|
specifier: ^0.154.0
|
||||||
version: 0.154.0
|
version: 0.154.0
|
||||||
three:
|
three:
|
||||||
specifier: ^0.154.0
|
specifier: ^0.155.0
|
||||||
version: 0.154.0
|
version: 0.155.0
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@skeletonlabs/skeleton':
|
'@skeletonlabs/skeleton':
|
||||||
|
@ -486,6 +492,19 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@threlte/core@6.0.0-next.11:
|
||||||
|
resolution: {integrity: sha512-mW7tCxUiXTrMvTb9NLD/fBNlMtnSDnIdBykf7bXKw6Jd5lKUGNq1zQp/8jg456g17XJazmAY1nO/oJ54ye1qoA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@threlte/extras@5.0.0-next.16(three@0.155.0):
|
||||||
|
resolution: {integrity: sha512-KcjvVrRlvTtHlzHdRtvEHmQa+ijyr6CFLIIN1kISZHvvnReg4HuNOZQRgAfjXCDs8Rrmoq31H9nvcayfEDrIwA==}
|
||||||
|
dependencies:
|
||||||
|
lodash: 4.17.21
|
||||||
|
troika-three-text: 0.47.2(three@0.155.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- three
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@tweenjs/tween.js@18.6.4:
|
/@tweenjs/tween.js@18.6.4:
|
||||||
resolution: {integrity: sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==}
|
resolution: {integrity: sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -751,6 +770,12 @@ packages:
|
||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/bidi-js@1.0.2:
|
||||||
|
resolution: {integrity: sha512-rzSy/k7WdX5zOyeHHCOixGXbCHkyogkxPKL2r8QtzHmVQDiWCXUWa18bLdMWT9CYMLOYTjWpTHawuev2ouYJVw==}
|
||||||
|
dependencies:
|
||||||
|
require-from-string: 2.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/binary-extensions@2.2.0:
|
/binary-extensions@2.2.0:
|
||||||
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -1449,6 +1474,10 @@ packages:
|
||||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/lodash@4.17.21:
|
||||||
|
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/lru-cache@6.0.0:
|
/lru-cache@6.0.0:
|
||||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -1817,6 +1846,11 @@ packages:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/require-from-string@2.0.2:
|
||||||
|
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/resolve-from@4.0.0:
|
/resolve-from@4.0.0:
|
||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
@ -2152,8 +2186,8 @@ packages:
|
||||||
any-promise: 1.3.0
|
any-promise: 1.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/three@0.154.0:
|
/three@0.155.0:
|
||||||
resolution: {integrity: sha512-Uzz8C/5GesJzv8i+Y2prEMYUwodwZySPcNhuJUdsVMH2Yn4Nm8qlbQe6qRN5fOhg55XB0WiLfTPBxVHxpE60ug==}
|
resolution: {integrity: sha512-sNgCYmDijnIqkD/bMfk+1pHg3YzsxW7V2ChpuP6HCQ8NiZr3RufsXQr8M3SSUMjW4hG+sUk7YbyuY0DncaDTJQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/to-regex-range@5.0.1:
|
/to-regex-range@5.0.1:
|
||||||
|
@ -2168,6 +2202,30 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/troika-three-text@0.47.2(three@0.155.0):
|
||||||
|
resolution: {integrity: sha512-qylT0F+U7xGs+/PEf3ujBdJMYWbn0Qci0kLqI5BJG2kW1wdg4T1XSxneypnF05DxFqJhEzuaOR9S2SjiyknMng==}
|
||||||
|
peerDependencies:
|
||||||
|
three: '>=0.125.0'
|
||||||
|
dependencies:
|
||||||
|
bidi-js: 1.0.2
|
||||||
|
three: 0.155.0
|
||||||
|
troika-three-utils: 0.47.2(three@0.155.0)
|
||||||
|
troika-worker-utils: 0.47.2
|
||||||
|
webgl-sdf-generator: 1.1.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/troika-three-utils@0.47.2(three@0.155.0):
|
||||||
|
resolution: {integrity: sha512-/28plhCxfKtH7MSxEGx8e3b/OXU5A0xlwl+Sbdp0H8FXUHKZDoksduEKmjQayXYtxAyuUiCRunYIv/8Vi7aiyg==}
|
||||||
|
peerDependencies:
|
||||||
|
three: '>=0.125.0'
|
||||||
|
dependencies:
|
||||||
|
three: 0.155.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/troika-worker-utils@0.47.2:
|
||||||
|
resolution: {integrity: sha512-mzss4MeyzUkYBppn4x5cdAqrhBHFEuVmMMgLMTyFV23x6GvQMyo+/R5E5Lsbrt7WSt5RfvewjcwD1DChRTA9lA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ts-interface-checker@0.1.13:
|
/ts-interface-checker@0.1.13:
|
||||||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -2282,6 +2340,10 @@ packages:
|
||||||
vite: 4.4.4
|
vite: 4.4.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/webgl-sdf-generator@1.1.1:
|
||||||
|
resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/which@2.0.2:
|
/which@2.0.2:
|
||||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
BIN
src/lib/assets/vectors/github.glb
Normal file
BIN
src/lib/assets/vectors/github.glb
Normal file
Binary file not shown.
1
src/lib/assets/vectors/github.svg
Normal file
1
src/lib/assets/vectors/github.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>
|
After Width: | Height: | Size: 963 B |
29
src/lib/components/gltf/Github3d.svelte
Normal file
29
src/lib/components/gltf/Github3d.svelte
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<!--
|
||||||
|
Auto-generated by: https://github.com/threlte/threlte/tree/main/packages/gltf
|
||||||
|
Command: npx @threlte/gltf@1.0.0-next.13 ./src/lib/assets/vectors/github.glb --transform
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Group } from 'three';
|
||||||
|
import { T, forwardEventHandlers } from '@threlte/core';
|
||||||
|
import { useGltf } from '@threlte/extras';
|
||||||
|
export const ref = new Group();
|
||||||
|
|
||||||
|
const gltf = useGltf('./github-transformed.glb', { useDraco: true });
|
||||||
|
|
||||||
|
const component = forwardEventHandlers();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
||||||
|
{#await gltf}
|
||||||
|
<slot name="fallback" />
|
||||||
|
{:then gltf}
|
||||||
|
<T.Mesh geometry={gltf.nodes.Github_Mesh.geometry}
|
||||||
|
><T.MeshPhysicalMaterial color={[0,0,0]} /></T.Mesh
|
||||||
|
>
|
||||||
|
{:catch error}
|
||||||
|
<slot name="error" {error} />
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
<slot {ref} />
|
||||||
|
</T>
|
45
src/lib/extrude-svg.ts
Normal file
45
src/lib/extrude-svg.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import type * as THREE from 'three';
|
||||||
|
import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader';
|
||||||
|
import type { SVGResult, SVGResultPaths } from 'three/examples/jsm/loaders/SVGLoader';
|
||||||
|
|
||||||
|
import { Mesh } from 'three/src/objects/Mesh';
|
||||||
|
import { Group } from 'three/src/objects/Group';
|
||||||
|
import { MeshNormalMaterial } from 'three/src/materials/MeshNormalMaterial';
|
||||||
|
import { ExtrudeGeometry } from 'three/src/geometries/ExtrudeGeometry';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the provided SVG markup and extrudes it into a 3D model using THREE.js.
|
||||||
|
* @param svgMarkup - SVG markup to extrude.
|
||||||
|
* @return Group containing all of the extruded SVG paths.
|
||||||
|
* @throws Error If the SVG markup is empty.
|
||||||
|
*/
|
||||||
|
export function extrudeSvg(svgMarkup: string): Group {
|
||||||
|
if (!svgMarkup) {
|
||||||
|
throw new Error('SVG markup is empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
const svgData: SVGResult = new SVGLoader().parse(svgMarkup);
|
||||||
|
const material: MeshNormalMaterial = new MeshNormalMaterial();
|
||||||
|
|
||||||
|
const svgGroup: Mesh[][] = svgData.paths.map(createShapeFromPath);
|
||||||
|
|
||||||
|
const group = new Group();
|
||||||
|
svgGroup.flat().forEach(mesh => group.add(mesh));
|
||||||
|
|
||||||
|
return group;
|
||||||
|
|
||||||
|
function createShapeFromPath(path: SVGResultPaths): Mesh[] {
|
||||||
|
const shapes: THREE.Shape[] = path.toShapes(true);
|
||||||
|
|
||||||
|
return shapes.map(shape => extrudeShape(shape, material));
|
||||||
|
}
|
||||||
|
|
||||||
|
function extrudeShape(shape: THREE.Shape, material: MeshNormalMaterial): Mesh {
|
||||||
|
const geometry = new ExtrudeGeometry(shape, {
|
||||||
|
depth: 20,
|
||||||
|
bevelEnabled: false
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Mesh(geometry, material);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,98 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { Canvas } from '@threlte/core';
|
||||||
import { browser } from '$app/environment';
|
import Scene from './Scene.svelte';
|
||||||
import * as THREE from 'three';
|
import Github3d from '$lib/components/gltf/Github3d.svelte';
|
||||||
import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js';
|
|
||||||
|
|
||||||
const svgGitHub = `<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>`;
|
|
||||||
const loader = new SVGLoader();
|
|
||||||
|
|
||||||
let canvasContainer: HTMLDivElement;
|
|
||||||
let scene: THREE.Scene;
|
|
||||||
let camera: THREE.PerspectiveCamera;
|
|
||||||
let renderer: THREE.WebGLRenderer;
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (!browser) return; // Ensure it runs only in the browser environment
|
|
||||||
|
|
||||||
initThreeJS();
|
|
||||||
animate();
|
|
||||||
});
|
|
||||||
|
|
||||||
function initThreeJS() {
|
|
||||||
scene = new THREE.Scene();
|
|
||||||
camera = new THREE.PerspectiveCamera(
|
|
||||||
75,
|
|
||||||
canvasContainer.clientWidth / canvasContainer.clientHeight,
|
|
||||||
0.1,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
camera.position.z = 5;
|
|
||||||
|
|
||||||
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
|
|
||||||
renderer.setSize(canvasContainer.clientWidth, canvasContainer.clientHeight);
|
|
||||||
renderer.setClearColor(0x000000, 0); // Transparent background
|
|
||||||
|
|
||||||
const svgData = loader.parse(svgGitHub);
|
|
||||||
const svgGroup = new THREE.Group();
|
|
||||||
const material = new THREE.MeshNormalMaterial();
|
|
||||||
|
|
||||||
// Loop through all of the parsed paths
|
|
||||||
svgData.paths.forEach((path, i) => {
|
|
||||||
const shapes = path.toShapes(true);
|
|
||||||
|
|
||||||
// Each path has array of shapes
|
|
||||||
shapes.forEach((shape, j) => {
|
|
||||||
// Finally we can take each shape and extrude it
|
|
||||||
const geometry = new THREE.ExtrudeGeometry(shape, {
|
|
||||||
depth: 20,
|
|
||||||
bevelEnabled: false
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a mesh and add it to the group
|
|
||||||
const mesh = new THREE.Mesh(geometry, material);
|
|
||||||
|
|
||||||
svgGroup.add(mesh);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add our group to the scene (you'll need to create a scene)
|
|
||||||
scene.add(svgGroup);
|
|
||||||
|
|
||||||
canvasContainer.appendChild(renderer.domElement);
|
|
||||||
|
|
||||||
// Handle window resizing
|
|
||||||
window.addEventListener('resize', onWindowResize);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onWindowResize() {
|
|
||||||
if (!camera || !renderer) return;
|
|
||||||
|
|
||||||
camera.aspect = canvasContainer.clientWidth / canvasContainer.clientHeight;
|
|
||||||
camera.updateProjectionMatrix();
|
|
||||||
renderer.setSize(canvasContainer.clientWidth, canvasContainer.clientHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
function animate() {
|
|
||||||
if (!browser) return; // Ensure it runs only in the browser environment
|
|
||||||
|
|
||||||
requestAnimationFrame(animate);
|
|
||||||
// Add animations or changes to the scene here if needed
|
|
||||||
if (scene && camera && renderer) {
|
|
||||||
renderer.render(scene, camera);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup function
|
|
||||||
function cleanup() {
|
|
||||||
if (!browser) return; // Ensure it runs only in the browser environment
|
|
||||||
|
|
||||||
window.removeEventListener('resize', onWindowResize);
|
|
||||||
renderer?.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup when the component is destroyed
|
|
||||||
onDestroy(cleanup);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -101,13 +10,9 @@
|
||||||
|
|
||||||
<main class="container mx-auto px-4 py-8 text-left">
|
<main class="container mx-auto px-4 py-8 text-left">
|
||||||
<h2 class="text-3xl font-bold mb-8">Tools</h2>
|
<h2 class="text-3xl font-bold mb-8">Tools</h2>
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Scene />
|
||||||
|
<Github3d />
|
||||||
|
</Canvas>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<div bind:this={canvasContainer} class="canvas-container" />
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.canvas-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
42
src/routes/tools/Scene.svelte
Normal file
42
src/routes/tools/Scene.svelte
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<script>
|
||||||
|
import Github3d from '$lib/components/gltf/Github3d.svelte';
|
||||||
|
import { T, useFrame } from '@threlte/core';
|
||||||
|
import { interactivity } from '@threlte/extras';
|
||||||
|
import { spring } from 'svelte/motion';
|
||||||
|
|
||||||
|
interactivity();
|
||||||
|
const scale = spring(1);
|
||||||
|
|
||||||
|
let rotation = 0;
|
||||||
|
useFrame((_state, delta) => {
|
||||||
|
rotation += delta;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<T.PerspectiveCamera
|
||||||
|
makeDefault
|
||||||
|
position={[10, 10, 10]}
|
||||||
|
on:create={({ ref }) => {
|
||||||
|
ref.lookAt(0, 1, 0);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<T.Mesh
|
||||||
|
rotation.y={rotation}
|
||||||
|
position.y={1}
|
||||||
|
scale={$scale}
|
||||||
|
on:pointerenter={() => scale.set(1.5)}
|
||||||
|
on:pointerleave={() => scale.set(1)}
|
||||||
|
on:click={() => scale.set(3)}
|
||||||
|
>
|
||||||
|
<T.BoxGeometry args={[1, 2, 1]} />
|
||||||
|
<T.MeshBasicMaterial color={[0, 0, 0]} />
|
||||||
|
</T.Mesh>
|
||||||
|
|
||||||
|
<Github3d
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
scale={$scale}
|
||||||
|
on:pointerenter={() => scale.set(1.5)}
|
||||||
|
on:pointerleave={() => scale.set(1)}
|
||||||
|
on:click={() => scale.set(3)}
|
||||||
|
/>
|
BIN
static/github-transformed.glb
Normal file
BIN
static/github-transformed.glb
Normal file
Binary file not shown.
|
@ -2,5 +2,8 @@ import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()]
|
plugins: [sveltekit()],
|
||||||
|
ssr: {
|
||||||
|
noExternal: ['three']
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue