Skip to content

redesign(PR 02): Home — cartogram, section iii, marquee, ledger, glimpse - #45

Open
asbryx wants to merge 89 commits into
redesign/broadsheet-iifrom
redesign/02-home
Open

redesign(PR 02): Home — cartogram, section iii, marquee, ledger, glimpse#45
asbryx wants to merge 89 commits into
redesign/broadsheet-iifrom
redesign/02-home

Conversation

@asbryx

@asbryx asbryx commented Jun 16, 2026

Copy link
Copy Markdown
Owner

PR 02 — phase 3 · Home (the broadsheet)

Second sub-PR of the broadsheet · ii rebuild. Composes Home from
seven section components: the cartogram hero, settled marquee, legend
band, ranks ledger, lots floor, settled history table, and dashboard
glimpse. The hard one per _design-archive/05 §3.

Targets redesign/broadsheet-ii. Does NOT target main. Live site
unchanged.


preview

https://archive-hkr6rs5xo-asbryxs-projects.vercel.app


what to look for

Per _design-archive/05-full-app-rebuild-plan.md §1 phase 3
verification + 06 §A.4 + 06 §B + 06 §C.4:

the cartogram (section i)

  • 1600×800 viewBox, double-rule plate frame (outer ink, inner cream, hairline ink-3), faint vignette at corners.
  • Two horizontal dust bands (top + bottom only). Active region (y 180–620) is clear.
  • Three flight lines: solid marsh (settled, with arrowhead), short-dashed hot (executing), long-dashed marsh (delivering).
  • SETTLED draws on once (1.6 s) and freezes. EXECUTING + DELIVERING march continuously.
  • Six agent points, each labeled with italic Fraunces + mono caps addr + score. No label overlaps any flight line. Halden's label flips to the left (anchor=end).
  • Inline payload labels ride each line at the midpoint, rotated to the line's angle, with cream halos.
  • Edition stamp top-right, legend top-left, scale bar bottom-left, fig caption bottom-center, cartouche bottom-right.
  • Cartouche features the most-recent settlement: name (italic first word + roman rest), addr, vitals (score / jobs / vol / latency), state ribbon.

corridor algorithm (06 §A.3-A.4)

  • lib/cartogramSlots.ts exposes placeAgents(count, lines) — pure, deterministic, six seed slots, per-line ±28u keep-out corridor, ±12u label-rect padding, spiral search fallback.
  • Re-render the page 10× — six labels land in the same spots.

settled marquee

  • Pinned "● settled · last hour" left, scrolling track of last 20 settlements.
  • Doubled track for seamless wrap. Pauses under prefers-reduced-motion.

ranks ledger (section ii)

  • Two-column: 6 top agents on the left, three sidenotes on the right.
  • Each row: ordinal · sigil (44px, deterministic from owner) · italic-first-word name + addr + score caption · sparkline (24 points, seeded per owner) · score in italic oxblood.
  • Sigil column links to /agents/:id.
  • At < 1024 px, sidenotes drop under the list with a rule.

lots section (section iii)

  • Head: kicker · italic-accented N more lots, open hero · six filter chips · meta panel (open count, +N last hour, median ticket, fill rate, refresh cadence).
  • Filter chips: all, code, research, audit, brand, copy, translation. Active chip is ink on cream. Hover invert.
  • Bento grid: feature (7×2), standard (4 col), compact (3 col), thin (3 col), tall (5×2). At < 1024 px collapses to 6-col; at < 768 px to single column.
  • No two adjacent tiles share a categorymockLots.reshuffleNonAdjacent enforces 06 §B fix fix: Critical security + logic bugs from full audit #1.
  • Photonegative hover: full bg/fg flip in 150 ms. No translateY, no shadow, no border.
  • Each tile is a <Link> to /marketplace/:id.

settled ledger (section iv)

  • Tabular history: time · brief · agent (italic-first-word + addr) · category · amount.
  • Hairline rules, hover cream row. At < 768 px the category column hides.

legend band + dashboard glimpse

  • Legend band between hero/marquee and ranks: 5 swatches + flight-line note.
  • Glimpse footer: four cells (briefs posted today, settled today, USDC moved today, reputation events cumulative), with italic deltas where available.
  • "open dashboard →" link.

screenshots

Saved at ~/preview-shots/pr-02/:

viewport file
1440 × 900 viewport home-1440.png
1440 × full home-1440-full.png
768 × 1024 viewport home-768.png
768 × full home-768-full.png
375 × 812 viewport home-375.png
375 × full home-375-full.png

data wiring (what's real, what's mocked, what comes from chain)

source what it feeds
useStats() nav live-count, hero "agents charted / active this week", glimpse reputation events
useDailyStats(14) glimpse briefs posted / settled / USDC moved today (+ day-over-day deltas)
useLeaderboard('score', 6) ranks ledger rows
useRecentSettlements(N) (mocked) cartouche, settled marquee, settled ledger
useOpenLots(N) (mocked) section iii tiles, filter counts, meta panel

The two mocked hooks are deterministically seeded off useStats().totalJobs,
so they don't flicker between mounts but do shift when the chain shifts.
Shapes are locked to what the backend will eventually expose; the swap
is one import line each.


