Spaces:
Running
Running
<script lang="ts"> | |
import { useCursor } from '@threlte/extras' | |
import { T } from "@threlte/core"; | |
import { HTML, type IntersectionEvent } from "@threlte/extras"; | |
import { GLTF, useGltf } from "@threlte/extras"; | |
import Model from "./GPUModel.svelte"; | |
import { Shape, Path, ExtrudeGeometry, BoxGeometry } from "three"; | |
import { onMount } from "svelte"; | |
import type { VideoInstance } from "$lib/elements/video/VideoManager.svelte"; | |
import { videoManager } from "$lib/elements/video/VideoManager.svelte"; | |
// Props interface | |
interface Props { | |
// Transform props | |
position?: [number, number, number]; | |
rotation?: [number, number, number]; | |
scale?: [number, number, number]; | |
rotating?: boolean; | |
} | |
// Props with defaults | |
let { position = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1], rotating = false }: Props = $props(); | |
// Create the TV frame geometry (outer rounded rectangle) | |
function createTVFrame( | |
tvWidth: number, | |
tvHeight: number, | |
tvDepth: number, | |
tvFrameThickness: number, | |
tvCornerRadius: number | |
) { | |
const shape = new Shape(); | |
const x = -tvWidth / 2; | |
const y = -tvHeight / 2; | |
const w = tvWidth; | |
const h = tvHeight; | |
const radius = tvCornerRadius; | |
shape.moveTo(x, y + radius); | |
shape.lineTo(x, y + h - radius); | |
shape.quadraticCurveTo(x, y + h, x + radius, y + h); | |
shape.lineTo(x + w - radius, y + h); | |
shape.quadraticCurveTo(x + w, y + h, x + w, y + h - radius); | |
shape.lineTo(x + w, y + radius); | |
shape.quadraticCurveTo(x + w, y, x + w - radius, y); | |
shape.lineTo(x + radius, y); | |
shape.quadraticCurveTo(x, y, x, y + radius); | |
// Create hole for screen (inner rectangle) | |
const hole = new Path(); | |
const hx = x + tvFrameThickness; | |
const hy = y + tvFrameThickness; | |
const hwidth = w - tvFrameThickness * 2; | |
const hheight = h - tvFrameThickness * 2; | |
const hradius = tvCornerRadius * 0.5; | |
hole.moveTo(hx, hy + hradius); | |
hole.lineTo(hx, hy + hheight - hradius); | |
hole.quadraticCurveTo(hx, hy + hheight, hx + hradius, hy + hheight); | |
hole.lineTo(hx + hwidth - hradius, hy + hheight); | |
hole.quadraticCurveTo(hx + hwidth, hy + hheight, hx + hwidth, hy + hheight - hradius); | |
hole.lineTo(hx + hwidth, hy + hradius); | |
hole.quadraticCurveTo(hx + hwidth, hy, hx + hwidth - hradius, hy); | |
hole.lineTo(hx + hradius, hy); | |
hole.quadraticCurveTo(hx, hy, hx, hy + hradius); | |
shape.holes.push(hole); | |
return new ExtrudeGeometry(shape, { | |
depth: tvDepth, | |
bevelEnabled: true, | |
bevelThickness: 0.02, | |
bevelSize: 0.02, | |
bevelSegments: 8 | |
}); | |
} | |
// Create the screen (video display area) | |
function createScreen(tvWidth: number, tvHeight: number, tvFrameThickness: number) { | |
const w = tvWidth - tvFrameThickness * 2; | |
const h = tvHeight - tvFrameThickness * 2; | |
// Create a very thin box for the screen area (only visible from front) | |
return new BoxGeometry(w, h, 0.02); | |
} | |
const frameGeometry = createTVFrame(1, 1, 1, 0.2, 0.15); | |
const screenGeometry = createScreen(1, 1, 0.2); | |
const gltf = useGltf("/gpu/scene.gltf"); | |
let fan_rotation = $state(0); | |
let rotationPerSeconds = $state(1); // 1 rotation per second by default | |
onMount(() => { | |
const interval = setInterval(() => { | |
// Calculate angle increment per frame for desired rotations per second | |
if (rotating) { | |
const angleIncrement = (Math.PI * 2 * rotationPerSeconds) / 60; | |
fan_rotation = fan_rotation + angleIncrement; | |
} | |
}, 1000/60); // Run at ~60fps | |
return () => { | |
clearInterval(interval); | |
}; | |
}); | |
</script> | |
<T.Group | |
{position} | |
{rotation} | |
{scale} | |
> | |
<!-- TV Frame --> | |
<!-- <T.Mesh geometry={frameGeometry}> | |
<T.MeshStandardMaterial | |
color={"#374151"} | |
metalness={0.05} | |
roughness={0.4} | |
envMapIntensity={0.3} | |
/> | |
</T.Mesh> --> | |
<T.Group | |
scale={[1, 1, 1]} | |
> | |
<Model fan_rotation={fan_rotation} /> | |
</T.Group> | |
<!-- <GLTF castShadow receiveShadow gltf={$gltf} position={{ y: 1 }} scale={3} /> --> | |
<!-- <T.Group scale={[1,1,1]}> | |
{#if $gltf} | |
<T is={$gltf.nodes['Sketchfab_model']} /> | |
{/if} | |
</T.Group> --> | |
</T.Group> | |