diff --git a/package.json b/package.json index bd13ced..7c8da14 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,9 @@ }, "type": "module", "dependencies": { + "@threlte/core": "6.0.0-next.11", + "@threlte/extras": "5.0.0-next.16", "@types/three": "^0.154.0", - "three": "^0.154.0" + "three": "^0.155.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84c2fd4..089d397 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,12 +5,18 @@ settings: excludeLinksFromLockfile: false 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': specifier: ^0.154.0 version: 0.154.0 three: - specifier: ^0.154.0 - version: 0.154.0 + specifier: ^0.155.0 + version: 0.155.0 devDependencies: '@skeletonlabs/skeleton': @@ -486,6 +492,19 @@ packages: - supports-color 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: resolution: {integrity: sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==} dev: false @@ -751,6 +770,12 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 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: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -1449,6 +1474,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -1817,6 +1846,11 @@ packages: picomatch: 2.3.1 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: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2152,8 +2186,8 @@ packages: any-promise: 1.3.0 dev: true - /three@0.154.0: - resolution: {integrity: sha512-Uzz8C/5GesJzv8i+Y2prEMYUwodwZySPcNhuJUdsVMH2Yn4Nm8qlbQe6qRN5fOhg55XB0WiLfTPBxVHxpE60ug==} + /three@0.155.0: + resolution: {integrity: sha512-sNgCYmDijnIqkD/bMfk+1pHg3YzsxW7V2ChpuP6HCQ8NiZr3RufsXQr8M3SSUMjW4hG+sUk7YbyuY0DncaDTJQ==} dev: false /to-regex-range@5.0.1: @@ -2168,6 +2202,30 @@ packages: engines: {node: '>=6'} 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: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true @@ -2282,6 +2340,10 @@ packages: vite: 4.4.4 dev: true + /webgl-sdf-generator@1.1.1: + resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==} + dev: false + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} diff --git a/src/lib/assets/vectors/github.glb b/src/lib/assets/vectors/github.glb new file mode 100644 index 0000000..e297dce Binary files /dev/null and b/src/lib/assets/vectors/github.glb differ diff --git a/src/lib/assets/vectors/github.svg b/src/lib/assets/vectors/github.svg new file mode 100644 index 0000000..37fa923 --- /dev/null +++ b/src/lib/assets/vectors/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/lib/components/gltf/Github3d.svelte b/src/lib/components/gltf/Github3d.svelte new file mode 100644 index 0000000..5e2c117 --- /dev/null +++ b/src/lib/components/gltf/Github3d.svelte @@ -0,0 +1,29 @@ + + + + + + {#await gltf} + + {:then gltf} + + {:catch error} + + {/await} + + + diff --git a/src/lib/extrude-svg.ts b/src/lib/extrude-svg.ts new file mode 100644 index 0000000..48b097c --- /dev/null +++ b/src/lib/extrude-svg.ts @@ -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); + } +} diff --git a/src/routes/tools/+page.svelte b/src/routes/tools/+page.svelte index f62f863..f453a69 100644 --- a/src/routes/tools/+page.svelte +++ b/src/routes/tools/+page.svelte @@ -1,98 +1,7 @@ @@ -101,13 +10,9 @@

Tools

+ + + + +
- -
- - diff --git a/src/routes/tools/Scene.svelte b/src/routes/tools/Scene.svelte new file mode 100644 index 0000000..1b985e3 --- /dev/null +++ b/src/routes/tools/Scene.svelte @@ -0,0 +1,42 @@ + + + { + ref.lookAt(0, 1, 0); + }} +/> + + scale.set(1.5)} + on:pointerleave={() => scale.set(1)} + on:click={() => scale.set(3)} +> + + + + + scale.set(1.5)} + on:pointerleave={() => scale.set(1)} + on:click={() => scale.set(3)} +/> diff --git a/static/github-transformed.glb b/static/github-transformed.glb new file mode 100644 index 0000000..743764f Binary files /dev/null and b/static/github-transformed.glb differ diff --git a/vite.config.ts b/vite.config.ts index bbf8c7d..cccd80e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,5 +2,8 @@ import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; export default defineConfig({ - plugins: [sveltekit()] + plugins: [sveltekit()], + ssr: { + noExternal: ['three'] + } });