デジタルガーデン
返信・カプセル・Wrapped:この星は「覚えている」ことを覚えた
序章:見られた、その次に
前回、この星の空に人が住み始めた:本物の月、季節ごとの星座、互いの光の跡。星の壁もずっとそこにあった——星を残し、誰かがそれを灯す。
けれど、灯されたあとは?一万四千の星にとって、「灯す」だけが唯一の動詞だった。今回やるのは三つのこと。テーマはひとつだけ:覚える。返信はひとつの星を、カプセルはひとつの言葉を、年鑑はひとつの年を覚える。
一:星への返信
星に初めて返事が届く。管理ページから、どの星にも返信できる——上限は百四十字、一文字たりとも入らない——そして返信が書かれた瞬間、WebSocket が星にいる全員へ即座に配信する。
フロントの演出:紫粉色の彗星が尾を引いてその星へ降り立ち、星の色は灯された暖色から、さらに暖かい白へとゆっくり変わる。星のそばには ↩ の小さなバッジ。ホバーすれば、返信の全文が浮かび上がる。
デバッグで静かな落とし穴をひとつ発見:Astro のビルドは型チェックをしないので、sealOff の i18n キーの漏れは緑のビルドのまま素通りした——この類のエラーは決して叫ばない。リリース前に全ページを自分でクリックして回るしかない。サイレント失敗の一番怖いところは、失敗したことすら報せないことだ。
二:タイムカプセル
ひとこと書いて、封印する:封印なし、三十日、または一年。封印中の星は氷青色に光り、内容は誰にも見えず、投票もできない——バックエンドは 404 を返す。秘密はフロントの良心ではなく、サーバーが守る。
時が来れば、Durable Object のネイティブアラームが起こしてくれる:秒になるや、接続中の全クライアントへ開封を配信する。誰もポーリングしなくていい。管理ページから早めに解くこともできる。
星の位置は id から決定論的に計算される——何度更新しても、その星は同じ場所にいる。ひとことを封印した星が、訪れるたびに引っ越すべきではない。
結合テストで、教科書的な並行バグを二つ捕まえた:
- WebSocket の配信が POST レスポンスより先に走り、遅れて届いたレスポンスがフロントのもう一度取得を誘発、同じカプセルの星が二つ描かれた。id と文言による重複排除で修正。
- 新しい星の位置を
WHERE ip=?で逆引きしていたため、空 IP のときにピン留めされた星の id を誤って取得。INSERT の直後にMAX(id)を取る形へ——推測した id は信用できない。今書き込んだばかりのそれを取るべきだ。
三:星の年鑑
/wrapped——この星自身の年度報告。四言語対応、データはバックエンドの実統計から:今年どれだけの星が届いたか、最も灯された星に何が書いてあるか、何の国と地域から訪れたか(国旗付き)、総訪問数、そして今も封印中の手紙の数。
数字はすべて count-up アニメーション:ビューポートに入ってから始まり、ゼロから実値まで数える。IntersectionObserver と gsap の力で、見えなければ数えず、数え終えたら止まる。コマンドパレットとフッターにも入口を追加。
公開時、/api/wrapped はこう返した:訪問 320 回、4 の国と地域。小さな数字だが、本物だ。
終章
この星は今、返信をし、想いを封印し、年末には年鑑を提出する。「記憶」はもう、ブラウザの更新で消えるものではない——データベースに、Durable Object のアラームの中に書き込まれている。
次はコマンドパレットのアクションと、月のイースターエッグ。星の壁の次章は、時間に委ねる。
コメント