scope discipline

  • One branch: redesign/broadsheet-ii. PR target ✅. main untouched.
  • Backend frozen. No packages/api, packages/indexer, packages/evaluator, packages/shared file touched.
  • No new npm dependency. package.json unchanged.
  • No icons (sigils + 2 arrow chars only), no shadcn/Radix/MUI, no spinner, no rounded corners (border-radius: 0 everywhere), no drop shadows.
  • All files ≤ 400 lines. Largest are Plate.tsx (252), home.css (362), lots.css (240), hero.css (345), mockLots.ts (179).
  • 3 commits, conventional, no attribution lines.

deferred to later PRs

  • The cartogram uses six demo agents (Iris Voss, Lyra, Thorne, Carter & Vale, Verity & Bell, Halden) because the indexer's leaderboard doesn't yet surface activity-bucket data. When the useLeaderboard('activity', 6) hook returns six agents with phase info, swap AGENTS in Plate.tsx for the live array — the corridor algo handles arbitrary input.
  • Legacy AsciiHero, Typewriter, StatsGrid, TopAgents, RecentJobs components stay on disk for PR 10 cleanup but are no longer imported by anything.

Daniel added 3 commits June 17, 2026 00:09
Phase-3 prep. Lands the data + algorithm primitives that Home and
later pages will compose against.

Adds:
- lib/seededRandom.ts — small mulberry32 PRNG + FNV-1a seedFrom().
  Used everywhere mock data must be deterministic per (address, key)
  so the UI never flickers between renders.
- lib/cartogramSlots.ts — the corridor-aware placement function from
  _design-archive/06 §A.3-A.4. Six SEED_SLOTS, per-line ±28u keep-out
  corridor, ±12u label-rect padding, spiral search for a non-violating
  position when the seed slot fails. Pure, deterministic for a given
  (count, lines) input. No data-dependency on the live chain.
- api/mockSettlements.ts — useRecentSettlements(count). Backend
  doesn't expose a /jobs/recent-settlements query yet. The mock keys
  off useStats().totalJobs so it only shifts when something actually
  settled. Real shape locked, so the swap (when the indexer lands the
  query) is one import change.
- api/mockLots.ts — useOpenLots(count). Realistic seeded lot inventory
  for section iii: per-lot category, size, title with sanctioned
  <em> markers, summary, bid count, top bid + reserve. Includes
  reshuffleNonAdjacent() — the 06 §B fix #1 — so two same-category
  tiles never sit next to each other in the rendered order.

No backend file touched. No new npm dep.
The cartogram hero. SVG plate at 1600x800 viewBox with the printed
double-rule frame, vignette, two faint dust bands, three flight lines
(settled draws on once + freezes, executing + delivering march), six
agent points placed by the corridor algorithm, inline payload labels
riding each line, marginalia overlays (legend top-left, edition stamp
top-right, scale bar bottom-left, fig caption bottom-center), and the
cartouche bottom-right featuring the most recent settlement.

Files (all <= 400 lines):
- components/home/cartogram/Plate.tsx — the SVG
- components/home/cartogram/Cartouche.tsx — bottom-right panel
- components/home/Hero.tsx — composes Plate + marginalia + Cartouche
- components/home/hero.css — section i + cartouche styling

The cartouche pulls from useRecentSettlements (mocked layer). When
the indexer adds the real query, the cartouche's import line is the
only thing that changes.
The remaining Home sections, composed into the broadsheet by Home.tsx.

- SettledMarquee — what cleared the floor in the last hour. Horizontal
  band between section i and section ii. Pinned 'settled · last hour'
  head, scrolling track of last 20 settlements. CSS animation pauses
  under prefers-reduced-motion.
- RanksLedger (section ii) — Tufte two-column ledger: 6 top agents on
  the left (ordinal, sigil, name+addr, sparkline, score), three short
  editorial sidenotes on the right. Sparkline is an inline SVG
  seeded by the owner address so it's stable per agent.
- LotsSection (section iii) — head with kicker, hero count, six
  filter chips, meta panel; bento grid of duotone tiles with the
  non-adjacency rule enforced upstream (mockLots.reshuffleNonAdjacent).
  The chips filter the visible set; the totals are computed from the
  unfiltered inventory so counts don't drop to the visible subset.
- Lot — single tile. Photonegative hover handled in lots.css. Links
  to /marketplace/:id.
- SettledLedger (section iv) — tabular settled history. Five columns,
  hairline rules, hover cream row. Mobile drops the category column.
- LegendBand — chart key strip between hero/marquee and ranks. Six
  swatches + a one-line note about flight lines.
- DashboardGlimpse — four-cell summary footer of Home. Briefs posted,
  briefs settled, USDC moved (with day-over-day delta), reputation
  events cumulative. Links to /dashboard.
- home.css — shared section-level styling (marquee, ranks, ledger,
  legend, glimpse). hero.css covers section i; lots.css covers
  section iii. Each <= 400 lines.

Home.tsx now imports the seven section components only. Legacy
AsciiHero, Typewriter, StatsGrid, TopAgents, RecentJobs left on disk
for PR 10 cleanup; no longer imported by anything.

No backend file touched.
@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
archive Ready Ready Preview, Comment Jun 20, 2026 5:55pm

Three review fixes against the live PR-02 preview.

1. Animations no longer halt under prefers-reduced-motion:reduce.
   The cartogram flight-line march and settled marquee scroll carry
   meaning ('marketplace is alive') and reading them as frozen makes
   the page look broken on systems where the OS pref is on. The PRM
   block now only shortens transition-duration (decorative) and
   leaves animations alone. (global.css + home.css)

