diff --git a/src/lib/components/VerticalHelix.svelte b/src/lib/components/VerticalHelix.svelte index 0636175..dcacefd 100644 --- a/src/lib/components/VerticalHelix.svelte +++ b/src/lib/components/VerticalHelix.svelte @@ -39,12 +39,15 @@ // Geometry (user-space units inside the SVG) const W = 1000; const CX = W / 2; - const AMP = 140; - const TOP_PAD = 120; - const BOTTOM_PAD = 120; - const SLOT_HEIGHT = 240; + const AMP = 130; + const TOP_PAD = 80; + const BOTTOM_PAD = 80; + const SLOT_HEIGHT = 180; - const PERIOD = SLOT_HEIGHT * 2; + // Wave period decoupled from slot spacing — nodes are at rung centers, so + // they don't need to line up with strand extremes. Pick a period that + // gives the helix a pleasant twist density. + const PERIOD = 320; const k = (2 * Math.PI) / PERIOD; type Rung = { y: number; x1: number; x2: number; depth: number; aFront: boolean }; @@ -52,6 +55,11 @@ project: StrandProject; index: number; y: number; + /** strand A x at the slot's y (where the node's rung meets strand A) */ + strandAx: number; + /** strand B x at the slot's y (where the node's rung meets strand B) */ + strandBx: number; + /** node always sits at the rung centre (x = CX) */ nodeX: number; side: 'left' | 'right'; }; @@ -98,15 +106,21 @@ const slots = $derived( projects.map((p, i) => { - const y = TOP_PAD + i * SLOT_HEIGHT; - const sign = p.strand === 'A' ? 1 : -1; - const nodeX = CX + sign * AMP * Math.sin(k * y); + // Y positions are slot-based but no longer constrained by the wave + // period — nodes sit on rungs (x = CX) at any Y. Tighten the spacing + // to let cards pack dynamically. + const y = TOP_PAD + i * SLOT_HEIGHT + SLOT_HEIGHT / 2; + const sA = Math.sin(k * y); return { project: p, index: i, y, - nodeX, - side: nodeX > CX ? 'right' : 'left' + strandAx: CX + AMP * sA, + strandBx: CX - AMP * sA, + nodeX: CX, + // Side is determined by strand identity, not geometry. + // Strand A (Projects) → left, Strand B (Innovations) → right. + side: p.strand === 'A' ? 'left' : 'right' }; }) ); @@ -211,7 +225,37 @@ filter="url(#vhelix-glow)" /> - + + {#each slots as s} + + {/each} + + + {#each slots as s} + + {/each} + + {#each slots as s} {/each} - - - {#each slots as s} - - {/each} @@ -331,8 +361,8 @@ .slide { position: absolute; width: 300px; - max-width: calc(50% - 90px); - padding: 1.1rem 1.25rem 0.95rem; + max-width: calc(50% - 60px); + padding: 0.95rem 1.15rem 0.85rem; border-radius: 12px; background: color-mix(in oklab, var(--color-helix-bg-2) 88%, transparent); border: 1px solid var(--color-helix-border); @@ -455,12 +485,12 @@ .summary { color: var(--color-helix-ink-dim); - font-size: 0.9rem; - line-height: 1.5; - margin: 0 0 0.7rem; + font-size: 0.88rem; + line-height: 1.45; + margin: 0 0 0.55rem; display: -webkit-box; - -webkit-line-clamp: 3; - line-clamp: 3; + -webkit-line-clamp: 2; + line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }