コンテンツにスキップ

トップの水墨の門と立体の庭

Overview

トップ(/)の最初の訪問では、署名と水墨の門を筆の順に描き、色を差して立体の庭に移し、カメラが門をくぐる。
2 回目以降の訪問は、門の内側の庭を、イントロなしで出す。
プロフィールの 4 つのセクションは、庭の木の枝に掛けた和紙に置く。

この文書は、コードの構成と、見た目の数値を持つ。
数値は、docs/design/prototypes/top/ の試作の値である。
サイトの全体像は fukuemon.dev Design Doc にある。

Scope

持つもの。

  • コードの構成と、ディレクトリの間の import の向き
  • 同じシードから同じ絵を作るための、乱数を使う順と、墨の絵の SVG のサイズの上限
  • イントロの各段の時間
  • 季節と時間帯の決め方
  • 時間帯ごとの場面の色と、季節ごとの葉とパーティクル
  • 和紙の文の幅、行間、見出しの大きさ、余白
  • 庭の中のボタンの並び
  • 試作のファイルと、試作の作り直し方の所在

持たないもの。

Design

コードの構成

apps/web/src/features/top-garden/ は、墨の絵の SVG を作るコード、立体の庭を three で描くコード、その両方が読む庭の配置、トップのプロフィールの本文を持つ。 墨の絵の SVG を作るモジュールは、layout.ts と、ink/ の brush.ts、ink-art.ts、ink-svg.ts、ink-trees.ts の 5 つである。 どれも React と DOM に依らない TypeScript で書く。 ビルドのときに Node で動く。 ink/InkGate.astro は、ヘッダーのロゴと同じ sign.svg を components/sign/ から読む。 stage/stage.ts の stageScript は、stage/season.ts と stage/visit.ts の関数と applyStage を、文字列にしてトップの head の inline script に埋め込む。 埋め込んだ関数は、ブラウザで、表示の前に動く。 readOverride は、開発のビルドの inline script にだけ埋め込む。

コードは、墨の絵、head のスクリプト、立体の場面という関心ごとで、3 つのディレクトリに分ける。 それぞれ、動く場所と制約が違う。 墨の絵と場面の両方が読む layout.ts、rng.ts、intro-timing.ts は、このディレクトリの直下に置く。 Profile.astro は、3 つのどれにも当たらないので、直下に置く。 ディレクトリの間の import は、scene/ から stage/ へは型だけ、stage/ から scene/ へは場面のバンドルの URL(?worker&url)だけにする。 ink/ と scene/ は、互いを import しない。 この 3 つの向きは、oxlint.config.ts の no-restricted-imports が止める。 pnpm run lint が、向きに反する import で失敗する。 stage/ から scene/ へは、?worker&url 以外の接尾辞と、接尾辞の無い import を止める。 scene/ から stage/ へは、import type だけを通す。 import { type X } の形は、Oxlint が通すので、import type を使う。 ../stage/../scene のように、途中で戻るパスと、直下のファイルを通った間接の import は、止めない。

