From 4b207c00c79020f42c3506c749398949d3a007d1 Mon Sep 17 00:00:00 2001 From: Nicholas Kissel Date: Thu, 27 Aug 2026 18:12:43 -0700 Subject: [PATCH 1/2] feat(site): careers page, brand kit, and SEO/OG polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Careers: classical-painting hero gallery, a global dot-map of team locations, expanded content, careers.ts helpers, and structured data (CollectionPage + BreadcrumbList) with a 1200x630 OG image + alt. Brand: new /brand brand-kit page — Rivet logos, downloadable accent-colored product marks, the agentOS script wordmark, the color palette, and type specimens — plus a self-hosted rivet-brand-kit.zip, a footer "Brand" link, and the logo context menu wired to the new kit. Product marks: masked accent-tile treatment refined across the header, docs landing, product bar, and homepage stack. SEO/infra: OG alt text + dimensions in BaseLayout/MarketingLayout, redirects, llms.txt, and removal of the oss-friends page. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 13 +- public/images/agent-os/agentos-wordmark.svg | 73 ++++ ...vascript-executor-readiness-state-dark.svg | 146 +++++++ ...vascript-executor-wakeup-sequence-dark.svg | 103 +++++ public/images/brand/actors-mark.svg | 21 + public/images/brand/agentos-mark.svg | 13 + public/images/brand/cloud-mark.svg | 6 + public/images/brand/dynamic-apps-mark.svg | 9 + public/images/brand/workflows-mark.svg | 9 + public/images/world-map.svg | 2 + public/rivet-brand-kit.zip | Bin 0 -> 11690 bytes redirects.mjs | 3 + src/components/Footer.jsx | 3 +- src/components/ProductBar.tsx | 53 ++- src/components/docs/DocsLanding.tsx | 16 +- src/components/marketing/BrandKit.tsx | 313 ++++++++++++++ .../marketing/CareerHeroGallery.astro | 247 +++++++++++ src/components/marketing/CareerMap.tsx | 386 ++++++++++++++++++ src/components/marketing/ProductLockup.tsx | 4 +- .../marketing/agentos/AgentOSPage.tsx | 4 +- .../diagrams/ConsolidatedStackDiagram.tsx | 4 +- .../marketing/sections/StackSection.tsx | 6 +- .../TalkToAnEngineerPageClient.tsx | 2 +- src/components/v2/Header.tsx | 22 +- src/components/v2/LogoContextMenu.tsx | 2 +- src/data/career-locations.ts | 77 ++++ src/layouts/BaseLayout.astro | 11 +- src/layouts/MarketingLayout.astro | 34 +- src/lib/careers.ts | 143 +++++++ src/pages/actors.astro | 2 +- src/pages/brand.astro | 259 ++++++++++++ src/pages/careers.astro | 312 ++++++++++++-- src/pages/dynamic-apps.astro | 2 +- src/pages/llms.txt.ts | 1 - src/pages/oss-friends.astro | 60 --- src/pages/workflows.astro | 2 +- src/sitemap/products.ts | 7 +- 37 files changed, 2217 insertions(+), 153 deletions(-) create mode 100644 public/images/agent-os/agentos-wordmark.svg create mode 100644 public/images/architecture/javascript-executor-readiness-state-dark.svg create mode 100644 public/images/architecture/javascript-executor-wakeup-sequence-dark.svg create mode 100644 public/images/brand/actors-mark.svg create mode 100644 public/images/brand/agentos-mark.svg create mode 100644 public/images/brand/cloud-mark.svg create mode 100644 public/images/brand/dynamic-apps-mark.svg create mode 100644 public/images/brand/workflows-mark.svg create mode 100644 public/images/world-map.svg create mode 100644 public/rivet-brand-kit.zip create mode 100644 src/components/marketing/BrandKit.tsx create mode 100644 src/components/marketing/CareerHeroGallery.astro create mode 100644 src/components/marketing/CareerMap.tsx create mode 100644 src/data/career-locations.ts create mode 100644 src/pages/brand.astro delete mode 100644 src/pages/oss-friends.astro diff --git a/CLAUDE.md b/CLAUDE.md index 2ec4045a..2b373e0a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,6 +35,17 @@ Applies to all user-facing writing on the website (docs, marketing, blog). Inter To add or update icons, see `frontend/packages/icons/CLAUDE.md`. +## Product Marks + +The product wordmarks in `src/images/products/*-logo.svg` are white-on-transparent: the alpha channel is the mark, so the file carries no color of its own. They are always painted as a masked element via `wordmarkMaskStyle` (`src/lib/product-accent.ts`), never as an ``. + +- **Never render a naked mark.** A wordmark always rides inside its tile: `rounded-[34.375%]` at the SVG's inset-ring geometry, filled ink or the product accent. A bare mark dropped on a light surface — an `` with `brightness-0`, an invert filter, or a raw mask on `paper` — is the failure mode this rule exists to prevent. It reads as a black outline box and matches nothing else on the site. +- **The mark inside the tile is white**, never cream. Cream is for text and fills inside ink panels; on a mark it reads as a dirty off-white against the pure-white Rivet badge in the header. +- **Ink tile** (`bg-ink`) is the default: product-page hero lockups (`ProductLockup`), `/docs` cards (`DocsLanding`), inline product mentions, and any product list on a light surface. +- **Accent tile** (`ProductBadge` in `src/components/ProductBar.tsx`) is the colored variant: header dropdowns, mobile sheet, product bar label, talk-to-an-engineer. Every place that lists products renders `ProductBadge` rather than hand-rolling the geometry, so the lockup cannot drift. +- **One sanctioned tile-less case:** on the homepage stack plates (`StackSection`) the mark is painted white directly on the product-accent field. The plate *is* the background — it is not a naked mark. +- **Rivet Cloud has no wordmark.** It takes the `faCloud` glyph — white inside an accent tile where `ProductBadge` supplies one, otherwise bare in ink, sized down so it sits level with the neighboring tiles rather than outweighing them (its own hero, and the careers grid). Do not invent a wordmark for it. + ## Registry Integration Icons Integration entries in `website/src/data/registry.ts` display icons on the registry page and detail pages. Each entry uses either an `image` (SVG file path) or an `icon` (Font Awesome icon). @@ -103,7 +114,7 @@ Import from `@rivet-gg/icons`. The full Font Awesome Pro library is available. C ## Theme -- Marketing pages and docs are light: cool porcelain (`paper`, `#EFEFEF`) with a `paper-deep` radial pooling bottom-left (`.depth-wash`) and a fine grain (`.paper-grain`). Warmth comes from warm-black `ink` text, classical imagery, and oil-paint textures, never from synthetic color gradients. Do not use the cream `mat` token as a surface/background design element on light surfaces (panels, dropdowns, badges, plate frames); use `paper`/`paper-mid`/`white` or `ink`-tint neutrals instead. `cream` stays valid only as the off-white text/fill inside dark `ink` panels. Docs paint the same porcelain field, render prose via `Prose surface="paper"`, and use `pine` for the active sidebar/TOC selected state; only the Learn section keeps a dark shell, and no other page may introduce a dark base. +- Marketing pages and docs are light: cool porcelain (`paper`, `#EFEFEF`) with a `paper-deep` radial pooling bottom-left (`.depth-wash`) and a fine grain (`.paper-grain`). Warmth comes from warm-black `ink` text, classical imagery, and oil-paint textures, never from synthetic color gradients. Do not use the cream `mat` token as a surface/background design element on light surfaces (panels, dropdowns, badges, plate frames); use `paper`/`paper-mid`/`white` or `ink`-tint neutrals instead. `cream` stays valid only as the off-white text/fill inside dark `ink` panels, and never on a product mark — those are white (see Product Marks). Docs paint the same porcelain field, render prose via `Prose surface="paper"`, and use `pine` for the active sidebar/TOC selected state; only the Learn section keeps a dark shell, and no other page may introduce a dark base. - Dark `ink` panels (`editorial/InkPanel`) are reserved for code, terminal, screenshot, and data moments. Code and data plates stay flat ink; the oil-texture backdrop (`textureSrc`) is for editorial moments only (CTA colophon, 404). - Orange is the spark: at most one `accent`/ember CTA per page. White text sits only on `accent-deep` (`#D63E00`) or `ink` fills, never on `accent`. Pine (`#2E4034`) is the structural color for links, eyebrows, diagrams, and selected states; sage (`#93A286`) replaces it inside ink panels. - No drop shadows on marketing cards or imagery; depth comes from `border-ink/10..25` hairlines, `bg-white/55` card fills, and `paper-mid`/`paper-deep` layering (inside ink panels: `border-cream/10..15`). Shadows stay acceptable on functional overlays (dropdowns, tooltips, modals) and the header's glass inset highlight. diff --git a/public/images/agent-os/agentos-wordmark.svg b/public/images/agent-os/agentos-wordmark.svg new file mode 100644 index 00000000..c51ce8b4 --- /dev/null +++ b/public/images/agent-os/agentos-wordmark.svg @@ -0,0 +1,73 @@ + + + + + + + diff --git a/public/images/architecture/javascript-executor-readiness-state-dark.svg b/public/images/architecture/javascript-executor-readiness-state-dark.svg new file mode 100644 index 00000000..c9c0e9ac --- /dev/null +++ b/public/images/architecture/javascript-executor-readiness-state-dark.svg @@ -0,0 +1,146 @@ + + + AgentOS coalesced readiness state machine + Dark-mode state machine demonstrating flags, per-capability revisions, per-VM wake epochs, acknowledgement races, and JavaScript backpressure. + + + + + + + + 4 · Coalescing — revisions are counters, not queued messages + Example for capability 42. One per-handle map entry survives races; one per-VM epoch identifies the currently outstanding doorbell. + + + Timeline: three readiness publications become at most two wakes + + + + 0 + Idle + queue = [] + flags = ∅ + revision = 7 + wake = Idle + No task or thread is spinning. + + + 1 + First Data event + queue = [chunk A] + flags = READABLE + revision = 8 + wake = Outstanding(11) + Enqueue ReadyWake(epoch 11). + + + 2 + More Data before drain + queue = [chunk A, chunk B] + flags = READABLE + revision = 9 + wake = Outstanding(11) + No second wake: already outstanding. + + + 3 + V8 takes batch + epoch = 11 + cap = 42 + flags = READABLE + observedRevision = 9 + This is a snapshot, not removal. + + + 4 + Race: chunk C + queue += chunk C + flags = READABLE + revision = 10 + wake = Outstanding(11) + Still no extra wake yet. + + + + + + + + + 5 + V8 acknowledges what it observed + complete_wake(epoch=11, observedRevision=9) + Current revision is 10, so flags are not cleared. + An old acknowledgement cannot erase newer work. + + + 6 + Broker atomically rearms + wake: Outstanding(11) → Idle + work remains → Outstanding(12) + Exactly one replacement wake is enqueued. + + + 7 + Next drain catches up + batch(epoch=12, revision=10) + ack revision=10 → clear READABLE + If no other work exists, wake returns to Idle. + + + + + + What is bounded? + • ReadyState has at most one entry per admitted capability. + • The wake mailbox has capacity one and state permits one queued/in-flight epoch. + • The socket completion queue is bounded by event count and charged bytes. + • ready_batch copies at most the configured work quantum. + + + What is not a queue? + • Revision 8 → 9 → 10 is one integer field being updated, not three queued revisions. + • READABLE is one level bit, not one event per packet or byte chunk. + • Epoch 11 identifies one wake cycle; it does not enumerate the socket events. + • The wake never owns payload bytes, so wake coalescing cannot lose data. + + + + Backpressure state: JavaScript controls whether the Tokio reader is allowed to read again + + Guest Readable buffer + reaches its high-water mark + Readable.push(bytes) === false + applicationReadDemand = false + bridge: SetReadInterest(false) + This is stream backpressure, not unref(). + + + Broker + socket capability pause + clear/suppress READABLE delivery + applicationReadInterest = false + reader waits on Notify + No repeated level-ready spin or wake storm. + + + Where bytes wait + bounded already-read completion state + plus OS receive buffer + plus sender-side TCP flow control + No additional readiness messages accumulate. + + + When JS needs more + _read() + SetReadInterest(true) + wake reader + republish if known + The bounded cycle begins again. + + + + + + diff --git a/public/images/architecture/javascript-executor-wakeup-sequence-dark.svg b/public/images/architecture/javascript-executor-wakeup-sequence-dark.svg new file mode 100644 index 00000000..fad63f61 --- /dev/null +++ b/public/images/architecture/javascript-executor-wakeup-sequence-dark.svg @@ -0,0 +1,103 @@ + + + AgentOS socket readiness to V8 sequence + Dark-mode sequence diagram showing how a Tokio socket task stores data, publishes readiness, wakes the separate V8 executor, and causes JavaScript to drain the data. + + + + + + + + + 2 · One TCP read — exact wake-up and call-into-V8 sequence + The wake is only a doorbell. The actual bytes take a separate path and are fetched by JavaScript after V8 is awake. + + + + OS kernelTCP + epoll + + Tokio socket taskshared runtime worker + + Completion queuebounded, contains bytes + + ReadyState brokerflags + revisions + + V8 executor threadowns isolate + selector + + Guest JS NetSocketreadiness target + Duplex + + + + + + + + + + A. Tokio discovers work and stores it + 1 + + fd readable → Tokio Waker schedules socket future + 2 + + bounded try_read() turn + + bytes: [48 65 6c 6c 6f] + 3 + + send Data(bytes, accounting reservation) + If full, this task stops reading; the bytes remain in the kernel. + + + B. The same publisher rings one coalesced doorbell + 4 + + publish(cap=42, gen=3, READABLE) + + ReadyState[42].flags |= READABLE + ReadyState[42].revision += 1 + Repeated publications overwrite/merge this entry. + 5 + + ReadyWake { generation, epoch } + Internally: Tokio MPSC[1] staging → immediate crossbeam[1] transfer. + No bytes, socket event, packet count, or revision list is in the wake. + + + C. The V8 thread notices the wake and enters JavaScript itself + + crossbeam Select unblocks + Tokio did not enter V8 + 6 + + take_batch(epoch) + + [(cap=42, gen=3, flags=R, revision=9)] + 7 + + V8 Function::call(_agentOSReadyDispatch, 42, 3, R) + + JS Map lookup → wakeSocketBridgeReads() + Queues a JS microtask; still on the V8 thread. + + + D. JavaScript fetches bytes over a call-specific bridge response + 8 + + _netSocketReadRaw.applySync(socketId) + V8 executor blocks only itself while the registered call waiter settles. + + dequeue Data → direct response → actual bytes + 9 + Readable.push(bytes) + 10 + + complete_batch(epoch, observed revisions) + Clears only unchanged observations; newer revisions cause a replacement wake. + + + Important: the readiness path wakes V8; the bridge read path transports bytes. They are separate so millions of readiness signals cannot become millions of queued payload messages. + diff --git a/public/images/brand/actors-mark.svg b/public/images/brand/actors-mark.svg new file mode 100644 index 00000000..3a94d564 --- /dev/null +++ b/public/images/brand/actors-mark.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/brand/agentos-mark.svg b/public/images/brand/agentos-mark.svg new file mode 100644 index 00000000..d5e05f02 --- /dev/null +++ b/public/images/brand/agentos-mark.svg @@ -0,0 +1,13 @@ + + + + + + + +OS + + + + + diff --git a/public/images/brand/cloud-mark.svg b/public/images/brand/cloud-mark.svg new file mode 100644 index 00000000..a3637185 --- /dev/null +++ b/public/images/brand/cloud-mark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/images/brand/dynamic-apps-mark.svg b/public/images/brand/dynamic-apps-mark.svg new file mode 100644 index 00000000..c89025cc --- /dev/null +++ b/public/images/brand/dynamic-apps-mark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/images/brand/workflows-mark.svg b/public/images/brand/workflows-mark.svg new file mode 100644 index 00000000..8f4f7b22 --- /dev/null +++ b/public/images/brand/workflows-mark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/images/world-map.svg b/public/images/world-map.svg new file mode 100644 index 00000000..453ad383 --- /dev/null +++ b/public/images/world-map.svg @@ -0,0 +1,2 @@ + + diff --git a/public/rivet-brand-kit.zip b/public/rivet-brand-kit.zip new file mode 100644 index 0000000000000000000000000000000000000000..820145d5879ff9b3880dd479ab281c0039b6468e GIT binary patch literal 11690 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: the SVG supplies the silhouette and a * Tailwind background class supplies the hue. Glyph fallbacks take the same - * accent as a text color. `tone="cream"` is for dark grounds: the accent tile + * accent as a text color. `tone="white"` is for dark grounds: the accent tile * inside `ProductBadge` and the dark Learn shell. */ export function ProductMark({ product, className, tone = "accent", -}: { product: Product; className?: string; tone?: "accent" | "cream" }) { +}: { product: Product; className?: string; tone?: "accent" | "white" }) { const accent = productAccent(product.id); const logo = productLogos[product.id]; if (logo) { @@ -36,7 +36,7 @@ export function ProductMark({ style={wordmarkMaskStyle(logo.src)} className={cn( "inline-block shrink-0", - tone === "cream" ? "bg-cream" : (accent?.fill ?? "bg-ink"), + tone === "white" ? "bg-white" : (accent?.fill ?? "bg-ink"), className, )} /> @@ -49,7 +49,7 @@ export function ProductMark({ aria-hidden="true" className={cn( "shrink-0", - tone === "cream" ? "text-cream" : (accent?.text ?? "text-ink-soft"), + tone === "white" ? "text-white" : (accent?.text ?? "text-ink-soft"), className, )} /> @@ -60,7 +60,7 @@ export function ProductMark({ /** * The colored product lockup: a solid tile in the product accent with the - * cream mark spanning it. The tile radius (34.375%) and the SVG's inset ring + * white mark spanning it. The tile radius (34.375%) and the SVG's inset ring * reproduce the Rivet badge geometry, so this is the same treatment as the * product bar on each product page. Size comes from the caller (`size-N`). * @@ -82,39 +82,54 @@ export function ProductBadge({ className, )} > - + ); } -/** - * Which product the subnav belongs to. - * - * Not a switcher: `Products` in the top row is the one place products are - * chosen, so a second control here was the same menu twice, one line apart. - */ +/** Which product the subnav belongs to, linking back to its overview. */ function ProductLabel({ current, label, + active = false, }: { current?: Product; /** Used by docs sections that are not a product vertical (integrations). */ label?: string; + active?: boolean; }) { // Same treatment as the Products dropdown: the color is the tile behind the // mark, and the mark and name are left uncolored. - return ( - + const content = ( + <> {current && } {current?.name ?? label} - + + ); + + if (!current) { + return {content}; + } + + const accent = productAccent(current.id); + return ( + + {content} + ); } /** - * Second header row inside a product vertical: which product you are in, a - * switcher to jump to the same tab of another product, and that product's three - * docs tabs. + * Second header row inside a product vertical: the product overview link and + * that product's remaining tabs. */ export function ProductBar({ initialPathname = "", @@ -144,7 +159,7 @@ export function ProductBar({ // band fill, no underline — the active tab is ink, the rest ink-faint, // and the product accent lives only in the label tile.
- +
{product && visibleTabs(product).map((tab) => { const accent = productAccent(product.id); diff --git a/src/components/docs/DocsLanding.tsx b/src/components/docs/DocsLanding.tsx index 7e09dcd4..fff55592 100644 --- a/src/components/docs/DocsLanding.tsx +++ b/src/components/docs/DocsLanding.tsx @@ -46,13 +46,15 @@ function HeroTitle({ if (logo === "actors") { return (
- {/* The mark is a solid-white SVG, so it is masked and refilled with - ink to read on the porcelain field. */}