トップページに、マイルームセクションとして3Dアイソメトリックルームとレコードラックを実装しました。(ほとんどGeminiにお任せですが)

こんにちは、 junprog です。

今回、トップページのビジュアルを一新し、以下の2つのインタラクティブなコンポーネントを導入しました。

  1. 3Dアイソメトリックルーム(部屋のイラストと所持ガジェットの連動)
  2. レコードラック(保有しているLP紹介スライダー)

見た目の楽しさだけでなく、モバイル環境でも「ガタツキ感」のないスムーズな操作性を実現するためのパフォーマンス最適化にもかなりこだわったので、技術的なポイントを振り返ります。

1. 3Dアイソメトリックルーム

概要

私の愛用ガジェットが配置されいてる部屋のイラストがアイソメトリックで描かれたコンポーネントです。

  • 仕様
    • 部屋の中にガジェット(HHKB、自作PC、カメラやレンズなど)が配置され、そこから引き出された動的なコネクションがガジェットの名前を指してブログ記事があればリンクを提供しています。
  • データ構造の分離
    • メンテナンス性を考慮し、ガジェットの位置情報(パーセンテージベースの座標)やブログ記事へのリンクは外部JSONファイルに切り出して一元管理するようにしました。
  • ダークモード対応
    • ダークモードのときに、イラストの部屋が暗くなり照明がつくようなデザインにしてみました。
    • ただ、ガジェットを増やしたいときにライトモードとダークモードとでイラストの一貫性を保つようにAIに描いてもらうのが大変なので、要改善です。

モバイル向け最適化のポイント

デスクトップではホバー時にガジェットの名前がふわふわと浮遊するアニメーション(CSS Keyframe Animation)が動きます。しかし、モバイル画面でもこのアニメーションを実行し、かつ画面上に引き出されるSVGの線を毎フレーム requestAnimationFrame で再計算(getBoundingClientRect() による座標取得)し続けると、レイアウトスラッシング(Forced Reflow)が発生し、スクロールが重くなる原因になります。

そこで、モバイル(画面幅768px以下)では以下の最適化を施しました:

  • CSSアニメーションの無効化
    • CSSメディアクエリで浮遊アニメーションを none !important に。
  • 描画ループのスキップ
    • JS側でモバイル viewport を判定し、接続線を再計算するフレームループへの登録自体をスキップ。

パーセンテージベースの静的な座標指定により、JSを一切動かさなくてもモバイル上で線とラベルが完璧に揃うようになり、モバイルでのCPU負荷をゼロに抑えました。

2. レコードラック

概要

私が保有しているLPを紹介するコンポーネントです。

レコードラック
29 records
Count Basie - On The Road
On The Road by Count Basie

On The Road

Count Basie

Count Basie - The Atomic Mr. Basie
The Atomic Mr. Basie by Count Basie

The Atomic Mr. Basie

Count Basie

Count Basie - Breakfast Dance and Barbecue
Breakfast Dance and Barbecue by Count Basie

Breakfast Dance and Barbecue

Count Basie

Helen Merrill - Helen Merrill
Helen Merrill by Helen Merrill

Helen Merrill

Helen Merrill

Sarah Vaughan - Sarah Vaughan
Sarah Vaughan by Sarah Vaughan

Sarah Vaughan

Sarah Vaughan

Miles Davis - Kind of Blue
Kind of Blue by Miles Davis

Kind of Blue

Miles Davis

John Coltrane - Giant Steps
Giant Steps by John Coltrane

Giant Steps

John Coltrane

John Coltrane - Ballads
Ballads by John Coltrane

Ballads

John Coltrane

Bill Evans - Waltz for Debby
Waltz for Debby by Bill Evans

Waltz for Debby

Bill Evans

Bill Evans - Explorations
Explorations by Bill Evans

Explorations

Bill Evans

Wes Montgomery - The Incredible Jazz Guitar of WES MONTGOMERY
The Incredible Jazz Guitar of WES MONTGOMERY by Wes Montgomery

The Incredible Jazz Guitar of WES MONTGOMERY

Wes Montgomery

Wes Montgomery - Full House
Full House by Wes Montgomery

Full House

Wes Montgomery

Oscar Peterson - Night Train
Night Train by Oscar Peterson

Night Train

Oscar Peterson

Oscar Peterson - The Oscar Peterson Collection
The Oscar Peterson Collection by Oscar Peterson

The Oscar Peterson Collection

Oscar Peterson

Oscar Peterson - The Way I Really Play
The Way I Really Play by Oscar Peterson

The Way I Really Play

Oscar Peterson

Dave Brubeck - Time Out
Time Out by Dave Brubeck

Time Out

Dave Brubeck

Clifford Brown & Max Roach - Study in Brown
Study in Brown by Clifford Brown & Max Roach

Study in Brown

