@threlte/extras
<Float>
This component is a port of drei’s <Float>
component and makes its contents float or hover.
<script lang="ts">
import { Canvas } from '@threlte/core'
import Scene from './Scene.svelte'
</script>
<div>
<Canvas>
<Scene />
</Canvas>
</div>
<style>
div {
height: 100%;
}
</style>
<script lang="ts">
import type { Snippet } from 'svelte'
import { Float } from '@threlte/extras'
import { Spring } from 'svelte/motion'
type Props = {
children?: Snippet<[{ hovering: boolean }]>
}
let { children }: Props = $props()
const scale = new Spring(1)
let hovering = $state(false)
const onPointerEnter = () => {
hovering = true
scale.set(1.1)
}
const onPointerLeave = () => {
hovering = false
scale.set(1)
}
</script>
<Float
floatIntensity={5}
scale={scale.current}
rotationIntensity={2}
rotationSpeed={[1, 0.5, 0.2]}
onpointerenter={onPointerEnter}
onpointerleave={onPointerLeave}
>
{@render children?.({ hovering })}
</Float>
<script lang="ts">
import Blob from './Blob.svelte'
import type { Mesh } from 'three'
import { Environment, Float, Grid, interactivity, useGltf, useDraco } from '@threlte/extras'
import { T } from '@threlte/core'
type Nodes = `ball-${'1' | '2' | '3' | '4' | '5'}`
const dracoLoader = useDraco()
const gltf = useGltf<{
nodes: Record<Nodes, Mesh>
materials: {}
}>('/models/blobs/blobs.glb', {
dracoLoader
})
interactivity()
const red = '#fe3d00'
const blue = '#0000ff'
</script>
<Environment url="/textures/equirectangular/hdr/shanghai_riverside_1k.hdr" />
<Float
rotationIntensity={0.15}
rotationSpeed={2}
>
<T.PerspectiveCamera
makeDefault
position.y={10}
position.z={10}
fov={90}
oncreate={(ref) => {
ref.lookAt(0, 0, 0)
}}
/>
</Float>
<Grid
position.y={-10}
sectionThickness={1}
infiniteGrid
cellColor="#dddddd"
sectionColor="#ffffff"
sectionSize={10}
cellSize={2}
/>
{#await gltf then { nodes }}
{#each Object.values(nodes) as node}
<Blob>
{#snippet children({ hovering })}
<T.Mesh>
<T.MeshPhysicalMaterial
reflectivity={1}
metalness={0.9}
roughness={0.2}
color={hovering ? red : blue}
/>
<T is={node.geometry} />
</T.Mesh>
{/snippet}
</Blob>
{/each}
{/await}
Examples
Basic Example
<script lang="ts">
import { T } from '@threlte/core'
import { Float } from '@threlte/extras'
</script>
<Float
floatIntensity={5}
scale={$scale}
rotationIntensity={2}
>
<T.Mesh>
<T.MeshStandardMaterial color={'orange'} />
<T.BoxGeometry args={[5, 5, 5]} />
</T.Mesh>
</Float>
Floating
floatingRange
determines the allowed range of position trasformation, and by extension the direction in which the children will move. If you provide a single number tuple, like [-0.1,0.1]
the movement will happen on y axis. Alternatively you can provide an array of three tuples to change the movement axes. For example [[0,0],[0,0],[-0.5,0.5]]
will move children between -0.5 and 0.5 relative to the starting position on the Z axis.
Rotation
Rotation is set by rotationSpeed
and rotationIntensity
. Both of them need to be different from 0 to enable rotation. Providing a number
in either of them applies it to all three axes. You get more granual control by passing an array [x: number, y: number, z: number]
. rotationSpeed
is responsible for the speed of the animation and rotationIntensity
for the angle.
seed
is responsible for the starting state of the animations and is random by default. Setting to a fixed value to get a predictable starting result.