Skip to content

Redesign the site around the thread animation - #18

Merged
LucaDeLeo merged 34 commits into
mainfrom
lucadeleo/threads-layout-prototype
Oct 9, 2026
Merged

LucaDeLeo merged 34 commits into
mainfrom
lucadeleo/threads-layout-prototype

Conversation

@LucaDeLeo

Copy link
Copy Markdown
Contributor

Why

A from-scratch redesign that keeps the background thread animation and makes it drive the layout. Each section has its own set of threads that frames the copy, and the threads form a different shape per section. The hero keeps the original meaning of the animation: most threads fall, a few rise.

What changes

New pages. Home, About, Programs, Research, Resources and Contact are rebuilt in app/[locale]/lab/**. On this branch, beforeFiles rewrites in next.config.ts serve them at the main routes (/, /about, /activities, /research, /resources, /contact). They are also reachable under /lab, which robots.ts disallows. The flag is SERVE_LAB_AT_MAIN_ROUTES. The original pages are still in the code and come back if the flag is set to false.

Thread animation.

  • Per-section canvases (ThreadSet), each with a scene: free, scatter, braid, rope, strands, fan, horizon or knot. Threads avoid the copy and are tinted per stage.
  • A pinned "what we do" section steps through four scenes as you scroll. It supports keyboard navigation and has a step rail.
  • Hovering links draws a pulse along a thread. Hovering calls to action turns a falling thread upward.
  • Reduced motion shows still frames.
  • WebGPU and WebGL output match.
  • Fixes an existing bug in the pointer mapping.

Copy and content.

  • Copy edits in both languages for flow and consistency. These are shared dictionary keys, so some also change the original pages.
  • The Spanish home headline is now "De la curiosidad a la contribución".
  • The contact form comes first. Calls are offered with Eitan only, and Luca's booking link is removed everywhere.
  • The meaning changes flagged in a full-diff review are fixed: "Fellowships joined", "newcomers", "typically 50–80", retreat eligibility, and the Spanish risk wording.
  • The #book-a-call and #press anchors still work.

SEO. Each redesigned page reuses the original page's metadata (title, description, canonical URL, hreflang links, social cards) and JSON-LD, via labPageMetadata.

Other.

  • skipjack/ (a separate worktree) is excluded from tsc and ESLint.
  • allowedDevOrigins is set for Orca worktree hosts.

Testing

  • bunx tsc --noEmit, bun run lint and bun run build pass. bun test app passes 12 of 12 tests.
  • Lighthouse (mobile): the redesign scores 75–80, against 77–80 for the current site. LCP is similar; the redesign runs more JavaScript on the main thread.
  • Reduced motion gives identical frames across ticks. Keyboard navigation of the pinned steps and the focus trap in the bio dialog were checked.
  • Metadata, canonical URLs and JSON-LD were checked on all six routes in both languages.
  • Checked in Chromium and WebKit. Headless Firefox sometimes showed smeared blur stripes that could not be reproduced reliably, so real Firefox still needs a check.

Deployment

⚠️ With SERVE_LAB_AT_MAIN_ROUTES = true, merging replaces the six main pages in production with the redesign. To merge the code without switching the live site, set the flag to false first.

🤖 Generated with Claude Code

LucaDeLeo and others added 20 commits September 25, 2026 17:33
Next 16 blocks /_next dev resources for hosts other than localhost, so pages
opened at <worktree>.orca.localhost rendered without any JavaScript.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"De Curioso a Investigador" was masculine and only about research, which
leaves out governance people and anyone contributing outside research.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pages can now give each section its own set of threads (ThreadSet), drawn
in a canvas that scrolls with the section. A set draws one of several
shapes (scatter, braid, rope, strands, fan, horizon, knot, or the original
free animation) inside a box marked in the layout, and a pinned section can
scrub through several shapes as it scrolls. Stages of the path tint the
threads towards their own hue, and hovering marked elements sends pulses
along a few threads.

Pages without sets are unchanged: the site-wide background keeps its free
animation and parallax.

Also fixes two existing bugs:
- Mouse interaction mapped the pointer into the square viewbox without the
  per-axis stretch both renderers apply, so threads bowed away from a point
  above or below the cursor on non-square screens.
- The WebGPU renderer only re-uploaded a thread's metadata when its colour
  stops changed, so opacity changes never reached the GPU.

The overlay wash opacity is now a per-frame value, so section canvases can
draw without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prototype pages at /[locale]/lab, /lab/about and /lab/contact, marked
noindex and left out of the sitemap. The live pages are unchanged.

- Home: hero with an entry point per kind of visitor, why-we-exist rows,
  a pinned Learn/Belong/Research/Launch section that morphs the threads,
  a programs table with the decision facts (free, in person, English,
  hours, prerequisites), AISAR and a book-a-call row, stories, and a join
  section ordered from least to most commitment.
- About: track record, team grid with bio dialogs, focus areas, funders.
- Contact: a table matching each reason to get in touch with its channel,
  the form, and the FAQ.
- Shared: title band for inner pages, announcement bar driven by course
  status, and a fuller footer.

Copy lives under `lab` in both dictionaries and reuses existing site copy
wherever it exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Reduced motion: the worker draws still frames only when something
  changes (no drift, flips or pulses, scene weights snap), the page stops
  sending per-frame ticks, and stepped sections switch shapes at step
  boundaries instead of morphing. This also applies to the site-wide
  background.
- Hover pulses: pulses a page asks for now deepen the thread and make it
  opaque. Brightening, which direction flips still use, made pink threads
  paler on the light page. Pulses are only wired to elements with a set in
  view (visitor links, stories, the join list); programs and contact rows had
  no threads nearby.
- Performance: sets start within half a screen instead of a full one,
  divider sets (horizon, rope) draw about half the threads, and the hidden
  site-wide background no longer starts on pages that draw their own sets.
- Bio dialogs are named after the person for screen readers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Research: BAISH Labs with its agenda and team grid, research directions
  with the threads splitting into one strand per area, the research
  journey, publications grouped by year with BAISH authors highlighted,
  and a closing section for collaborators.
- Programs: the courses decision table, what's coming next, community
  items over a braided band, a scrollable strip of event photos, past
  programs, and sister projects.
- Resources: the METR chart and evidence, every concrete risk visible as a
  numbered row (they were behind tabs), the upside with the threads
  fanning out, self-study, and a closing list of next steps.

Links between redesigned pages now stay inside /lab (labHref); drop the
mapping when the lab pages replace the live ones. The team grid card is
shared between About and Research. Scatter/fan ropes that enter from the
left of their box run below it, clear of copy beside the box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rope strip under each inner-page title packed 40 threads into about
140px, which read as one noisy stripe. Title bands now use the home hero's
layout: copy on the left and the signature free animation in the right
column, with the threads taking a band below the text on phones.

The rope scene (still used for the Programs community band) now fills its
band: threads enter spread over the full height, twist into a thick rope and
fan out in a different order. Divider bands are taller, and the horizon
scene spreads its threads further.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Path steps get their own descriptions without numbers, since the stats
  beside them already show them, and the metaphor lines read as one
  sentence about the threads.
- "Why we exist" ends with who runs BAISH instead of repeating the path
  section below it.
- The programs intro covers the fellowship as well as the courses; stories
  are titled "Where our members are now".
- About's track record intro no longer repeats the numbers shown below it,
  and "What we focus on" keeps only the focus areas.
- Research's closing section is framed for people who want to get involved
  in research, which is who its two rows address.
- Resources' self-study becomes "Go deeper", without the year-old date or
  the off-topic coding workshop link.
- The announcement bar only shows while applications are open; before that
  the programs table already says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These keys also feed the live pages, so they change there too.

- One name per thing: the Technical AI Safety Project (not "Projects
  Sprint"), monthly socials, directors (not co-founders), fellowship
  acceptances (not placements), and the same three research areas on About
  and Research.
- Sentence case for headings and buttons; section titles say what the
  section holds instead of "Our …".
- Two FAQ answers now match the course criteria: courses ask for good
  English (not programming), and course materials are in English while
  events are mostly in Spanish.
- Contact form: plain labels, "Write to us", "Send message".
- Spanish: anglicisms replaced (placements, roles full-time, part-time,
  staff pago, networking, compute, accountability, background, rapid and
  career transition grants), masculine or research-only phrasing made
  neutral, and title case removed.
- Ranges use an en dash (50–80).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A separate git worktree is checked out at ./skipjack. The "**/*.ts" include
pulled its files into this project's type-check, where its older
dictionary types failed the production build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each link sat on a tinted box, with the first cell unpadded so it lined up
with the heading, so the boxes looked uneven and the first one's hover fill
ran right up to its text. The cells are now transparent with the same
spacing, and hovering one turns its stretch of the top rule accent, like
the rail in the pinned section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Stories: the fan's box now runs behind the list, so the threads keep
  flowing behind the stories, which sit on frosted cards. "See all stories"
  moves up under the section intro.