ディレクトリ 動く場所 制約
ink/ ビルドのときの Node React、DOM、three に依らない
stage/ トップの head の inline script(ブラウザ) season.ts、visit.ts、stage.ts の関数は文字列にして埋め込むので、関数の外の名前を参照できない
scene/ ブラウザの場面のバンドル(garden-entry.ts 起点) three を import してよい
ファイル 持つもの
layout.ts 門、塀、飛び石、山並み、池、和紙を掛ける 4 つの場所の配置、木の位置と幹の形、最初のカメラの投影
rng.ts 墨の絵と立体の場面の両方が使う、シードから決まった順の値を返す乱数
intro-timing.ts 最初の訪問のイントロの時刻。墨の絵の CSS(ink/InkGate.astro)と、場面のバンドルの両方が読む
Profile.astro プロフィールの 4 つのセクションの本文と、庭を出すときにセクションを和紙の上の文として見せる CSS
ink/brush.ts 筆の線と松の円を配列に足していく brush
ink/ink-art.ts 墨の絵の線を、山並み、塀、門、飛び石、石、近景の松、塀の向こうと門の奥の木の順に作る
ink/ink-trees.ts 塀の向こうと門の奥の木の線を、立体の木と同じ位置と形から作る。奥の木から手前の木へ、1 本ごとに幹、枝、葉の順で描く。塀、門の梁、屋根に隠れる部分は描かず、切った後に 24px より短く残る区間も描かない
ink/ink-svg.ts 線を、線ごとの path を持つ 1 枚の SVG の文字列にする
ink/InkGate.astro 墨の絵と署名を、描き終えた状態で出す Astro のコンポーネント。トップでは、scene/GardenStage.astro の slot に置く。html に class intro と enter が付いている間の、筆の順に描く動きと、線を消す動きの CSS も持つ
stage/season.ts 端末の日付と時刻から、季節と時間帯を返す
stage/visit.ts 端末で初めてトップを開いたかを返す
stage/stage.ts 季節と時間帯を html の属性に、庭を出すかと最初の訪問かを class に書く。場面の準備が 6 秒で終わらなければ、ふつうのページに戻す。URL の引数を読む関数と、head の inline script を組み立てる関数も持つ
stage/TopStageScript.astro stage.ts が組み立てた inline script を、トップの head に置く。場面のバンドルの URL を渡す
scene/scene-colors.ts 時間帯ごとの場面の色と光の表、季節の木の葉の色、2 つを掛け合わせて場面の色を決める関数。場面の色の値は、このファイルだけに書く
scene/scene-parts.ts 石、木、灯籠を作る関数と、canvas に描いた絵をテクスチャにする関数。石、木、灯籠は、後から絵やモデルに差し替えられるよう、物ごとに関数を分けてある
scene/scene.ts 配置と場面の色から、門、塀、飛び石、石、池、灯籠、松、季節の木、空、遠景、地面を組み立てる
scene/paper.ts 和紙と軸木と紐を組む。和紙を掛ける木から和紙の上の両端へ枝を伸ばす
scene/ink-pass.ts 場面を描いた絵に、墨の輪郭線、淡彩、紙の質感、端の余白を重ねる全画面のパス
scene/garden.ts canvas に庭を描く。最初の訪問では、墨だけの絵から色を差し、カメラが門をくぐる。プロフィールの 4 つのセクションを CSS3DRenderer で和紙の位置に置く。カメラが動く間だけフレームごとに描く。WebGL を使えないときは何も描かない
scene/garden-entry.ts 場面のバンドルで最初に動くファイル。最初の訪問のイントロの段を進め、「飛ばす」のボタン、Esc、Tab で最後の状態にする。庭の中のボタン、矢印キー、セクションへのフォーカスを和紙の間の移動につなぐ。庭を描けないときは、庭とイントロの class をすべて外してふつうのページに戻す
scene/GardenStage.astro canvas と、庭の中のボタンと、画面の上端と下端の霞を置く。イントロの墨の絵を slot に受け取り、「飛ばす」のボタンと、イントロの間の canvas とヘッダーと霞の CSS と、フォーカスが当たった「本文へスキップ」を庭とヘッダーより上に出す CSS を持つ。stage-on が付いたときだけ、画面の全体に出す

同じシードから同じ絵ができる

同じシードからは、同じ線のデータと、同じ SVG の文字列ができる。 乱数を使う順は、試作の docs/design/prototypes/top/src/h-strokes.mjs と同じにしてある。 線を足すか、消すか、並べ替えると、それより後の線がすべて変わる。

試作の i-mon.html の墨の絵の 281 本の線の後ろに、ink/ink-trees.ts が、塀の向こうと門の奥の木の線を足す。 木の線は、試作の線より後に乱数を使うので、試作の線を変えない。 出力は、線が 399 本、path が 543 本である。 SVG のサイズの上限は gzip で 45 KB で、ユニットテストが確認する。

イントロの各段の時間

最初の訪問は、開いてから約 10.1 秒で終わる。
署名を出さないときは、署名の段がなくなり、墨の絵から後ろの段が 0.6 秒早まる。

