Skip to content

Commit 4416c61

Browse files
authored
Merge pull request #129 from botmaster/feature/tres/Add-3d-dog-in-cover
feature/tres/Add-3d-dog-in-cover
2 parents c3db855 + 77ef938 commit 4416c61

9 files changed

Lines changed: 3075 additions & 2436 deletions

File tree

components/app/CoverComponent.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import { Expo, gsap } from 'gsap';
33
import { ScrollTrigger } from 'gsap/ScrollTrigger';
4+
import ExperienceWrapper from "~/components/tres/ExperienceWrapper.vue";
45
56
// Props type definition
67
interface IProps {
@@ -232,6 +233,9 @@ onBeforeUnmount(() => {
232233
<div ref="coverBg" class="cover__background" />
233234
<div ref="bubblesContainer" class="cover__bubbles" />
234235
<div ref="coverDimmer" class="cover__dimmer" />
236+
<ClientOnly>
237+
<LazyExperienceWrapper></LazyExperienceWrapper>
238+
</ClientOnly>
235239
<div class="cover__content">
236240
<div class="container mx-auto">
237241
<div class="line-mask">
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<script setup lang="ts">
2+
import { useProgress } from '@tresjs/cientos'
3+
4+
const { hasFinishLoading, progress } = await useProgress()
5+
</script>
6+
7+
<template>
8+
<Transition
9+
name="fade-loader"
10+
>
11+
<div
12+
v-if="!hasFinishLoading"
13+
class="absolute t-0 l-0 w-full h-full z-20 flex justify-center items-center font-mono"
14+
>
15+
<div class="-mt-20 flex gap-2 items-center w-200px text-sm">
16+
<AppLoader class="text-2xl" />
17+
<code >Loading {{ progress }} %</code>
18+
</div>
19+
</div>
20+
</Transition>
21+
<TresCanvas
22+
:clearAlpha="0"
23+
>
24+
<TheExperience />
25+
</TresCanvas>
26+
</template>
27+
28+
<style scoped lang="scss">
29+
/*
30+
Je ne comprends pas pourquoi, mais je suis obligé de mettre des
31+
classes personnalisées pour les transitions ici, sinon ça ne fonctionne pas si je les mets dans _base.scss
32+
*/
33+
.fade-loader-enter-active,
34+
.fade-loader-leave-active {
35+
transition: opacity 0.3s ease;
36+
}
37+
38+
.fade-loader-enter-from,
39+
.fade-loader-leave-to {
40+
opacity: 0;
41+
}
42+
</style>

components/tres/TheDog.vue

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<script setup lang="ts">
2+
import { computed, ref, watch } from 'vue'
3+
4+
const { state: model, nodes } = useGLTF('/models/husky.glb', {
5+
draco: true,
6+
})
7+
const rig = computed(() => {
8+
console.log('Nodes:', nodes.value)
9+
return nodes.value.Root_Scene
10+
})
11+
12+
const animations = computed(() => model.value?.animations || [])
13+
console.log('Loaded animations:', animations.value)
14+
15+
const { actions } = useAnimations(animations, rig)
16+
console.log('Available actions:', actions)
17+
const currentAction = ref<AnimationAction>()
18+
19+
const transitionToAnimation = (animationName: string, duration = 0.5) => {
20+
if (!actions) { return }
21+
22+
const nextAction = actions[animationName]
23+
if (!nextAction) { return }
24+
25+
// Fade out current animation
26+
if (currentAction.value) {
27+
currentAction.value.fadeOut(duration)
28+
}
29+
30+
// Fade in new animation
31+
nextAction.reset()
32+
nextAction.setEffectiveWeight(1)
33+
nextAction.play()
34+
nextAction.fadeIn(duration)
35+
36+
currentAction.value = nextAction
37+
}
38+
39+
// Définir la séquence d'animations
40+
const animationSequence = [
41+
{ name: 'Idle', duration: 1000, fadeDuration: 0.5 },
42+
{ name: 'Idle', duration: 5000, fadeDuration: 0.5 },
43+
{ name: 'Walk', duration: 5000, fadeDuration: 0.5 },
44+
{ name: 'Gallop', duration: 5000, fadeDuration: 0.5 },
45+
{ name: 'Gallop_Jump', duration: 1000, fadeDuration: 0.5 },
46+
{ name: 'Gallop', duration: 4000, fadeDuration: 0.5 },
47+
{ name: 'Walk', duration: 3000, fadeDuration: 0.5 },
48+
{ name: 'Idle_2', duration: 3000, fadeDuration: 0.5 },
49+
{ name: 'Idle', duration: 0, fadeDuration: 0.5 },
50+
]
51+
52+
const isPlaying = ref(false)
53+
54+
const playAnimationSequence = async () => {
55+
if (!actions || isPlaying.value) { return }
56+
57+
isPlaying.value = true
58+
59+
for (const step of animationSequence) {
60+
console.log('Step:', step)
61+
transitionToAnimation(step.name, step.fadeDuration)
62+
if (step.duration > 0) {
63+
await new Promise(resolve => setTimeout(resolve, step.duration))
64+
}
65+
}
66+
67+
isPlaying.value = false
68+
}
69+
70+
watch(actions, (newValue) => {
71+
console.log('Actions ready:', newValue)
72+
if (!newValue) { return }
73+
playAnimationSequence()
74+
}, { immediate: true })
75+
76+
/* // Example: Transition from Idle to Cheer
77+
const playCheerAnimation = () => {
78+
transitionToAnimation('Walk', 0.3)
79+
}
80+
81+
const playIdleAnimation = () => {
82+
transitionToAnimation('Idle', 0.3)
83+
}
84+
85+
watch(actions, (actions) => {
86+
if (!actions) { return }
87+
console.log('Actions:', actions)
88+
89+
// Start with Idle animation
90+
playIdleAnimation()
91+
92+
// After 5 seconds, switch to Cheer animation
93+
setTimeout(() => {
94+
playCheerAnimation()
95+
}, 5000)
96+
}, { immediate: true }) */
97+
</script>
98+
99+
<template>
100+
<primitive v-if="rig" :object="rig" />
101+
</template>

components/tres/TheExperience.vue

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<script setup lang="ts">
2+
import { OrbitControls } from '@tresjs/cientos'
3+
4+
import TheDog from './TheDog.vue'
5+
</script>
6+
7+
<template>
8+
<TresPerspectiveCamera
9+
:position="[7, 3, 2]"
10+
:look-at="[0, 1, 0]"
11+
/>
12+
<OrbitControls :target="[0, 1, 0]" />
13+
<TresAmbientLight :intensity="1" />
14+
<Suspense>
15+
<Environment preset="sunset" :background="false" :blur="1" />
16+
</Suspense>
17+
<TheDog />
18+
<!-- Render the animated model here -->
19+
</template>

nuxt.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ export default defineNuxtConfig({
190190
'@pinia/nuxt',
191191
'@nuxt/image',
192192
'@nuxt/fonts',
193+
'@tresjs/nuxt'
193194
],
194195

195196
/* features: {

package.json

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"type": "module",
44
"version": "2.27.0",
55
"private": true,
6-
"packageManager": "pnpm@10.22.0",
6+
"packageManager": "pnpm@10.24.0",
77
"description": "Pascal Achard's personal website",
88
"author": "Pascal Achard",
99
"scripts": {
@@ -16,27 +16,29 @@
1616
"lint:fix": "eslint . --fix"
1717
},
1818
"dependencies": {
19-
"@headlessui/tailwindcss": "^0.2.2",
2019
"@notionhq/client": "^2.3.0",
21-
"@vueuse/components": "^13.9.0",
22-
"@vueuse/nuxt": "^13.9.0",
23-
"@vueuse/router": "^13.9.0",
20+
"@tresjs/cientos": "^5.1.1",
21+
"@tresjs/nuxt": "^5.1.1",
22+
"@vueuse/components": "^14.1.0",
23+
"@vueuse/nuxt": "^14.1.0",
24+
"@vueuse/router": "^14.1.0",
2425
"gsap": "^3.13.0",
2526
"install": "^0.13.0",
2627
"lenis": "^1.3.15",
2728
"splitting": "^1.1.0",
29+
"three": "^0.181.2",
2830
"vue-router": "^4.6.3"
2931
},
3032
"devDependencies": {
31-
"@antfu/eslint-config": "^4.19.0",
32-
"@eslint/eslintrc": "^3.3.1",
33+
"@antfu/eslint-config": "^6.2.0",
34+
"@eslint/eslintrc": "^3.3.3",
3335
"@iconify-json/brandico": "^1.2.3",
3436
"@iconify-json/cib": "^1.2.3",
3537
"@iconify-json/eos-icons": "^1.2.4",
3638
"@iconify-json/fa6-brands": "^1.2.6",
37-
"@iconify-json/fluent": "^1.2.34",
39+
"@iconify-json/fluent": "^1.2.35",
3840
"@iconify-json/logos": "^1.2.10",
39-
"@iconify-json/material-symbols": "^1.2.46",
41+
"@iconify-json/material-symbols": "^1.2.48",
4042
"@iconify-json/mdi": "^1.2.3",
4143
"@iconify-json/pajamas": "^1.2.15",
4244
"@nuxt/content": "^2.13.4",
@@ -55,16 +57,15 @@
5557
"@types/node": "^22.19.1",
5658
"@types/splitting": "^1.0.6",
5759
"@types/uuid": "^10.0.0",
58-
"@typescript-eslint/parser": "^8.46.4",
60+
"@typescript-eslint/parser": "^8.48.0",
5961
"eslint": "^9.39.1",
6062
"eslint-config-prettier": "^10.1.8",
6163
"eslint-plugin-prettier": "^5.5.4",
62-
"eslint-plugin-tailwindcss": "^3.18.2",
6364
"nuxt": "^3.20.1",
64-
"nuxt-headlessui": "^1.2.1",
65-
"sass": "^1.94.0",
65+
"nuxt-headlessui": "^1.2.2",
66+
"sass": "^1.94.2",
6667
"typescript": "^5.9.3",
67-
"uuid": "^11.1.0",
68+
"uuid": "^13.0.0",
6869
"vite-svg-loader": "^5.1.0",
6970
"vue-tsc": "^2.2.12"
7071
},

0 commit comments

Comments
 (0)