Skip to content

Redesign livepeer.org - #93

Open
adamsoffer wants to merge 75 commits into
mainfrom
claude/livepeer-redesign-plan-110a98
Open

Redesign livepeer.org#93
adamsoffer wants to merge 75 commits into
mainfrom
claude/livepeer-redesign-plan-110a98

Conversation

@adamsoffer

@adamsoffer adamsoffer commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

🚧 Work in progress — not ready to merge. Opened as a draft for review of direction and shape. See Before this can ship for the blocking items.

Rebuilds the marketing site against Peace Node's Livepeer UI registry. The registry theme is now the only token layer.

Pages

Nine linked pages, all built from the mockup set except where noted:

Page Route Notes
Home /
Agent /agent flagship product surface
Ecosystem /ecosystem /[slug], /submit — markdown-driven catalog
Provide GPU compute /compute one page for running + earning
Token /token
Foundation /foundation
Latest /blog nav says "Latest", URL stays /blog
Brand /brand no mockup — designed from design.md + registry Foundations
Roadmap /roadmap no mockup — built from the requirements doc

/primer stays intact and unlinked with its own scoped legacy slice — the one page deliberately left unmigrated.

Content is split on its shape and how often it changes. Page copy is authored in-repo as typed objects matching the registry's content contracts (lib/site.ts) — versioned and reviewed alongside the design it belongs to. Blog and ecosystem are markdown in content/.