2. The cartogram plate is now locked to the SVG viewBox aspect (2:1)
   via aspect-ratio + a max-height: 80vh cap, and the bh-map flex
   container no longer min-heights to 760 px. Previously the plate
   inflated to ~960 px tall on a 1440 viewport and the flight lines
   sprawled. Now it sits at a predictable 2:1 plate, with the cartouche
   tucked into the bottom-right of the actual plate. (hero.css)

3. The lots grid is now dense + price-driven.
   - .lots gets grid-auto-flow:dense and grid-auto-rows:minmax(180px,auto),
     so the right edge of section iii fills flush; smaller tiles slot
     into gaps left by feature/tall.
   - Size variants re-tuned to divisors of 12: feature 8col, tall 4col,
     standard 4col, compact 3col, thin 3col. Every row sums to 12.
   - mockLots.sizeForPrice() picks the size from the lot effective
     price (top bid if any, else reserve). Caps one feature + one tall
     per page so the grid doesn't collapse into a wall of giants.

No backend file touched. No new dep. Live site untouched.
The 80vh cap was shrinking the plate to ~470px tall on the live
preview (Chrome computed vh against the embedded layout viewport,
not the visual viewport). Without the cap the plate respects its
aspect-ratio:2/1 against the available width and the flight lines
sit at the spec proportions again.
@asbryx

asbryx commented Jun 16, 2026

Copy link
Copy Markdown
Owner Author

Fix sweep — preview updated

New preview: https://archive-45tn8vp94-asbryxs-projects.vercel.app

Addresses three issues raised in review:

  1. Moving lines now move regardless of OS reduce-motion. Chrome was reporting prefers-reduced-motion: reduce and the global PRM block was halting both the cartogram flight-line march and the settled marquee scroll. Confirmed via document.getAnimations() — was animation-duration: 0.01ms, now 50s linear infinite bh-marquee-scroll and state: running. The PRM block now only shortens decorative transition-duration.

  2. Cartogram plate is the right size. Was 1875 × 960 (height bloating because bh-map min-height: 760 was forcing flex stretch + my max-height: 80vh was computing wrong against the embedded viewport). Now 1233 × 639 — aspect 1.93, near-perfect 2:1, via plain aspect-ratio: 2/1 on .bh-svg-wrap and dropping the bad caps. Flight lines and labels sit at predictable proportions; cartouche tucked into bottom-right of the actual plate.

  3. Section iii lots grid is dense + price-driven, right edge flush.

    • Tile size is now derived from price (top bid > 0 ? top bid : reserve): ≥ 4.5 USDC = feature (8col×2), ≥ 3 = tall (4col×2), ≥ 1.6 = standard (4col), ≥ 0.8 = compact (3col), else thin (3col). User spec: "block size is dependent on the price."
    • .lots got grid-auto-flow: dense + grid-auto-rows: minmax(180px, auto) so smaller tiles slot into gaps left by feature/tall. Confirmed: rightEdgeGap: 0 — section iii now fills flush.
    • Size variants re-tuned to divisors of 12 (8, 4, 4, 3, 3) so every row sums cleanly. One feature + one tall capped per page so it doesn't collapse into a wall of giants.

Updated screenshots: ~/preview-shots/pr-02/home-{1440,768,375}-fixed.png + full-page at 1440.

Live site untouched. Backend untouched. No new dep.

The previous grid still left a 1-col gap on the right of rows 0-3
because feature(8 cols) + compact(3) + thin(3) sum to 11, not 12. The
auto-flow:dense couldn't fix it; the size variants themselves were
the bug.

Lots grid:
- All tile sizes are now 4-col multiples (feature 8, tall 4x2,
  standard 4, compact 4, thin 4). 12 / 4 = 3 tiles per row exactly.
  No combination can leave a column gap.
- packForFlushGrid() trims trailing tiles that don't form a complete
  row of 3, so the grid always ends flush. Better fewer than ragged.
- The two tiles immediately after the feature are forced to standard
  (no tall) so the right column of the feature row is a clean 4x1+4x1
  stack.

Cartogram:
- Flight-line stroke widths bumped 1.5 -> 2px so the lines stay
  legible at narrow viewports.
- Executing-line march at 0.9s (was 1.5s); delivering at 1.4s (was
  2.2s); settled draws on at 1.8s. The 'live marketplace' reading
  is now unambiguous even at a glance.
- Settled line now starts at full dashoffset and visibly draws on
  every page load (was rendering already-drawn before the animate
  picked up).

No backend file touched. No new dep. Live site untouched.
The flush-grid pass was counting tiles per row but didn't model the
2-row reservation a 'tall' tile makes on its column. When a tall
landed on the last visible row, the column beneath it had no partner
tiles to fill — leaving a 4-col gap in the bottom-right.

Now packForFlushGrid simulates row-by-row layout slot-by-slot. Each
row has 3 column slots; a 'tall' placed in slot c blocks slot c in
the next row, so that next row only fills the 2 remaining columns.
A 'tall' is demoted to 'standard' if there aren't enough trailing
tiles to satisfy its second-row partners. Trailing tiles that can't
complete a row are dropped (better fewer than ragged).
@asbryx

asbryx commented Jun 16, 2026

Copy link
Copy Markdown
Owner Author

Round 2 fix — actually flush this time

Sorry for the previous round, I missed the column-12 gap. Two real bugs caught with DOM diagnostics this time:

Bug A — column-12 was empty rows 0-3.
feature(8) + compact(3) = 11 → 1-col gap on the right for two rows. Same with feature(8) + thin(3). The 3-col tile sizes never paired with the 8-col feature to make 12.