- Tables (programs, contact routing, funders, sister projects): rows get
  a side inset, so text no longer runs to the edges and the hover fill has
  room around it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three CSS layers behind the thread sets, so they cost nothing per frame:
soft lavender, blue and pink washes fixed to the screen, faint grain, and a
fine dot grid that scrolls with the content and fades toward the sides.
The veils behind copy are tinted to match, so they no longer show as pale
patches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While SERVE_LAB_AT_MAIN_ROUTES is on (next.config.ts), /, /about,
/activities, /research, /resources and /contact serve the pages in
app/[locale]/lab, so the prototype can be explored through the normal
header and URLs. The original pages stay in the code; turning the flag off
brings them back. Sub-pages such as /activities/reading and the privacy
policy are unchanged, and /lab keeps working.

Links inside the lab pages now point at the main routes, so the /lab path
mapping in SmartLink is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Contact: the form now opens the page; the purpose table follows as
  "Other ways to reach us", and career advice points to the form first
  with a call with Eitan as the secondary option.
- About: the booking box under the directors becomes "Want to talk to
  us?", pointing to the form, with a small "Or book a call with Eitan".
- Home programs table, Research closing section and the Programs page's
  career support item send people to the form rather than to a call.
- Luca's booking link is removed everywhere, including the original About
  and Research pages; the test that required it now asserts it is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copy (both languages unless noted):
