Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add shared state documentation #699

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
157 changes: 157 additions & 0 deletions docs/cookbook/shared-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
title: Shared State
description: How to use a reactive composable to share your objects across component files.
author: whitespacecode
thumbnail: /recipes/animations.png
difficulty: 0
---

# Shared State in TresJS

This guide will help you get started with shared state in TresJS by building a simple scene with a cube that can be shared across component files.

<StackBlitzEmbed project-id="tresjs-minimal-reproduction-rycc4j" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @whitespacecode since the example doesn't rely on third party libs, can we replace this with a Tresjs repl playground https://play.tresjs.org/ ?

You can find an example on how here

<SandboxDemo url="https://play.tresjs.org/#eNqVVt1y2jwQfRUN30WSKdimhLbjL3Qo9GfaadpM4K7uhbAXUGpLGkn8pJm8e1eSDXZCMmRCGGv37NHZ1XrFXWuqQH+QMlivoBW3LnSqmDREg1lJklO+GCQto5PW+4SzQgplyB3RS5rnYnMNc3JP5koU5ASjT/6vQSzrmPI11W2y0nANPAP1XQhZBQwNIm50mArVjPypZsyMBTdK5HrHv4Mz4EboRsSIapZOljQTm0sq22Ry/WU0FrlQE0lTaJMfYio4oEsyvtgxmqUCOEl4wlPBtSGLnAzIXcIJSXOgyhHE5OS/d68/jsb9k7b1YOK4iY6JUStwFprLJY3JnObaGzwEN5veSogfarMIsTJyhRlWAuOHgi3I7BXHzQTQfb9XPRNbewyD2pmcnu3dd0RwW3XMetA8B4/y3tPTMzJ475Nn81PPGaxpvoIzZ6xbAiUMNUzw4Ja8GpAoiLoWgpruHWXCL0LfRNgyuDBQyJwawBUhF/u+IOvOjPEM22uRJy2ywWex6Wj21yMR2+yEsDJbiitQWkJq2BrGtABFSSyFZlYWEv7qt8nbwH/9Ru54LtZoPu/bZ+oCcdm1K45Hjc9R4FZzt+hGUYSrxoaXoJfNPTqv2wQ/kdugqol1RG1ySc0yuPrqvSVNlTye5BcQBRh1i2LUQtuYbpt0reCeZas2rm09FYIjKShGc5LaVsGosjXrUsMq4JF2BXMM8QeJESnVpuN7tZkWqrefR7pHYntAttVcfb1I+vln+3ec9LrWplisvz2Gx2oncglqX+ejZX0ejaLe6NiKpoD991QVO71DzdEpW4OErnkOab/CqXuoRRC8/3+i2BNDeUZV9jiz+Vv791Rmtdw+FDM7Y7+zxdKQmHEDHPO6LV+YxkvxkWENbGY09/Dnumr3rhym9HL8aEDDRVibG612yw/7TkFlcKMFx5vKDaakdOAFFfv5ZW31u8U6ktbSGKnjMEwzjvEZ5GytAg4m5LII6/BhL+gHUZgxbUJrRnTSchO5QexvoZdw+wikf1OnL83NXcwG6B+JTXAE/w47PA9wiJXMlTEomI2pc9tb7xheixsiY/8d6n0FuqiXAW97vEyOrm8NPuxGrsA47WEbFM3qljhsIAXZC4h9wHPUCOxkULAjSCuoTf48eBPmbFanrO467Emj8ZKds8WDjkxFIVkO6qe03d/sTHdHf3O23U8IF7OE9M8B+43eeslX2Cyg1lju/VHiZADj3Z8mP2CLzztnIbJVXh7OE85r0CJfWY0eNlrxDGXXcE7tV/eC4Q+Pqf60dW9umVRDqMFfO876q5pJu17zht+ucA7vjmP8TJX2mfWC3q7g9/8AWlN6bg==" />

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @alvarosabu
I tried with the playground and i'm getting this error:
'get' on proxy: property 'modelViewMatrix' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '#<cr>' but got '#<cr>')
I tried a few things but i'm keep getting errors on the playground.

Copy link
Author

@whitespacecode whitespacecode Nov 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


## Creating a State Composable

First, we'll create a composable to store the objects.

### Setting the object to the state
Next, we'll assign an object to the state and include it in a subcomponent where we can access and use it.

### Using the object in other components
With the mesh assigned to the reactive state, it's available throughout your project.

::: code-group

```vue [App.vue]
<script setup lang="ts">
import { BoxGeometry, Mesh, MeshNormalMaterial } from 'three';

import SubComponent from './SubComponent.vue';
import { useState } from '../composables/state';

const { mesh } = useState();

//assinging the object to the state
mesh.value = new Mesh(new BoxGeometry(), new MeshNormalMaterial());
</script>

<template>
<TresPerspectiveCamera />

<SubComponent />
</template>
```

```vue [Subcomponent.vue]
<script setup lang="ts">
import { useState } from '../composables/state';
const { mesh } = useState();

</script>

<template>
<primitive v-if="mesh" :object="mesh" />
</template>
```

```ts [composables/state.ts]
import { reactive, toRefs } from "vue";

const state = reactive({
mesh: null,
//you can add more objects here
})

export function useState() {
return {
...toRefs(state)
}
}
```
:::

## Using TresMesh components

You can also add TresMesh components to the reactive state. Here, we'll use a reference and assign it to the state when mounted.

```vue
<script setup lang="ts">
import { BoxGeometry, Mesh, MeshNormalMaterial } from 'three';

import SubComponent from './SubComponent.vue';
import { useState } from '../composables/state';

const { mesh } = useState();

//reference the object
const exampleRef = ref(null);

//assinging the object to the state when mounted
onMounted(() => {
mesh.value = exampleRef.value;
});
</script>

<template>
<TresPerspectiveCamera />

<TresMesh ref="exampleRef" :position="[0, 0, 0]" cast-shadow>
<TresBoxGeometry :args="[1.5, 1.5, 1.5]" />
<TresMeshToonMaterial color="#4F4F4F" />
</TresMesh>

<SubComponent />
</template>
```

## Using Pinia Store

By using the same logic we can also use Pinia.
By using pinia we also have full access to actions and getters.

::: code-group

```ts [model.ts]
import { defineStore } from "pinia";

export const useModelStore = defineStore('model', {
state: () => {
return {
exampleModel: null,
}
},
actions: {},
});
```

```vue [App.vue]
<script setup lang="ts">
import { BoxGeometry, Mesh, MeshNormalMaterial } from 'three';
import { useModelStore } from '../stores/model';

const modelStore = useModelStore();

//reference the object
const exampleRef = ref(null);

//assinging the object to the state when mounted
onMounted(() => {
modelStore.exampleModel = exampleRef.value;
});
</script>

<template>
<TresPerspectiveCamera />

<TresMesh ref="exampleRef" :position="[0, 0, 0]" cast-shadow>
<TresBoxGeometry :args="[1.5, 1.5, 1.5]" />
<TresMeshToonMaterial color="#4F4F4F" />
</TresMesh>
</template>
```

:::

With these steps, you can easily manage and share objects across different components in your Vue 3 project using a reactive composable.