Session — Redesign: make the interface look like the approved design
What this session is for
tmp/latest-design/ holds an approved visual design for the launchpad. The interface in app/
works but does not look like it. Bring the look across.
This is a visual change to a working application. Every number on every screen is read from a chain or an indexer, and the trading path was debugged transaction by transaction on 21 Sep. None of that may be disturbed. If a change would alter what the app does rather than how it looks, it is out of scope for this session.
Read first
CLAUDE.md— the constitution. Especially Working with Claude, and the Frontend and deployment trap list, which has already-paid-for answers for several things this touchesnotes/STATUS.md— where the project standstmp/latest-design/Stadium-Money-Dev-Pack-36/README-DEV.md— the designer's own handoff, which states the UI constraints and is authoritative about their intentapp/src/theme/tokens.css— the token system the app already has
Where the design is, and how to look at it
cd tmp/latest-design/Stadium-Money-Dev-Pack-36 && PORT=8768 node serve.cjs
Then http://127.0.0.1:8768/. Hash routing — #/lab/, #/create/, and so on.
tmp/ is gitignored. Nothing in it is a build input for app/. Do not import its CSS, do not
copy its JavaScript, do not vendor its HTML. It is a reference to look at and reproduce, and its
own README says the compiled HTML is not source.
index.html / Stadium-Money-Launchpad.html | Identical compiled output. What to look at |
previous-preview.html | Legacy build input, superseded. Ignore |
*.css | Ordered refinement layers, last-wins. Read for values, never import |
README-DEV.md | The constraints the designer set. Honour them |
The good news
The design is closer to the app than it looks. Both use Fraunces and Manrope. The accent is
#a3c791 in both. Both theme through data-theme on <html> and both ship a light theme. So this
is a layout, composition and density change, not a palette or type rewrite.
What actually differs
Judged from the rendered design, not from its stylesheets:
| Rail | A narrow icon rail with a collapse control, not a wide text rail |
| Top bar | A global search field across the width, and a gold wallet pill at the right |
| Hero | Dark forest green, a faded stadium photograph bled into the right, cream "Welcome to" over gold "the stadium.", and exactly two CTAs — one filled gold pill, one outlined |
| Pairing ticker | A "PAIR WITH" strip of small round asset logos along the bottom of the hero |
| Catalogue | Filter chips (Trending / New / Top / Volume / Near graduation / Advanced), a density control, "Refine results", then a dense table: token, FDV, 24h, volume, holders, stage, with a star and a copy-address control per row |
| Lab | A grid of large illustrated mechanic cards, each with a category tag, an interactive illustration and an "Add to launch" action |
| Shape language | Rounded pills, more gold, quieter panel borders |
Keep the designer's stated constraints: the approved Welcome copy, exactly two hero CTAs, the light theme working, and no filler captions, preview labels or development disclaimers in the interface — with the deliberate exception below.
What the design shows that does not exist yet
This is the one thing that needs judgement rather than transcription. The design was drawn against the vision, not against what is deployed.
The lab. The design shows nine mechanics — Dynamic Fee, Anti-MEV Guard, TWAMM Orders, On-Chain
Limit Orders, Holder Rebate, Circuit Breaker, Auto-Compounding LP, Liquidity Vesting Lock, Gated
Launch. Five exist, and they are not the same five: app/src/chain/mechanics.ts owns the real
list — Fees, Anti-sniping, Graduation protection, Maximum trade size, Maximum wallet — and each is
a module deployed on Sepolia and readable in contracts/deploy/421614.json.
So: render the real five in the new card treatment, fully working. Render the design's
aspirational ones as visibly "Coming soon" — same card shape, clearly inert, no "Add to launch".
Never let a coming-soon card reach mechanics.ts or the create form.
Stock pairing. The hero's ticker shows GOOGL, TSLA, AAPL, MSFT and friends. Stock pairing is real ambition and is deployed nowhere (D31). The live quote menu on Sepolia is two stand-ins, mock ARB and mock RHUB, and the factory will refuse anything else. Show the real quote assets as selectable; if you keep the stock logos for the look, they must be unmistakably not choosable.
The rule. A control that cannot do anything must not look like one that can. A launchpad that offers a mechanic it cannot attach is worse than one that shows fewer.
What must still work when you are done
These were each found the hard way. Breaking one silently is the main risk of this session.
- The trade panel quotes by simulating the real call (
app/src/chain/trade.ts). It is not a formula and must not become one. A module runs inside the trade and the curve cannot report it from aview. - The gas floor.
sendRawhands over 3,000,000 becauseBondingCurve,LaunchHookandLaunchTokeneach checkgasleft()and revert when short, and the floors are sequential. Do not "tidy" that into an estimate. - The wallet picker offers the EIP-6963-discovered wallets.
connectors[0]reaches whichever extension won the injection race, which is how MetaMask was unreachable. - The faucet appears only where the quote asset will actually mint, decided by simulating it.
- The ETH pay option appears only where a v3 route exists. On Sepolia it never does.
- The deadline comes from the chain's clock, not the browser's.
- Sign-in is currently broken on staging by design — see issue #3. The watchlist depends on it. Do not "fix" it here.
Scope
Yours: app/src/** — components, CSS, theme/, page composition. app/index.html if the head
needs it. New assets under app/public/ or app/src/assets/.
Not yours: contracts/, services/, supabase/, notes/ other than this file, the Makefile,
CI, and anything under tmp/. app/src/chain/** is data-layer code — read it, and change it
only where the redesign genuinely requires a new read, never to alter behaviour.
Work on a branch. The developer is on master at the same time, on the indexer and on getting
a launch through Sepolia. git switch -c redesign, and rebase rather than merge when you land.
Proving it
make checkgreen before every commit. It runsbuild-app-testnet, which typechecks the app against the chain it is actually deployed on — that check exists because a type error invisible at 31337 broke the Vercel build at 421614.- Both themes. Toggle it and look. The light theme is a stated constraint.
- Measure the responsive behaviour, do not eyeball it. Compare
documentElement.scrollWidthagainstclientWidthper route. A grid or flex item will not shrink below its content, somin-width: 0on the item andoverflow-wrap: anywhereon display text. lightweight-chartsparses colours itself and knows nothing ofcolor-mix(), nor of thecolor(srgb …)a browser resolves one to. It throws inside its own render loop, so the symptom is a 300x150 canvas in the corner of a correctly sized box, not a wrong colour. Resolve tokens torgba()before handing them over.- Run it against the local stack —
make devbrings up a chain, 305 seeded launches, the indexer and the interface on:5175. A catalogue with real rows in it is the only honest way to judge a catalogue.
How to work
CLAUDE.md governs, and its Working with Claude section is the part that matters most here:
build in small pieces, explain each one, and stop at the edge of what was asked. Screen by screen,
committed as you go, is far better than one enormous diff nobody can review.
Comments explain why. A comment restating the line above it is noise; one recording why a thing is done the hard way is the most valuable line in the file.
Commit as [type] A sentence in prose, sentence case, no trailing period. Never add a Claude
attribution. Use /commit.
Write to this file when something is decided or abandoned — not at the end.
The record
Branch redesign, off a94ab9f. One commit per screen.
Gate per commit
make fmt-app, yarn lint (tsc) and make build-app-testnet — the app half of make check,
which is the half this session can break. A full make check runs before landing; running the
contract suite and Slither between screen commits spends minutes on code nothing here touches.
Decided
- Two emphasis colours, not one.
--accentstays semantic (a gain, a link, the focus ring);--goldis ornamental (rims, an active rail icon, the second word of a heading);--ctais the filled call to action. All three resolve to greens in the light theme, so no rule below them asks which theme is on. Radius scale moved intokens.cssat the same time. - The search is real or it is not there. The design draws a field across every screen and gives
the catalogue none of its own. It navigates to
/launches?q=…, a URL the catalogue already understood, and/focuses it. The catalogue now watchesqrather than reading it once, because a second search from the top bar changes nothing else about the URL. - The hero photograph is cropped in CSS, not on disk. The supplied asset is a screenshot of the
whole approved hero and only its right-hand region is artwork; the handoff asks for those bytes
preserved. The odd percentages in
.hero-field imgare that rectangle. - The hero paragraph stays ours. The design's says "paired with crypto or stocks". Stock pairing is deployed nowhere (D31), so the claim would be false in the product. The approved headline is unchanged, which is what the handoff's constraint names.
- The pairing ticker shows only real quote assets, built from the catalogue's own rows, each filtering the catalogue. No stock logos at all — the brief allowed keeping them if unmistakably not choosable, and none of them being there is simpler and says the same thing. This retired the separate "Paired with" band, which repeated the information further down.
- The hero's three totals moved out, to a rule-separated row beneath it: the design gives the whole right-hand side to the photograph and there is nowhere in it for them.
- FDV stays out of the catalogue table. The design has a column for it;
CatalogRowhas no supply to compute one, and adding a read to fill a column is a change to what the page does. - The lab's nine aspirational mechanics are a separate band, not interleaved. Same card shape, tint drained, "Coming soon", and no action element at all rather than a disabled one — a greyed-out button says "this would work if something were different".
- The card's tinted head carries a diagram, not an illustration: which of a trade's three
moments the mechanic acts on, derived from
Catalogued.scope. Real information we already have, where the design has artwork we would have had to invent. - Category is a lab-local map, not a field on
Catalogued. It is how one page groups cards; putting it inchain/mechanics.tswould make three screens carry it so one could use it. - One page title for every screen, as
h1.titleinbase.css. A class rather than a selector list naming each page, so the next screen opts in rather than having to be added to a file it does not own. - The create form's sections are numbered by a CSS counter, not by numbers typed into the JSX: adding or dropping a panel renumbers the rest.
- The catalogue leads with the table, as the design draws it. The grid and the 4/6/8 control are the alternative, and the count is clamped by breakpoint rather than obeyed — eight cards abreast at tablet width is eight unreadable cards, and the choice is kept for when the window is wide again.
- Brand artwork and the hero JPEG are copied into
app/src/assets/, downscaled. They are deliverables, not the CSS/JS/HTML the brief rules out vendoring. The dark theme burns the wordmark to cream withbrightness(0) invert(.94) sepia(.18), so one file serves both themes.
Changed outside app/src styling
Createaccepts?mechanic=<key>so the lab's "Add to launch" leads somewhere. Applied only onceuseLaunchMenuconfirms the factory offers that key, because the form renders a card per offered mechanic and a choice with no card cannot be undone.
Found on the way
.tickerwas two different things. None of these stylesheets is scoped, so they all end up in one sheet: the discover page's trade strip was giving the token page'sSYMBOL / QUOTEline a border above and below and masking its first characters away. It looked like a clipped label on a page that had never heard of that file, and in a production bundle it would have been there from the first load. The strip istrade-tickernow. Worth watching for elsewhere — a class as generic as.card,.panelor.gridis shared across this app by accident, not by design.
Measured
documentElement.scrollWidth against clientWidth, per route, in a same-origin iframe of a fixed
width — Chrome will not resize its window below its minimum, and page zoom decouples innerWidth
from it. Every route clean at 320 and 360px. Two overflows found and fixed this way: the header's
search squeezed to eighty pixels below 700px (now wraps to its own row), and the lab grid's
minmax(300px, …) track pushing nine pixels of scroll at 320px (now min(300px, 100%)).
Proved
make checkgreen on the branch: fmt, boundaries, lint, all four builds, 276 contract tests.- Both themes looked at on every screen.
- No horizontal overflow on any of the eight routes at 320px.
- The trading path still quotes by simulation: 100 dRHUB on a graduated launch simulates to
155.17k MER9 at 0.04% impact against the local chain, with the worst case under it. Nothing in
chain/trade.ts, the gas floor, the wallet picker, the faucet test or the deadline was touched.
The second pass — literal
Asked for on review: the first pass reproduced the design's system and left every structural difference alone, and it did not read as the design. The direction given was as literal as the data allows, and the illustrations to be commissioned rather than substituted.
- The lab is one grid of ten, with the design's card anatomy: tinted head bleeding to three
edges, gold last word, the sentence at nearly full strength, and a foot of a gold-rimmed
+beside a wide outlined action. The+reveals where the mechanic runs. What separates the five that exist from the nine that do not is the card, not a heading — drained tint, dashed border, "Coming soon", a label where the action would be — so the difference survives being scrolled past. The tenth card the design draws, On-chain TWAP oracle, had been missed. - The token page figures became one rule-divided line; the chart and the prose share the left
column and the trade panel takes nearly the other half. The disc between the two boxes turns the
trade around and clears the amount with it. The panel's foot carries what it is paired against
and how close the curve is to closing. The price shows its 24h move — one more column on a
launch_statsselect the page already made. - The create form is one panel, two numbered steps and the action inside it. It now collects a logo, a description and socials, a pairing select with its threshold written underneath, and one fee number until "Advanced" asks for two. The right-hand card became what a stranger will meet.
- The front page is the hero and then the catalogue, which is what the design's is. The
catalogue moved to
catalog/Catalogue.tsxand both screens render it, so the table cannot gain a column on one and not the other.
Decided in the second pass
- Metadata is collected before the launch and written after it. The design's form asks for a picture and a description alongside the name, and so does ours now. It cannot be saved any earlier: the row is keyed by the token's address and the edge function asks the factory who the creator is, so there is nothing to sign against until the transaction has landed. The form holds it; the screen afterwards offers one signature for the lot, and never appears if nothing was typed. This is a behaviour change, made deliberately and on request.
- The podium and the endorsement bands became one strip. The design has neither, and two bands of cards above a 305-row table were competing with it. What we chose is not what the chain says, which is the only editorial thing on the page, so it survives rather than being deleted — the podium's three keep their rank. One component to delete if it should go entirely.
- The stats row and the trade ticker stay on the front page. The design has no slot for either; both are read from the chain.
- Trade presets stay percentages. The design's are fixed amounts, which need a sensible magnitude per quote asset that nothing here knows.
- The lab's illustrations have to be drawn. They are not assets: the pack builds its versions
from about fifty class names of divs under 3D transforms in
playful-lab.css, animated byvisual-lab.js— code the brief rules out vendoring, and drawn for the design's nine subjects rather than our five. The slot is built to its dimensions and globbed, so saving an SVG intoapp/src/assets/mechanics/is the whole of adding one. That directory's README is the contract.
How to compare the two
A scratch page at 127.0.0.1:8770 renders the design and the app side by side, each laid out at
a real desktop width and scaled to fit its column, with route, width and layout switches. Built
because judging fidelity from two windows at half width compares each one's narrow layout, and
Chrome will not resize below its minimum.
The third pass — measured, not read
Reviewed again and the palette, the type, the sidebar and the "glass" were all called out as
wrong. They were. The mistake was writing tokens.css from the design pack's stylesheets —
a dozen last-wins layers where what a rule says and what the browser paints are different things.
The fix was to serve a copy of the compiled design from the same origin as a probe page and read
getComputedStyle off the live document. Everything below came out of that, and it is how any
future question about this design should be answered.
| Was | Is | |
|---|---|---|
| Page ground | #111e18 only | #2d595f teal on html, #16312f on content |
| Panels | opaque #192920 | rgb(16 38 43 / .86) + backdrop-filter: blur(10px) |
| Accent | green #a3c791 | gold #c5a46a — green is only a price going up |
| Ink | #f0eee1 | #f2e9d6 |
| Type | Fraunces + Manrope | Helvetica Neue at 14px |
| Headings | 800, -0.5px | 500, -0.04em |
| Table head | 11px | 9px, rows 52px |
| Rail | 56px, muted icons | 72px, 44px icons at 13px radius, gold at rest |
- The design sets 2,542 elements in Helvetica Neue and six in Fraunces. It ships Fraunces and Manrope from an earlier draft and overrides them nearly everywhere. The brief said both stacks were shared with the app; that was true of the pack's files and not of its output. Helvetica Neue is an Apple font — Windows and Linux fall to Arial. That is the design's own stack and worth a decision at some point.
- The glass is
backdrop-filter, not transparency. Every surface that sits over the page is frosted; a translucent colour without the blur is a see-through box. A worn canvas (assets/page-grain.jpg, extracted from the pack) sits fixed over the page at 9% in dark and 16% in light. - The sidebar logo was cropped because
.brandwas 44px tall and the wordmark needs the design's 78px box. docs.stadium.moneyis in the rail, as asked.- The portfolio became one summary panel with an allocation bar plus a tray of three views, instead of three stacked bands and three cards.
- The watchlist became the catalogue narrowed to a saved set —
Cataloguenow takesonly, a title and an empty state, and serves three screens.
Still open in this thread
- The nine illustrations, and one more for each of the five real mechanics. The lab's cards have a correctly proportioned tint and nothing in it until they are drawn.
- The design's stock pairing is not represented at all. The brief allowed keeping the stock logos if they were unmistakably not choosable; the strip shows only real quote assets instead. If the hero should still gesture at stocks before D31 lands, that is a decision to take, not an omission to fix quietly.
- The hero paragraph is ours, not the design's. The design's says "paired with crypto or stocks" and that is not true of anything deployed. Worth a look when it is.
- The lab has fifteen cards. Five real, ten benched. If that many unbuilt mechanics reads as
over-promising rather than as direction, the bench is one
BENCHarray to trim. - Five of the six things the design had no slot for are gone, removed on request after their
cost was put in writing. The sixth came back; the rest are worth re-reading before launch:
- The mechanics disclosure was put back before landing. It went with the other five,
and then the public documentation written on
masterthe same day turned out to promise it in four places —mechanics.mdtwice,intro.mdandhow-a-launch-works.mdall say a launch's mechanics are stated on its token page. Removing it made the public site false about the one thingCLAUDE.mdcalls most important. So the design gains a section it does not draw, and the docs stay true as written. Five removed, not six. - The catalogue's source line. "305 of 305 · indexed" is how D38's fallback stays visible: with the indexer down the page still works and says fewer numbers, and that line was how a visitor could tell. A column of dashes now explains itself to nobody.
- Also gone: the front page's three totals, its live trade ticker, the "Chosen by us" strip, and the lab's essay (the three seams, why the hook stays boring, the three conditions).
data/discover.tskeepsuseCurationanduseRecentTradeswith no caller. The curation table andmake dev-curateare untouched, so the strip is one component to restore.
- The mechanics disclosure was put back before landing. It went with the other five,
and then the public documentation written on
- The wallet write path still has not been exercised — unchanged by this session, and still
the thing
STATUS.mdlists as outstanding. - Brand artwork is 132KB of PNG across two files, downscaled from the pack's 1.2MB. An SVG wordmark would be a fraction of that if the designer has one.