Bus finance reused the chart foundation and put Leaderboard at two of three
/bus-revenueCaptured at a 375px viewport. Long pages scroll inside the frame.
The screenshots stay in Japanese. Every round is a real screen for a real Japanese industry, so an English re-render would no longer be the screen the agent actually produced.
Write-up
Bus finance reused the chart foundation and put Leaderboard at two of three
Build log series: I give an AI that has never seen Gunjo (
@gunjo/ui) only the public npm package and the gunjo.jp docs, then ask it to build a real screen. This fourth staff-facing bus round covered a dense revenue and route-profit dashboard for planners and depot managers: route results, operating ratio, ridership, subsidies, and costs.
Result: 4/5. The analytics foundation carried directly into bus finance
The data-driven desktop screen passed tsc. The agent reported:
This library was clearly designed for Japanese finance and operations consoles. The source vocabulary was evidence:
Deltadefaults to increase and decrease,formatCurrencydefaults to JPY andja-JP,AmountBreakdownexamples name billing, estimates, assessment, and settlement, andActionQueuehas critical, warning, information, and normal states. I assembled the screen instead of fighting the library.
The first core observation: finance reused the chart foundation without static drawing
Route finance is unusual: many services run at a loss, an operating ratio above 100 is bad, and subsidies matter. Yet almost the whole dense dashboard used existing components:
StatGroupgave the KPI row for revenue, operating ratio, ridership, subsidies, and profit or loss. Its thirdhintline made it the best fit.- An area
LineChartshowed profit trends with an average-costreferenceValue, driven by variable monthly data and no hand-written SVG. LabeledDonutCardprovided the cost breakdown with labor, fuel, and fleet costs, a center total, and segment callouts.DataTableembeddedDeltaandMeterfor route results, profit, and operating ratio.ActionQueuesorted deteriorating ratios, subsidy dependence, and falling ridership by severity.
Charts and analytics are the library's home ground.
LineChart,LabeledDonutCard,StatGroup,Delta,ActionQueue, andDataTableall worked without friction, took variable arrays, and never forced static or decorative rendering.
After Stringline validated bus planning in #153, the chart foundation validated bus finance here. Deeper staff coverage increasingly tested existing foundations across industries.
The second core observation: Leaderboard reached two of three
The screen needed top and bottom routes by profitability. The agent found:
There is no ranking or leaderboard component.
ParetoChartshows cumulative ABC percentages, not top and bottom ranking. I hand-rolled an<ol>with rank pills, operating ratio, and profit inside a card. It was the only structured UI written from scratch, and a dedicated ranking component would add the most value.
This was the second case for issue #395, after taxi driver revenue in #143. The catalog again actively misled by listing ParetoChart under rankings even though Pareto analysis is not a leaderboard. One more case would trigger a build.
The third core observation: lower-is-better metrics lacked semantics
An operating ratio is better when lower and signals a loss above 100. The agent reported:
Statisticinfers tone from trend, treating up as positive, the opposite of operating ratio, so I overrode trend and tone manually.Metercan express higher-is-worse, which captures the direction, but it cannot express an absolute threshold of 100. Its marker is proportional tomax, not an absolute value. I inverted the value so the bar filled in the good direction, but that calculation should have belonged to the component, not my screen.
I opened issue #412 for goodWhen="lower" on Statistic and an absolute threshold on Meter. Cost rate, defect rate, churn, delay rate, and CPA all share the pattern. I also noted DataTable.rowTone: getRowState can emit data-state="loss", but the table only styles selected, so loss-making rows cannot receive a tone.
What I took away: deeper mode coverage increasingly validates what already exists
The previous round described two ways to close a gap: build on the third case, or validate an earlier build through later discovery. Deeper staff-facing bus coverage had become mostly the second:
- #153 validated
Stringlinein bus planning. - #154 validated the analytics foundation in bus finance.
A mature foundation changes the role of a new screen. It mostly confirms that existing components fit another industry, while occasionally revealing a thin domain-specific gap, here ranking, inverted metrics, and row tone.
Nothing new was added under src this round. The 4/5 validated the chart foundation, put Leaderboard at two of three, and recorded inverted metrics and row tone.
📊 Component scoreboard (15 built, plus intraday Gantt)
Stringline / StatusBoard / ExpiryBadge / BottomActionBar / Gantt with intraday resolution In progress: Leaderboard at two of three, SegmentedControl beyond three cases, ReferralCard, ComparisonTable, and inverted metrics.
📋 Mode progress
- ✈️ Air ✅ / 🚆 Rail ✅ / 🚕 Taxi ✅ / 🚌 Bus: four staff (operations, dispatch, planning, revenue) + three passenger screens
- 🚚 Trucking: not started
Next up: build log #155
- Continue staff-facing bus with fleet inspections, complaints, incidents, or safety to match the five or six screens in other modes, or open trucking.
The run
- gunjo.jp / LineChart / LabeledDonutCard / StatGroup / Delta / npm
@gunjo/ui/ GitHub / previous rounds #1 through #153 - GunjoUI by UIXHERO
Bus finance reused the chart foundation without static drawing. Deeper mode coverage now mostly validates what exists, while Leaderboard waits one case from a build.
This series is co-created with AI (Claude and Codex). A human designs the experiments, makes the calls, and fact-checks before publishing; the AI does the hands-on work and drafting.
Components from @gunjo/ui
The components this screen's source imports directly.
The code the agent actually wrote
Click a file to expand its source.