時刻 動き
0.2〜1.7 秒 左下に、筆記体の「Fukuemon」の署名を、左から書く
0.6〜5.6 秒 紙の上に、山並み、塀、門、飛び石、石、近景の松、塀の向こうと門の奥の木の順で、墨の線を筆の順に描く
5.6〜7.1 秒 墨の線の下に立体の庭の絵を出し、墨だけの絵から淡い色へ移す
6.9〜9.7 秒 墨の線と署名を消し、カメラが門をくぐる。近景の松の枝は、頭上へ抜ける
9.3〜10.1 秒 門の内側の、松の枝に掛けた和紙の前で止まり、プロフィールの文を出す。ヘッダーと、庭の中のボタンを出す
  • 色を差し始めるのは、墨の絵を描き終える時刻と、場面の準備が終わる時刻の、遅いほうである。
    • 墨の絵を描き終える時刻は、開いてからの時刻で決めず、墨の線と署名の CSS の遷移が終わった時刻にする。遷移は最初にスタイルが付いた時点から動くので、HTML が遅く届くと、その分だけ後ろにずれるためである。
    • 遷移を取れなかったときに早く色が差さないよう、開いてから 5.6 秒より前には色を差さない。
    • 松の円の不透明度の遷移は、墨の線より後に終わるので待たない。色が差した後も、松の円は現れ続ける。
  • 墨の門、塀、飛び石、石、木の線は、立体の配置を最初のカメラで投影した位置に描く。色が差すときに、線と立体がずれないためである。
    • 木の線は、立体の木と同じ幹と枝の形から作る。 奥の木から手前の木へ、1 本ごとに幹、枝、葉の順で描く。 塀、門の梁、屋根に隠れる部分は描かない。 隠れる部分で切った後に 24px より短く残る区間は、点のように見えるので描かない。
  • 墨の線は、SVG の path の stroke-dashoffset を CSS の遷移で動かして描く。
  • 左下の署名は、イントロの間だけ出す。
  • 文を出す時刻とカメラが止まる時刻は、色を差し始めた時刻からタイマーで決める。描くのが遅い端末でも、決めた長さで終わるためである。
  • 文を出してからイントロを終えるまで(色を差し始めてから 3.7〜4.5 秒)に、庭の中のボタンか矢印キーで別の和紙へ移ると、カメラは 4.5 秒まで門をくぐる動きのまま進み、その後に移った先の和紙へ動く。
  • 「飛ばす」のボタン、Esc、Tab では、カメラを動かさずに、門の内側の最後の状態にする。
    • 「飛ばす」は、押したボタンが消えるので、プロフィールの見出しへフォーカスを移す。
    • Tab は、ブラウザのデフォルトの動作を止めず、最後の状態でそのまま次の要素へフォーカスを移す。Esc は、フォーカスを動かさない。
    • 場面の準備ができるまでは、最後の状態を描けないので、「飛ばす」のボタンを出さず、Esc と Tab を受けない。

墨の絵と署名の置き方

墨の絵は、設計の画面(1600 × 900)の座標で描いた SVG で、絵を置く枠の中央に置く。 絵の幅は、枠の縦横比で変える。 cqw と cqh は、枠の幅と高さの 1% である。

枠の縦横比 絵の幅
16:9 より横長 枠の幅(100cqw)
16:9 から正方形の手前まで 枠の高さの 16/9 倍(177.78cqh)
正方形か、正方形より縦長 枠の幅の 1.25 倍(125cqw)
  • 墨の線: 色は --fd-color-text である。遠景の山並みはにじませ、中景と近景の線はかすれさせる。
  • 松の円: 色は --fd-color-primary で、不透明度は 0.2 である。
  • 署名: 色は --fd-color-text である。枠の左から 5cqw、下から 4cqh に置き、幅は clamp(11rem, 24cqw, 24rem) にし、反時計回りに 5 度回す。

墨の絵と署名の色と長さは、InkGate.astro の <style> に、セマンティックトークンと値を直に書く。 デザインシステムの規則(色はテーマ変数のユーティリティで書く)の例外である。 SVG を set:html で HTML に置くので、SVG の中の path にユーティリティを付けられないためである。

