multi cards
All checks were successful
Deploy App / build (push) Successful in 2m4s
Deploy App / deploy (push) Successful in 21s

This commit is contained in:
valere
2026-02-11 16:49:34 +01:00
parent 620112d9ba
commit 399519d1d4
8 changed files with 276 additions and 105 deletions

View File

@@ -6,10 +6,13 @@
<b v-else>normal</b>
</button>
<button @click="Rewind">
rewind
Rewind
</button>
<button @click="Wind">
Wind
</button>
<!-- <div>{{ progressPercentage }}</div> -->
<div>{{ currentSpeed }}</div>
<div>{{ (currentSpeed).toFixed(2) }}</div>
</div>
<div class="disc" ref="discRef" id="disc">
<div class="bobine" :style="{
@@ -31,6 +34,7 @@ import type { Card } from '~~/types/types'
import { ref, onMounted, onUnmounted, watch, computed, nextTick } from 'vue'
import Disc from '~/utils/platine/disc'
import Sampler from '~/utils/platine/sampler'
import { duration } from 'drizzle-orm/gel-core';
const props = defineProps<{ card?: Card, autoplay?: boolean }>()
const autoplay = props.autoplay ?? false
@@ -184,9 +188,97 @@ const Reverse = () => {
const Rewind = async () => {
if (!disc.value || !sampler.value) return
Reverse()
play()
// Sauvegarder l'état actuel
disc.value.isStopped() ? play() : null
const wasPlaying = !disc.value.isStopped()
const currentSpeed = disc.value.playbackSpeed
// Fonction pour l'effet de scratch/pull up
const scratchEffect = async () => {
// Ralentir progressivement
const slowDownDuration = 300 // ms
const startTime = performance.now()
const startSpeed = wasPlaying ? currentSpeed : 0.1
const slowDown = (timestamp: number) => {
const elapsed = timestamp - startTime
const progress = Math.min(elapsed / slowDownDuration, 1)
// Courbe d'accélération pour un effet plus naturel
const easeOut = 1 - Math.pow(1 - progress, 2)
// Ralentir progressivement jusqu'à presque l'arrêt
const newSpeed = startSpeed * (1 - easeOut) + 0.05
sampler.value?.setPlaybackRate(newSpeed)
if (progress < 1) {
requestAnimationFrame(slowDown)
} else {
// Une fois ralenti, effectuer le rembobinage
performRewind()
}
}
requestAnimationFrame(slowDown)
}
const performRewind = () => {
// Mettre en pause la lecture actuelle
if (wasPlaying) {
sampler.value?.pause()
}
// Remettre à zéro la position
sampler.value?.play(0)
disc.value?.setAngle(0)
// Effet de scratch rapide
const scratchDuration = 200 // ms
const scratchStart = performance.now()
const scratch = (timestamp: number) => {
const elapsed = timestamp - scratchStart
const progress = Math.min(elapsed / scratchDuration, 1)
// Créer un effet de scratch en variant la vitesse
if (progress < 0.5) {
// Phase de scratch vers l'arrière
const scratchProgress = progress * 2
const scratchSpeed = 1 - (scratchProgress * 1.8) // Ralenti jusqu'à -0.8
sampler.value?.setPlaybackRate(scratchSpeed)
} else {
// Phase de pull up
const pullProgress = (progress - 0.5) * 2
const pullSpeed = -0.8 + (pullProgress * 1.8) // Accélère de -0.8 à 1.0
sampler.value?.setPlaybackRate(pullSpeed)
}
if (progress < 1) {
requestAnimationFrame(scratch)
} else {
// Remettre la vitesse normale à la fin
sampler.value?.setPlaybackRate(1)
// Si c'était en lecture avant, relancer la lecture
if (wasPlaying) {
setTimeout(() => {
sampler.value?.play(0)
}, 50)
}
}
}
requestAnimationFrame(scratch)
}
// Démarrer l'effet
scratchEffect()
}
const Wind = () => {
disc.value.secondsPlayed = duration
sampler.value.secondsPlayed = duration
}
const handleKeyDown = (e: KeyboardEvent) => {
@@ -237,7 +329,7 @@ watch(() => props.card, (newCard) => {
.disc {
pointer-events: auto;
position: fixed;
position: absolute;
background-color: transparent;
position: relative;
aspect-ratio: 1;

View File

@@ -0,0 +1,85 @@
<template>
<section class="playing-card" :class="{ 'playing-card--platine-open': platineOpen }">
<Card :card="props.card!" :is-face-up="props.isFaceUp" @click="clickOnCard" :role="platineOpen ? 'img' : 'button'"
showPlayButtonFaceUp />
<Platine v-if="platineOpen && card" :card="card" autoplay />
<CloseButton v-if="platineOpen" @click="platineOpen = false" />
</section>
</template>
<script setup lang="ts">
import type { Card } from '~~/types/types'
const props = defineProps<{ card: Card, isFaceUp: boolean }>()
const platineOpen = ref(false)
const clickOnCard = () => {
platineOpen.value = !platineOpen.value
}
</script>
<style scoped lang="scss">
$open-speed: 0.4s;
.playing-card {
display: flex;
justify-content: center;
align-items: center;
:deep(.card) {
transition: width $open-speed, height $open-speed, transform 0.1s;
position: absolute;
.face-up,
.pochette {
transition: border-radius $open-speed, box-shadow $open-speed;
&:active {
.play-button {
@apply scale-90;
}
}
}
}
&--platine-open {
.card {
pointer-events: none;
&:focus {
@apply z-auto scale-100;
}
}
.card,
.platine {
width: 100vmin;
height: 100vmin;
}
&:deep(.card) {
.face-up {
border-radius: 999px;
@apply shadow-xl;
.pochette {
border-radius: 999px;
}
.rank,
.play-button {
opacity: 0;
}
}
.play-button,
.card-body,
.face-down {
display: none;
opacity: 0;
}
}
}
}
</style>