1import { HOME, esc } from "./data.js"; 2import { siteFooterHTML } from "./footer.js"; 3import { figureHTML } from "./figures.js"; 4import { mountHeroArena } from "./hero-arena.js"; 5import { bindMobileNav } from "./mobile-nav.js"; 6import { bindEarlyAccess } from "./early-access.js"; 7import { logoHTML } from "./logo.js"; 8import { 9 MENU_ICON, 10 bindReveal, 11 bindStickyNav, 12 cardGridHTML, 13 closingHTML, 14 heroHTML, 15 specStripHTML, 16} from "./page-shell.js"; 17 18/* Lucide at stroke 1.5, square-cornered to match the blueprint world. */ 19const ICONS = { 20 database: `<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/>`, 21 chip: `<rect x="4" y="4" width="16" height="16"/><rect x="9" y="9" width="6" height="6"/><path d="M9 2v2"/><path d="M15 2v2"/><path d="M9 20v2"/><path d="M15 20v2"/><path d="M2 9h2"/><path d="M2 15h2"/><path d="M20 9h2"/><path d="M20 15h2"/>`, 22 clearance: `<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M15 2v5h5"/><path d="m9 15 2 2 4-4"/>`, 23}; 24 25const icon = (name, size = 18) => 26 `<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${ICONS[name]}</svg>`; 27 28function sectionHTML(section, i) { 29 const copy = ` 30<div class="cap-copy reveal"> 31 <span class="cap-eyebrow">${icon(section.icon)}${esc(section.eyebrow)}</span> 32 <h2>${esc(section.title)}</h2> 33 <p>${esc(section.body)}</p> 34 ${section.link ? `<a class="cap-link" href="${esc(section.link.href)}">${esc(section.link.label)}</a>` : ""} 35</div>`; 36 const fig = figureHTML(section); 37 const flipped = i % 2 === 1; 38 return ` 39<section id="${esc(section.id)}" class="cap${flipped ? " is-flipped" : ""}"> 40 ${flipped ? fig + copy : copy + fig} 41</section>`; 42} 43 44/** Split a sentence into words that fade up in reading order. */ 45function staggered(text) { 46 return text 47 .split(" ") 48 .map((word, i) => `<span class="wd" style="transition-delay:${40 + i * 34}ms">${esc(word)}</span>`) 49 .join(" "); 50} 51 52/** Company homepage (physical AI / foundation models). */ 53export function mountHome(root) { 54 let arenaCleanup = null; 55 let unbindReveal = () => {}; 56 let unbindNav = () => {}; 57 let unbindMobile = () => {}; 58 let unbindArenaMq = () => {}; 59 let unbindEarlyAccess = () => {}; 60 const arenaMq = window.matchMedia("(min-width:901px)"); 61 62 function syncArena() { 63 if (arenaCleanup) { arenaCleanup(); arenaCleanup = null; } 64 if (!arenaMq.matches) return; 65 const mount = root.querySelector("[data-hero-arena]"); 66 if (mount) arenaCleanup = mountHeroArena(mount); 67 } 68 69 function bindArenaMq() { 70 const onChange = () => syncArena(); 71 arenaMq.addEventListener("change", onChange); 72 return () => arenaMq.removeEventListener("change", onChange); 73 } 74 75 function paint() { 76 if (arenaCleanup) { arenaCleanup(); arenaCleanup = null; } 77 unbindReveal(); 78 unbindNav(); 79 unbindMobile(); 80 unbindArenaMq(); 81 unbindEarlyAccess(); 82 83 root.innerHTML = ` 84<div class="home"> 85 <!-- .stl-topbar first: the system bar supplies the wordmark's box and its 86 distance from the top of the bar, so it is identical here and on the 87 legal pages. .home-top now only adds what is genuinely marketing 88 behaviour -- sticky, translucent, and the scroll-triggered .is-top 89 transparent state. Before this the two were parallel components and 90 the wordmark came out 20px tall at +24 here against 36px at +16 there. --> 91 <header class="stl-topbar home-top is-top"> 92 <div class="wrap home-top-inner"> 93 <a class="stl-brand" href="/" aria-label="Stateloop home"> 94 ${logoHTML()} 95 </a> 96 <nav class="navlinks home-nav"> 97 <a class="lp-link" href="#vision">Vision</a> 98 <a class="lp-link" href="#company">Company</a> 99 <a class="lp-link" href="/careers/senior-ai-engineer/">Careers</a> 100 </nav> 101 <div class="home-top-end"> 102 <button type="button" class="btn btn-primary home-top-cta" data-act="early-access">Request early access</button> 103 <button type="button" class="stl-nav-toggle" data-nav-toggle aria-expanded="false" aria-controls="home-mobile-nav" aria-label="Open menu">${MENU_ICON}</button> 104 </div> 105 </div> 106 <nav class="stl-mobile-nav" id="home-mobile-nav" data-nav-panel hidden> 107 <a href="#vision">Vision</a> 108 <a href="#company">Company</a> 109 <a href="/careers/senior-ai-engineer/">Careers</a> 110 <button type="button" data-act="early-access">Request early access</button> 111 </nav> 112 </header> 113 114 ${specStripHTML({ 115 left: "Stateloop · Sheet A-01", 116 center: "Grid 24 / 120 · Scale 1:1", 117 right: "Ver 0.1", 118 })} 119 120 ${heroHTML({ 121 titleHTML: `
122 <span>Supplying the right data and model</span> 123 <span>for every <em>physical AI</em> task</span>`, 124 lede: "We provide specialized datasets and domain-specific foundation models for physical AI.", 125 actionsHTML: ` 126 <button type="button" class="btn btn-primary" data-act="early-access">Request early access</button>`, 127 belowHTML: ` 128 <div class="hero-arena reveal" style="transition-delay:240ms" data-hero-arena></div>`, 129 })} 130 131 <section id="vision" class="vision"> 132 <div class="sheet vision-inner"> 133 <p class="reveal words">${staggered(HOME.vision[1].body)}</p> 134 <p class="reveal words">${staggered(HOME.vision[2].body)}</p> 135 </div> 136 </section> 137 138 <div class="sheet"> 139 ${HOME.sections.map(sectionHTML).join("")} 140 </div> 141 142 <section class="teams"> 143 <div class="sheet"> 144 ${cardGridHTML(HOME.teams.cards, { heading: HOME.teams.heading, headingClass: "teams-head" })} 145 </div> 146 </section> 147 148 <section id="company" class="company"> 149 <div class="sheet company-inner"> 150 <div class="company-head stl-band stl-prose reveal"> 151 <h2>${esc(HOME.company.eyebrow)}</h2> 152 <p>${esc(HOME.company.blurb)}</p> 153 </div> 154 <ul class="company-team reveal" style="transition-delay:90ms"> 155 ${HOME.company.team.map((m) => ` 156 <li class="person"> 157 <span class="person-plate blueprint"> 158 <i class="corner tl"></i><i class="corner tr"></i><i class="corner bl"></i><i class="corner br"></i> 159 <img src="${esc(m.photo)}" alt="${esc(m.name)}" width="96" height="96" loading="lazy" /> 160 </span> 161 <span class="person-name">${esc(m.name)}</span> 162 <span class="person-title">${esc(m.title)}</span> 163 </li>`).join("")} 164 </ul> 165 <div class="hiring blueprint reveal" style="transition-delay:140ms"> 166 <i class="corner tl"></i><i class="corner tr"></i><i class="corner bl"></i><i class="corner br"></i> 167 <div class="hiring-copy"> 168 <h3>${esc(HOME.company.hiring.title)}</h3> 169 <span class="hiring-loc">${esc(HOME.company.hiring.location)}</span> 170 </div> 171 <a class="btn btn-ghost" href="${esc(HOME.company.hiring.href)}">${esc(HOME.company.hiring.cta)} â</a> 172 </div> 173 </div> 174 </section> 175 176 ${closingHTML({ 177 title: "Incorporate the right data and foundation models for your physical AI task.", 178 ctaHTML: `<button type="button" class="btn btn-primary" data-act="early-access">Request early access â</button>`, 179 })} 180 181 ${siteFooterHTML()} 182</div>`; 183 184 syncArena(); 185 unbindArenaMq = bindArenaMq(); 186 unbindReveal = bindReveal(root); 187 unbindNav = bindStickyNav(root); 188 unbindMobile = bindMobileNav(root); 189 unbindEarlyAccess = bindEarlyAccess(root); 190 } 191 192 paint(); 193 194 return () => { 195 if (arenaCleanup) { arenaCleanup(); arenaCleanup = null; } 196 unbindReveal(); 197 unbindNav(); 198 unbindMobile(); 199 unbindArenaMq(); 200 unbindEarlyAccess(); 201 }; 202}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.