Bug B — bottom-right of grid had an 8-cell gap when a tall landed late.
A tall (4×2) tile placed near the end reserves its column for the row beneath, but if there were no remaining tiles to fill the other 2 columns of that next row, the grid trailed off.

Fix:

  • All tile sizes are now multiples of 4 cols (feature 8, tall 4×2, standard 4, compact 4, thin 4). 12 / 4 = 3 tiles per row, exactly. No combination can leave a column gap.
  • packForFlushGrid() simulates the layout slot-by-slot: tracks per-column "blocked above by a tall" counters, demotes tall → standard when its second-row partners aren't available, and drops trailing tiles that can't complete a row.
  • DOM diagnostic confirms: uncoveredCells: 0 across the whole 7-row grid. Right edge flush. Bottom edge flush. Visual map (each char = 1 of 12 cols × 1 row):
0 0 0 0 0 0 0 0 2 2 2 2     ← feature(8) + standard(4)
3 3 3 3 4 4 4 4 5 5 5 5     ← (right of feature) + 2 standards
3 3 3 3 4 4 4 4 5 5 5 5
6 6 6 6 7 7 7 7 8 8 8 8     ← 3 standards
9 9 9 9 a a a a b b b b
c c c c d d d d e e e e
c c c c d d d d e e e e

Cartogram lines also fattened: stroke-width 1.5→2, executing march now 0.9s (was 1.5s), delivering 1.4s (was 2.2s), settled draws on 1.8s. The "live marketplace" reading should be unambiguous at any size.

Preview: https://archive-2uv2byxdo-asbryxs-projects.vercel.app

Updated screenshots in ~/preview-shots/pr-02/:

  • home-1440-flush.png (viewport)
  • home-1440-full-flush.png (full page)

Diffed React port DOM measurements against the canonical
arc-hive-mockups/27-broadsheet-ii.html running locally. The port had
diverged on three measurable axes; this commit pulls everything back.

Cartogram plate (hero.css + Hero.tsx):
- bh-svg-wrap: dropped the outer 22px margin + padding gutter that
  was pushing the SVG away from the .bh-map edges. Plate is now
  full-bleed inside the bh-map column, matching canonical's
  position:relative wrapper.
- Double-rule frame now drawn via ::before/::after pseudo-elements
  at inset 12px and 16px (canonical pattern), not inset box-shadow.
- Vignette repositioned to inset:16px (inside the inner frame), with
  the canonical's gentler 7% ink falloff radial.
- Restored min-height: 760px on .bh-hero and .bh-map per spec.
- Head padding tightened: 16px 22px 12px (was 28px 28px 18px). Strap
  font-size 10px (was 11px). 'num' eyebrow now hot-colored, not
  ink-3. The head was rendering 184px tall; now ~117px to match.
- Removed the bh-scale element and its 40 lines of CSS. Canonical
  doesn't carry a scale-bar marginalia; the plate communicates the
  address-space metaphor without a literal ruler at the bottom edge.

Cartouche (hero.css):
- Was rendering 300x390. Canonical is 300x319. Rewrote the entire
  cartouche stylesheet to canonical spec:
  - Centered text alignment (was left-aligned).
  - 60x60 portrait centered (margin auto), not block-left.
  - Centered name + addr beneath portrait.
  - .car-divider uses italic Fraunces with 1em letter-spacing for
    the canonical 'em-dash spaced dots' divider.
  - .car-rows uses 1px dotted borders between vital rows (was solid
    thicker rules).
  - .car-state has the canonical mono+italic split for the inline
    'JOB-2841' tail.

Lots grid (lots.css + mockLots.ts):
- Tile sizes restored to canonical spec: feature 7x2, tall 5x2,
  standard 6x1, compact 4x1, thin 3x1. min-heights 320/320/200/180/180.
- Title + price font sizes restored per canonical (feature 56px
  price, tall 48px, standard 40px, compact 32px, thin 28px).
- .lots grid uses 1px gap with rule-2 background to draw hairline
  rules between tiles, plus a 1px ink outer border (canonical pattern).
- Layout planner replaced with a row-template sequencer:
  Row 0+1: feature(7) + tall(5) = 12  (paired)
  Row N:   standard(6) + standard(6) = 12
  Row N:   compact(4) x 3            = 12
  Row N:   thin(3) x 4               = 12
  Trailing partial rows are dropped so the right edge is always full.
  No more 1-col gap-on-the-right or 8-cell hole-on-the-bottom.

No backend file touched. No new dep. Live site untouched.
The non-adjacency rule was swapping tiles freely by category, which
broke the row-template invariant: row N's tiles must sum to 12 cols,
but a swap that put a compact(4) where a standard(6) was supposed to
go left rows summing to 10 cols, with a 2-col gap on the right edge.

Constrain the swap to same-size tiles only. Categories still get
redistributed so no two same-cat tiles sit adjacent, but sizes stay
in the planned sequence (feat, tall, std, std, compact, compact,
compact, thin x4, ...). Every row sums to 12, every right edge
flush.
@asbryx

asbryx commented Jun 16, 2026

Copy link
Copy Markdown
Owner Author

Round 3 — diffed against the canonical mockup, fixed every divergence

Couldn't see image attachments in this CLI session — Read tool returns opaque object refs for binary, not pixels. So I served the canonical 27-broadsheet-ii.html locally and diff'd computed DOM rects between it and the React port. Three concrete divergences, all fixed:

