Skip to content

Commit eb799f9

Browse files
gmoonclaude
andcommitted
Rewrite homepage trace with founder-friendly example and fan-out
- Replace self-referential Lattice example with Kahneman/freemium scenario (research paper → pricing thesis → 3 product requirements → code) - Fan out requirements into responsive 3-column grid (stacks on mobile) - Add source file badges to implementation card (auth.ts, plans.ts, etc.) - Add italic lead-in copy framing the scenario for the reader - Update drift narrative to match new example Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c901457 commit eb799f9

1 file changed

Lines changed: 142 additions & 59 deletions

File tree

src/pages/HomePage.tsx

Lines changed: 142 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -182,33 +182,55 @@ function WhoItsFor() {
182182

183183
// --- How It Works (Vertical Trace) ---
184184

185-
const traceNodes = [
186-
{
187-
type: 'Source',
188-
color: LATTICE_LAYERS[0].color,
189-
id: 'SRC-REQUIREMENTS-DRIFT',
190-
title: 'Requirements Documentation Drifts From Implementation',
191-
},
185+
interface TraceNode {
186+
type: string
187+
color: string
188+
id: string
189+
title: string
190+
}
191+
192+
const traceSource: TraceNode = {
193+
type: 'Source',
194+
color: LATTICE_LAYERS[0].color,
195+
id: 'SRC-ENDOWMENT',
196+
title: 'Kahneman et al. 1990 \u2014 The Endowment Effect and Loss Aversion',
197+
}
198+
199+
const traceThesis: TraceNode = {
200+
type: 'Thesis',
201+
color: LATTICE_LAYERS[1].color,
202+
id: 'THX-FREE-TIER',
203+
title: 'A Free Tier Creates Ownership That Drives Paid Conversion',
204+
}
205+
206+
const traceRequirements: TraceNode[] = [
192207
{
193-
type: 'Thesis',
194-
color: LATTICE_LAYERS[1].color,
195-
id: 'THX-VERSION-AWARE',
196-
title: 'Traceability Must Be Version-Aware to Enable Drift Detection',
208+
type: 'Requirement',
209+
color: LATTICE_LAYERS[2].color,
210+
id: 'REQ-BILLING-002',
211+
title: 'Freemium Plan With Usage Limits Per Tier',
197212
},
198213
{
199214
type: 'Requirement',
200215
color: LATTICE_LAYERS[2].color,
201-
id: 'REQ-CORE-005',
202-
title: 'Automatic Drift Detection',
216+
id: 'REQ-ONBOARD-003',
217+
title: 'Time-to-Value Under Five Minutes for New Users',
203218
},
204219
{
205-
type: 'Implementation',
206-
color: LATTICE_LAYERS[3].color,
207-
id: 'IMP-GRAPH-001',
208-
title: 'Graph Traversal and Drift Detection',
220+
type: 'Requirement',
221+
color: LATTICE_LAYERS[2].color,
222+
id: 'REQ-UPGRADE-001',
223+
title: 'Contextual Upgrade Prompts at Usage Boundaries',
209224
},
210225
]
211226

227+
const traceImplementation: TraceNode = {
228+
type: 'Implementation',
229+
color: LATTICE_LAYERS[3].color,
230+
id: 'IMP-BILLING-001',
231+
title: 'Plan Enforcement and In-App Upgrade Flow',
232+
}
233+
212234
const traceEdges = LATTICE_EDGES
213235

214236
const howStyles: Record<string, React.CSSProperties> = {
@@ -327,7 +349,7 @@ const driftStyles: Record<string, React.CSSProperties> = {
327349
display: 'flex',
328350
alignItems: 'flex-start',
329351
gap: '0.6rem',
330-
maxWidth: '520px',
352+
maxWidth: '560px',
331353
margin: '1rem auto 0',
332354
background: `${colors.accentRed}0a`,
333355
border: `1px solid ${colors.accentRed}30`,
@@ -379,47 +401,106 @@ const feedbackStyles: Record<string, React.CSSProperties> = {
379401
},
380402
}
381403

404+
function TraceCard({
405+
node,
406+
inView,
407+
delay,
408+
style,
409+
footer,
410+
}: {
411+
node: TraceNode
412+
inView: boolean
413+
delay: number
414+
style?: React.CSSProperties
415+
footer?: React.ReactNode
416+
}) {
417+
return (
418+
<div
419+
style={{
420+
...traceStyles.card,
421+
borderLeft: `4px solid ${node.color}`,
422+
opacity: inView ? 1 : 0,
423+
transform: inView ? 'none' : 'translateY(12px)',
424+
transition: `opacity 0.5s ease ${delay}s, transform 0.5s ease ${delay}s`,
425+
...style,
426+
}}
427+
>
428+
<div style={traceStyles.cardHeader}>
429+
<span style={{ ...traceStyles.typePill, color: node.color, background: `${node.color}14` }}>{node.type}</span>
430+
<span style={traceStyles.nodeId}>{node.id}</span>
431+
<span style={traceStyles.version}>v1.0.0</span>
432+
</div>
433+
<p style={traceStyles.nodeTitle}>{node.title}</p>
434+
{footer}
435+
</div>
436+
)
437+
}
438+
439+
function TraceConnector({ label, inView, delay }: { label: string; inView: boolean; delay: number }) {
440+
return (
441+
<div
442+
style={{
443+
...traceStyles.connector,
444+
opacity: inView ? 1 : 0,
445+
transition: `opacity 0.3s ease ${delay}s`,
446+
}}
447+
>
448+
<div style={traceStyles.connectorLine} />
449+
<span style={traceStyles.connectorLabel}>{label}</span>
450+
<div style={traceStyles.connectorLine} />
451+
<span style={traceStyles.connectorArrow}>{'\u25BC'}</span>
452+
</div>
453+
)
454+
}
455+
456+
const implFiles = ['src/middleware/auth.ts', 'src/billing/plans.ts', 'src/components/UpgradePrompt.tsx']
457+
382458
function VerticalTrace({ inView }: { inView: boolean }) {
383459
return (
384460
<div style={traceStyles.wrapper}>
385-
{traceNodes.flatMap((node, i) => [
386-
<div
387-
key={node.id}
388-
style={{
389-
...traceStyles.card,
390-
borderLeft: `4px solid ${node.color}`,
391-
opacity: inView ? 1 : 0,
392-
transform: inView ? 'none' : 'translateY(12px)',
393-
transition: `opacity 0.5s ease ${i * 0.2}s, transform 0.5s ease ${i * 0.2}s`,
394-
}}
395-
>
396-
<div style={traceStyles.cardHeader}>
397-
<span style={{ ...traceStyles.typePill, color: node.color, background: `${node.color}14` }}>
398-
{node.type}
399-
</span>
400-
<span style={traceStyles.nodeId}>{node.id}</span>
401-
<span style={traceStyles.version}>v1.0.0</span>
402-
</div>
403-
<p style={traceStyles.nodeTitle}>{node.title}</p>
404-
</div>,
405-
...(i < traceEdges.length
406-
? [
407-
<div
408-
key={`edge-${i}`}
461+
<TraceCard node={traceSource} inView={inView} delay={0} />
462+
<TraceConnector label={traceEdges[0]} inView={inView} delay={0.1} />
463+
<TraceCard node={traceThesis} inView={inView} delay={0.2} />
464+
<TraceConnector label={traceEdges[1]} inView={inView} delay={0.3} />
465+
<div
466+
style={{
467+
display: 'grid',
468+
gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))',
469+
gap: '0.75rem',
470+
width: '100%',
471+
maxWidth: '720px',
472+
}}
473+
>
474+
{traceRequirements.map((req, i) => (
475+
<TraceCard key={req.id} node={req} inView={inView} delay={0.4 + i * 0.15} style={{ maxWidth: 'none' }} />
476+
))}
477+
</div>
478+
<TraceConnector label={traceEdges[2]} inView={inView} delay={0.85} />
479+
<TraceCard
480+
node={traceImplementation}
481+
inView={inView}
482+
delay={0.9}
483+
footer={
484+
<div style={{ display: 'flex', gap: '0.4rem', flexWrap: 'wrap', marginTop: '0.5rem' }}>
485+
{implFiles.map((f) => (
486+
<span
487+
key={f}
409488
style={{
410-
...traceStyles.connector,
411-
opacity: inView ? 1 : 0,
412-
transition: `opacity 0.3s ease ${i * 0.2 + 0.1}s`,
489+
fontFamily: fonts.mono,
490+
fontSize: '0.68rem',
491+
padding: '0.15rem 0.5rem',
492+
borderRadius: '100px',
493+
background: `${colors.accentGreen}12`,
494+
color: colors.accentGreen,
495+
border: `1px solid ${colors.accentGreen}30`,
413496
}}
414497
>
415-
<div style={traceStyles.connectorLine} />
416-
<span style={traceStyles.connectorLabel}>{traceEdges[i]}</span>
417-
<div style={traceStyles.connectorLine} />
418-
<span style={traceStyles.connectorArrow}>{'\u25BC'}</span>
419-
</div>,
420-
]
421-
: []),
422-
])}
498+
{f}
499+
</span>
500+
))}
501+
</div>
502+
}
503+
/>
423504
</div>
424505
)
425506
}
@@ -436,8 +517,8 @@ function DriftBadge({ inView }: { inView: boolean }) {
436517
>
437518
<span style={driftStyles.icon}>{'\u26A0'}</span>
438519
<span>
439-
drift detected &mdash; <strong>THX-VERSION-AWARE</strong> changed v1.0.0 &rarr; v1.1.0 &mdash;{' '}
440-
<strong>REQ-CORE-005</strong> needs review
520+
drift detected &mdash; <strong>THX-FREE-TIER</strong> changed v1.0.0 &rarr; v1.1.0 &mdash; 3 requirements need
521+
review
441522
</span>
442523
</div>
443524
)
@@ -472,13 +553,15 @@ function HowItWorks() {
472553
<div ref={ref} style={howStyles.container}>
473554
<h2 style={howStyles.sectionTitle}>How it works</h2>
474555
<p style={howStyles.intro}>
475-
Lattice connects four layers of knowledge &mdash; research, strategy, requirements, and code. Here&rsquo;s a
476-
real trace from Lattice&rsquo;s own knowledge graph:
556+
Lattice connects four layers of knowledge &mdash; research, strategy, requirements, and code.
557+
</p>
558+
<p style={{ ...howStyles.intro, fontStyle: 'italic', color: colors.textMuted }}>
559+
Your team is deciding between freemium and paid-only. Here&rsquo;s how that decision flows through Lattice:
477560
</p>
478561
<VerticalTrace inView={inView} />
479562
<p style={howStyles.body}>
480-
Every edge records the version it was bound to. When something upstream changes,{' '}
481-
<code style={inlineCode}>lattice drift</code> tells you exactly what downstream needs review:
563+
Six months later, your free tier is attracting the wrong users. You update the thesis &mdash;{' '}
564+
<code style={inlineCode}>lattice drift</code> tells you exactly which requirements need review:
482565
</p>
483566
<DriftBadge inView={inView} />
484567
<FeedbackArc inView={inView} />

0 commit comments

Comments
 (0)