- The 28 is now "Fellowships joined" (EN), matching the data (programs
  members entered) and the Spanish "ingresos"; "acceptances" said less.
- Monthly socials: "newcomers" (not "new to AI safety") and "typically"
  50–80 people, as impact.ts defines it.
- AISAR chips pair each stipend with its hours.
- Retreat is again for the organizing team and members joining it (EN had
  widened it).
- "Why it matters" follows the source again: some respected researchers
  aren't convinced there's a serious risk at all (EN had softened it to
  "disagree about the risk").

Routing and SEO:
- Lab pages use the original pages' metadata (title, description,
  canonical, hreflang, social cards) and structured data, and are no longer
  noindex, so serving them at the main routes changes nothing for search
  engines. The /lab copies point their canonical at the main route and
  robots.txt disallows them.
- #book-a-call (About) and #press (Contact) resolve again.

Bugs:
- Worker: turning on reduced motion after the animation had been running
  stepped time backwards, which drove the pointer easing to NaN/Infinity
  and could break pointer interaction for good. The time step is clamped
  and the clock and pointer state reset when entering still mode.
- Lab pages have a <main> landmark again.
- Table headers stay available to screen readers on phones, and the
  "Not sure which one fits?" row sits after the programs table instead of
  inside it with the wrong column count.