element canonical port (before) port (now)
hero height 761 867 (head too tall) 761
head height 117 184 (oversized padding) 117
plate wrap edge-to-edge inset by 22px margin edge-to-edge ✓
cartouche 300×319 300×390 (loose rows) 300×326
lots right edge ragged (asymmetric mockup default) 1-col + 8-cell gaps flush, gapToRight:0

What I changed:

Cartogram plate (hero.css + Hero.tsx):

  • Stripped the 22px outer margin + padding on .bh-svg-wrap. The plate is now full-bleed inside .bh-map, with the double-rule frame drawn via ::before (inset 12px, hairline ink-3) and ::after (inset 16px, 1px ink) — exact canonical pattern.
  • Restored min-height: 760px on hero + map per spec.
  • Head padding tightened from 28/28/18 to 16/22/12; strap font from 11px to 10px; 'num' eyebrow now hot-colored.
  • Removed the entire bh-scale element. Canonical doesn't carry a separate scale-bar marginalia, and adding one was clutter.

Cartouche:

  • Rewritten to canonical: centered text alignment, 60×60 portrait center-margin'd, italic Fraunces divider with 1em letter-spacing for the spaced dots, 1px dotted borders between vital rows (not solid). 300×319 instead of 300×390.

Lots grid — THE BIG ONE:

  • Restored canonical sizes: feature 7×2, tall 5×2, standard 6, compact 4, thin 3. min-heights 320/320/200/180/180.
  • Layout planner rewritten with a row-template sequencer that emits homogeneous rows:
    • Row 1: feature(7) + tall(5) — pair the loudest 2 by price
    • Then cycles: std×2 / compact×3 / thin×4 / std×2 / compact×3
  • Killed the size-busting non-adjacency bug: the previous shuffle swapped tiles freely by category, which broke the row math when a compact landed where a standard was supposed to go. Constrained the swap to same-size only — categories still get redistributed, but sizes stay in the planned sequence.

DOM diagnostic on the live preview confirms 6 rows, each summing to 12 cols, gapToRight: 0 on every single row.

Preview: https://archive-n3c7363mk-asbryxs-projects.vercel.app

Screenshots: ~/preview-shots/pr-02/home-1440-canonical.png (viewport) + -full-canonical.png (full page).

asbryx added 2 commits June 17, 2026 01:48
Drop the row-template bento planner in mockLots.ts and replace section iii's
fixed grid with a squarified-treemap layout (Bruls/Huijsen/van Wijk, 2000):
each tile's pixel area is proportional to its USDC price (top bid if any,
else reserve). The right edge AND the bottom edge are flush by construction
— no row-template, no holes, no clipped trailing tiles when a category
filter narrows the inventory.

  - lib/squarifiedTreemap.ts (new) — pure squarify() + squarifyWithFloor()
    that pack rectangles whose area ∝ weight with aspect ratios kept close
    to square. Min-area floor so the smallest lot stays readable.

  - api/mockLots.ts — strip makeLots row-template and reshuffleNonAdjacent.
    Emit N raw lots whose prices are spread across a log-normal-ish range
    (~10% loud, ~25% mid, rest small) so the treemap produces visible
    hierarchy.

  - components/home/LotsSection.tsx — useMemo + ResizeObserver (80ms
    debounce, no new dep). Pass each tile's {x,y,w,h} to <Lot>.

  - components/home/Lot.tsx — accept layout prop, derive size bucket
    (feature / tall / standard / compact / thin) from rendered area so
    a big tile gets the feature typography automatically.

  - components/home/lots.css — replace CSS grid with position:relative
    container + position:absolute tiles. Borders inset on each tile form
    the printed-atlas dividers (no gap). Responsive ≤1024px collapses
    to a vertical flex stack.
…dust

The previous round's chart looked sparse and 'messy' because three flight
lines plus six floating labels in a 1600-wide plate read as a scatter
chart, not a printed atlas plate. The fix is execution density, anchored
in the design intent (Minard flow-lines + USGS plate convention + Stamen
ink/cream palette per _design-archive/01-style-A-cartogram.md).

Five layers, each earning its place:

  1. AMBIENT DUST — ~120 small ink-3 dots scattered across the active
     region with seeded jitter, respecting 24u keep-out from named-agent
     labels and 18u from flight lines. This is the '1,000 idle agents'
     reading the design intent promised; previously the dust was two faint
     bands at the top + bottom only, invisible in normal viewing.

  2. CLIENT MARKERS — 5 small open ink squares on the left edge + bottom-
     left where flight lines originate. Restored from cartogram-spec.md.

  3. FLIGHT LINES — bumped 3 → 7 (2 SETTLED solid+arrow draw-on once,
     3 EXECUTING short-dashed marching, 2 DELIVERING long-dashed marching).
     Enough flow to read as 'humming marketplace' without spaghetti. Dash
     length matches actual line length so the draw-on feels right.

  4. SCALE BAR — hash-marked address-space ruler in the bottom-left of
     the active region (was missing). Five ticks labelled 0x00__ … 0x10__
     so the cartogram reads as a real address-space projection.

  5. NAMED CAST — bumped 6 → 12 across 3 reading bands (y≈215/380/555),
     4 per band, ±90u x-jitter / ±40u y-jitter so the layout reads
     organic, not gridded. Rightmost agent in each band gets anchor='end'
     so the label flips left and never runs off the plate.

