跳到內容

每條游來游去的小魚,都是正在瀏覽這一頁的訪客,有一條是你自己 ( ´ ▽ ` )ノ 覺得干擾閱讀的話,可以把小魚關掉。

魚花

bg

魚花(hî-hue),指水裡魚群游動時,於靜止水面上泛開的如花般漣漪。

與日花同樣來自《日花閃爍:台語的美麗詞彙&一百首詩》。

看著魚兒在水底悠游,水面泛起一圈圈魚花,就像看著一首寫不完的詩。

名稱描述
Canvas 2D API基礎的 2D 繪圖 API,可以高效繪製比 DOM 更複雜的圖形
SVG FilterSVG 濾鏡效果,例如:模糊、扭曲、顏色調整等等
物理模擬模擬真實世界物理現象,如重力、碰撞、速度等物理效果
Pointer 事件偵測滑鼠或觸控點移動、點擊、懸停等等事件,取得座標、目標等等資訊
SVG feDisplacementMap依位移圖的色值偏移取樣來源像素,可做出扭曲、凹陷、波動等效果
Canvas ImageData以 createImageData/putImageData 逐像素寫入資料,常用於程序化生成圖樣

點擊畫面便泛開一朵魚花,範圍內隨機浮出幾尾小魚,繞游片刻後潛入水底消失。

台語裡獨有的漂亮詞彙 魚花 hî-hue 水裡魚群游動,在靜止的水面上
泛出如花一般的漣漪,
台語將此波紋稱為「魚花」。
《魚花》 午後的池塘睡得很沉
連雲都繞著走
魚兒在水面綻開
一朵朵 看一眼便忘的花
池塘記不住
雲也記不住
只有蹲在岸邊的我
記了一整個下午
The afternoon pond sleeps deep,
even the clouds detour around it.

On the water, fish bloom —
flower after flower, forgotten at a glance.

The pond does not remember,
nor do the clouds.
Only I, crouched on the bank,
remembered the whole afternoon.
<template>
<div class="w-full flex flex-col gap-4">
<bg-hi-hue class="w-full cursor-pointer border rounded-xl">
<div class="font-wenkai h-full flex flex-col items-center justify-center gap-12 p-8 md:p-14">
<!-- 名詞解釋 -->
<div class="flex flex-col items-center gap-6 text-center">
<span class="text-xs tracking-[0.5em] opacity-60">
台語裡獨有的漂亮詞彙
</span>
<span class="flex items-baseline gap-4">
<span class="text-6xl md:text-7xl tracking-[0.15em]">
魚花
</span>
<span class="text-xl md:text-2xl italic tracking-wider text-cyan-700/60 dark:text-cyan-300/70">
hî-hue
</span>
</span>
<span class="block max-w-md text-base tracking-wider leading-loose">
水裡魚群游動,在靜止的水面上
<br>
泛出如花一般的漣漪,
<br>
台語將此波紋稱為「魚花」。
</span>
</div>
<span class="block h-px w-16 bg-gray-300 dark:bg-slate-700" />
<!-- 新詩 -->
<div class="flex flex-col items-center gap-7 text-center">
<span class=" tracking-[0.4em]">
《魚花》
</span>
<span class="block tracking-[0.15em] leading-[2.4]">
午後的池塘睡得很沉
<br>
連雲都繞著走
</span>
<span class="block tracking-[0.15em] leading-[2.4]">
魚兒在水面綻開
<br>
一朵朵 看一眼便忘的花
</span>
<span class="block tracking-[0.15em] leading-[2.4]">
池塘記不住
<br>
雲也記不住
<br>
只有蹲在岸邊的我
<br>
記了一整個下午
</span>
<!-- 英譯 -->
<span class="block max-w-md text-sm italic leading-relaxed opacity-60">
The afternoon pond sleeps deep,
<br>
even the clouds detour around it.
<br><br>
On the water, fish bloom —
<br>
flower after flower, forgotten at a glance.
<br><br>
The pond does not remember,
<br>
nor do the clouds.
<br>
Only I, crouched on the bank,
<br>
remembered the whole afternoon.
</span>
</div>
</div>
</bg-hi-hue>
</div>
</template>
<script setup lang="ts">
import BgHiHue from '../bg-hi-hue.vue'
</script>

每次點擊在點擊位置附近隨機出生數條小魚,依序經歷三個階段:

  • 浮出(emerging):從深處上升至水面,透明度由 0 漸顯為最大值,尺寸同步放大。
  • 游動(swimming):在水面繞行,隨機改變游動目標,產生自然的探索軌跡。
  • 下潛(diving):透明度與尺寸同步衰減,沉入水底後從畫面移除。

整個生命週期約 4 至 7 秒,期間以深度(depth)參數同時驅動透明度與縮放,模擬游近水面與潛入深處的視覺差異。

魚的身體由多段組成,每段跟隨前一段移動並加上正弦擺動偏移,模擬魚類游動姿態。尾鰭擺動振幅隨段數遞增,越靠近尾端擺動越明顯。繪製時利用每段的位置與朝向描出紡錘形輪廓,再延伸出燕尾鰭,呈現自然的魚形。

點擊產生的水波同時運用兩種技術:

  • SVG feDisplacementMap:以動態位移圖扭曲水波範圍內的背景內容,對有紋理的畫面(如卡片、文字)產生強烈折射感。
  • Canvas 明暗環:在獨立的覆蓋層上繪製徑向漸層環(內側陰影、外側反光),確保在純色背景下仍能清楚看到波紋擴散。

兩者各司其職,無論背景是空白還是有內容,水波都能保持可見度。

interface Props {
/** feDisplacementMap scale。@default 10 */
displacementIntensity?: number;
/** 點擊扭曲半徑(px),0 表示自動擴散至最遠角落。@default 0 */
distortionRadius?: number;
/** 水波衰減時間(秒)。@default 3 */
distortionDecay?: number;
/** 每次點擊生成的魚數量。@default 3 */
count?: number;
/** 魚的尺寸倍率。@default 1 */
sizeScale?: number;
}
interface Slots {
default?: () => unknown;
}