Round #114Score 3/5Transport: air

The third hand-rolled seat map is the one that became a component

Route: /flight-checkin
Desktop preview
Mobile preview

Captured 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

The third hand-rolled seat map is the one that became a component

⁠Build log series⁠: An AI that has never seen Gunjo (@gunjo/ui) gets the public npm package and the gunjo.jp docs, then builds a real screen. ⁠This was the first of three passenger-facing air rounds run together⁠, an ⁠online check-in flow⁠ covering flight confirmation, seat changes, baggage, and the boarding pass.

Passenger-facing screens are the weak side of the library, so I decided to go deeper there and ran three air screens (#114 through ) in parallel. This is the first. What I was watching: ⁠would the seat map be hand-rolled a third time?⁠

Result: 3/5, and the third SeatMap case fired

The screen passed tsc, fit a 375px mobile-first layout, produced no console errors, and covered four steps: confirm, seat, baggage, boarding pass. The agent reported:

⁠The seat map was hand-rolled from scratch, and it is the leading gap.⁠ The nearest thing, ScheduleGrid for staff availability across days, has no aisle gap and no type or fee per seat. "⁠A SeatMap component needs configurable aisle positions, {id, state, type, fee} per cell, controlled selected and onSelect, states that do not rely on color alone, a legend with fees, and keyboard movement across the grid. The library has nothing anywhere near this.⁠"

⁠That makes three rounds running.⁠ Rail seats in , cabin seats in , and the seat change during check-in here. ⁠Three separate agents independently hand-rolled a seat map of about 190 lines each.⁠ The rule of three fired, so I built it.

What I built: SeatMap

const columns = ["A","B","C", null, "D","E","F"]   // null = aisle (a 3-3 cabin)
<SeatMap columns={columns} seats={seats}
  selectedIds={selected} maxSelectable={2} onToggle={toggle} />
  • Aisle gaps as null columns, covering 3-3, 2-4-2, and 2-2 layouts; a state, type, position, and fee per seat; ⁠controlled multi-select with a capacity cap⁠, where reaching the cap disables the seats not yet chosen.
  • ⁠Grid accessibility⁠: role=grid, arrow keys to move focus, aria-selected and aria-disabled, and a composed accessible name ("seat 12A, window, exit row, available, 1,500 yen"). ⁠State never depends on color alone⁠: a check for selected, a cross for booked, and screen-reader-only labels.
  • It contains its own horizontal scrolling, so a 3-3 cabin does not break the page at 375px.
  • That closes issue #356 in PR#361, verified on a real 375px render with 36 seats, 34 of them disabled once two were selected and the cap was reached, composed names carrying type, fee, and position, and no errors. ⁠I also corrected the table's seat-selection lead to HeatmapChart, which is now documented as read-only.

Logged, not built

  • 🟢 TicketStub or PassCard for a boarding pass: origin and destination, times, a prominent gate, a perforation, and a barcode area. SignedRecord is an audit record, not a pass. Recorded on issue #363 at one of three.
  • 🟢 StatusScreen has no success variant⁠ even though the table sends confirmation and completion screens to it, so a "boarding complete" message could arrive in error styling. Recorded on issue #366.
  • 🟢 ⁠44px touch targets.⁠ Button defaults to 36px and its xl size does reach 44px, but the agent never found it. Recorded on issue #362, now seen three times across #114, , and .

⁠What I built under src this round: SeatMap, on its third case.⁠ AmountBreakdown crossed an industry boundary again, this time for baggage fees.⁠

What I took away: mode-specific passenger components settle under the rule of three too

SeatMap is a passenger-facing foundation specific to one mode. It reached its third case across rail seats, cabin seats, and a seat change during check-in, and settled. That contrasts with ListCard, a shared foundation that paid off across industries at once: SeatMap had to collect its evidence across modes and flows before it could be built. ⁠Going deeper on the passenger side fills both kinds under the same rule.⁠ The weak side of the library is where the next foundation shows up.

Next up

  • The other two rounds in this passenger-facing air batch: the flight status board in and booking management with mileage in .

The run

A seat map hand-rolled on three screens became a component the same day.

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.

業界別「AI指示書パック」、先行登録を受付中です。