import { intervalLanesLayout, activeCountOverDomain } from "semiotic/recipes" // The recipe owns the packed sub-tracks, period bands, lane labels, and time // axis. We reserve a bottom strip and compose the concurrency line on top. const warTimelineLayout = (ctx) => { const base = intervalLanesLayout({ ...ctx, config: { laneAccessor: "sphere", startAccessor: "startYear", endAccessor: "endYear", domain: [1770, 2026], lanes: SPHERES, unit: 1, minBarWidth: 5, bottomInset: 82, color: (war, sphere) => COLORS[sphere], }, }) return { nodes: base.nodes, overlays: <>{base.overlays}<ConcurrencyLine /></> } } const countsByYear = activeCountOverDomain(wars, { start: "startYear", end: "endYear", domain: [1770, 2026], }) <OrdinalCustomChart data={wars} layout={warTimelineLayout} categoryAccessor="sphere" valueAccessor="startYear" oExtent={SPHERES} rExtent={[1770, 2026]} projection="horizontal" annotations={periods.map(period => ({ type: "x-band", x0: period.start, x1: period.end, label: period.name }))} width={width} height={650} />