AI に配車・積込を作らせてみた — 容量メーターが3回目で primitive 化、Badge の hydration バグも出た(やってみた #51)
/loading375px のビューポートで撮影。縦長のページはフレーム内をスクロールします。
解説記事
AI に配車・積込を作らせてみた — 容量メーターが3回目で primitive 化、Badge の hydration バグも出た(やってみた #51)
やってみたシリーズ: 自作のデザインシステム
@gunjo/ui(群青)を、文脈ゼロの cold な AI に実 UI で作らせる連載。物流/倉庫(WMS)5枚目——配車 / 積込 / 配送ルート(便/車両 × トラック積載率メーター × 積込スキャン × 配送ルート/順序/ETA × 積み残し)。
#47-50 の倉庫内オペに続き、出庫の最後——トラックに積んでルートを組んで出発させる配送センターの配車画面。車両の重量・容積の積載率を見ながら出荷を割り当て、積込をスキャンし、配送順を並べて出発確定する。
結果 — 4/5
tsc/build 緑・console 0(Badge 修正後)・375px・閾値で色が変わる積載率メーター・出荷割当でメーターが「積んだら何%になるか」をプレビュー・超過は積み残しでブロック・積込スキャン・配送順の並べ替えで ETA 再計算・出発確定ゲート・h1 1個。
今回の本題① — 容量メーターが3回目 → primitive 化
倉庫の3画面(#48 棚の充填・#50 ロケーション充填・#51 トラック積載率)が、同じ容量メーターを毎回手組みしていた。Progress+tone で平らなバーは出せても、容量メーターが本当に欲しい3つを Progress は持たない:
Missing higher-order primitive: a capacity
Meter/Gauge.Progressは (a) 閾値からトーンを導出できない(毎画面fillTone(pct)を書く)・(b) 現在+入荷分のオーバーレイで「これを積んだら超過するか」をプレビューできない・(c) テーブルセル内のコンパクト inline が無い。CapacityMeter.tsxを毎回手組み。
3回ルール発火で Meter(#230)(PR #235)を出荷:
<Meter label="重量積載率" value={2100} max={3000} incoming={350} unit="kg"
thresholds={{ warning: 0.8, over: 1 }} />
<Meter size="inline" value={41} max={40} label="棚 D-03 充填" />
role="meter"・thresholdsからトーンを自動導出(満載間近→warning・超過→destructive)incomingがvalueの上に縞模様のオーバーレイを重ね、トーンも駆動——コミット前に超過を警告(読み上げは「2100kg + 350kg → 82%」に)size="inline"はテーブルセル用の細バー+コンパクト%・unit・label(accessible name)・aria-valuetext=色だけに意味を乗せない・トークン駆動でダークモード無料
ブラウザ実証: 70%→success / 84%→warning / 100・102%→destructive、incoming で縞セグメント(left 70%・幅 11.67%=350/3000)+プレビュー読み上げ、inline がセル内に収まる。Progress は平バー用に tone(#229) を維持、Meter は容量特化の兄弟(role="meter" vs progressbar)。
今回の本題② — Badge の hydration バグ(🔴 実バグ)
cold AI が <Badge>到着 08:30</Badge> を <p> の中に置いたら、実行時に hydration クラッシュ——「div cannot be a descendant of p」。tsc も next build も通り、ブラウザでだけ捕まった。
Badge はデフォルト as="div" だった。status pill は phrasing content で、文章・段落・インライン行の中に常に置かれる。block の <div> デフォルトは footgun。Badge は inline-flex スタイルなので <span> で見た目は同一・flow content で valid(onRemove の <button> も span 内で valid)。→ デフォルトを span に修正(#233・PR #234)。型チェックとビルドをすり抜けるバグは、cold テストで実際にブラウザに載せるからこそ出る。
複利も全採用
ScanGate(#49 build) — 車両/便→カートンの2段積込スキャンに採用「used, excellent fit・advance:"stay"でカートンを連続スキャン」。#49→#50→#51 と3回連続で別画面に使われた。Delta(残容量・空き=success/超過=destructive 上書き)・Statistic(残重量/容積・積載個数の KPI)・Badge/Alert(状態・積み残し読み上げ)・Progresstone も。
起票だけした穴(3回ルール未達)
- 🟠 配送ルート/ストップリスト(#228・2回目=#47 ピッキングのウォークパス+#51 配送順)。順序付きの配送先(ETA 付き・並べ替え可)を
Timeline(表示専用)/Stepper(固定 wizard) では組めず手組み。RouteStops(orTimelineにonReorder+per-itemtime/eta)が理想。あと1回で build。
学び — 同じラウンドで「3回目を build」「実バグを fix」が両立した
build(3回目の合成穴): 容量 Meter #230(#48+#50+#51)
fix (ブラウザでだけ出た実バグ): Badge の <div> デフォルト #233
起票(2回目) : ルートストップ #228
cold テストの価値は、(a) 頻度で primitive を浮かび上がらせるだけでなく、(b) tsc/build をすり抜ける実行時バグを実ブラウザで捕まえること。#51 はその両方が1回で出た回——容量メーターは3画面で育って Meter に、Badge は <p> の中という"普通の使い方"で初めてクラッシュした。規律(3回ルール)と検証(実ブラウザ)が、別々の穴を同時に拾う。
次回予告(やってみた #52)
- 物流をもう1枚(返品入荷/リバース or 配送追跡)でルートストップ#228 を3回目=build 閾値へ、または別業界へ。方針: 1業界3〜5枚・可能な限り違う内容・業界特有UI最優先。
試す
まだ alpha。容量メーターが3回目で primitive 化し、Badge の hydration バグも実ブラウザで捕まえた回。
<!-- 公開前: 相互URL差込/スクショ確定/EN(dev.to)ミラー -->
使用した @gunjo/ui コンポーネント
この画面のソースが直接 import している部品です。
cold AI が組み上げた実コード
ファイル名をクリックでソースを展開できます。