Templated content that gets updated frequently moves to Notion, and the roadmap register is the first of it. It is maintained by people across several organisations who do not open pull requests, and a commitment whose state is a week stale is worse than no page at all. The blog is planned next; scope is those two for now, not a general move of the site into a CMS. So this PR is the pattern as much as the page. lib/notion.ts reads it over plain fetch with ISR at a minute; content/roadmap/*.md is the fallback when no workspace token is present, so a clone still builds. Every record carries an owner, a target and a checkable link, and anything missing one fails the build rather than rendering a card that claims less than it should.

Cleanup

globals.css 1209 → 585 lines. Removed the second --color-* token layer, the Holographik grid, hero classes, .blog-prose, 19 keyframes and 37 custom properties. Chart/sidebar/radius tokens are kept — unused today, but they're the registry's theme contract.

Deleted ~73 files: components/home/*, components/legacy/*, components/ecosystem/* (superseded by components/livepeer-ui/*), the PascalCase components/ui/* visuals, lib/constants.ts, and the five app/use-cases/* routes — redirects in next.config.ts already served those URLs, so the pages were unreachable.

Share images

Rebuilt on the registry's own og item. / renders the brand card verbatim — the lockup centred on #000000. Every other page renders the same canvas with a page title, from one shared lib/og.tsx. Two bugs fixed along the way:

  • Only the root had a twitter-image, and metadata files cascade — so /foundation and /blog served their own og:image but the root's Twitter card. Every segment now has a re-export beside its opengraph-image.
  • Ecosystem project pages had no share image at all: their generateMetadata declares an openGraph object without images, which drops the inherited card. All 12 projects now get their own titled card.

Incidental fixes

  • app/not-found.tsx styled its link text-green — green as an affordance colour, which the design system explicitly rules out. Rebuilt on the registry type scale.
  • sitemap.ts advertised the five dead /use-cases URLs and never listed /agent or /compute. Rewritten, with ecosystem projects added.
  • Instrument Serif was downloaded on every page load with zero consumers. Removed.
  • package-lock.json deleted. Six deps had been added via npm in a pnpm-pinned repo, leaving pnpm-lock.yaml stale — pnpm install --frozen-lockfile was failing, which would have broken the Vercel build. Lockfile regenerated and verified.

Verification

pnpm typecheck, pnpm lint (0 warnings) and pnpm build (130 static pages) all clean, against both the Notion register and the markdown fallback. Pages verified in light and dark at 390px, sm, md and wide desktop.

Before this can ship

  • agentAppOrigin is the console's Vercel preview (lib/site.ts) — livepeer-console.vercel.app, not its final address. It feeds the most prominent CTA on every page, so it still needs one edit before launch. The Agent playbooks link is the one product link left on livepeer.peaceno.de: the console has no playbooks page, and a mockup beats a 404.
  • Blog art hotlinks Peace Node's Sanity CDN — confirm permanence or vendor the assets.
  • Placeholder people in the register. Names, portraits and rosters are stand-ins except Doug Petkanics. Replacing them is a Notion edit, not a deploy.
  • Commitment links mostly cite venue roots — 11 of 19 point at forum.livepeer.org/ or similar rather than a permalink.
  • The Notion webhook is not subscribed yet — needs an integration admin and the production domain. Until then the one-minute window is what carries edits to the site, which is sufficient but serves one stale reload.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
website Ready Ready Preview Sep 10, 2026 2:21pm UTC

Request Review

@adamsoffer adamsoffer changed the title WIP: Redesign livepeer.org on the Livepeer UI design system WIP: Redesign livepeer.org Aug 8, 2026
In-progress rows now carry the day the update was posted, as shipped
rows carry theirs. Owner and date are set in the foreground and the
update in the muted voice, so the break in colour is the boundary
between the record and the words.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The change set is very large and includes new routes/security-sensitive behaviors; it needs final human review even though only a few specific issues were identified here.

Review details

Suppressed comments (2)

app/changelog/roundup.json/route.ts:54

  • roundup.json defaults to the current (in-progress) month, but /changelog/<month> intentionally 404s for the current month. As written, the url field will therefore point consumers at a 404 for the default case; consider pointing to the index when r.current is true.
    app/api/revalidate/route.ts:44
  • This endpoint compares the bearer token with a normal string equality check. Using a timing-safe comparison avoids leaking information via response timing and is a common hardening for shared-secret auth.
  • Files reviewed: 127/338 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Owner and date keep theirs; the words follow after a wider gap in the
muted voice. A third middot gave them the weight of a third field.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The ecosystem project OG image route currently renders the same non-titled card for every project (contradicting the stated behavior) and the revalidation endpoint should use constant-time token comparison for a safer auth gate.

Review details

Suppressed comments (2)

app/ecosystem/[slug]/opengraph-image.tsx:16

  • This dynamic OG image is identical for every ecosystem project (it ignores params.slug and renders renderArtCard(ogArt.ecosystem)), which contradicts the PR description that project pages get their own titled card and makes all shares from /ecosystem/ indistinguishable.
    app/api/revalidate/route.ts:46
  • Bearer token validation uses a direct string comparison (offered !== secret). For an authentication gate, prefer a constant-time comparison to reduce exposure to timing attacks (even if low-risk over the network).
  • Files reviewed: 127/338 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Several new UI primitive modules are missing an explicit "use client" directive despite being imported by client components and/or using hooks, which can break Next.js App Router client/server boundary rules.

Review details
  • Files reviewed: 127/338 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

adamsoffer and others added 2 commits September 10, 2026 08:19
A month's entry is a record and does not change, but a reader who saw
"At risk" in August and opened a record that said On track felt the
site contradict itself. A row now carries the story since the month
closed, after its own word and only where it differs — "now on track",
"now shipped", "now no update" — so the record stays what it was and
the click through is not a surprise.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The updated GitHub Actions workflow references non-existent action majors (actions/checkout@v7 and actions/setup-node@v7), which will break CI execution.

Review details
  • Files reviewed: 127/338 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The PR is a large, cross-cutting redesign with new ISR/revalidation and content pipeline behavior, and it includes at least two concrete correctness issues to address before merge.

Review details

Suppressed comments (2)

app/api/revalidate/route.ts:50

  • revalidatePath(PATH) only invalidates the exact /roadmap route; it won’t reliably refresh nested pages like /roadmap/[slug] that also depend on the Notion register. Use the "layout" scope so an agent-triggered revalidation actually updates the whole roadmap segment.
    app/changelog/roundup.json/route.ts:54
  • This endpoint defaults to returning the month currently under way, but /changelog/<current-month> is intentionally not published (it 404s until the month ends). Returning a URL that is expected to 404 makes the JSON harder to consume; consider pointing url at /changelog when current is true.
  • Files reviewed: 127/338 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

adamsoffer and others added 2 commits September 10, 2026 09:22
The register cut by the body answerable for each commitment: every
owner as a heading linking to its page, its commitments beneath with
what needs attention first — off track, at risk, silent, on track, then
committed work with no health yet by target — and the bodies ordered by
the worst thing under them, so the page opens on whoever has something
to answer for. In the URL as ?group=owner, so it is a link you can send.
Roadmap only; Shipped keeps its months.

The control sits at the far end of the view tabs from lg up and inside
the Filters panel below that, where a second line in the tab row would
have slid the sticky bands under it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Shipped by owner is a track record per body, most recent first. The
"Nothing is committed past …" line answers when, so it shows under the
quarter cut and not the owner cut, which is answering who.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It’s a large, cross-cutting redesign (routing, metadata/sharing, content sources, and new endpoints), so it needs careful human validation beyond the specific issues flagged.

Review details

Suppressed comments (2)

app/ecosystem/submit/page.tsx:51

  • fs.readFileSync runs during render, so this page will re-read content/ecosystem-template.md every time it’s requested (or every time the server component is evaluated). Since the template is static, cache the computed GitHub “new file” URL at module scope (or behind a simple in-module memo) to avoid repeated synchronous I/O.
    app/people/[slug]/opengraph-image.tsx:22
  • This people share-card is rendered with ogArt.organizations, which means people pages will share the Organizations background art (and any future changes intended for org pages will also affect people). If this is accidental (copy/paste from the org route), consider adding a dedicated ogArt.people entry in lib/og.tsx (or selecting an existing non-org art constant) and using it here.
  • Files reviewed: 127/338 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The change set is a full-site redesign with many new routes/components and content model changes, so it warrants final human validation despite only a couple of concrete issues found in the reviewed hunks.

Review details

Suppressed comments (1)

app/people/[slug]/opengraph-image.tsx:22

  • This person card uses ogArt.organizations, which will make every /people/ share image look like an organization page. There isn’t a dedicated people art token in lib/og.tsx; using the roadmap art is a closer match for people being a roadmap-adjacent surface.
  • Files reviewed: 127/338 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

The four words of the scale with their counts, always all four — Off
track 0 is news — read as a filter the way Linear filters projects by
health. It doubles as the tally the accountability board kept in its
footer, and puts the silent ones one click away. Roadmap only, in the
URL as ?health=, dropped on the way to Shipped like the state flag.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The change set is a broad redesign touching routing, UI primitives, and dynamic data/metadata surfaces, and it includes at least one correctness issue that should be fixed and then re-verified end-to-end.

Review details

Suppressed comments (1)

app/ecosystem/[slug]/opengraph-image.tsx:17

  • This OG image implementation renders the same generic renderArtCard(ogArt.ecosystem) for every project. That contradicts the PR description (“All 12 projects now get their own titled card”) and makes different ecosystem project links indistinguishable in timelines.

Use renderTitledCard(...) and the project’s name (from the slug) so each project gets a unique share image.

  • Files reviewed: 127/338 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

adamsoffer and others added 2 commits September 10, 2026 09:49
A route and a tick for the two views, a calendar and a building for
the two cuts, the way Linear marks its filters.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The change set is a broad site redesign spanning routing, content sourcing, build/runtime behavior, and security-sensitive endpoints, which warrants focused human validation beyond automated review.

Review details

Suppressed comments (2)

app/api/revalidate/route.ts:2

  • The token check should use a constant-time comparison; timingSafeEqual (node:crypto) is a straightforward way to do that, but it needs to be imported.
    app/api/revalidate/route.ts:47
  • Bearer token validation uses a plain string comparison (offered !== secret), which can leak information via timing differences. Compare in constant time (and check equal length) before allowing revalidation.
  • Files reviewed: 127/338 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment on lines +138 to +145
<a
key={item.label}
href={item.href}
target="_blank"
rel="noreferrer"
onClick={close}
className={className}
>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are user-visible regressions/discrepancies in the ecosystem surface (share cards not titled per project and loss of URL-deep-linking for filters/search) that should be resolved before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

app/ecosystem/[slug]/opengraph-image.tsx:17

  • This OpenGraph image generator returns renderArtCard(ogArt.ecosystem), so every ecosystem project page gets the same lockup-only card with no project title. The PR description states each project should get its own titled card; as written, shared links won’t be distinguishable in a timeline.
  • Files reviewed: 127/338 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread app/ecosystem/page.tsx
Comment on lines +41 to 62
export default function EcosystemPage() {
const apps: EcosystemListingApp[] = getAllApps().map((app) => ({
slug: app.slug,
name: app.name,
url: app.url,
hostname: app.hostname,
displayUrl: app.displayUrl,
description: app.description,
categories: app.categories,
logo: app.logo,
logoBg: app.logoBg,
logoMonochrome: app.logoMonochrome,
}));
const categories = getEcosystemCategories();

return (
<EcosystemListingClient
<EcosystemListing
apps={apps}
categories={categories}
initialCategories={
catsParam ? catsParam.split(",").map(decodeURIComponent) : []
}
initialSearch={q ?? ""}
categories={getEcosystemCategories()}
heading={ecosystem.heading}
searchPlaceholder={ecosystem.searchPlaceholder}
emptyMessage={ecosystem.emptyMessage}
submitLabel={ecosystem.submitLabel}
submitHref={ecosystem.submitHref}
/>
adamsoffer and others added 2 commits September 10, 2026 10:02
A post on a commitment now has a kind: the monthly update while the
work is under way, or the one retrospective once it has shipped. Marked
in Notion with a Kind select rather than inferred from its date, because
a retro is often written the day something ships and an "it's out"
update lands after; a retrospective carries no health, since "on track"
means nothing about something finished.

- Shipped cards read "Retro done" or "No retro" after the state.
- A shipped record leads with its retrospective, or with the fact that
  none has been written, and the activity log runs in date order so the
  retro sits where it happened rather than under a pinned "shipped it".
- The changelog's shipped rows carry the retro's line where one existed
  by the month's end, and roundup.json lists the month's shipped work
  without a retro as noRetro beside the silent.
- Both readers accept the kind; the fallback gains a seed retro.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The tick disc and "Retrospective" where one exists, a hollow ring and
"No retrospective" in the foreground where not. Not a checkbox, which
on a card looks clickable; this is a fact.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The PR is a large WIP site redesign touching many routes, content sources, and metadata/share-image behaviors, so it needs targeted manual validation of key user flows and deploy/runtime behavior beyond automated review.

Review details

Suppressed comments (3)

app/ecosystem/[slug]/opengraph-image.tsx:17

  • This project share-image route renders an art-only card (renderArtCard), but the PR description says ecosystem project pages now get a titled card. As written, the OG image will not include the project name, so shared links are harder to distinguish in a feed.
    app/api/revalidate/route.ts:46
  • The bearer token check uses a direct string comparison (offered !== secret). For secret validation endpoints, a constant-time compare is safer to avoid leaking information via timing differences.
    app/changelog/roundup.json/route.ts:54
  • The JSON payload always advertises url: https://livepeer.org/changelog/<month>, but roundup.json defaults to the current month (r.current=true) and the changelog month pages intentionally do not publish the current month. For the default case, this URL will point at a 404.
  • Files reviewed: 127/339 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

adamsoffer and others added 3 commits September 10, 2026 10:11
In medium weight above the muted write-up, in the log and on the card,
so it reads as the lead rather than a paragraph that forgot its colour.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The row's header has already said who, what and when, and a second
title fought the write-up's bold lead-ins. The card keeps the title
treatment, having no header row to lean on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Weight alone left it level with the write-up's bold lead-ins; at the
body's size it was a paragraph in a different colour. One step up, in
the log and on the card.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Several routes hard-disable dynamic params for Notion-backed records (risking permanent 404s for newly added rows) and there is at least one inconsistent shipped date that can misgroup changelog output.

Review details

Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

app/organizations/[slug]/page.tsx:25

  • dynamicParams = false prevents organization pages for new org rows added in Notion after the last build, even if the roadmap starts crediting/owning work under that org. Leaving dynamic params enabled keeps unknown slugs 404ing via notFound() while allowing new orgs to be served on first request.
    app/people/[slug]/page.tsx:19
  • With dynamicParams = false, any new person added in Notion after the last build will 404 permanently (until a rebuild), even if commitments start linking to them. Consider leaving dynamic params enabled and relying on notFound() for unknown slugs so the People table can grow without a deploy.
    app/roadmap/[slug]/page.tsx:32
  • dynamicParams = false means any new commitment added in Notion after the last build can appear on /roadmap but its detail page will still 404 because it wasn’t in generateStaticParams() at build time. Leaving dynamic params enabled allows new slugs to be served on first request while still 404ing unknown slugs via notFound().
  • Files reviewed: 127/339 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

adamsoffer and others added 2 commits September 10, 2026 10:18
The expanded body started on the header's line and the title's leading
was tight. More above the title, a looser line, a beat more below.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

There’s at least one confirmed functional issue (checkbox ::after never renders without content) plus a verified mismatch between the PR description and the ecosystem project OG card behavior (art-only vs titled card).

Review details

Suppressed comments (1)

app/ecosystem/[slug]/opengraph-image.tsx:17

  • The PR description says ecosystem project pages now get “their own titled card”, but this opengraph image currently renders the generic art-only card (no project title). Either update the description or render a titled card using the project’s name (similar to blog post cards).
  • Files reviewed: 127/339 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

This is a wide-ranging site redesign touching many routes/content systems, and there are unresolved review findings (security + UI class issue) that should be addressed alongside final human verification.

Review details

Suppressed comments (1)

app/api/revalidate/route.ts:46

  • The bearer token check uses a direct string comparison (offered !== secret), which is vulnerable to timing attacks. For a shared-secret auth check, use a constant-time comparison to avoid leaking information about the secret via response timing.
  • Files reviewed: 127/339 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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.

2 participants