イントロの遷移とアニメーションの時間とイージングも、InkGate.astro と GardenStage.astro の <style> に値を直に書く。 デザインシステムの規則(動きはテーマ変数のユーティリティで書く)の例外である。 値はこの文書の「イントロの各段の時間」の時刻に合わせたイントロだけのもので、ほかの画面では使わないためである。

季節と時間帯の決め方

head のスクリプトが、ページを開いた時点の端末の日付と時刻で、季節と時間帯を決める。

季節 月
春(spring) 3〜5 月
夏(summer) 6〜8 月
秋(autumn) 9〜11 月
冬(winter) 12〜2 月
時間帯 時刻
朝(morning) 5〜10 時
昼(day) 10〜16 時
夕(evening) 16〜19 時
夜(night) 19〜5 時
  • 境目の時刻は、後ろの時間帯に入る。10 時は昼、19 時は夜になる。
  • 場面の色は、時間帯で決める。紙と墨の色(イントロの墨の絵、端の余白、色が差す前の「飛ばす」のボタン)は、テーマで決める。
  • 開いたまま OS のテーマが変わったら、紙と墨の色をトークンから読み直し、庭を描き直す。場面の色は変えない。
  • 夜の場面の端の余白だけは、テーマの紙の色を使わず、夜の mist の色にする。

時間帯ごとの場面の色

場面の色は、場面のモジュールの中に置き、トークンにしない。
キーは試作の名前で、色は sRGB の 16 進数である。

キー 塗る物 朝 昼 夕 夜
skyTop 空の上端 #d9dbd6 #cfd8d6 #c2bbbd #0c121c
sky 空の地平の近く #f5e8d4 #ece8dc #edcfae #1f3858
mist 霞 #f3eadc #ebe7db #ead3ba #22324a
far 遠くの山並み #a09f97 #8f9b95 #9a8c88 #34475f
sand 白砂 #e9e3d4 #e9e3d4 #e6dac6 #6a7078
rake 白砂の砂紋 #cdc4ae #cdc4ae #cdc4ae #565c64
earth 門の外の土 #ddd4bf #ddd4bf #ddd4bf #5b5f63
moss 苔 #72805a #72805a #72805a #2c3724
mossDark 苔の暗い所 #596843 #596843 #596843 #1f2819
stone 石 #8d897f #8d897f #8d897f #4f545a
bark 幹と枝 #4a3b2e #4a3b2e #4a3b2e #1e1813
pine 松の葉 #40543a #40543a #40543a #24342a
pineLight 松の葉の明るい所 #586c45 #586c45 #586c45 #31453a
wood 門と灯籠の木 #4d3d2f #4d3d2f #4d3d2f #17110c
woodLight 木の明るい所 #8a7257 #8a7257 #8a7257 #3a2e22
plaster 塀の漆喰 #eee8da #eee8da #ecdfca #5d5a55
roof 門の屋根 #45413d #45413d #45413d #101216
lamp 灯籠の明かり #ecd08f #ecd08f #ecd08f #ecd08f
paper 和紙 #f6f2e7 #f6f2e7 #f6f2e7 #2b303b
water 池 #8fb4b0 #8fb4b0 #8fb4b0 #27405e
text 和紙の字 #1a1714 #1a1714 #1a1714 #f4f1ea
link 和紙のリンクの字 #3d4b2b #3d4b2b #3d4b2b #b9cca3
textMist 使わない rgba(251, 249, 243, 0.95) rgba(251, 249, 243, 0.95) rgba(251, 249, 243, 0.95) rgba(18, 24, 34, 0.92)
hemiSky 半球光の空の側 #f6f2e8 #f6f2e8 #f6f2e8 #8ea4c6
hemiGround 半球光の地面の側 #7b785e #7b785e #7b785e #1a1f17
sun 日の光(夜は月の光) #ffe0b0 #fff1d8 #ffb37a #a9bce6

時間帯ごとの光と明かりの強さ。

