Skip to content
This repository was archived by the owner on Feb 1, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions docs/.vitepress/theme/components/CameraShakeDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<script setup lang="ts">
import { Backdrop, CameraShake, ContactShadows, Environment, OrbitControls, useGLTF } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { SRGBColorSpace } from 'three'
import { computed } from 'vue'

const gl = {
clearColor: '#333',
alpha: true,
outputColorSpace: SRGBColorSpace,
}

const { state } = useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/ugly-naked-bunny/ugly-naked-bunny-animated.gltf', { draco: true })

const model = computed(() => state?.value?.scene)
</script>

<template>
<div class="hud-overlay"></div>

<TresCanvas
v-bind="gl"
>
<TresPerspectiveCamera :position="[0, 1.25, 3]" />

<TresGroup name="model" :position="[0, -0.5, 0]" :scale="[0.5, 0.5, 0.5]">
<primitive v-if="model" :object="model" />
</TresGroup>

<Backdrop
:floor="5"
:segments="10"
receive-shadow
:scale="[20, 8.5, 1]"
:position="[0, -0.5, -2]"
>
<TresMeshPhysicalMaterial color="orange" />
</Backdrop>

<ContactShadows
:position="[0, -0.475, 0]"
:scale="5"
:blur="1"
:opacity="0.5"
/>

<TresAmbientLight :intensity="0.5" />

<Suspense>
<Environment preset="dawn" :environment-intensity="0.5" />
</Suspense>

<OrbitControls make-default :max-polar-angle="Math.PI / 2" />

<CameraShake
:intensity="1"
:maxYaw="0.1"
:maxPitch="0.05"
:maxRoll="0.05"
:yawFrequency="0.05"
:pitchFrequency="0.2"
:rollFrequency="0.2"
:decayRate="0.65"
/>
</TresCanvas>
</template>