- Jumping between pinned steps scrolls instantly under reduced motion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Placing the original animation in a box had squashed it: the rising threads
climbed past the top of the section and faded out, and every thread shared
one colour, so the hopeful line and the dying ones looked the same.

- The free scene now maps its whole vertical range into the box: threads
  cross ("today") low in the box, rise into the space above it, and settle
  on its floor.
- It keeps the original colouring: falling threads fade to dark at the
  floor, rising ones stay bright, and rising threads are drawn thicker and
  fully opaque, easing in as they turn.
- Labels on the hero ("Today", "Futures that go well", "Futures that
  don't") and a caption under the calls to action say what the lines are.
- Hovering or focusing a call to action (hero buttons, the visitor links,
  the join steps) turns one falling thread into a rising one. Not under
  reduced motion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Too literal; the rising and falling threads carry the idea on their own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Section sets use 75% of the background's stroke width, and rising threads
in the hero get a 1.5x boost instead of 2.2x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
nextbaish Ready Ready Preview Oct 2, 2026 11:28am UTC

Request Review

- METR chart: phones get a narrower viewBox, so axis and point labels
  render at about 10px instead of 6px and no longer collide
- Home hero: the phone thread band sits under the copy, above the fold,
  instead of after the visitor links
- Team link icons: 28px tap targets (were 20px) without moving the icon
- Bio dialog: the page behind no longer scrolls while it is open
- 320px phones: smaller display headings so long Spanish words don't
  leave a single word on its own line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The menu becomes a full-screen sheet in the redesign's style: serif page
names in numbered rows, the thread motif with one rising thread, a mono
EN/ES toggle and the dark pill call to action. It keeps the focus trap,
Escape to close and scroll lock, and now focuses the close button on the
first open too (the effect ran before the portal mounted). The loading
fallback is a plain sheet instead of an English-only spinner.

The header, menu and footer "Join Us" buttons scroll to #get-involved,
which the redesigned home page didn't have; the join section now carries
that id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Focus areas move into the title band as chips; the separate section,
  and its now unused heading key, are gone
- On phones, the success stories become a swipe row, the 18-person team
  group becomes one row per person with a small round photo, and advisors
  sit in two columns
- Desktop keeps the photo grid and the story cards

On an iPhone 13 the page goes from about 13,200px to 9,800px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The language links used view-transition links. Switching locale remounts
the [locale] layout, including the ViewTransitions provider, so the
transition never finished: browsers with view transitions showed the old
page frozen until Chrome's 4s timeout ("Transition was aborted because of
timeout in DOM update"). They are plain links now; the new language
renders in about 70ms from the prefetched page.

Thread canvases also restart faster after any client navigation:
- generated thread data is reused instead of regenerated per mount
- the wait for the browser to go idle only applies to the first load
- once a canvas falls back to WebGL, later canvases skip the WebGPU
  attempt, which takes about a second on browsers that expose WebGPU
  without a usable adapter (many Android phones, headless Chrome)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Headline: "Work on AI safety from Argentina" / "Trabajá en AI safety
  desde Argentina", replacing "From curious to contributing"
- Drop the thread-metaphor lines from the "What we do" steps and the
  metaphor eyebrows ("Where the threads lead", "Your thread", "Start
  where you are"); "Nobody has a reliable map" becomes "Nobody knows how
  it will go"
- "Why Buenos Aires" becomes "Why Argentina"
- Success stories become testimonials: a card leads with the person's
  own quote when there is one, then who they are and where they are now
  (team roster role and photo when they are on it), with their path as a
  footnote. Most senior first: MIRI, Equistamp, BAISH Labs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Ink text, a dark pill "Join Us →" and a mono EN/ES toggle, matching
  the redesign and the new mobile menu; the name still collapses to
  BAISH on scroll
- A soft highlight slides between nav links on hover and focus; the
  current page gets a short accent thread under its label
- Floating, the bar is frosted glass with a reading-progress thread
  along its bottom edge
- The header's paint containment clipped the floating shadow; it now
  contains layout and style only

Fixes the current page and the language links on rewritten routes:
usePathname() reports the lab path (/es/lab/programs), so no link was
marked current and the language links pointed at /lab URLs. The route
list moves to app/lab-routes.ts, shared by next.config.ts and the
header, with publicPathname() mapping lab paths back to the main routes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The hero no longer fills the viewport, which left a large gap above
  the visitor links on tall screens
- On wide layouts the free animation (hero and title bands) spans most
  of its section's height instead of only the square beside the copy,
  with 40% more threads at 90% of the background's stroke width, closer
  to the old site-wide background
- The visitor links sit on a frosted strip so threads can pass behind
  them without hurting legibility

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first column sat flush left to line up with the heading; with the
frosted strip behind it the text touched the edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Tu carrera puede ayudar a que la IA avanzada sea segura" in Spanish.
The team wanted a line that isn't tied to staying in Argentina, speaks to
people changing careers, and reads well to a policymaker. The display
size drops to fit a full sentence in three to four lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pinned frame was a full viewport tall with its content centred, so
the way in showed about half a screen of empty space. On wide layouts it
is now only as tall as its content and sticks centred in the viewport
(sticky top), so it looks the same once pinned. The step maths reads the
frame's top and height from [data-step-pin] instead of assuming a full
viewport at the top; phones keep the full-height frame.

The "Why we exist" section also drops most of its bottom padding, since
its thread band already separates it from the next section. Together the
gap goes from about 790px to 400px on a 1180px-tall window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two unused home dictionary strings hardcoded "350" instead of using the
{communityMembers} placeholder; they use it now too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Team reports: the nav bar felt sluggish scrolling up and down on
Resources, and the site was laggy on an Android phone.

Measured with a scripted wheel scroll (real GPU, desktop, and a phone
viewport at 4x CPU throttling):
- The header's in-flow height changed during its collapse transition
  (75px -> 74px through in-between sizes), so every frame re-laid out the
  whole page. It now has a fixed 78px height with size containment.
- Switching its backdrop blur on as it floats cost a ~150ms frame. The
  floating bar is now opaque, faintly lavender white, with no blur.
Desktop Resources went from 6 frames over 50ms (1.1s in total, worst
317ms) to none; the phone run from 5 (560ms) to none.

For phone GPUs, which the test machine can't reproduce: the router strip
and story cards drop their backdrop blur below 820px or on touch
screens (they sit on live thread canvases, so the blur was redone every
frame), and the hero and title bands only draw the extra 40% threads on
wide screens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Team feedback in the copy doc (Tomás): "9.4/10 de probabilidad de
recomendar" sounded odd, a literal translation of the survey question.
It becomes "nota promedio de recomendación" / "average recommendation
score", and Spanish now writes the score with a decimal comma (9,4/10):
impactValue() and fillImpact() take the locale.

Guido's quote gets "transicionar a la investigación", as Tomás edited it
in the doc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A custom events section replaces the "Upcoming events are on Luma" line:
upcoming public events hung on a single thread, with a date knot per
event, time and place, a Register button and the cover image; a strip of
recent events below; and the Google Calendar subscription and Luma
links from the old embed. With nothing scheduled it says so and offers
the subscription.

Events come from app/data/luma.ts, server-side and cached for 10
minutes. With LUMA_API_KEY set it uses the official Luma API (Luma
Plus); without it, the public endpoint behind Luma's own calendar
embed. Failures return no events rather than breaking the page or the
build. Dates are shown in the event's timezone and the page's language.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@LucaDeLeo
LucaDeLeo merged commit bdd2347 into main Oct 9, 2026
3 checks passed
@LucaDeLeo
LucaDeLeo deleted the lucadeleo/threads-layout-prototype branch October 9, 2026 09:32

This branch was successfully deployed

1 active deployment
Preview — a81ca284 Deployed Oct 2, 2026 by vercel[bot]
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