@threlte/rapier
usePrismaticJoint
Use this hook to initialize a PrismaticImpulseJoint.
A prismatic joint is a slider — it constrains two rigid bodies to translate along a single axis with optional min/max travel limits, and locks all rotation. Reach for it for pistons, hydraulic rams, elevators, sliding doors, drawers, and linear actuators.
<script lang="ts">
import { Canvas } from '@threlte/core'
import { HTML } from '@threlte/extras'
import { World } from '@threlte/rapier'
import { Button, Checkbox, Pane } from 'svelte-tweakpane-ui'
import Scene from './Scene.svelte'
let debug = $state(false)
let resetKey = $state(0)
</script>
<Pane
position="fixed"
title="Prismatic Joint"
>
<Button
title="Reset"
on:click={() => resetKey++}
/>
<Checkbox
bind:value={debug}
label="Debug"
/>
</Pane>
<div>
<Canvas>
<World>
<Scene
{debug}
{resetKey}
/>
{#snippet fallback()}
<HTML transform>
<p class="text-xs">
It seems your browser<br />
doesn't support WASM.<br />
I'm sorry.
</p>
</HTML>
{/snippet}
</World>
</Canvas>
</div>
<style>
div {
height: 100%;
}
</style>
<script lang="ts">
import type { RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat'
import { T, useTask } from '@threlte/core'
import { Collider, CollisionGroups, RigidBody, usePrismaticJoint } from '@threlte/rapier'
let rail = $state<RapierRigidBody>()
let platform = $state<RapierRigidBody>()
const { rigidBodyA, rigidBodyB } = usePrismaticJoint([0, 0, 0], [0, 0, 0], [0, 1, 0], [-2.5, 2.5])
$effect(() => {
if (rail && platform) {
rigidBodyA.set(rail)
rigidBodyB.set(platform)
}
})
const PUMP_INTERVAL = 1.4
let elapsed = 0
useTask((delta) => {
if (!platform) return
elapsed += delta
if (elapsed >= PUMP_INTERVAL) {
elapsed = 0
platform.applyImpulse({ x: 0, y: 70, z: 0 }, true)
}
})
</script>
<CollisionGroups
memberships={[1]}
filter={[0]}
>
<T.Group position={[0, 3, 0]}>
<RigidBody
type="fixed"
bind:rigidBody={rail}
>
<Collider
shape="cuboid"
args={[0.15, 3, 0.15]}
/>
<T.Mesh>
<T.BoxGeometry args={[0.3, 6, 0.3]} />
<T.MeshStandardMaterial
color="#444"
metalness={0.7}
roughness={0.3}
/>
</T.Mesh>
</RigidBody>
</T.Group>
<T.Group position={[0, 0.5, 0]}>
<RigidBody bind:rigidBody={platform}>
<Collider
shape="cuboid"
args={[1.5, 0.2, 1]}
density={5}
friction={1.5}
/>
<T.Mesh
castShadow
receiveShadow
>
<T.BoxGeometry args={[3, 0.4, 2]} />
<T.MeshStandardMaterial
color="#222"
metalness={0.6}
roughness={0.4}
/>
</T.Mesh>
</RigidBody>
</T.Group>
</CollisionGroups>
<script lang="ts">
import { T } from '@threlte/core'
import { OrbitControls } from '@threlte/extras'
import { Collider, Debug, RigidBody } from '@threlte/rapier'
import Press from './Press.svelte'
interface Props {
debug: boolean
resetKey: number
}
let { debug, resetKey }: Props = $props()
const cubes: [number, number, number][] = [
[-1.1, 1.0, -0.6],
[-0.5, 1.0, 0.5],
[0.2, 1.0, -0.3],
[0.8, 1.0, 0.4],
[1.2, 1.0, -0.5]
]
</script>
<T.PerspectiveCamera
makeDefault
position={[5, 4, 10]}
fov={50}
>
<OrbitControls
enableDamping
enableZoom={false}
target={[0, 2.5, 0]}
/>
</T.PerspectiveCamera>
<T.DirectionalLight
castShadow
position={[8, 20, -3]}
/>
<T.AmbientLight intensity={0.4} />
{#if debug}
<Debug />
{/if}
{#key resetKey}
<Press />
{#each cubes as pos (pos)}
<T.Group position={pos}>
<RigidBody>
<Collider
shape="cuboid"
args={[0.15, 0.15, 0.15]}
density={3}
friction={1.5}
/>
<T.Mesh castShadow>
<T.BoxGeometry args={[0.3, 0.3, 0.3]} />
<T.MeshStandardMaterial color="#FE3D00" />
</T.Mesh>
</RigidBody>
</T.Group>
{/each}
{/key}
<T.Group position={[0, -0.5, 0]}>
<RigidBody type="fixed">
<Collider
shape="cuboid"
args={[10, 0.5, 5]}
/>
<T.Mesh receiveShadow>
<T.BoxGeometry args={[20, 1, 10]} />
<T.MeshStandardMaterial color="#888" />
</T.Mesh>
</RigidBody>
</T.Group>
<script>
import { usePrismaticJoint, RigidBody, Collider } from '@threlte/rapier'
const { joint, rigidBodyA, rigidBodyB } = usePrismaticJoint({ x: 1 }, {}, { y: 1 }, [0, 1])
</script>
<RigidBody bind:rigidBody={$rigidBodyA}>
<Collider
shape="cuboid"
args={[1, 1, 1]}
/>
</RigidBody>
<RigidBody bind:rigidBody={$rigidBodyB}>
<Collider
shape="cuboid"
args={[1, 1, 1]}
/>
</RigidBody>
Signature
const {
joint: Writable<PrismaticImpulseJoint>
rigidBodyA: Writable<RAPIER.RigidBody>
rigidBodyB: Writable<RAPIER.RigidBody>
} = usePrismaticJoint(
anchorA, // Position
anchorB, // Position
axis, // Rotation
limits // [min, max] | undefined
)