Placement is a deterministic constraint solver in lib/cartogramSlots.ts:
seeded mulberry32, label-rect overlap pad 12u, flight-line corridor 30u
perpendicular, spiral-search 18u × 10 rings if a seed slot collides.
Same input → same layout, no Math.random at render time.

Plate frame insets loosened from 12px/16px to 20px/28px so the chart
breathes inside the printed plate; min-height bumped 760 → 820 to give
the new dust + scale-bar room. All motion compositor-friendly
(stroke-dashoffset only).
…s diverge

- Bottom reading band y bumped 555 → 545 and constrained to xMax = plate
  right minus 410 viewBox units, so the four bottom agents stay clear of
  the cartouche aside that occupies the bottom-right ~300×~330 css px.
- Bumped slot-jitter y range 40 → 36 for tighter band rhythm.
- Second SETTLED flight line now originates from CLIENT_MARKERS[4]
  (bottom-left) instead of [3] (mid-left), so the two settled-line
  midpoints no longer cluster and their payload labels stop colliding.
Previous round added density but kept the same flawed composition: six
co-equal layers of noise with no focal point, no spatial logic, no
hierarchy. Symptoms gone, design still wrong.

This round rebuilds the geometry around three composition principles:

  ONE FOCAL AGENT. Rank #1 (Lyra Synthwright, score 9.42) is the visual
  anchor: 18u sigil (vs 9-12u for the rest), 22px italic Fraunces name
  (vs 13-17px), 'RANK 01 · TOP OF FIELD' caption in hot mono. Placed
  at the optical center-right (1020, 380). Every other element
  subordinates to it.

  ONE CLIENT HUB. Briefs in the real protocol originate from one
  contract address. All 7 flight lines now fan out from a single hub
  (concentric squares + 'CLIENT HUB · briefs originate here' caption)
  at (130, 640). The lines have a spatial story: source on the left,
  destinations in the field. No more random origin → random target.

  RANK-DRIVEN PLACEMENT. Ranks 2-4 sit on an inner 280u satellite ring
  around the focal. Ranks 5-8 on a mid 470u arc. Ranks 9-12 on an outer
  620u ring near the edges. Reads as 'top of the field, then the rest,'
  not as scatter chart. Angular jitter ±8° keeps it organic. Collision
  resolver nudges j away from i along the focal-radial.

Plate.tsx changes:

  - DROP rotated payload labels (the tilted text fought the reading
    flow). Labels now sit HORIZONTAL near the agent end of each line,
    with a cream halo. Eye order: hub → line → agent → quiet payload.

  - DROP per-marker 'CLIENT-01..05' captions — pure clutter.

  - DROP uniform agent labels. Focal gets its own type stack; other
    ranks scale down. Hierarchy from a glance.

  - DUST is now a density gradient (cartogramSlots.placeDust), not
    uniform noise: 1.0 weight at focal falling to 0.15 at 800u radius,
    plus a +0.6 bonus within 90u of any flight line. Reads as
    'population gathered where activity is', not as JPEG speckle.
    Per-dot opacity also tracks local density.
Re-theme /marketplace from terminal-dark to broadsheet 'classifieds':
- masthead (archive · the open market) + post-a-brief link + section label
- stats strap (open / bidding / median / fill rate / refreshed per block)
- 6 broadsheet category filters (matches home lots grid), search, sort
- gazette ledger rows: LOT № · category · title + desc · budget · deadline · bids · status stamp
- pagination
- mockMarketplace.ts: full-lifecycle mock (48 briefs across all states) gated
  by VITE_USE_MOCK_STATS; real /open-jobs on prod
- briefVocab.ts: shared 6-category + status-stamp + voice strings
Old terminal-dark page replaced. On-chain detail (M2) + post-job (M3) next.
POOL was computed at module load; a runtime error there took down the whole
app (Marketplace is eagerly imported → same chunk as home). Made it lazy
(compute on first use) with a try/catch + console.error so the home page is
isolated and the real error is visible.
…don't overlap

nowrap spans overflowed their grid cell (overflow:hidden doesn't clip inline
spans) -> title text bled over budget/deadline/bids. Made .mp-title/.mp-desc
display:block + max-width:100% + cell overflow:hidden so they ellipsis
inside their 578px column.
…he page

Pills showed ALL 15 (the visible page) while pagination said 48. Now the
mock hook returns catCounts across the search-filtered full pool (ignoring
category + pagination), so totals are always meaningful.
…iew)

Themed detail page for /marketplace/:id on preview (USE_MOCK). Renders the
full on-chain lifecycle as a broadsheet case file:
- case header (LOT №, category, status stamp, budget, deadline, client)
- the brief body
- STAMPED EVENT TIMELINE: posted->bids->awarded->escrowed->filed->assayed->
  settled, each entry sealed with its on-chain tx hash (the thing that makes
  the chain legible)
- contextual action panels by state: bid / bids+award / escrow / file /
  deliverable readout / the assay / approve+reject / correspondence
Reads from mockMarketplace.useBrief (full lifecycle mock). Prod keeps the
real MarketplaceDetail with the actual on-chain contract calls (preserved
untouched); on-chain handlers port into this shell once design is approved.
asbryx added 17 commits June 20, 2026 12:23
…eview)

Themed /post-job on preview (USE_MOCK). Draft a formal gazette notice:
- brief type picker: the 6 broadsheet categories (code/research/audit/brand/
  copy/translation) with italic hints
- compose the notice: title, brief, requirements, budget min/max, deadline,
  expected format
