[READ-ONLY] Mirror of https://github.com/flo-bit/svelte-depth-3d-component. svelte component to show a fake 3d image with depth map flo-bit.dev/svelte-depth-3d-component/
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3 from flo-bit/main

performance

authored by

Florian and committed by
GitHub
(Aug 31, 2024, 9:44 AM +0200) 8bb8ea3b 20051f28

+422 -364
+70
README.md
··· 1 1 # svelte depth 3d component 2 2 3 + Display an image with a fake 3D effect, using a depth map. Made for svelte, using threlte, threejs and tailwindcss. Still a work in progress, but usable. 4 + 5 + [Try the demo here.](https://flo-bit.github.io/svelte-depth-3d-component/) 6 + 7 + 8 + https://github.com/flo-bit/svelte-depth-3d-component/assets/45694132/bea0d04f-487b-4119-ba1a-a5743728195a 9 + 10 + 11 + ## How to use 12 + 13 + 1. Copy and paste the [`src/lib/Depth3D/`](https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Fflo-bit%2Fsvelte-depth-3d-component%2Ftree%2Fmain%2Fsrc%2Flib%2FDepth3D) folder of this repository into your svelte projects `src/lib/` folder. 14 + 2. Install [tailwindcss](https://tailwindcss.com/docs/guides/sveltekit) and [threlte (core and extras)](https://threlte.xyz/docs/learn/getting-started/installation) (work through their setup or see below for commands) 15 + 3. Get an image and generate a accompanying depth map, for example using [zoedepth](https://replicate.com/cjwbw/zoedepth) 16 + 4. Use the `Depth3D` component in your pages directly like so: 17 + 18 + ```svelte 19 + <script> 20 + // Depth3D example 21 + import Depth3D from '$lib/Depth3D'; 22 + </script> 23 + 24 + <!-- will adjust to the parents size/position --> 25 + <Depth3D 26 + image={{ 27 + image: 'your-image.png', 28 + depth: 'your-depth.png' 29 + }} 30 + /> 31 + ``` 32 + 33 + ## Which images work well 34 + 35 + This effect only simulates 3D, so some images will show weird artifacts. Portraits with a single person in the middle tend to work well. The effect will also depend on the quality of the depth map. Some trial and error might be necessary to get the desired effect. 36 + 37 + ## Installing the dependencies 38 + 39 + ### TailwindCSS (assuming you created your svelte app with the svelte create command) 40 + 41 + 1. Install 42 + ```bash 43 + npm install -D tailwindcss postcss autoprefixer 44 + npx tailwindcss init -p 45 + ``` 46 + 2. Update your tailwind.config.js file to find files with tailwind classes: 47 + ```js 48 + content: ['./src/**/*.{html,js,svelte,ts}'], 49 + ``` 50 + 3. Create a app.css file in your src folder. 51 + ```css 52 + @tailwind base; 53 + @tailwind components; 54 + @tailwind utilities; 55 + ``` 56 + 4. Import the css file in your +layout.svelte file 57 + ```svelte 58 + <script> 59 + import "../app.css"; 60 + </script> 61 + 62 + <slot /> 63 + ``` 64 + 65 + ### Threlte (core and extras) 66 + 67 + 1. Install 68 + ```bash 69 + npm install three @threlte/core \ 70 + @threlte/extras \ 71 + @types/three 72 + ```
+3
svelte.config.js
··· 15 15 16 16 prerender: { 17 17 handleHttpError: 'ignore' 18 + }, 19 + paths: { 20 + base: '/svelte-depth-3d-component' 18 21 } 19 22 } 20 23 };
-69
src/lib/Demo.svelte
··· 1 - <script> 2 - import Hero3D from '$lib/Depth3D/Components/Hero3D.svelte'; 3 - import Quote3D from '$lib/Depth3D/Components/Quote3D.svelte'; 4 - import Team3D from '$lib/Depth3D/Components/Team3D.svelte'; 5 - 6 - let url = '/svelte-depth-3d-component'; 7 - 8 - let members = [ 9 - { 10 - name: 'Fiona Firestarter', 11 - role: 'Head of Desk Decoration', 12 - description: 13 - 'Brings the office to life with quirky decorations. Known for her seasonal desk themes and a collection of rubber ducks.', 14 - image: url + '/images/member1.png', 15 - depth: url + '/images/member1-depth.png' 16 - }, 17 - { 18 - name: 'Johnny Appletini', 19 - role: 'Chief Snack Officer (CSO)', 20 - description: 21 - 'Responsible for keeping the snack drawer stocked and the team fueled. Rumored to have a secret stash of gummy bears.', 22 - image: url + '/images/member2.png', 23 - depth: url + '/images/member2-depth.png' 24 - }, 25 - { 26 - name: 'Chuckles McGee', 27 - role: 'Director of Fun Times (DFT)', 28 - description: 29 - 'Ensures everyone is having a good time with spontaneous dance-offs and meme sharing. The unofficial morale booster.', 30 - image: url + '/images/member3.png', 31 - depth: url + '/images/member3-depth.png' 32 - } 33 - ]; 34 - </script> 35 - 36 - <a class="absolute top-4 right-4" href="https://github.com/flo-bit/svelte-depth-3d-component"> 37 - <svg fill="currentColor" viewBox="0 0 24 24" aria-hidden="true" class="w-8 h-8"> 38 - <path 39 - fill-rule="evenodd" 40 - d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" 41 - clip-rule="evenodd" 42 - /> 43 - </svg> 44 - </a> 45 - 46 - <Hero3D 47 - image={{ 48 - image: url + '/images/couple.jpg', 49 - depth: url + '/images/couple-depth.png' 50 - }} 51 - /> 52 - 53 - <div class="py-8 md:py-16"> 54 - <div class="mx-auto max-w-2xl lg:max-w-4xl px-6 lg:px-8"> 55 - <h2 class="text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl">Examples</h2> 56 - </div> 57 - </div> 58 - 59 - <Quote3D 60 - quote={`"Two things are infinite: the universe and the number of times people misattribute quotes to me; and I'm not sure about the universe."`} 61 - author="Albert Einstein" 62 - role="Famous person" 63 - image={{ 64 - image: url + '/images/albert_einstein.png', 65 - depth: url + '/images/albert_einstein-depth.png' 66 - }} 67 - /> 68 - 69 - <Team3D {members} />
-1
src/lib/index.ts
··· 1 - // place files you want to import through the `$lib` alias in this folder.
+1 -1
src/routes/+page.svelte
··· 1 1 <script> 2 - import Demo from '$lib/Demo.svelte'; 2 + import Demo from '$lib/Demo/Demo.svelte'; 3 3 </script> 4 4 5 5 <Demo />
+66
src/lib/Demo/Demo.svelte
··· 1 + <script> 2 + import Hero from './Hero.svelte'; 3 + import Quote from './Quote.svelte'; 4 + import Team from './Team.svelte'; 5 + 6 + let url = '/svelte-depth-3d-component'; 7 + 8 + let members = [ 9 + { 10 + name: 'Fiona Firestarter', 11 + role: 'Head of Desk Decoration', 12 + description: 13 + 'Brings the office to life with quirky decorations. Known for her seasonal desk themes and a collection of rubber ducks.', 14 + image: url + '/images/member1.png', 15 + depth: url + '/images/member1-depth.png' 16 + }, 17 + { 18 + name: 'Johnny Appletini', 19 + role: 'Chief Snack Officer (CSO)', 20 + description: 21 + 'Responsible for keeping the snack drawer stocked and the team fueled. Rumored to have a secret stash of gummy bears.', 22 + image: url + '/images/member2.png', 23 + depth: url + '/images/member2-depth.png' 24 + }, 25 + { 26 + name: 'Chuckles McGee', 27 + role: 'Director of Fun Times (DFT)', 28 + description: 29 + 'Ensures everyone is having a good time with spontaneous dance-offs and meme sharing. The unofficial morale booster.', 30 + image: url + '/images/member3.png', 31 + depth: url + '/images/member3-depth.png' 32 + } 33 + ]; 34 + </script> 35 + 36 + <a class="absolute top-4 right-4" href="https://github.com/flo-bit/svelte-depth-3d-component"> 37 + <svg fill="currentColor" viewBox="0 0 24 24" aria-hidden="true" class="w-8 h-8"> 38 + <path 39 + fill-rule="evenodd" 40 + d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" 41 + clip-rule="evenodd" 42 + /> 43 + </svg> 44 + </a> 45 + 46 + <Hero 47 + image={{ 48 + image: url + '/images/couple.jpg', 49 + depth: url + '/images/couple-depth.png' 50 + }} 51 + /> 52 + 53 + <div class="py-8 md:py-16"> 54 + <div class="mx-auto max-w-2xl lg:max-w-4xl px-6 lg:px-8"> 55 + <h2 class="text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl">Examples</h2> 56 + </div> 57 + </div> 58 + 59 + <Quote 60 + image={{ 61 + image: url + '/images/albert_einstein.png', 62 + depth: url + '/images/albert_einstein-depth.png' 63 + }} 64 + /> 65 + 66 + <Team {members} />
+38
src/lib/Demo/Hero.svelte
··· 1 + <script lang="ts"> 2 + import Depth3D from '$lib/Depth3D'; 3 + 4 + export let image: { 5 + image: string; 6 + depth: string; 7 + }; 8 + </script> 9 + 10 + <div class="relative isolate overflow-hidden pt-14"> 11 + <div class="mx-auto max-w-7xl px-6 py-32 sm:py-40 lg:px-8"> 12 + <div 13 + class="mx-auto max-w-2xl lg:mx-0 lg:grid lg:max-w-none lg:grid-cols-2 lg:gap-x-16 lg:gap-y-6 xl:grid-cols-1 xl:grid-rows-1 xl:gap-x-8" 14 + > 15 + <h1 16 + class="max-w-2xl text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl lg:col-span-2 xl:col-auto" 17 + > 18 + Depth based 3D effect 19 + </h1> 20 + <div class="mt-6 max-w-xl lg:mt-0 xl:col-end-1 xl:row-start-1"> 21 + <p class="text-lg leading-8 text-gray-600"> 22 + For your svelte website, made with Threlte, Three.js and TailwindCSS 23 + </p> 24 + <div class="mt-10 flex items-center gap-x-6"> 25 + <a href='https://github.com/flo-bit/svelte-depth-3d-component' class="text-sm font-semibold leading-6 text-gray-900" 26 + >Get the code <span aria-hidden="true">→</span></a 27 + > 28 + </div> 29 + </div> 30 + 31 + <div 32 + class="mt-10 aspect-[6/5] w-full max-w-lg rounded-2xl overflow-hidden sm:mt-16 lg:mt-0 lg:max-w-none xl:row-span-2 xl:row-end-2 xl:mt-36" 33 + > 34 + <Depth3D {image} detail={1000} cameraPosition={[0, 0, 7]} /> 35 + </div> 36 + </div> 37 + </div> 38 + </div>
+32
src/lib/Demo/Quote.svelte
··· 1 + <script lang="ts"> 2 + import Depth3D from '$lib/Depth3D'; 3 + 4 + export let image: { 5 + image: string; 6 + depth: string; 7 + }; 8 + </script> 9 + 10 + <section class="isolate overflow-hidden px-6 lg:px-8"> 11 + <div class="relative mx-auto max-w-2xl py-24 sm:py-32 lg:max-w-4xl"> 12 + <figure class="grid grid-cols-1 items-center gap-x-6 gap-y-8 lg:gap-x-10"> 13 + <div class="relative col-span-2 lg:col-start-1 lg:row-start-2"> 14 + <blockquote class="text-xl font-semibold leading-8 text-gray-900 sm:text-2xl sm:leading-9"> 15 + <p> 16 + "Two things are infinite: the universe and the number of times people misattribute 17 + quotes to me; and I'm not sure about the universe." 18 + </p> 19 + </blockquote> 20 + </div> 21 + <div class="col-end-1 w-32 lg:row-span-4 lg:w-72 h-32 lg:h-72 relative"> 22 + <div class="absolute inset-0"> 23 + <Depth3D {image} rounded /> 24 + </div> 25 + </div> 26 + <figcaption class="text-base lg:col-start-1 lg:row-start-3"> 27 + <div class="font-semibold text-gray-900">Albert Einstein</div> 28 + <div class="mt-1 text-gray-500">Famous person</div> 29 + </figcaption> 30 + </figure> 31 + </div> 32 + </section>
+78
src/lib/Demo/Team.svelte
··· 1 + <script lang="ts"> 2 + import Depth3D from '$lib/Depth3D'; 3 + 4 + export let title = 'The Team'; 5 + export let description = 'These are real people with totally not AI generated names and descriptions.'; 6 + 7 + export let members: { 8 + name: string; 9 + role: string; 10 + description: string; 11 + image: string; 12 + depth: string; 13 + }[]; 14 + </script> 15 + 16 + <div class="bg-white py-24 md:py-32"> 17 + <div 18 + class="mx-auto grid max-w-2xl lg:max-w-4xl grid-cols-1 gap-x-8 gap-y-20 px-6 lg:px-8 xl:grid-cols-5" 19 + > 20 + <div class="max-w-2xl xl:col-span-2"> 21 + <h2 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">{title}</h2> 22 + <p class="mt-6 text-lg leading-8 text-gray-600"> 23 + {description} 24 + </p> 25 + </div> 26 + <ul role="list" class="-mt-12 space-y-12 divide-y divide-gray-200 xl:col-span-3"> 27 + {#each members as member} 28 + <li class="flex flex-col gap-10 pt-12 sm:flex-row"> 29 + <div class="aspect-[4/5] w-52 flex-none rounded-2xl overflow-hidden"> 30 + <Depth3D 31 + image={{ 32 + image: member.image, 33 + depth: member.depth 34 + }} 35 + cameraPosition={[0, -0.5, 8]} 36 + /> 37 + </div> 38 + <div class="max-w-xl flex-auto"> 39 + <h3 class="text-lg font-semibold leading-8 tracking-tight text-gray-900"> 40 + {member.name} 41 + </h3> 42 + <p class="text-base leading-7 text-gray-600">{member.role}</p> 43 + <p class="mt-6 text-base leading-7 text-gray-600"> 44 + {member.description} 45 + </p> 46 + <ul role="list" class="mt-6 flex gap-x-6"> 47 + <li> 48 + <a href="https://twitter.com/flobit_dev" class="text-gray-400 hover:text-gray-500"> 49 + <span class="sr-only">X</span> 50 + <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"> 51 + <path 52 + d="M11.4678 8.77491L17.2961 2H15.915L10.8543 7.88256L6.81232 2H2.15039L8.26263 10.8955L2.15039 18H3.53159L8.87581 11.7878L13.1444 18H17.8063L11.4675 8.77491H11.4678ZM9.57608 10.9738L8.95678 10.0881L4.02925 3.03974H6.15068L10.1273 8.72795L10.7466 9.61374L15.9156 17.0075H13.7942L9.57608 10.9742V10.9738Z" 53 + /> 54 + </svg> 55 + </a> 56 + </li> 57 + <li> 58 + <a 59 + href="https://linkedin.com/in/floriankillius" 60 + class="text-gray-400 hover:text-gray-500" 61 + > 62 + <span class="sr-only">LinkedIn</span> 63 + <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"> 64 + <path 65 + fill-rule="evenodd" 66 + d="M16.338 16.338H13.67V12.16c0-.995-.017-2.277-1.387-2.277-1.39 0-1.601 1.086-1.601 2.207v4.248H8.014v-8.59h2.559v1.174h.037c.356-.675 1.227-1.387 2.526-1.387 2.703 0 3.203 1.778 3.203 4.092v4.711zM5.005 6.575a1.548 1.548 0 11-.003-3.096 1.548 1.548 0 01.003 3.096zm-1.337 9.763H6.34v-8.59H3.667v8.59zM17.668 1H2.328C1.595 1 1 1.581 1 2.298v15.403C1 18.418 1.595 19 2.328 19h15.34c.734 0 1.332-.582 1.332-1.299V2.298C19 1.581 18.402 1 17.668 1z" 67 + clip-rule="evenodd" 68 + /> 69 + </svg> 70 + </a> 71 + </li> 72 + </ul> 73 + </div> 74 + </li> 75 + {/each} 76 + </ul> 77 + </div> 78 + </div>
+13
src/lib/Depth3D/Depth3D.svelte
··· 1 + <script lang="ts"> 2 + import { Canvas } from '@threlte/core'; 3 + import Scene3D from './Scene3D.svelte'; 4 + 5 + export let image: { 6 + image: string; 7 + depth: string; 8 + }; 9 + </script> 10 + 11 + <Canvas> 12 + <Scene3D {image} {...$$restProps} /> 13 + </Canvas>
+119
src/lib/Depth3D/Scene3D.svelte
··· 1 + <script lang="ts"> 2 + import { T, useTask } from '@threlte/core'; 3 + import { useTexture, Align } from '@threlte/extras'; 4 + 5 + import { Vector2, ShaderMaterial, PlaneGeometry, LinearSRGBColorSpace } from 'three'; 6 + 7 + type DepthImage = { 8 + image: string; 9 + depth: string; 10 + }; 11 + export let image: DepthImage; 12 + 13 + export let rounded = false; 14 + 15 + export let cameraPosition: [number, number, number] = [0, 0, 9]; 16 + 17 + export let rotate = true; 18 + export let rotationScale = 0.2; 19 + export let rotationSpeed = 1.5; 20 + 21 + export let detail = 200; 22 + 23 + export let depthScale = 2; 24 + 25 + const map = useTexture(image.image, { 26 + transform: (texture) => { 27 + texture.colorSpace = LinearSRGBColorSpace; 28 + //texture.encoding = LinearEncoding; 29 + return texture; 30 + } 31 + }); 32 + const depthMap = useTexture(image.depth, { 33 + transform: (texture) => { 34 + //texture.encoding = LinearEncoding; 35 + return texture; 36 + } 37 + }); 38 + 39 + const rotation = new Vector2(0.5, 0.5); 40 + 41 + const uniforms = { 42 + uTexture: { type: 't', value: map }, 43 + depthMap: { type: 't', value: depthMap } 44 + }; 45 + const material = new ShaderMaterial({ 46 + uniforms: uniforms, 47 + vertexShader: ` 48 + varying vec2 vUv; 49 + uniform sampler2D depthMap; 50 + 51 + void main() { 52 + vUv = uv; 53 + // move z position based on the depth map 54 + float depth = texture2D(depthMap, vUv).r; 55 + vec3 newPosition = position + vec3(0.0, 0.0, depth * ${depthScale.toFixed(1)}); 56 + gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); 57 + }`, 58 + fragmentShader: ` 59 + uniform sampler2D uTexture; 60 + varying vec2 vUv; 61 + 62 + void main() { 63 + ${ 64 + rounded 65 + ? `// get distance from center 66 + vec2 center = vec2(0.5, 0.5); 67 + float dist = distance(vUv, center); 68 + 69 + // if distance is greater than 0.5, discard the pixel 70 + if (dist > 0.5) discard;` 71 + : '' 72 + } 73 + 74 + gl_FragColor = texture2D(uTexture, vUv); 75 + }` 76 + }); 77 + 78 + const geometry = new PlaneGeometry(7, 7, detail, detail); 79 + 80 + export let time = 0; 81 + const { start, stop } = useTask( 82 + (dt) => { 83 + time += dt * rotationSpeed; 84 + rotation.x = Math.sin(time) * 0.5; 85 + rotation.y = Math.cos(time) * 0.5; 86 + }, 87 + { autoStart: false } 88 + ); 89 + 90 + $: if (rotate) { 91 + start(); 92 + } else { 93 + stop(); 94 + } 95 + </script> 96 + 97 + <T.PerspectiveCamera makeDefault position={cameraPosition}></T.PerspectiveCamera> 98 + 99 + {#await map then mapValue} 100 + {#await depthMap then depthValue} 101 + <Align> 102 + <T.Mesh 103 + rotation.x={rotation.y * rotationScale} 104 + rotation.y={rotation.x * rotationScale} 105 + scale.x={mapValue.image.width / mapValue.image.height} 106 + > 107 + <T is={geometry} /> 108 + <T 109 + is={material} 110 + uniforms={{ 111 + depthMap: { value: depthValue }, 112 + uTexture: { value: mapValue }, 113 + mouse: { value: rotation } 114 + }} 115 + /> 116 + </T.Mesh> 117 + </Align> 118 + {/await} 119 + {/await}
+2
src/lib/Depth3D/index.ts
··· 1 + export { default as Depth3D } from './Depth3D.svelte'; 2 + export { default } from './Depth3D.svelte';
-119
src/lib/Depth3D/Base/Depth3D.svelte
··· 1 - <script lang="ts"> 2 - import { T, useTask, useThrelte } from '@threlte/core'; 3 - import { useTexture, Align } from '@threlte/extras'; 4 - 5 - import { Vector2, ShaderMaterial, PlaneGeometry, LinearSRGBColorSpace, Color } from 'three'; 6 - 7 - type DepthImage = { 8 - image: string; 9 - depth: string; 10 - }; 11 - export let image: DepthImage; 12 - 13 - export let rounded = false; 14 - 15 - export let cameraPosition: [number, number, number] = [0, 0, 9]; 16 - 17 - export let rotate = true; 18 - export let rotationScale = 0.2; 19 - export let rotationSpeed = 1.5; 20 - 21 - export let detail = 1000; 22 - 23 - export let depthScale = 2; 24 - 25 - const map = useTexture(image.image, { 26 - transform: (texture) => { 27 - texture.colorSpace = LinearSRGBColorSpace; 28 - //texture.encoding = LinearEncoding; 29 - return texture; 30 - } 31 - }); 32 - const depthMap = useTexture(image.depth, { 33 - transform: (texture) => { 34 - //texture.encoding = LinearEncoding; 35 - return texture; 36 - } 37 - }); 38 - 39 - const rotation = new Vector2(0.5, 0.5); 40 - 41 - const uniforms = { 42 - uTexture: { type: 't', value: map }, 43 - depthMap: { type: 't', value: depthMap } 44 - }; 45 - const material = new ShaderMaterial({ 46 - uniforms: uniforms, 47 - vertexShader: ` 48 - varying vec2 vUv; 49 - uniform sampler2D depthMap; 50 - 51 - void main() { 52 - vUv = uv; 53 - // move z position based on the depth map 54 - float depth = texture2D(depthMap, vUv).r; 55 - vec3 newPosition = position + vec3(0.0, 0.0, depth * ${depthScale.toFixed(1)}); 56 - gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); 57 - }`, 58 - fragmentShader: ` 59 - uniform sampler2D uTexture; 60 - varying vec2 vUv; 61 - 62 - void main() { 63 - ${ 64 - rounded 65 - ? `// get distance from center 66 - vec2 center = vec2(0.5, 0.5); 67 - float dist = distance(vUv, center); 68 - 69 - // if distance is greater than 0.5, discard the pixel 70 - if (dist > 0.5) discard;` 71 - : '' 72 - } 73 - 74 - gl_FragColor = texture2D(uTexture, vUv); 75 - }` 76 - }); 77 - 78 - const geometry = new PlaneGeometry(7, 7, detail, detail); 79 - 80 - export let time = 0; 81 - const { start, stop } = useTask( 82 - (dt) => { 83 - time += dt * rotationSpeed; 84 - rotation.x = Math.sin(time) * 0.5; 85 - rotation.y = Math.cos(time) * 0.5; 86 - }, 87 - { autoStart: false } 88 - ); 89 - 90 - $: if (rotate) { 91 - start(); 92 - } else { 93 - stop(); 94 - } 95 - </script> 96 - 97 - <T.PerspectiveCamera makeDefault position={cameraPosition}></T.PerspectiveCamera> 98 - 99 - {#await map then mapValue} 100 - {#await depthMap then depthValue} 101 - <Align> 102 - <T.Mesh 103 - rotation.x={rotation.y * rotationScale} 104 - rotation.y={rotation.x * rotationScale} 105 - scale.x={mapValue.image.width / mapValue.image.height} 106 - > 107 - <T is={geometry} /> 108 - <T 109 - is={material} 110 - uniforms={{ 111 - depthMap: { value: depthValue }, 112 - uTexture: { value: mapValue }, 113 - mouse: { value: rotation } 114 - }} 115 - /> 116 - </T.Mesh> 117 - </Align> 118 - {/await} 119 - {/await}
-49
src/lib/Depth3D/Components/Hero3D.svelte
··· 1 - <script lang="ts"> 2 - import Depth3D from '$lib/Depth3D/Base/Depth3D.svelte'; 3 - import { Canvas } from '@threlte/core'; 4 - 5 - export let image: { 6 - image: string; 7 - depth: string; 8 - }; 9 - </script> 10 - 11 - <div class="bg-white"> 12 - <div class="relative isolate overflow-hidden pt-14"> 13 - <div class="mx-auto max-w-7xl px-6 py-32 sm:py-40 lg:px-8"> 14 - <div 15 - class="mx-auto max-w-2xl lg:mx-0 lg:grid lg:max-w-none lg:grid-cols-2 lg:gap-x-16 lg:gap-y-6 xl:grid-cols-1 xl:grid-rows-1 xl:gap-x-8" 16 - > 17 - <h1 18 - class="max-w-2xl text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl lg:col-span-2 xl:col-auto" 19 - > 20 - Depth based 3D effect 21 - </h1> 22 - <div class="mt-6 max-w-xl lg:mt-0 xl:col-end-1 xl:row-start-1"> 23 - <p class="text-lg leading-8 text-gray-600"> 24 - For your website, made with Svelte, Threlte and Three.js 25 - </p> 26 - <div class="mt-10 flex items-center gap-x-6"> 27 - <a href="https://github.com/flo-bit/svelte-depth-3d-component" class="text-sm font-semibold leading-6 text-gray-900" 28 - >See on Github <span aria-hidden="true">→</span></a 29 - > 30 - </div> 31 - </div> 32 - <!-- <img 33 - src="https://images.unsplash.com/photo-1567532900872-f4e906cbf06a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1280&q=80" 34 - alt="" 35 - class="mt-10 aspect-[6/5] w-full max-w-lg rounded-2xl object-cover sm:mt-16 lg:mt-0 lg:max-w-none xl:row-span-2 xl:row-end-2 xl:mt-36" 36 - /> --> 37 - 38 - <div 39 - class="mt-10 aspect-[6/5] w-full max-w-lg rounded-2xl overflow-hidden sm:mt-16 lg:mt-0 lg:max-w-none xl:row-span-2 xl:row-end-2 xl:mt-36" 40 - > 41 - <Canvas> 42 - <Depth3D {image} cameraPosition={[0, 0, 7]} /> 43 - </Canvas> 44 - </div> 45 - </div> 46 - </div> 47 - <div class="absolute inset-x-0 bottom-0 -z-10 h-24 bg-gradient-to-t from-white sm:h-32"></div> 48 - </div> 49 - </div>
-41
src/lib/Depth3D/Components/Quote3D.svelte
··· 1 - <script lang="ts"> 2 - import Depth3D from '$lib/Depth3D/Base/Depth3D.svelte'; 3 - import { Canvas } from '@threlte/core'; 4 - 5 - export let quote: string; 6 - 7 - export let author: string; 8 - export let role: string | undefined = undefined; 9 - 10 - export let image: { 11 - image: string; 12 - depth: string; 13 - }; 14 - </script> 15 - 16 - <section class="isolate overflow-hidden px-6 lg:px-8"> 17 - <div class="relative mx-auto max-w-2xl py-24 sm:py-32 lg:max-w-4xl"> 18 - <figure class="grid grid-cols-1 items-center gap-x-6 gap-y-8 lg:gap-x-10"> 19 - <div class="relative col-span-2 lg:col-start-1 lg:row-start-2"> 20 - <blockquote class="text-xl font-semibold leading-8 text-gray-900 sm:text-2xl sm:leading-9"> 21 - <p> 22 - {quote} 23 - </p> 24 - </blockquote> 25 - </div> 26 - <div class="col-end-1 w-32 lg:row-span-4 lg:w-72 h-32 lg:h-72 relative"> 27 - <div class="absolute inset-0"> 28 - <Canvas> 29 - <Depth3D {image} rounded /> 30 - </Canvas> 31 - </div> 32 - </div> 33 - <figcaption class="text-base lg:col-start-1 lg:row-start-3"> 34 - <div class="font-semibold text-gray-900">{author}</div> 35 - {#if role} 36 - <div class="mt-1 text-gray-500">{role}</div> 37 - {/if} 38 - </figcaption> 39 - </figure> 40 - </div> 41 - </section>
-84
src/lib/Depth3D/Components/Team3D.svelte
··· 1 - <script lang="ts"> 2 - import Depth3D from '$lib/Depth3D/Base/Depth3D.svelte'; 3 - import { Canvas } from '@threlte/core'; 4 - 5 - export let members: { 6 - name: string; 7 - role: string; 8 - description: string; 9 - image: string; 10 - depth: string; 11 - }[]; 12 - </script> 13 - 14 - <div class="bg-white py-24 md:py-32"> 15 - <div 16 - class="mx-auto grid max-w-2xl lg:max-w-4xl grid-cols-1 gap-x-8 gap-y-20 px-6 lg:px-8 xl:grid-cols-5" 17 - > 18 - <div class="max-w-2xl xl:col-span-2"> 19 - <h2 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">The Team</h2> 20 - <p class="mt-6 text-lg leading-8 text-gray-600"> 21 - These are real people with totally not AI generated names and descriptions. 22 - </p> 23 - </div> 24 - <ul role="list" class="-mt-12 space-y-12 divide-y divide-gray-200 xl:col-span-3"> 25 - {#each members as member} 26 - <li class="flex flex-col gap-10 pt-12 sm:flex-row"> 27 - <!-- <img 28 - class="aspect-[4/5] w-52 flex-none rounded-2xl object-cover" 29 - src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=1024&h=1024&q=80" 30 - alt="" 31 - /> --> 32 - 33 - <div class="aspect-[4/5] w-52 flex-none rounded-2xl overflow-hidden"> 34 - <Canvas> 35 - <Depth3D 36 - image={{ 37 - image: member.image, 38 - depth: member.depth 39 - }} 40 - cameraPosition={[0, -0.5, 8]} 41 - /> 42 - </Canvas> 43 - </div> 44 - <div class="max-w-xl flex-auto"> 45 - <h3 class="text-lg font-semibold leading-8 tracking-tight text-gray-900"> 46 - {member.name} 47 - </h3> 48 - <p class="text-base leading-7 text-gray-600">{member.role}</p> 49 - <p class="mt-6 text-base leading-7 text-gray-600"> 50 - {member.description} 51 - </p> 52 - <ul role="list" class="mt-6 flex gap-x-6"> 53 - <li> 54 - <a href="https://twitter.com/flobit_dev" class="text-gray-400 hover:text-gray-500"> 55 - <span class="sr-only">X</span> 56 - <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"> 57 - <path 58 - d="M11.4678 8.77491L17.2961 2H15.915L10.8543 7.88256L6.81232 2H2.15039L8.26263 10.8955L2.15039 18H3.53159L8.87581 11.7878L13.1444 18H17.8063L11.4675 8.77491H11.4678ZM9.57608 10.9738L8.95678 10.0881L4.02925 3.03974H6.15068L10.1273 8.72795L10.7466 9.61374L15.9156 17.0075H13.7942L9.57608 10.9742V10.9738Z" 59 - /> 60 - </svg> 61 - </a> 62 - </li> 63 - <li> 64 - <a 65 - href="https://linkedin.com/in/floriankillius" 66 - class="text-gray-400 hover:text-gray-500" 67 - > 68 - <span class="sr-only">LinkedIn</span> 69 - <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"> 70 - <path 71 - fill-rule="evenodd" 72 - d="M16.338 16.338H13.67V12.16c0-.995-.017-2.277-1.387-2.277-1.39 0-1.601 1.086-1.601 2.207v4.248H8.014v-8.59h2.559v1.174h.037c.356-.675 1.227-1.387 2.526-1.387 2.703 0 3.203 1.778 3.203 4.092v4.711zM5.005 6.575a1.548 1.548 0 11-.003-3.096 1.548 1.548 0 01.003 3.096zm-1.337 9.763H6.34v-8.59H3.667v8.59zM17.668 1H2.328C1.595 1 1 1.581 1 2.298v15.403C1 18.418 1.595 19 2.328 19h15.34c.734 0 1.332-.582 1.332-1.299V2.298C19 1.581 18.402 1 17.668 1z" 73 - clip-rule="evenodd" 74 - /> 75 - </svg> 76 - </a> 77 - </li> 78 - </ul> 79 - </div> 80 - </li> 81 - {/each} 82 - </ul> 83 - </div> 84 - </div>