Scroll Zoom Reveal(スクロールズームリビール) は何をしますか?
ドロップインで使える、依存関係ゼロのスクロールエフェクト:
- ピン留めされたフルブリードシーン:見出しが薄暗くなったシーンの上に表示され、ビューポートを埋め尽くします。
- ドリー + プルバック:シーンが少し落ち着き、その後「カメラ」が引き、シーンがラップトップのディスプレイ上にあることが明らかになります(ベゼルとベースが表示されます)。
- アプリのリビール:エディターパネル(ツールバー、アウトライナー、プロパティ、タイムライン)がスライドインし、シーンがそのビューポートパネルに縮小されます。
- 下にフェードインするコピー(
data-zr-fade)、その後にタブ付きクロスフェードギャラリーとスライドするピル型トグル。
すぐに使えるファイルはすべて、このファイルの隣の assets/ にあります。
| ファイル | 目的 |
|---|---|
assets/zoom-reveal.css | すべてのスタイル(.zr 上のテーマトークン) |
assets/zoom-reveal.js | コンポーネント + フェード + ギャラリー。window.ZoomReveal を公開し、[data-zoom-reveal] / [data-zr-gallery] / [data-zr-fade] を自動初期化します |
assets/oled-field.js | オプション。カーソルに反応するOLEDサブピクセルフィールド(window.OledField、[data-zr-oled] を自動初期化)。スタイルは zoom-reveal.css に含まれています |
assets/placeholder-scenes.js | オプション。実際の画像が存在するまで、プロシージャルにプレースホルダーアートをcanvasに描画します(ZRScenes.drawCity、ZRScenes.drawCanyon) |
assets/demo.html | 完全な動作ページ。このマークアップから始めてください。 |
サイトでの使い方
- アセットをプロジェクトにコピーします(例:
public/zoom-reveal/またはsrc/vendor/zoom-reveal/)。まだ本物のアートワークがない場合のみ、placeholder-scenes.jsもコピーしてください。 assets/demo.htmlを読み、<section class="zr" data-zoom-reveal>…</section>ブロック(必要に応じてギャラリーブロックも)をコピーします。クラス構造は正確に保ってください:
section.zr[data-zoom-reveal] ← スクロール長はここにあります(--zr-length)
.zr-sticky ← ピン留めされた100vhステージ
.zr-glow (オプションのアンビエントグロー)
.zr-device ← JSによってスケーリングされます
.zr-lid > .zr-display
.zr-viewport > .zr-media > img | video | canvas ← あなたのシーン
.zr-chrome > .zr-panel.zr-toolbar / .zr-left / .zr-right / .zr-bottom (オプションのアプリUI)
.zr-base (ラップトップベース。モニター/タブレットの場合は削除)
.zr-scrim + header.zr-intro ← シーン上の見出し。最初にフェードアウトします
.zr-caption ← 小さなキャプション。最後にフェードインします
zoom-reveal.cssを<head>に、zoom-reveal.jsを<body>の最後にロードします。- メディアを差し替えます:デモのcanvasを実際のシーンに置き換えます。
- 画像:
<img src="scene.avif" alt="" decoding="async">。少なくともビューポートサイズ × DPR(2560~3200px幅)でエクスポートしてください。効果は画像が画面全体を埋めるところから始まります。 - スクロール連動動画:
<video data-zr-scrub muted playsinline preload="auto" src="scene.mp4"></video>。JSがスクロール進行度をcurrentTimeにマッピングします。シークがスムーズになるよう、すべてのフレームをキーフレームとしてエンコードしてください:ffmpeg -i in.mov -c:v libx264 -g 1 -crf 22 -an -movflags +faststart scene.mp4。
- 画像:
- すべてのコピー(アイブロウ、見出し、キャプション、パネルラベル、ファイル名、ギャラリーラベル)をサイトに合わせて書き換えてください。デモの架空の「Orbit / Forge」テキストは決して出荷しないでください。
.zr上のトークンでテーマを設定します:--zr-bg、--zr-fg、--zr-muted、--zr-accent、--zr-length(スクロール距離。デフォルトは360vh)。
オプション
属性にJSONを渡します(例:data-zoom-reveal='{"maxWidth":1000,"viewport":{"top":0,"right":0,"bottom":0,"left":0}}')、またはJSで構築します:new ZoomReveal(el, options)。
| オプション | デフォルト | 意味 |
|---|---|---|
maxWidth | 1180 | 最終的なディスプレイの最大幅(px) |
widthRatio / heightRatio | 0.82 / 0.64 | ビューポートに対する最終的なディスプレイサイズ |
aspect | 0.625 | ディスプレイの縦横比(16:10)。スマートフォンは約 2.16、ウルトラワイドは約 0.42 |
overscan | 1.04 | ディスプレイがビューポートを超えて開始する距離(ベゼルを隠す) |
dolly | 1.14 | メディアの初期内部ズーム。1に落ち着く |
lift | 0.035 | デバイスが最後に上昇する量 |
timeline | JS参照 | intro、dolly、zoom、chrome、caption の [開始、終了] 進行ウィンドウ |
viewport | {top:6.5,right:21,bottom:22,left:15} | アプリUI内のシーンパネルの最終的なインセット(ディスプレイの%)。アプリUIなしで純粋な「シーン→デバイス画面」プルバックにするには、すべてを 0 に設定し、.zr-chrome を削除します |
onProgress | — | fn(p) コールバック。進行度は0..1 |
イベント:セクションは {width, height, finalWidth} を含む zr:resize をディスパッチします。これはメディアがレイアウトされるピクセルサイズです。canvasのサイズ設定や画像ソースの選択に使用します。
React / Next.js
CSSをグローバルにインポートします。マークアップから data-zoom-reveal を削除し、コンポーネントライフサイクルに結び付けて手動で構築します(Nextの場合は 'use client'):
useEffect(() => {
import('./zoom-reveal/zoom-reveal.js').then(() => { // window.ZoomReveal を登録
const zr = new window.ZoomReveal(ref.current, { maxWidth: 1100 });
const gal = galRef.current && new window.ZoomReveal.Gallery(galRef.current);
window.ZoomReveal.initFades();
cleanup = () => zr.destroy();
});
let cleanup = () => {};
return () => cleanup();
}, []);
class → className、style="--v:78%" → style={{'--v':'78%'}} に変換します。
OLEDピクセルフィールド(カーソルホバー効果)
微細なRGBサブピクセルバーのフルブリード背景で、かすかに光ります。カーソルを動かすと、小さな流体シミュレーションがかき混ぜられます。軌跡に沿ったピクセルが発光し、成長し、紫からシアン、ライム、温かみのある白へと色が変化し、グローがカーソルの方向に漂い、広がり、消えていきます。クリックまたはタップで波紋が発生します。カーソルがアイドル状態(およびタッチスクリーン)のときは、ゆっくりとした「ゴーストカーソル」が動きを維持します。レンダリングはWebGL1のフラグメントシェーダーで行われ、シミュレーションは小さなCPUグリッドで行われ、セクションが画面に表示されている間だけ実行されます。WebGLがない場合は、CSSスポットライトにフォールバックします。
スペック/統計ブロック、ヒーロー、CTAバンドの背後で使用します。任意の要素で動作します:class="zr-oled" data-zr-oled を追加し、中にコンテンツを配置し、zoom-reveal.css + oled-field.js をロードします。コンポーネントが自動的にcanvasを挿入します。assets/demo.html の「OLED PIXEL FIELD」ブロックを参照してください。
<section class="zr-oled" data-zr-oled='{"cell":7}'>
<div class="your-content">…統計/見出し…</div>
</section>
<script src="oled-field.js"></script>
| オプション | デフォルト | 意味 |
|---|---|---|
cell | 6 | ピクセルあたりのCSS px(3サブピクセルバー)。5~9が適切。モバイルではパフォーマンスのために大きめに |
radius | 2.4 | ブラシ半径(セル単位) |
strength | 0.55 | カーソルが追加する光の量。デフォルトは意図的に控えめ。1 は大胆 |
decay | 0.94 | フレームあたりの減衰。高いほど軌跡が長く残る(0.92 短い … 0.97 長い) |
flow | 0.55 | グローがカーソルの方向に漂う距離 |
diffusion | 0.35 | グローの広がり速度 |
base | 0.09 | 未点灯グリッドの明るさ |
palette | ['#5a3cff','#1fd6ff','#b6ff4a','#fff4d8'] | 4色。低エネルギー→高エネルギー。ブランドに合わせる(例:暖色系 ['#ff3c5a','#ff9a1f','#ffe14a','#fff8e8']) |
ambient / ripples | true | アイドル時のゴーストカーソル / クリック波紋 |
より大胆な外観(ショーケース効果に近い)には {"radius":3.2,"strength":1,"decay":0.962,"flow":0.9} を使用します。テキストが多いセクションの背後では控えめなデフォルトを維持します。
API:const f = new OledField(el, opts)、f.pulse(clientX, clientY)(コードから波紋をトリガー)、f.destroy()(Reactのクリーンアップで呼び出し)。フィールド上のテキストには、明るい軌跡の上でも読みやすくするために、柔らかい暗い text-shadow を付けます。
落とし穴(仕上げ前に確認)
- スティッキーが壊れる:
.zrの先祖にoverflow: hidden/auto/clipまたはtransformがある場合。水平方向のオーバーフローを隠す必要がある場合は、bodyにoverflow-x: clipを使用します。 .zrを、ページを変形するスムーススクロールライブラリ(Locomotive v4など)でラップしないでください。Lenisは問題ありません。- デバイスは大きくレイアウトされてから縮小されるため、メディアはシャープに保たれます。
.zr-device内に固定pxサイズを入れないでください。代わりにemを使用します(1em = ディスプレイ幅の1%)。 - 動きの抑制に対応:セクションのピン留めが解除され、最終状態が表示されます。ギャラリーの自動再生が停止します。OLEDフィールドはカーソルへの反応を続けますが、ゴーストカーソルと波紋は停止します。
- アニメーションはバックグラウンドタブで一時停止します(requestAnimationFrameが停止)。ブラウザペインでOLEDフィールドをテストするときは、ページを表示したままにしないと、停止しているように見えます。
- 幅が約500px未満ではラップトップが小さくなります。モバイルでは、
{"widthRatio":0.92}またはスマートフォンフレームに合わせたaspectを検討してください。 - デスクトップとモバイルの幅で、ページの一番上から一番下までゆっくりスクロールしてテストしてください。見出しがプルバック開始前にフェードアウトすること、開始時にベゼルが表示されないこと、キャプションがベースと重ならないことを確認します。
- オリジナルまたはライセンスされたアートワークとコピーを使用してください。これはモーションテクニックを再現するものです。他のブランドの画像、製品レンダリング、テキストをコピーしないでください。