キー 意味 朝 昼 夕 夜
sunI 日の光の強さ 2.0 2.4 2.2 1.5
hemiI 半球光の強さ 1.45 1.5 1.25 2.3
sunPos 日の光の光源の位置(x, y, z、m) 10, 6, -5 -8, 12, 6 -11, 4.5, -3 -6, 12, 5
lampOn 灯籠の明かりの強さ 0.3 0.3 0.8 1

空に描く日と月。
位置は、1600 × 900 の設計の画面での座標である。

時間帯 描く物 色 位置(x, y) 半径 光の量
朝 日 #f1cf8e 1170, 230 30 0.5
昼 描かない — — — —
夕 日 #d5683f 330, 250 40 0.45
夜 月 #ecd08f 640, 150 34 0.55
  • 墨の濃さは、時間帯で変えない。
  • 夜は、季節の木の葉の色に #10151c を 30% 混ぜる。

季節ごとの葉とパーティクル

季節 季節の木の葉の色 葉の形 パーティクル パーティクルの色 パーティクルの数
春 #e3a5b6、#f0c4cf、#f6dbe1 桜の花びら 桜の花びら #e9a9bb 70
夏 #56743d、#6f8d4e、#88a262 青もみじ 蛍(夕と夜だけ) #e9f58a 34
秋 #a83c26、#c65a2e、#d98a3c 紅葉 紅葉 #b8482d 60
冬 葉なし(枝だけ) — 雪 #fbfaf6 110
  • 冬は、白砂の色に白を 55%、苔の色に白を 60% 混ぜる。
  • 夏の蛍は、朝と昼には出さない。夜の蛍は、加算で重ねて光らせる。
  • 時間帯の表と季節の表を掛け合わせて、16 通りの絵を作る。組み合わせごとの素材は持たない。

和紙の文

文は DOM のまま、three の CSS3DRenderer で 3D に置く。
3D の場面の 1 m は、文の 260px に当たる。

項目 画面の幅が 768px 以上のとき 768px より狭いとき
文の幅 25rem 17.5rem
字の大きさ 1rem 1rem
行間 1.9 1.8
見出しの大きさ 1.5rem 1.5rem
  • 見出しは、下に 0.625rem の余白をとって、字の色を 35% にした罫を引き、罫の下を 1rem あける。
  • 段落の間は、1rem あける。
  • 一覧の行は、上下に 0.625rem の余白をとり、字の色を 25% にした罫で区切る。
  • 和紙は、文の左右に 0.18 m、上下に 0.2 m の余白を持つ。和紙の上下に軸木を付け、2 本の紐で木から伸びる枝に掛ける。
  • 和紙を掛ける木は 4 本である。門の内側の松(プロフィール)、季節の木(経歴)、池のほとりの松(技術スタック)、灯籠のそばの季節の木(ポートフォリオ)の順に並ぶ。
  • 見せる文は、今いる場所の 1 つだけにする。ほかの場所の和紙は、字の無い紙として見え、クリックを受けない。
  • 文は、0.7 秒で不透明度を上げて出す。
  • 庭を出したまま画面の幅が 768px をまたいだときは、和紙の大きさをセクションの大きさから測り直し、和紙と枝を掛け直す。 文の幅は、768px をまたいだときだけ変わるためである。

庭の中のボタンの並び

