トップの水墨の門と立体の庭¶
Overview¶
トップ(/)の最初の訪問では、署名と水墨の門を筆の順に描き、色を差して立体の庭に移し、カメラが門をくぐる。
2 回目以降の訪問は、門の内側の庭を、イントロなしで出す。
プロフィールの 4 つのセクションは、庭の木の枝に掛けた和紙に置く。
この文書は、コードの構成と、見た目の数値を持つ。
数値は、docs/design/prototypes/top/ の試作の値である。
サイトの全体像は fukuemon.dev Design Doc にある。
- ADR-0026: トップの最初の訪問で水墨の門を描き、門をくぐった立体の庭にプロフィールを置く
- ADR-0027: トップの庭の絵を、訪問者の端末の日付と時刻で、季節と時間帯ごとに変える
Scope¶
持つもの。
- コードの構成と、ディレクトリの間の import の向き
- 同じシードから同じ絵を作るための、乱数を使う順と、墨の絵の SVG のサイズの上限
- イントロの各段の時間
- 季節と時間帯の決め方
- 時間帯ごとの場面の色と、季節ごとの葉とパーティクル
- 和紙の文の幅、行間、見出しの大きさ、余白
- 庭の中のボタンの並び
- 試作のファイルと、試作の作り直し方の所在
持たないもの。
- 版画風の挿絵の版の仕様。挿絵の Design Doc が持つ。
- 紙と墨の色のトークン。デザインシステム(packages/ui)の Design Doc が持つ。
- 動きの規則と、トップの庭の例外。全体の Design Doc の「動き」 が持つ。
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)。
- 字は 16px のままにする(
- 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)。