@@ -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+
212234const traceEdges = LATTICE_EDGES
213235
214236const 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+
382458function 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 — < strong > THX-VERSION-AWARE </ strong > changed v1.0.0 → v1.1.0 —{ ' ' }
440- < strong > REQ-CORE-005 </ strong > needs review
520+ drift detected — < strong > THX-FREE-TIER </ strong > changed v1.0.0 → v1.1.0 — 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 — research, strategy, requirements, and code. Here’s a
476- real trace from Lattice’s own knowledge graph:
556+ Lattice connects four layers of knowledge — 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’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 — { ' ' }
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