庭の中のボタンは、画面の下に固定する。
画面の端から、幅が 768px 以上のときは 1.25rem、768px より狭いときは 0.5rem 離す。

  • 4 つの文へ移るボタンは、隣どうしの境の線を 1 本にしてつなぐ。
    • ボタンは、霞の色の面に、時間帯の枠の色(garden-edge-day、garden-edge-night)の枠を付ける。
    • 角は丸めない。4 つのボタンで 1 本の帯にするので、ボタンの間に角が出ないようにするためである。
    • 今いる場所のボタンは、背景と字の色を反転する。
  • 「動きを止める」と「文だけで読む」は、下線を付けた字のボタンにして、1rem の間をあけて並べる。
    • 押した状態の「動きを止める」は、下線を 2px にする。
  • 幅が 768px 以上のときは、4 つの文へ移るボタンと 2 つの操作を、1.5rem の間をあけて 1 段に並べ、下の中央に置く。
  • 幅が 768px より狭いときは、2 段にする。上の段に 4 つの文へ移るボタン、下の段に 2 つの操作を、それぞれ中央に並べる。
  • ボタンの字は、操作の字の text-label(16px)である。
  • 4 つの文へ移るボタンの左右の余白は、幅が 768px 以上のときは 1rem、768px より狭いときは 0.25rem にし、幅と高さを 44px 以上にする。
  • 幅 320px では、「ポートフォリオ」の 7 文字のため、4 つの文へ移るボタンが 1 行に収まらないので、2 行に折り返す。
    • 字は 16px のままにする(TEXT-MIN-SIZE)。
  • 4 つの文へ移るボタンの枠は 4 辺に付け、隣のボタンと 1px 重ねる。
    • 折り返した行の境も、線が 1 本になる。
    • 今いる場所のボタンの枠は、隣の枠より手前に出す。
  • イントロの間は、場面の準備ができてから文を出すまで、「飛ばす」のボタンだけを右下に出す。
    • ボタンは、面に枠を付け、角を丸めない。
    • 面と枠と字は、色が差す前はテーマの紙と墨の色にし、色が差した後は、庭の中のボタンと同じく時間帯の色にする。
    • 色は、transition-colors で 150ms かけて替える。
    • 画面の端からの距離は、庭の中のボタンと同じにする。

ヘッダーと霞

庭を出している間、サイトのヘッダーは、背景を透明にし、下の罫を消して、画面の上端に重ねる。
字が場面の色に重なって読みにくくならないよう、画面の上端と下端に霞を敷き、ヘッダーのロゴとリンク、庭の中の字のボタンを霞の上に置く。
ヘッダーは、stage-on が付いた時点で文書の流れの外に置き、庭を描くまでは庭の面の下に隠す。
庭を描いた時点で外すと、本文が上へずれ、CLS に数えられるためである。
庭を描けずに stage-on を外したときは、ヘッダーが文書の流れに戻り、本文がヘッダーの高さだけ下がる。

霞の高さと、霞の色で塗りつぶす範囲は次のとおり。

霞 高さ 霞の色で塗りつぶす範囲
上端 6.5rem 上から 65%
下端 768px 以上のときは 6.5rem、768px より狭いときは 8.5rem 下から 65%
  • 残りの範囲は、霞の色から透明へ、縦の線形のグラデーションで薄くする。
  • 面を持たない字(ヘッダーのロゴとリンク、2 つの操作)は、霞の色で塗りつぶす範囲に収める。 4 つの文へ移るボタンは、霞の色の面を持つので、範囲から出てもよい。
  • 768px より狭いときは、ヘッダーのロゴの高さを 2rem、ロゴとリンクの間とリンクどうしの間を 0.5rem にする。 幅 320px でも、ヘッダーを 1 段に収めるためである。
  • 霞、字、ボタンの枠、フォーカスの輪の色は、和紙と同じく時間帯で決め、テーマに依らない。 どれもセマンティックトークンで、組はコントラストのチェック(pnpm run check:contrast)が確認する。
時間帯 霞の色 字とフォーカスの輪の色 ボタンの枠の色
朝、昼、夕 garden-mist-day garden-ink-day garden-edge-day
夜 garden-mist-night garden-ink-night garden-edge-night
  • 庭を出している間は、ヘッダー、庭の中のボタン、霞の範囲で、surface、text、border-field、focus をこの表の色に差し替える。 イントロで色が差した後は、「飛ばす」のボタンの範囲でも差し替える。 ヘッダーとボタンのコードは、テーマの色の名前のまま書く。
  • 庭を出している間、フォーカスが当たった「本文へスキップ」のリンクは、画面に固定した庭とヘッダーより上に出す。
    • 場面の準備の前は、Tab でイントロが止まらない。 このときも、リンクを描いている途中の墨の絵の上に出す。 リンクが絵に重なるほうが、フォーカスが見えないより害が小さいためである。

Interface

試作のファイル

試作は docs/design/prototypes/top/ にある。
バンドルの作り方、録画の作り直し方、URL の引数、署名の差し替え方は、試作の README にある。