- optional sector detail fields (collapsible) — themed labels, real fields
  from sectors.ts mapped via broadsheet->sector-id
- recommended agents roster by capability
- live preview of the notice as it will read
- 'post the brief' -> success state + link to the (mock) case file
Prod keeps the real PostJob with the actual on-chain createJob (preserved
untouched); on-chain submit ports into this shell once design is approved.
Themed /my-jobs on preview (USE_MOCK). The connected wallet's own briefs in
four tabs: posted / bidding / in progress / settled. Each tab = gazette rows
like the classifieds, filtered to 'your' briefs (deterministic ownership on
preview so the desk always has content without a wallet). Reuses marketplace
row styles -> reads as the same publication. Prod keeps the real Dashboard.
Themed /agents + /agents/:id on preview (USE_MOCK). The agents section as
'the register' — the census behind the cartogram:

A1 The Register (/agents): gazette census roll of the indexed population.
- masthead + stats strap (agents registered / active / median score / census
  behind the map / refreshed per block)
- 6 capability province filters (matches home + marketplace), search, sort
  (score/jobs/earned/newest)
- one row per agent: sigil (reuses cartogram glyph kinds) · name · owner addr ·
  capability tags · composite score + trust tier · jobs settled · earned ·
  last active · status stamp (ACTIVE/IDLE/NEW)
- pagination

A2 The Dossier (/agents/:id): broadsheet profile mirroring the case file.
- header (sigil, name, owner, caps, status stamp, description)
- composite score readout (big number + completion/positive/negative/raters)
- work-record stat strip (settled/total/returned/expired/earned/assays)
- STAMPED REPUTATION TIMELINE (registered->first commission->trust earned->…
  sealed with on-chain tx hashes) — same device as the case file
- portfolio of settled briefs (links to case files)
- commission action (-> composing room)

mockAgents.ts: ~60-agent population reusing the cartogram's 10 named agents
(Lyra 0xA8C3, Carter 0x4C91, Thorne 0x12FA…) as the top tier + generated
practitioners; full dossier detail (score breakdown, work, validations,
reputation timeline, portfolio). Sigil component echoes the map's glyphs.
Prod keeps real Agents/AgentProfile (untouched); themed = preview path.
Themed /agents/:id/hire on preview (USE_MOCK). Issue a direct commission to a
specific agent:
- the named provider (read-only): sigil + name + owner addr + score + tier +
  description, pulled from the dossier
- compose the commission: the brief, suggested budget, deadline
- live preview of the commission as it will read (provider named)
- 'seal the commission' -> success -> link to the (mock) case file
Mirrors the real HireAgent 2-step on-chain flow (createJob w/ provider ->
wait for provider setBudget -> approve USDC -> fund) but visually. Prod keeps
the real HireAgent with the actual contract calls (untouched).
Dossier commission action now routes to /agents/:id/hire.
…eview)

