feat(stage-ui): refactor animators in poppin'text into creator pattern; rainbow text

This commit is contained in:
Makito
2025-07-08 04:44:58 +09:00
parent bb5929ceb2
commit d37ea81ff5
6 changed files with 111 additions and 38 deletions
@@ -1,11 +1,13 @@
<script setup lang="ts">
import { FieldRange } from '@proj-airi/ui'
import { ref } from 'vue'
import PoppinText from './PoppinText.web.vue'
import { fadeAnimator, popupAnimator } from './animators'
import { createFadeAnimator, createFloatAnimator, createPopupAnimator } from './animators'
const text = ref('キラキラドキドキキラキラドキドキキラキラドキドキキラキラドキドキ')
const text = ref('行こう、七色のキラキラドキドキに向かって!')
const duration = ref(750)
</script>
<template>
@@ -15,7 +17,13 @@ const text = ref('キラキラドキドキキラキラドキドキキラキラ
:layout="{ type: 'grid', width: '100%' }"
>
<template #controls>
<ThemeColorsHueControl />
<FieldRange
v-model.number="duration"
:min="50"
:max="3000"
:step="50"
label="Duration"
/>
</template>
<Variant
@@ -23,7 +31,7 @@ const text = ref('キラキラドキドキキラキラドキドキキラキラ
title="Popup"
>
<div h-auto w-full p-4>
<PoppinText :text="text" :animator="popupAnimator" />
<PoppinText :text="text" :animator="createPopupAnimator({ duration })" />
</div>
</Variant>
@@ -32,7 +40,16 @@ const text = ref('キラキラドキドキキラキラドキドキキラキラ
title="Fade"
>
<div h-auto w-full p-4>
<PoppinText :text="text" :animator="fadeAnimator" />
<PoppinText :text="text" :animator="createFadeAnimator({ duration })" />
</div>
</Variant>
<Variant
id="float"
title="Float"
>
<div h-auto w-full p-4>
<PoppinText :text="text" :animator="createFloatAnimator({ duration })" />
</div>
</Variant>
</Story>
@@ -26,12 +26,13 @@ watch([graphemeClusters, () => props.animator], ([_, animator]) => {
</script>
<template>
<div class="relative overflow-hidden whitespace-nowrap">
<div class="relative overflow-hidden whitespace-nowrap text-2xl font-bold font-m-plus-rounded">
<span
v-for="(cluster, index) in graphemeClusters"
:key="index"
ref="elements"
class="inline-block"
class="inline-block color-primary-400"
:style="{ '--chromatic-hue': index * 360 / graphemeClusters.length }"
>
{{ cluster }}
</span>
@@ -1,20 +1,26 @@
import type { Animator } from '.'
import type { Animator, CreateAnimatorOptions } from '.'
import { createTimeline } from 'animejs'
export const fadeAnimator: Animator = (elements: HTMLElement[]) => {
const timeline = createTimeline({ loop: true })
.set(elements, {
opacity: 0,
})
.add(elements, {
opacity: [0, 1],
easing: 'easeInOutQuad',
duration: 2250,
delay: (_, i) => 150 * (i + 1),
})
export function createFadeAnimator(options: CreateAnimatorOptions): Animator {
return (elements: HTMLElement[]) => {
if (elements.length === 0) {
// NO DIV0
return () => {}
}
return () => {
timeline.remove(elements)
const timeline = createTimeline({ loop: true })
.set(elements, {
opacity: 0,
})
.add(elements, {
opacity: [0, 1],
...options,
delay: (_, i) => options.duration / elements.length * (i + 1),
})
return () => {
timeline.remove(elements)
}
}
}
@@ -0,0 +1,34 @@
import type { Animator, CreateAnimatorOptions } from '.'
import { createTimeline } from 'animejs'
export function createFloatAnimator(options: CreateAnimatorOptions): Animator {
return (elements: HTMLElement[]) => {
if (elements.length === 0) {
// NO DIV0
return () => {}
}
const timeline = createTimeline({ loop: true })
.set(elements, {
opacity: 0,
translateX: '0.55em',
translateY: '1.1em',
rotateZ: 180,
translateZ: 0,
})
.add(elements, {
opacity: [0, 1],
translateY: ['1.1em', 0],
translateX: ['0.55em', 0],
translateZ: 0,
rotateZ: [180, 0],
...options,
delay: (_, i) => options.duration / elements.length * i,
})
return () => {
timeline.remove(elements)
}
}
}
@@ -1,4 +1,12 @@
import type { EasingParam } from 'animejs'
export interface CreateAnimatorOptions {
duration: number
ease?: EasingParam
}
export type Animator = (elements: HTMLElement[]) => (() => void)
export * from './fade'
export * from './float'
export * from './popup'
@@ -1,23 +1,30 @@
import type { Animator } from '.'
import type { Animator, CreateAnimatorOptions } from '.'
import { createTimeline } from 'animejs'
export const popupAnimator: Animator = (elements: HTMLElement[]) => {
const timeline = createTimeline({ loop: true })
.set(elements, {
opacity: 0,
translateY: '1.1em',
translateZ: 0,
})
.add(elements, {
opacity: [0, 1],
translateY: ['1.1em', 0],
translateZ: 0,
duration: 750,
delay: (_, i) => 50 * i,
})
export function createPopupAnimator(options: CreateAnimatorOptions): Animator {
return (elements: HTMLElement[]) => {
if (elements.length === 0) {
// NO DIV0
return () => {}
}
return () => {
timeline.remove(elements)
const timeline = createTimeline({ loop: true })
.set(elements, {
opacity: 0,
translateY: '1.1em',
translateZ: 0,
})
.add(elements, {
opacity: [0, 1],
translateY: ['1.1em', 0],
translateZ: 0,
...options,
delay: (_, i) => options.duration / elements.length * i,
})
return () => {
timeline.remove(elements)
}
}
}