<style scoped>
.hud-overlay {
position: absolute;
z-index: 2;
width: 90%;
height: 100%;
background-image: url('/camera-shake/fake-hud.svg');
background-repeat: no-repeat;
background-position: center;
background-size: contain;
pointer-events: none;
left: 50%;
transform: translateX(-50%);
aspect-ratio: 486 / 274;
}
</style>
1 change: 1 addition & 0 deletions docs/component-list/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export default [
{ text: 'AccumulativeShadows', link: '/guide/staging/accumulative-shadows' },
{ text: 'ContactShadows', link: '/guide/staging/contact-shadows' },
{ text: 'Precipitation', link: '/guide/staging/precipitation' },
{ text: 'CameraShake', link: '/guide/staging/camera-shake' },
{ text: 'Sparkles', link: '/guide/staging/sparkles' },
{ text: 'Ocean', link: '/guide/staging/ocean' },
{ text: 'Fit', link: '/guide/staging/fit' },
Expand Down
54 changes: 54 additions & 0 deletions docs/guide/staging/camera-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Camera Shake

`<CameraShake />` is a component that adds **natural**, *noise-driven motion* to the **active camera**.
It offers **per-axis control**, **adjustable intensity**, and *optional decay* — perfect for *handheld feel*, *footsteps*, *impacts*, or *engine rumble* — and is based on the [Drei `CameraShake` component](https://drei.docs.pmnd.rs/staging/camera-shake#camerashake).

<DocsDemo>
<CameraShakeDemo />
</DocsDemo>

<details>
<summary>Demo code</summary>

<<< @/.vitepress/theme/components/CameraShakeDemo.vue{0}
</details>

## Usage

You can use `<CameraShake />` component without passing any props, but still if you want you can tweak the props to find the best setup for you

```vue{8}
<template>
<TresCanvas>
<TresPerspectiveCamera :position="[0, 2, 5]" />

<!-- YOUR SCENE -->

<OrbitControls make-default />
<CameraShake :intensity="0.5" />
</TresCanvas>
</template>
```

::: info
`<CameraShake />` is fully compatible with **`<OrbitControls />`**.
To ensure it works *as expected*, make sure to add the **`make-default`** prop:

```vue
<OrbitControls make-default />
```
:::

## Props

| **Prop** | **Description** | **Default** |
|---------------------|-------------------------------------------------------------------------------------------------------------------|-------------|
| `intensity` | **Controls the overall strength** of the shake effect. | `1` |
| `decay` | **Enables gradual reduction** of shake intensity over time. | `false` |
| `decayRate` | **Sets the speed** at which intensity decays per second when `decay` is enabled. Multiplied by `delta` each frame.| `0.65` |
| `maxYaw` | **Maximum amplitude** for yaw (horizontal rotation) in radians. | `0.01` |
| `maxPitch` | **Maximum amplitude** for pitch (vertical rotation) in radians. | `0.01` |
| `maxRoll` | **Maximum amplitude** for roll (tilt) in radians. | `0.01` |
| `yawFrequency` | Frequency of **yaw oscillation**, used with elapsed time in Simplex noise calculations. | `0.1` |
| `pitchFrequency` | Frequency of **pitch oscillation**. | `0.1` |
| `rollFrequency` | Frequency of **roll oscillation**. | `0.1` |
1 change: 1 addition & 0 deletions docs/public/camera-shake/fake-hud.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
130 changes: 130 additions & 0 deletions playground/vue/src/pages/staging/CameraShakeDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<script setup lang="ts">
import { CameraShake, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { NoToneMapping, SRGBColorSpace } from 'three'
import { TresLeches, useControls } from '@tresjs/leches'
import '@tresjs/leches/styles'

const gl = {
clearColor: '#333',
alpha: true,
outputColorSpace: SRGBColorSpace,
toneMapping: NoToneMapping,
}

const {
intensity,
decay,
decayRate,
maxYaw,
maxPitch,
maxRoll,
yawFrequency,
pitchFrequency,
rollFrequency,
} = useControls({
intensity: {
label: 'Intensity',
value: 1,
min: 0,
max: 2,
step: 0.01,
},
decay: false,
decayRate: {
label: 'Decay Rate',
value: 0.65,
min: 0,
max: 1,
step: 0.01,
},
maxYaw: {
label: 'Max Yaw',
value: 0.01,
min: 0,
max: 0.2,
step: 0.001,
},
maxPitch: {
label: 'Max Pitch',
value: 0.01,
min: 0,
max: 0.2,
step: 0.001,
},
maxRoll: {
label: 'Max Roll',
value: 0.01,
min: 0,
max: 0.2,
step: 0.001,
},
yawFrequency: {
label: 'Yaw Freq',
value: 0.5,
min: 0,
max: 2,
step: 0.01,
},
pitchFrequency: {
label: 'Pitch Freq',
value: 0.5,
min: 0,
max: 2,
step: 0.01,
},
rollFrequency: {
label: 'Roll Freq',
value: 0.4,
min: 0,
max: 2,
step: 0.01,
},
}, {
uuid: 'camera-shake-demo',
})
</script>

<template>
<TresLeches
class="top-0 important-right-4"
uuid="camera-shake-demo"
/>

<TresCanvas
v-bind="gl"
>
<TresPerspectiveCamera :position="[0, 2, 5]" />

<TresMesh>
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshBasicMaterial color="orange" />
</TresMesh>

<TresMesh :position-x="-2.5">
<TresSphereGeometry :args="[.5, 32, 32]" />
<TresMeshBasicMaterial color="hotpink" />
</TresMesh>

<TresMesh :position-x="2.5">
<TresConeGeometry :args="[.5, 1, 32]" />
<TresMeshBasicMaterial color="lime" />
</TresMesh>

<TresGridHelper :args="[10, 10]" />

<OrbitControls make-default />

<CameraShake
:intensity="intensity.value"
:decay="decay.value"
:decayRate="decayRate.value"
:maxYaw="maxYaw.value"
:maxPitch="maxPitch.value"
:maxRoll="maxRoll.value"
:yawFrequency="yawFrequency.value"
:pitchFrequency="pitchFrequency.value"
:rollFrequency="rollFrequency.value"
/>
</TresCanvas>
</template>
5 changes: 5 additions & 0 deletions playground/vue/src/router/routes/staging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ export const stagingRoutes = [
name: 'Smoke',
component: () => import('../../pages/staging/SmokeDemo.vue'),
},
{
path: '/staging/camera-shake',
name: 'CameraShake',
component: () => import('../../pages/staging/CameraShakeDemo.vue'),
},
{
path: '/staging/precipitation',
name: 'Precipitation',
Expand Down
Loading
Loading