ファイル 持つもの
i-mon.html 採った形の試作のページ
build-i.mjs 墨の絵の SVG、CSS、head のスクリプトを i-mon.html に書き、場面のバンドルを作る
record-i.mjs 試作の録画と、静止画の一覧と、測定
src/i-scene.js 立体の庭の場面。時間帯の色の表と季節の表を持つ
src/i-layout.mjs 門、塀、飛び石、山並み、文の置き場の配置と、最初のカメラの投影
src/h-strokes.mjs 墨の線を作る関数
src/sign.svg 署名の輪郭の SVG
src/sign-path.py 書体から署名の輪郭を取り出すスクリプト
src/shared.css トークンの値の CSS

ページが持つ状態

head のスクリプトは、次の値を書く。

置き場 値
html の data-season spring、summer、autumn、winter
html の data-time morning、day、evening、night
html の class stage-on 庭を出す
html の class intro 最初の訪問のイントロを出す
localStorage の fd-top-seen 端末でトップを開いたことがある
  • 動きを減らす設定のときは、stage-on を付けず、場面のバンドルを読み込まない。
  • localStorage を読めないか書けない端末では、最初の訪問かを判定できないので、intro を付けず、庭だけを出す。
  • fd-top-seen は、庭を出すかにかかわらず、ページを開いた時点で書く。
  • 場面のバンドルの読み込みに失敗したら、stage-on と intro を外し、ふつうのページにする。書いた fd-top-seen は消さない。
  • WebGL を使えない端末でも、読み込みに失敗したときと同じく、stage-on と intro を外し、ふつうのページにする。
  • ページを開いてから 6 秒たった時点で、場面のバンドルが scene-ready を書いていなければ、stage-on と intro を外し、ふつうのページにする。通信が応答を返さずに止まると、読み込みの失敗が届かないためである。この判定は、2 回目以降の訪問でも行う。
    • 6 秒の時点で場面を組み立てている途中なら、組み立て終えてから判定する。組み立ては同期の処理でメインスレッドを占め、その間はタイマーの関数が動かないためである。

場面のバンドルは、庭を描き始めた後に、次の値を書く。

書く先 値
html の class scene-ready 場面を組み立て、最初の 1 枚を描いた
html の class enter 最初の訪問のイントロで、色を差して門をくぐる間
html の class garden-ready 庭を描き、和紙と庭の中のボタンを出せる
html の class no-anim イントロを飛ばした直後で、遷移を止める
html の CSS 変数 --scene-paper、--scene-text、--scene-link 和紙の背景、字、リンクの字の色(時間帯の場面の色)
html の CSS 変数 --scene-pad-x、--scene-pad-y 和紙の、文の外の左右と上下の余白
セクションの class is-current 今いる場所の文
  • 最初の訪問では、garden-ready を、文を出す時刻(9.3 秒)に書き、カメラが止まる時刻(10.1 秒)に intro と enter を外す。
  • 場面を組み立てた時刻、色を差し始めた時刻、イントロを終えた時刻を、performance.mark の garden-scene-ready、garden-enter、garden-intro-done で記録する。E2E が、イントロの段の時刻を確認するために読む。
  • 「文だけで読む」を押したときと、描く途中の例外か WebGL のコンテキストの喪失で描けなくなったときは、この値をすべて外し、セクションを元の場所に戻し、stage-on と intro を外す。

場面のバンドル

場面のバンドルは、three と場面のモジュールを 1 つにまとめた JavaScript のファイルである。 トップの head の inline script が、庭を出すときだけ、module の script で読み込む。

  • バンドルの大きさの上限は、gzip で 160 KB(160,000 バイト)である。
    • ビルドの後に pnpm run check:garden-bundle が確認する。
  • バンドルは、ビルドのときに Vite が IIFE の 1 ファイルにまとめ、ファイル名にハッシュを付けて /_astro/ に置く。
    • 開発サーバーはバンドルを ES モジュールのまま配るので、どちらでも動く module の script で読み込む。
  • 場面の色は、デザインシステムのトークンの対象の外である(デザインシステムの Design Doc の Scope)。