Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Analytics } from '@vercel/analytics/react'
import { SpeedInsights } from '@vercel/speed-insights/next'
import MetricoolPixel from '@/components/MetricoolPixel'
import '@/styles/globals.css'
import '@/styles/inference-day.css'

// Google Analytics 4. The Measurement ID is not secret (it ships to the
// browser). Loaded in production only so local development doesn't send hits.
Expand Down
70 changes: 70 additions & 0 deletions pages/inference-day.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import Seo from '@/components/Seo'
import Footer from '@/components/Footer'
import { SITE_URL } from '@/lib/site'
import EventNav from '@/components/inference-day/EventNav'
import EventHero from '@/components/inference-day/EventHero'
import RegisterSection from '@/components/inference-day/RegisterSection'
import Agenda from '@/components/inference-day/Agenda'
import Speakers from '@/components/inference-day/Speakers'
import ClosingCta from '@/components/inference-day/ClosingCta'
import EventLockup from '@/components/inference-day/EventLockup'

const TITLE = 'Inference Day · November 5, 2026 | Modelplane'
const DESCRIPTION =
'A free, live virtual event on the future of AI infrastructure. Kelsey Hightower, Viktor Farcic and open source maintainers from NVIDIA, Red Hat, Tetrate, Ericsson, Qualcomm, Dash0 and Upbound.'

// Schema.org Event structured data. Times are expressed in PST (-08:00), matching
// the 8 a.m.–11 a.m. PST / 5 p.m.–8 p.m. CET agenda.
const eventJsonLd = {
'@context': 'https://schema.org',
'@type': 'Event',
name: 'Inference Day',
description:
'A free, live virtual event on the future of AI infrastructure.',
url: `${SITE_URL}/inference-day`,
startDate: '2026-11-05T08:00:00-08:00',
endDate: '2026-11-05T11:00:00-08:00',
eventAttendanceMode: 'https://schema.org/OnlineEventAttendanceMode',
eventStatus: 'https://schema.org/EventScheduled',
isAccessibleForFree: true,
location: {
'@type': 'VirtualLocation',
url: `${SITE_URL}/inference-day`,
},
organizer: { '@type': 'Organization', name: 'Modelplane', url: SITE_URL },
sponsor: { '@type': 'Organization', name: 'Upbound', url: 'https://www.upbound.io' },
performer: [
{ '@type': 'Person', name: 'Kelsey Hightower' },
{ '@type': 'Person', name: 'Viktor Farcic' },
],
}

export default function InferenceDay() {
const url = `${SITE_URL}/inference-day`

return (
<>
{/* TODO(og-image): render a 1200×630 card (wordmark + date + contrail) and
pass it as `image`. Until then <Seo> falls back to the generic card. */}
<Seo title={TITLE} description={DESCRIPTION} url={url}>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(eventJsonLd) }}
/>
</Seo>

