文字が粒で集まり、光が走って、風に流れていくオープニング

IXcode®

Freelance coding partner
Okayama, JP

Coding partner for studios & designers

Thousands of tiny particles form the wordmark, a streak of light crosses it, and the wind carries it away.

Scroll

( How it opens )

  1. 01

    Gather

    The wordmark is drawn once on a hidden canvas. Every opaque pixel becomes a particle that drifts in from the left and settles into its letter.

  2. 02

    Shine

    A soft band of light runs across the settled letters, once, from left to right, like light sliding over polished metal.

  3. 03

    Blow away

    The particles scatter to the right on the same wind. While they fly, the black behind them fades and the page rises into view.

← ブログ一覧へ

文字が粒で集まり、光が走って、風に流れていくオープニング

要点

  • 文字を canvas に 1 回描き、画素を読み取って、粒の最終位置にする
  • 粒は、ImageData を直接書き換えて、1 フレーム 1 回で描く
  • 全体を1 本の時計から計算し、区間をつないで一続きに見せる

仕組み

  1. 文字を粒にする:見えない canvas に文字を描き、不透明な画素を読み取ります。間引いて、粒の数を PC で約 26,000、スマホで約 14,000 にします。
  2. 集まる:出発位置を文字の左側にばらまき、パーリンノイズでうねりを付けます。左の粒から順に、ゆっくり動き出して、ゆっくり止まります。
  3. 光が走る:集まりきったら、光の帯が左から右へ一度だけ走ります。近い粒ほど明るくなります(ガウス関数)。
  4. 風で散る:光が抜けきる少し手前から、左の粒から順に右上へ。時間を累乗にして、最初はふわっと、あとは一気に流します。
  5. ページを出す:散り始めに重ねて、背景の黒を透明にし、見出しを 1 文字ずつ押し上げます。

粒を打つ部分

fillRect を 26,000 回呼ぶ代わりに、ImageData を書き換えて、putImageData で一度に描きます。位置は小数なので、隣の 4 画素に配分して、1 画素より小さな粒もなめらかに動かします。重なった所は足すので、自然に明るくなります。

// 粒の位置は小数。1 画素に収めず、隣の 4 画素に配分して足す
var x0 = x | 0, y0 = y | 0, fx = x - x0, fy = y - y0;
var w00 = (1 - fx) * (1 - fy) * alpha;
var w10 = fx * (1 - fy) * alpha;
var w01 = (1 - fx) * fy * alpha;
var w11 = fx * fy * alpha;

var p = (y0 * W + x0) * 4;
data[p]     += r * w00;  data[p + 1] += g * w00;
data[p + 2] += b * w00;  data[p + 3] += 255 * w00;
// …右・下・右下の画素にも、同じように足す

時間の組み立て

区間の終わりが、次の区間の始まりになります。blowOffset をマイナスにすると、光が抜けきる前から散り始め、一続きに見えます(全体で約 4.5 秒)。

T.gatherEnd  = gatherStagger + 0.12 + gatherDur;   // 集まりきる
T.sheenStart = T.gatherEnd + sheenDelay;           // 光が走り出す
T.sheenEnd   = T.sheenStart + sheenDur;            // 光が抜けきる
T.holdEnd    = T.sheenEnd + blowOffset;            // 粒が散り始める
T.end        = T.holdEnd + blowStagger + 0.15 + blowDur;

こだわり・気をつけたこと

  • 最初から覆われた状態にします。覆いの背景を CSS で最初から黒にして、読み込み中に中身が見えるのを防ぎます。
  • フォントを待ってから、粒を作ります。document.fonts.load を待ち、2.5 秒で諦めます。代わりのフォントで粒ができるのを防ぎます。
  • 描画の大きさを抑えます。canvas の画素数は約 240 万画素まで。超えたら解像度を下げ、スマホは粒も減らします。
  • 覆っている間は、スクロールさせません。途中で例外が起きても、必ず終了の処理を通して、覆いとスクロール禁止を残しません。
  • リサイズしたら、粒を作り直します。経過した時間は保ちます。
  • 動きを減らす設定には、粒を出さず、すぐに内容を見せます。

外部ライブラリは使いません。英字フォント(Space Grotesk)だけを、Google Fonts から読み込んでいます。