Skip to content

Commit 4aba3dc

Browse files
andresdjassoclaudewaleedlatif1
authored
improvement(landing): homepage redesign with live hero and real platform UI feature cards (#5408)
* improvement(landing): homepage redesign with live hero and real platform UI feature cards * improvement(landing): build-card workflow showcase, real Logs UI monitor window, proportional feature cards - Build card: replace the Mothership chat loop with a static left-to-right support-triage workflow showcase (two triggers converging on a triage agent, fanning out to Linear/Slack/Gmail/Tables) on the hero's solid --surface-3 stage, with the goo cycle loader phasing in the bottom-left corner; the chat animation component stays parked in build-callout/components for reuse - Monitor card: swap the floating logs panel for the REAL platform Logs page captured as a full window (new capture-logs-ui pipeline), framed and positioned identically to the Context card, over a new canyon backdrop - Feature cards scale like Cursor's: media stages are aspect-locked (3:2 desktop, 4:3 stacked) instead of fixed-height, and the UI-window callouts use percentage insets so the whole composition scales proportionally with the browser - Eyebrow chips relocate into the copy column above the title on stacked breakpoints instead of overlapping the full-width media - Extract the hero stage's block card for reuse; export the horizontal smoothstep edge helper; drop the unused formation-graph and logs-table-preview components Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(landing): use surface-hover token for voice input button Matches the token already used by its sibling composer buttons instead of a raw hex hover color. * fix(landing): restore SandboxWorkspacePermissionsProvider for the capture harness Staging removed the sandbox provider as unused when the academy pages were deleted (#5388), but the landing-preview capture route committed on this branch imports it - the branch failed to compile after rebasing. Restore the lightweight provider with its consumer documented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(landing): satisfy HydrationState type in capture harness The mock hydration state set by the readme-tour-capture route was missing the required requestId/error fields added to HydrationState, breaking the production typecheck. * fix(landing): address Greptile/Cursor review findings - hero.tsx: object-top-left isn't a real Tailwind v3 utility, so the crop fell back to center; use object-left-top. - hero-workflow-stage.tsx: byId/builtIds were rebuilt on every render, including every drag pointermove frame; hoist the STAGE_BLOCKS lookup to module scope and memoize builtIds on builtCount. - hero-platform-loop.tsx: prefers-reduced-motion was only read once on mount, so toggling it mid-loop didn't stop the scheduled animation; listen for the media query's change event like BuildChatAnimation does. - landing-preview/page.tsx and readme-tour-capture/[workspaceId]/page.tsx: both are dev/preview-only scaffolds (one explicitly "local-only... delete before committing") that were reachable in production with no auth guard. 404 them outside of production instead of leaving them open. * fix(landing): reset fading when reduced motion cuts the loop short showFinished (added when wiring up the prefers-reduced-motion change listener) set the finished phase but left fading true if the preference flipped mid reset-fade, leaving HeroChatLoop stuck at opacity-0. * fix(landing): sync reduced-motion mid-reply in HeroChatLoop The word-reveal effect only checked prefers-reduced-motion once per showReply transition. If HeroPlatformLoop's showFinished set phase to 'reply' while it was already 'reply' (no re-render, no dependency change), the running stream interval kept ticking at normal speed instead of snapping to the full reply. Listen for the media query's change event, mirroring the fix already applied to HeroPlatformLoop and BuildChatAnimation. * fix(landing): sync reduced-motion mid-entrance in HeroStat HeroStat's staggered count-up entrance only checked prefers-reduced-motion once on mount, unlike the hero loops in this PR that now listen for the media query's change event. Toggling the preference mid-entrance left the scheduled timers/RAF running instead of snapping to the settled value. * fix(landing): stop double-seeding query cache in capture harness seed(queryClient) ran inside a useState lazy initializer, a render-phase side effect that Strict Mode invokes twice. Replace it with a ref guard so the store mutation runs exactly once, still synchronously before first paint. Flagged across three Greptile review rounds. * fix(landing): type the capture harness log filter seed as LogFilters qc.setQueryData(logKeys.list(...)) requires LogFilters, but the inline seed object had no annotation and timeRange inferred as string, which TypeScript widened past the TimeRange literal union. Failed prod build type-check. Also swap the stray `sandbox` prop back to `embedded` to match Workflow's actual prop name. --------- Co-authored-by: andresdjasso <andresdjasso@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: waleed <walif6@gmail.com>
1 parent 12fb4a9 commit 4aba3dc

95 files changed

Lines changed: 3176 additions & 715 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/sim/app/(landing)/CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ The landing page looks like the product. Its visual language is the workspace UI
1818
- **Never touch global styles.** No additions to `app/_styles/globals.css`. All styling is local Tailwind classes; `cn()` from `@/lib/core/utils/cn` for conditionals; no inline `style` attributes.
1919
- **Responsive - desktop is the source of truth, scaled down via `max-*` overrides.** The page is fully responsive (iPad + phone). The desktop layout stays the unprefixed baseline; smaller screens are handled by *layering* `max-*` overrides on top, so desktop renders byte-identically. Tiers:
2020
- `max-xl:` (≤1279) - the hero's two-panel split (absolute visual + logos) collapses to a stacked, in-flow column. The split needs ≥1280 to avoid the headline colliding with the visual panel; iPad-landscape (1024) therefore gets the stacked hero with the desktop nav.
21-
- `max-lg:` (≤1023) - the desktop nav clusters hide (`hidden lg:flex`) and `MobileNav` (hamburger sheet) takes over; multi-column grids step down (mothership 4→2, footer 7→3); shared gutter `px-12 → max-lg:px-8`; section gaps tighten.
21+
- `max-lg:` (≤1023) - the desktop nav clusters hide (`hidden lg:flex`) and `MobileNav` (hamburger sheet) takes over; multi-column grids step down (mothership 4→2, footer 7→3); shared gutter `px-20 → max-lg:px-8`; section gaps tighten.
2222
- `max-md:` (≤767) - Features beats drop the floating callout (`max-md:hidden`) and show the un-masked backdrop preview full-width.
2323
- `max-sm:` (≤639) - single-column grids, smallest type scale, `px-5` gutter, hero CTA row stacks.
2424

25-
When adding a new section, give it the same `px-12 max-lg:px-8 max-sm:px-5` gutter so the navbar wordmark stays aligned with section content at every width. Verify desktop is unchanged and there is zero horizontal overflow at 1280 / 1024 / 768 / 390 before shipping.
25+
When adding a new section, give it the same `px-20 max-lg:px-8 max-sm:px-5` gutter so the navbar wordmark stays aligned with section content at every width. Verify desktop is unchanged and there is zero horizontal overflow at 1280 / 1024 / 768 / 390 before shipping.
2626

2727
## Performance - page speed is a feature
2828

apps/sim/app/(landing)/blog/[slug]/loading.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Skeleton } from '@sim/emcn'
33
export default function BlogPostLoading() {
44
return (
55
<article className='w-full bg-[var(--bg)]'>
6-
<div className='mx-auto w-full max-w-[1446px] px-12 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
6+
<div className='mx-auto w-full max-w-[1460px] px-20 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
77
<div className='mb-6'>
88
<Skeleton className='h-[16px] w-[100px] rounded-[4px] bg-[var(--surface-hover)]' />
99
</div>
@@ -31,8 +31,8 @@ export default function BlogPostLoading() {
3131

3232
<div className='mt-8 h-px w-full bg-[var(--border)]' />
3333

34-
<div className='mx-auto w-full max-w-[1446px]'>
35-
<div className='mx-12 border-[var(--border)] border-x max-sm:mx-5 max-lg:mx-8'>
34+
<div className='mx-auto w-full max-w-[1460px]'>
35+
<div className='mx-20 border-[var(--border)] border-x max-sm:mx-5 max-lg:mx-8'>
3636
<div className='mx-auto max-w-[900px] px-6 py-16'>
3737
<div className='space-y-4'>
3838
<Skeleton className='h-[16px] w-full rounded-[4px] bg-[var(--surface-hover)]' />

apps/sim/app/(landing)/blog/[slug]/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
3939
return (
4040
<article className='w-full bg-[var(--bg)]' itemScope itemType='https://schema.org/TechArticle'>
4141
<JsonLd data={graphJsonLd} />
42-
<header className='mx-auto w-full max-w-[1446px] px-12 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
42+
<header className='mx-auto w-full max-w-[1460px] px-20 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
4343
<div className='mb-6'>
4444
<BackLink href='/blog' label='Back to Blog' />
4545
</div>
@@ -118,7 +118,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
118118

119119
<div className='mt-8 h-px w-full bg-[var(--border)]' />
120120

121-
<div className='mx-auto w-full max-w-[1446px] px-12 max-sm:px-5 max-lg:px-8'>
121+
<div className='mx-auto w-full max-w-[1460px] px-20 max-sm:px-5 max-lg:px-8'>
122122
<div className='border-[var(--border)] border-x'>
123123
<div className='mx-auto max-w-[900px] px-6 py-16' itemProp='articleBody'>
124124
<div className='prose prose-lg max-w-none prose-blockquote:border-[var(--border-1)] prose-hr:border-[var(--border)] prose-headings:font-season prose-a:text-[var(--text-primary)] prose-blockquote:text-[var(--text-muted)] prose-code:text-[var(--text-primary)] prose-headings:text-[var(--text-primary)] prose-li:text-[var(--text-body)] prose-p:text-[var(--text-body)] prose-strong:text-[var(--text-primary)] prose-headings:tracking-[-0.02em]'>

apps/sim/app/(landing)/blog/loading.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { Skeleton } from '@sim/emcn'
33
export default function BlogLoading() {
44
return (
55
<section className='bg-[var(--bg)]'>
6-
<div className='mx-auto w-full max-w-[1446px]'>
6+
<div className='mx-auto w-full max-w-[1460px]'>
77
{/* Header skeleton */}
8-
<div className='px-12 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
8+
<div className='px-20 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
99
<Skeleton className='mb-5 h-[20px] w-[60px] rounded-md bg-[var(--surface-hover)]' />
1010
<div className='flex flex-col gap-4 md:flex-row md:items-end md:justify-between'>
1111
<Skeleton className='h-[40px] w-[240px] rounded-[4px] bg-[var(--surface-hover)]' />
@@ -14,7 +14,7 @@ export default function BlogLoading() {
1414
</div>
1515

1616
{/* Content area with vertical border rails */}
17-
<div className='mx-12 mt-8 border-[var(--border)] border-x max-sm:mx-5 max-lg:mx-8'>
17+
<div className='mx-20 mt-8 border-[var(--border)] border-x max-sm:mx-5 max-lg:mx-8'>
1818
<div className='h-px w-full bg-[var(--border)]' />
1919

2020
{/* Featured skeleton */}

apps/sim/app/(landing)/blog/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export default async function BlogIndex({
103103
<JsonLd data={collectionJsonLd} />
104104

105105
{/* Section header */}
106-
<div className='mx-auto w-full max-w-[1446px] px-12 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
106+
<div className='mx-auto w-full max-w-[1460px] px-20 pt-[112px] max-sm:px-5 max-sm:pt-20 max-lg:px-8'>
107107
<div className='flex flex-col gap-4 md:flex-row md:items-end md:justify-between'>
108108
<h1 className='text-balance text-[28px] text-[var(--text-primary)] leading-[100%] tracking-[-0.02em] lg:text-[40px]'>
109109
Latest from Sim
@@ -118,7 +118,7 @@ export default async function BlogIndex({
118118
<div className='mt-8 h-px w-full bg-[var(--border)]' />
119119

120120
{/* Content area with vertical border rails */}
121-
<div className='mx-auto w-full max-w-[1446px] px-12 max-sm:px-5 max-lg:px-8'>
121+
<div className='mx-auto w-full max-w-[1460px] px-20 max-sm:px-5 max-lg:px-8'>
122122
<div className='border-[var(--border)] border-x'>
123123
{/* Featured posts */}
124124
{featured.length > 0 && (

apps/sim/app/(landing)/careers/careers.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ interface CareersProps {
2121
* crawlable HTML; the interactive {@link JobBoard} hydrates on top to add
2222
* Team/Location filtering.
2323
*
24-
* Both sections share the landing gutter — capped and centered at `max-w-[1446px]`
25-
* with the navbar-aligned `px-12 max-lg:px-8 max-sm:px-5` so the headline starts on
24+
* Both sections share the landing gutter — capped and centered at `max-w-[1460px]`
25+
* with the navbar-aligned `px-20 max-lg:px-8 max-sm:px-5` so the headline starts on
2626
* the same vertical line as the wordmark. The hero carries the single `<h1>`
2727
* (containing "Sim" and "AI workspace") plus an sr-only product summary for AI
2828
* citation (landing CLAUDE.md → GEO); the roles section owns its own `<h2>`.
@@ -45,7 +45,7 @@ export default async function Careers({ searchParams }: CareersProps) {
4545
<section
4646
id='careers-hero'
4747
aria-labelledby='careers-heading'
48-
className='mx-auto flex w-full max-w-[1446px] flex-col gap-5 px-12 pt-20 pb-10 max-sm:px-5 max-sm:pt-16 max-lg:px-8'
48+
className='mx-auto flex w-full max-w-[1460px] flex-col gap-5 px-20 pt-20 pb-10 max-sm:px-5 max-sm:pt-16 max-lg:px-8'
4949
>
5050
<p className='sr-only'>
5151
Careers at Sim, the open-source AI workspace where teams build, deploy, and manage AI
@@ -70,7 +70,7 @@ export default async function Careers({ searchParams }: CareersProps) {
7070
<section
7171
id='open-roles'
7272
aria-labelledby='open-roles-heading'
73-
className='mx-auto flex w-full max-w-[1446px] flex-col gap-10 px-12 pt-6 pb-24 max-sm:px-5 max-sm:pb-16 max-lg:px-8'
73+
className='mx-auto flex w-full max-w-[1460px] flex-col gap-10 px-20 pt-6 pb-24 max-sm:px-5 max-sm:pb-16 max-lg:px-8'
7474
>
7575
<h2
7676
id='open-roles-heading'

apps/sim/app/(landing)/components/cta/cta.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import { ChipLink } from '@sim/emcn'
1111
* `landing.tsx`) above it and the `Footer`'s top margin below it. The headline
1212
* mirrors the hero `<h1>` exactly (48px / `leading-[1.1]` and the same responsive
1313
* ramp), so the page opens and closes on the same display size. Horizontal
14-
* padding (`px-12`) matches every section above, and the section is capped and
15-
* centered at the shared `max-w-[1446px]`.
14+
* padding (`px-20`) matches every section above, and the section is capped and
15+
* centered at the shared `max-w-[1460px]`.
1616
*/
1717
export function Cta() {
1818
return (
1919
<section
2020
id='cta'
2121
aria-labelledby='cta-heading'
22-
className='mx-auto flex w-full max-w-[1446px] flex-col items-center gap-[22px] px-12 text-center max-sm:px-5 max-lg:px-8'
22+
className='mx-auto flex w-full max-w-[1460px] flex-col items-center gap-[22px] px-20 text-center max-sm:px-5 max-lg:px-8'
2323
>
2424
<h2
2525
id='cta-heading'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { WorkflowShowcase } from '@/app/(landing)/components/features/components/build-callout/components/workflow-showcase'
2+
import { ThinkingLoader } from '@/app/(landing)/components/thinking-loader'
3+
4+
/**
5+
* The Build beat's callout - the finished workflow canvas centered on the
6+
* card's solid grey stage, with the goo cycle loader phasing through its
7+
* world-state phrases in the bottom-left corner. The Mothership chat loop
8+
* (`components/build-chat-animation`) is parked here unwired, kept for reuse
9+
* on another surface.
10+
*/
11+
export function BuildCallout() {
12+
return (
13+
<div aria-hidden='true' className='pointer-events-none absolute inset-0'>
14+
<WorkflowShowcase />
15+
<div className='absolute bottom-8 left-8 max-sm:bottom-4 max-sm:left-4'>
16+
<ThinkingLoader size={22} phase className='text-[var(--text-body)]' />
17+
</div>
18+
</div>
19+
)
20+
}

0 commit comments

Comments
 (0)