<div className="id-page">
<EventNav />
<main>
<EventHero />
<RegisterSection />
<Agenda />
<Speakers />
<ClosingCta />
</main>
<EventLockup />
<Footer />
</div>
</>
)
}
1 change: 1 addition & 0 deletions pages/sitemap.xml.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const getServerSideProps: GetServerSideProps = async ({ res }) => {
const entries = [
urlEntry(`${SITE_URL}/`),
urlEntry(`${SITE_URL}/manifesto`),
urlEntry(`${SITE_URL}/inference-day`),
urlEntry(`${SITE_URL}/blog`),
...posts.map((p) =>
urlEntry(`${SITE_URL}/blog/${p.slug}`, new Date(p.date).toISOString())
Expand Down
Binary file added public/inference-day/contrail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions public/inference-day/inference-day.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Modelplane//Inference Day//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
UID:inference-day-2026-11-05@modelplane.ai
DTSTAMP:20261020T000000Z
DTSTART:20261105T160000Z
DTEND:20261105T190000Z
SUMMARY:Inference Day
URL:https://modelplane.ai/inference-day
DESCRIPTION:Free, live virtual event on the future of AI infrastructure. The StreamYard link is sent on registration.
LOCATION:Virtual
END:VEVENT
END:VCALENDAR
Binary file added public/inference-day/lockup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/annie.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/dennis.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/erica.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/filippe.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/itay.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/julia.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/kashif.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/kelsey.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/nic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/shivay.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/inference-day/speakers/viktor.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions src/components/inference-day/Agenda.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import agenda from '@/data/inference-day/agenda.json'

// Agenda: a two-column grid per row (time | body). The time column stacks above
// the body on small screens. Rendered as a semantic ordered list.
export default function Agenda() {
return (
<section className="id-agenda" id="agenda">
<div className="id-wrap">
<p className="id-eyebrow">{agenda.eyebrow}</p>
<h2 className="id-h2">{agenda.heading}</h2>

<ol className="id-agenda-list">
{agenda.sessions.map((s, i) => (
<li key={i} className="id-agenda-row">
<div className="id-agenda-time">
<div className="pst">{s.pst}</div>
<div className="cet">{s.cet}</div>
</div>
<div className="id-agenda-body">
{s.type && <p className="id-agenda-type">{s.type}</p>}
<h3 className="id-agenda-title">{s.title}</h3>
{s.description && <p className="id-agenda-desc">{s.description}</p>}
<p className="id-agenda-meta">{s.meta}</p>
</div>
</li>
))}
</ol>
</div>
</section>
)
}
24 changes: 24 additions & 0 deletions src/components/inference-day/ClosingCta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import EventActions from './EventActions'

// Closing CTA: the wordmark again, a one-line reminder, the date, and the same
// two buttons as the hero, over the contrail art anchored to the bottom.
export default function ClosingCta() {
return (
<section className="id-cta">
<img src="/inference-day/contrail.png" alt="" aria-hidden="true" className="id-cta-art" />

<div className="id-wrap id-cta-inner">
<h2 className="id-wordmark">Inference Day</h2>
<p className="id-cta-line">Every session is live. Bring your questions.</p>
<p className="id-date">
<time dateTime="2026-11-05T16:00:00Z">
November 5, 2026 · 8 a.m. PST / 5 p.m. CET · Virtual
</time>
</p>
<div className="id-cta-actions">
<EventActions />
</div>
</div>
</section>
)
}
13 changes: 13 additions & 0 deletions src/components/inference-day/EventActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// The Register / Add to calendar button pair, shared by the hero and the
// closing CTA. "Add to calendar" downloads the static .ics; the StreamYard link
// itself is emailed on registration, not shown on the page.
export const ICS_HREF = '/inference-day/inference-day.ics'

export default function EventActions() {
return (
<div className="id-hero-actions">
<a href="#register" className="btn-primary">Register →</a>
<a href={ICS_HREF} download className="btn-ghost">Add to calendar</a>
</div>
)
}
36 changes: 36 additions & 0 deletions src/components/inference-day/EventHero.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import EventActions from './EventActions'

// Hero: full-bleed contrail art behind left-aligned content. The wordmark is the
// page's single <h1> and stays real (gradient-clipped) text for accessibility.
export default function EventHero() {
return (
<section className="id-hero" id="top">
<img src="/inference-day/contrail.png" alt="" aria-hidden="true" className="id-hero-art" />

<div className="id-wrap">
<div className="id-hero-inner">
<h1 className="id-wordmark">Inference Day</h1>

<p className="id-hero-intro">
<span>Hear where AI infrastructure is going from the engineers building it.</span>
<span>Inference Day is a free, live virtual event on the future of AI infrastructure.</span>
</p>

<p className="id-date">
<time dateTime="2026-11-05T16:00:00Z">
November 5, 2026 · 8 a.m. PST / 5 p.m. CET · Virtual
</time>
</p>

<EventActions />
</div>
</div>

<img
src="/inference-day/lockup.png"
alt="Hosted by Modelplane · Sponsored by Upbound"
className="id-hero-lockup"
/>
</section>
)
}
11 changes: 11 additions & 0 deletions src/components/inference-day/EventLockup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// The "Hosted by Modelplane · Sponsored by Upbound" lockup row that sits directly
// above the shared site <Footer /> on the event page.
export default function EventLockup() {
return (
<div className="id-footer-lockup">
<div className="id-wrap">
<img src="/inference-day/lockup.png" alt="Hosted by Modelplane · Sponsored by Upbound" />
</div>
</div>
)
}
61 changes: 61 additions & 0 deletions src/components/inference-day/EventNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useEffect, useState } from 'react'

// Event-specific top bar for /inference-day. Separate from the site Nav so the
// links are the on-page anchors rather than the marketing nav. Sticky on a
// midnight background; collapses to a toggle menu on small screens.
const DOCS_URL = 'https://docs.modelplane.ai'

const LINKS = [
{ label: 'Register', href: '#register' },
{ label: 'Agenda', href: '#agenda' },
{ label: 'Speakers', href: '#speakers' },
{ label: 'Docs', href: DOCS_URL },
]

export default function EventNav() {
const [open, setOpen] = useState(false)

// Close the mobile menu when the hash changes (an anchor link was followed).
useEffect(() => {
const close = () => setOpen(false)
window.addEventListener('hashchange', close)
return () => window.removeEventListener('hashchange', close)
}, [])

return (
<nav className="id-nav" aria-label="Inference Day">
<div className="id-wrap id-nav-inner">
<a href="#top" className="id-nav-logo" aria-label="Modelplane">
<img src="/logo-inverted.svg" alt="Modelplane" />
</a>

<ul className="id-nav-links">
{LINKS.map((l) => (
<li key={l.href}>
<a href={l.href}>{l.label}</a>
</li>
))}
<li>
<a href="#register" className="btn-primary">Register →</a>
</li>
</ul>

<button
className="id-nav-toggle"
onClick={() => setOpen((v) => !v)}
aria-label="Toggle menu"
aria-expanded={open}
>
<span /><span /><span />
</button>
</div>

<div className={`id-nav-mobile${open ? ' open' : ''}`}>
{LINKS.map((l) => (
<a key={l.href} href={l.href} onClick={() => setOpen(false)}>{l.label}</a>
))}
<a href="#register" className="btn-primary id-btn-block" onClick={() => setOpen(false)}>Register →</a>
</div>
</nav>
)
}
42 changes: 42 additions & 0 deletions src/components/inference-day/RegisterSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import RegistrationForm from './RegistrationForm'

// About copy (left) + the registration card (right). Stacks below ~1024px with
// the form second.
export default function RegisterSection() {
return (
<section className="id-register" id="register">
<div className="id-wrap id-register-grid">
<div className="id-about">
<p className="id-eyebrow">About the event</p>
<h2 className="id-about-h2">
The future of AI infrastructure, from the people building it.
</h2>
<p>
Kelsey Hightower opens with a 45-minute fireside chat on where AI infrastructure is
headed, what platform teams should build now, and which lessons from cloud native still
apply.
</p>
<p>
From there, open source maintainers, infrastructure leaders, and practitioners working
with AI in production come together for live conversations about what it actually takes
to run inference at scale.
</p>
<p>
Viktor Farcic closes the event with Inference 101, bringing the pieces together and
breaking down what platform engineers need to understand about this emerging
infrastructure layer.
</p>
<p className="id-about-highlight">
Every session is live. Bring your questions. They&rsquo;ll answer them.
</p>
</div>

<div className="id-form-card">
<p className="id-eyebrow">Free · Virtual · November 5</p>
<h3>Save your spot</h3>
<RegistrationForm />
</div>
</div>
</section>
)
}
31 changes: 31 additions & 0 deletions src/components/inference-day/RegistrationForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Registration is handled by StreamYard's embedded registration. We keep the
// form card (the eyebrow + "Save your spot" heading in RegisterSection, and the
// fine print below) as the visual wrapper, and drop the custom fields in favour
// of StreamYard's own registration form rendered in the iframe. To point at a
// different broadcast, change STREAMYARD_EMBED_URL.
const STREAMYARD_EMBED_URL = 'https://streamyard.com/watch/4crxFjQ5wd2h?embed=true'

// Registration is handled by Upbound via StreamYard, so the privacy link points
// at Upbound's policy. Open item: confirm the target with Annie.
const PRIVACY_URL = 'https://www.upbound.io/privacy-policy'

export default function RegistrationForm() {
return (
<>
<div className="id-embed">
<iframe
src={STREAMYARD_EMBED_URL}
title="Register for Inference Day"
allow="autoplay; fullscreen"
loading="lazy"
/>
</div>

<p className="id-form-fine">
You&rsquo;ll get the StreamYard link and a calendar invite by email. Registration is handled by
Upbound.{' '}
<a href={PRIVACY_URL} target="_blank" rel="noopener noreferrer">Privacy policy</a>
</p>
</>
)
}
Loading
Loading