E.D.E.N.という、わたし専用のAIアシスタントを作っています。従量課金のAPIを増やさず、手元のPCで動かすことを条件にしているプロジェクトです。
ブラウザで開く画面なので、見る場所によって画面の形が変わります。横長のモニター、縦に置いたモニター、スマホ。最初の作りでは、画面の比率が変わると中央の表示が拡大されたり、切れたりしていました。今回はそれを直した記録です。
何が崩れていたか
当初、画面の中央には人物の画像を置いていました。この画像が、画面の比率によって拡大されたり、端で切られたりしていました。
そこで人物画像はやめて、中央を「コア」と呼んでいる抽象的な図形に置き換えました。同心円、72本の放射線、42個の粒子、多角形、光る核でできていて、Canvas(ブラウザで図形を描く仕組み)に描いています。大きさは画像のように固定せず、画面の寸法から毎フレーム計算します。画像を引き伸ばすのではなく、その場の大きさで描き直すので、比率が変わっても切れません。
ただ、コアだけ直しても、画面全体の並びが1種類のままでは足りませんでした。
画面の大きさを基準に、並びを4通りにした
レイアウトは、画面(ビューポート)の幅・高さ・向きで切り替えるCSSにまとめました。実際の区切りは次のとおりです。
| 条件 | 並び |
|---|---|
| 通常(横長) | 3列。左にモード選択、中央にコア、右に対話 |
| 幅1100px以下、または縦向き | モード選択を上に横並びにし、その下を2列に |
| 縦向き、かつ幅701px以上 | 1列。上段にコア、下段に対話 |
| 幅700px以下 | 1列。コアは高さ140〜220pxに縮め、対話を広く取る |
ほかに、幅2200px以上の大きな画面では対話欄を広げ、高さ550px以下の横長画面では見出しを省いて詰める指定も入れています。
もう1つ決めたのは、画面そのものはスクロールさせないことです。画面全体の高さを表示領域の高さに固定し、スクロールするのは対話のログや一覧の中身だけにしました。長い会話をしても、コアや入力欄が画面の外へ流れていきません。
ワイド(1600×900)で開いた状態です。

縦置き(900×1400)では、上段にコア、下段に対話が並びます。モード選択は一番上に横並びになります。

スマホ(390×844)では、コアを小さくして、対話の欄を広く取っています。

この3つの大きさで、コアを描いているCanvasの表示寸法を測りました。
| 画面 | Canvasの表示寸法 | 横スクロール |
|---|---|---|
| ワイド 1600×900 | 728×756 | なし |
| 縦置き 900×1400 | 532×497 | なし |
| スマホ 390×844 | 204×192 | なし |
どの大きさでも、ページの横幅は画面の幅と一致していて、横にはみ出していませんでした。
詰まったところ1: 並びを直したら、円が消えた
レイアウト用のCSSを足したあと、コアの一部が表示されなくなりました。原因は、そのCSSの中で、コアを構成する層の1つを誤って非表示にしていたことです。
小さい画面では要素を減らすために、いくつかの部品を非表示にしています。その指定が、消してはいけない層にもかかっていました。見た目の崩れを直すつもりで、別のものを消していたことになります。この指定を外して、層を復旧しました。
詰まったところ2: 円が描かれない原因は、初期化前の参照だった
もう1つは、Canvasの描画そのものが止まっていたことです。CSSではなく、JavaScriptのエラーでした。
JavaScriptでは、let や const で宣言した変数を、宣言の行より前で使うとエラーになります。宣言までのこの区間は TDZ(Temporal Dead Zone)と呼ばれています。E.D.E.N.では、描画の処理がこの区間で変数に触れてしまい、エラーが起きて描画が止まっていました。
描画は毎フレーム繰り返す処理なので、途中で1回エラーが出ると、その先の図形が何も描かれません。画面には枠や文字は出ているのに、中央だけが空いている、という状態になります。エラーの箇所を直して、描画が続くようにしました。
確認したこと
- ふだん使っているChromeで、通常の画面表示を確認
- 今回あらためて、ワイド・縦置き・スマホの3つの大きさで表示し、横にはみ出さないことを確認(上の表)
- コアを1600×1000で3つのモードとも描画できることを確認
- 縦長の1100×1800でも、コアが切れたり拡大されたりしないことを確認
- コアが回転していることを、変形の値が変わっていくことで確認
- 今回の3枚のスクリーンショットは、予定・ToDo・家電などをすべて架空のデータに差し替えた表示用の環境で撮影(時計の表示は隠しています)
わたしが学んだこと
画面の崩れを直すとき、わたしは「見えているもの」を直そうとしていました。ところが実際に詰まったのは、直す途中で見えなくなったもののほうでした。
非表示の指定は、効きすぎても何も言いません。描画のエラーも、画面を見ているだけでは「真ん中が空いている」としか分かりません。レイアウトを変えたら、消していないはずのものが残っているかを、大きさごとに確かめる。今回はその確認を3つの画面サイズで行いました。
このシリーズの続き
- 前回の記事: E.D.E.N.開発ログ #6|ローカルLLMが「株価は取得できません」と答えた原因は、振り分けの正規表現に「株価」が無かったこと
- 最初の記事: 個人用AIアシスタントを、課金APIに頼らず作ってみている話(開発ログ #1)
E.D.E.N.を作る途中で何を決めて、何をやめたかは、noteのマガジンにまとめています。


コメント