Clifford Brown & Max Roach

Tommy Flanagan - Eclypso
Eclypso by Tommy Flanagan

Eclypso

Tommy Flanagan

Herbie Hancock - Speak Like A Child
Speak Like A Child by Herbie Hancock

Speak Like A Child

Herbie Hancock

Kenny Drew - The Lullaby
The Lullaby by Kenny Drew

The Lullaby

Kenny Drew

Great Jazz Trio - The Great Jazz Trio At The Village Vanguard Vol.2
The Great Jazz Trio At The Village Vanguard Vol.2 by Great Jazz Trio

The Great Jazz Trio At The Village Vanguard Vol.2

Great Jazz Trio

Earth, Wind & Fire - THE BEST OF EARTH WIND & FIRE VOL.1
THE BEST OF EARTH WIND & FIRE VOL.1 by Earth, Wind & Fire

THE BEST OF EARTH WIND & FIRE VOL.1

Earth, Wind & Fire

THE SQUARE - ADVENTURES
ADVENTURES by THE SQUARE

ADVENTURES

THE SQUARE

THE SQUARE - S・P・O・R・T・S
S・P・O・R・T・S by THE SQUARE

S・P・O・R・T・S

THE SQUARE

中島みゆき - 寒水魚
寒水魚 by 中島みゆき

寒水魚

中島みゆき

松田聖子 - SQUALL
SQUALL by 松田聖子

SQUALL

松田聖子

Luckey Kilimanjaro - TOUGH PLAY
TOUGH PLAY by Luckey Kilimanjaro

TOUGH PLAY

Luckey Kilimanjaro

宇多田ヒカル - One Last Kiss
One Last Kiss by 宇多田ヒカル

One Last Kiss

宇多田ヒカル

Cory Wong - The Lucky One
The Lucky One by Cory Wong

The Lucky One

Cory Wong

More to come...

ラックに収納されたレコードを指でパラパラと掘る動作をブラウザ上に表現しました。

  • 立体的な3D表現:
    • 通常時(非アクティブ時)は、レコードが斜め手前に傾いた状態(transform: skewY(-15deg) scaleX(0.3))で隙間なく並んでいます。
    • スクロールして画面中央に来たアルバム(アクティブ)は、立体的な傾きからすっと真っ直ぐに開き、さらに右側から黒いレコード盤(ビニール)がスライドアウトします。
    • 左右のレコードは、アクティブ盤が開くスペースを空けるため、自動的に左右対称にスライドして避ける挙動(is-past は左へ、is-future は右へ)をとります。
  • 透明レコードプレースホルダー:
    • 一番右端には、次に紹介したいレコード用の「More to come…」という破線仕様のカードを配置。
    • こちらも中央に来た際には、クリア(半透明)のガラス風ビニール盤が美しくスライドアウトする遊び心を加えました。
  • データ構造の分離
    • アイソメトリックルームと同様に、メンテナンス性を考慮してレコードの情報を外部JSONファイルに切り出して一元管理するようにしました。

パフォーマンスと「ガタツキ感(Jitter)」の解消

初期の実装ではタッチスワイプ操作をJSのイベントリスナーでハンドリングして手動でスクロール位置を制御していたため、モバイル端末で操作した際に指の動きに追従せず、ガタツキが発生していました。

これを解消するために、以下のドラスティックなアプローチを取りました:

  1. ネイティブスクロール & CSS Snap の採用:
    • JSによるスワイプの乗っ取りを全て廃止。
    • ブラウザ標準のハードウェアアクセラレーションが効く overflow-x-autosnap-x snap-mandatory(CSS Scroll Snap)に置き換えました。これにより、モバイルのシステムに最適化されたスムーズな慣性スクロールが100%機能します。
  2. モバイル用のサイズ最適化:
    • スマートフォンなどの小さな画面では、レコードジャケットサイズを w-40(160px)から w-32(128px) へと一回り小さく設計。
    • レコードが小さくなった分、避ける隙間(translateX のオフセット値)やセンターへのアライメントの計算式を再調整し、完璧に対称なグリッドを保つようにしました。
  3. ナビゲーションボタンのレスポンシブ化:
    • デスクトップだけでなく、モバイル表示時にもタッチフレンドリーな小型の丸型矢印ボタン(横幅40px)を配置し、タップ操作でも快適にレコードを切り替えられるようにしました。

まとめ

今回のリニューアルを通じて、Astroの高速な表示速度は維持したまま、動きがあって触って楽しいトップページを作ることができました。

特にアニメーションや3D表現は、モバイル表示を「ただ非表示にする」のではなく、「表示させたまま、実行される処理(計算・CSS)を最小限に抑えることでヌルヌル動かす」というアプローチを取ることで、パフォーマンスと表現力の両立ができたと感じています。

ぜひ新しくなったトップページで、遊んでみてください!