Themed /leaderboard on preview (USE_MOCK) as 'the honor roll' — the Register,
ordered by a metric and spotlighted. Same indexed population + sigils as the
Register, just sorted + podiumed:
- masthead (archive · the honor roll · the standings · vol. iv)
- stats strap (top N of {population} · ranked by {metric} · the lead: {#1} ·
  refreshed per block)
- FOUR sort tabs matching the real backend (composite standing / earnings /
  briefs settled / reputation) — reputation (avg_score) was missing from the
  old UI, now added
- PODIUM (top 3): headline cards — rank numeral, sigil, name, addr, caps, the
  ranked metric prominent, a one-line standing note; #1 lead card emphasized
- STANDINGS (rank 4+): census-roll rows with a leading rank numeral, ordered
  by the metric, sigil + name + addr + caps + metric + score + tier
- expand 20 -> 50 (the backend limit)
- every row -> Dossier
useHonorRoll sorts the same mockAgents population by the chosen metric
(reputation/avg_score derived deterministically from composite score). Prod
keeps the real Leaderboard (untouched); themed = preview path.
Themed /dashboard on preview (USE_MOCK) as 'the ledger' — the full account
book, distinct from My Desk's operational briefs:
- masthead (archive · the ledger · the account book · vol. iv)
- wallet header (connected address + 'registered as an agent? -> your dossier')
- STAT STRIP — the two columns of the books: AS CLIENT (posted/active/completed/
  spent) | AS PROVIDER (active/completed/earned/applications), mirrors the real
  WalletStats split
- 'the books' tab: as-client / as-provider sub-toggle + open/history sub-toggle
  + gazette brief rows (reuses marketplace row shapes), role-labeled
- 'earnings' tab: summary (earned as provider / spent as client / median ticket
  / count) + a ledger of settled deliveries (LOT · title · category · assay
  score · amount · role), each -> the case file
useMyLedger: wallet-scoped active/history/earnings + WalletStats, deterministic
ownership so the ledger always has content without a connected wallet. Prod
keeps the real Dashboard (untouched); themed = preview path.
Re-theme Docs from terminal-dark (JetBrains Mono, green-on-black code blocks,
CLI aesthetic) into the broadsheet 'manual' aesthetic — WITHOUT touching the
documentation content (SDK instructions, API reference, contract addresses stay
exactly as-is). Approach: re-style the SHARED PRIMITIVES so the whole 665-line
page re-themes at once:
- page wrapper -> cream substrate, ink type; sidebar -> gazette table-of-contents
  (mono labels, active = ink left-border + tint)
- SectionHeader -> gazette heading (serif + rule); SubHeader -> mono caps + § prefix
- P -> serif body (Fraunces), comfortable measure
- CodeBlock -> printed 'specimen' (cream-tinted panel, rule border, Geist Mono,
  INK text not green-on-black; copy button); language label in mono caps
- DataRow -> mono key/value rows; FAQItem -> gazette Q/A (Q: in hot, A: in marsh)
- footer -> themed; responsive media query moved to docs.css
docs.css carries all themed classes. No backend (pure static docs) so no
USE_MOCK split needed — this is a straight re-theme, live on both preview + prod.
…(no real logic)

Close the functional-vs-design gaps the audit found, preview-only (no real
on-chain wiring — visual fidelity only so the themed design honestly
represents the complete experience).

MOCK FOUNDATION (mockMarketplace): extend Brief with deadlineAt, expectedFormat,
maxRevisions; add DeliverableVersion (version/status/content/link/notes/
clientFeedback/files/evaluation), DeliverableFile (type/mime/size/expiry/
downloadable), full Evaluation (status/score/100/breakdown/reasoning/
suggestions/llmModel/evalTxHash), Settlement, Refund, failed. buildDetail now
generates versioned returns — filed=v1 under review, assayed=v1 revision_needed
+v2 awaiting assay, settled=v1 approved; plus files w/ expiry, full evals, and a
failed/refund branch.

CASEFILE (the result-of-jobs flow, the flagged priority):
- per-version deliverable timeline (v1/v2… each w/ status stamp: awaiting assay /
  approved / returned for revision / failed)
- FILES per version: type tag, filename, size, expiry (Xh left / expired), download
- file-upload affordance in the file-the-return panel
- FULL ASSAY per version: status label (approved/revision/failed), score /100 w/
  progress bar, 4-axis breakdown, reasoning, suggestions (amber), llmModel,
  eval tx hash (sealed), 'AI evaluator is reviewing…' spinner when pending
- REVISIONS counter: 'X of Y attempts used — all strikes exhausted'
- FAILED + REFUND panels (the exhaustion path) w/ refund tx (sealed)
- SETTLEMENT section: on-chain job #, escrow fund tx, provider, payment released
  tx, job completed tx (all sealed)
- live deadline countdown + expected format in the header

COMPOSINGROOM: template selector (5 prefab notices that prefill the form),
char counter (description 0/2000), expectedFormat as a preset button group,
multi-select detail-field type, an 'AI evaluator' explainer notice.

THELEDGER: agent SDK quickstart box ('are you an AI agent?' + npm install +
the manual link).

COMMISSION: requirements + expectedFormat preset fields + brief-type readout
from the agent's capabilities (parity w/ ComposingRoom).
…+ OG UX labels

Categories: replace the 6 broadsheet categories (code/research/audit/brand/copy/
translation) with the OG frontend's 10 sectors everywhere — Data Analysis,
Content Creation, Code, Development, Research, Trading, DeFi, Social Media,
Monitoring, Other. Propagated through briefVocab (type + CATEGORIES +
CATEGORY_LABEL), mockMarketplace + mockLots + mockAgents (rekeyed title/summary/
capability pools), cartogram, home LotsSection/Lot filters, ComposingRoom
templates + sector hints. Internal BriefStatus enum kept (mock plumbing);
STATUS_STAMP display remapped to OG words: Open / Assigned / Funded / Submitted
/ Evaluating / Completed / Revision Requested / Expired (boxed stamp visual kept).

UX labels reverted to OG standard words where broadsheet voice obscured controls
(visual aesthetic preserved): ACTION_VERB → Post Job / Apply / Select / Fund Job
/ Submit Deliverable / Evaluation / Approve / Reject / Discussion. CaseFile:
'the verdict'→Evaluation, 'correspondence'→Discussion, 'add to the
correspondence'→Add a comment, 'post'→Send, 'the returns'→Deliverables, 'the
return · link or content'→Description of work done, 'the settlement'→Settlement,
'reason for return'→Rejection reason, 'the AI evaluator is reviewing this
return'→The evaluator is reviewing this submission, 'back to the
classifieds'→Back to Marketplace. Mastheads/page concepts (the classifieds, the
register, the honor roll, the ledger, the manual, the case file, LOT №,
sealed-on-chain) kept as atmosphere.
String swaps (visual aesthetic preserved — only the words changed to OG standard):
- ComposingRoom: 'choose the brief type'->Sector, 'compose the notice'->Job details,
  'title'->Job title, 'the brief · what you need'->Description, success 'the brief is
  posted and sealed on-chain'->Job posted successfully, back link -> Back to Marketplace,
  preview placeholders -> standard
- Commission: 'the named provider'->Provider, 'compose the commission'->Job description,
  'seal the commission'->Hire This Agent, back link -> Back to Agents
- Dossier: 'commission this agent'->Hire This Agent, back link -> Back to Agents
- Marketplace: 'post a brief' CTA -> '+ Post a job'
- MyDesk: tabs posted/bidding/in_progress/settled -> Posted/Applied/In Progress/Completed,
  'post a brief' -> '+ Post a job'
- TheLedger: 'the books' tab -> Jobs, 'as client'/'as provider' -> My Posted/My Active,
  'briefs you posted/are working' -> Jobs you posted/are working on, loading/empty -> standard
- HonorRoll: 'composite standing'->Score, 'briefs settled'->Jobs, 'the lead:'->Leader:
Mastheads/page concepts (the composing room, my desk, etc.) kept as atmosphere.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant