diff --git a/public/features/blocks-gallery.png b/public/features/blocks-gallery.png
new file mode 100644
index 00000000..f257c326
Binary files /dev/null and b/public/features/blocks-gallery.png differ
diff --git a/public/features/blocks.png b/public/features/blocks.png
new file mode 100644
index 00000000..4362f2e8
Binary files /dev/null and b/public/features/blocks.png differ
diff --git a/public/features/faq.png b/public/features/faq.png
new file mode 100644
index 00000000..4c8caeaf
Binary files /dev/null and b/public/features/faq.png differ
diff --git a/public/features/intermission-1.jpg b/public/features/intermission-1.jpg
new file mode 100644
index 00000000..e1a49276
Binary files /dev/null and b/public/features/intermission-1.jpg differ
diff --git a/public/features/intermission-2.jpg b/public/features/intermission-2.jpg
new file mode 100644
index 00000000..16611bec
Binary files /dev/null and b/public/features/intermission-2.jpg differ
diff --git a/public/features/jobs.png b/public/features/jobs.png
new file mode 100644
index 00000000..a2869f06
Binary files /dev/null and b/public/features/jobs.png differ
diff --git a/public/features/public-site.png b/public/features/public-site.png
new file mode 100644
index 00000000..6624194d
Binary files /dev/null and b/public/features/public-site.png differ
diff --git a/public/features/schedule.png b/public/features/schedule.png
new file mode 100644
index 00000000..45936449
Binary files /dev/null and b/public/features/schedule.png differ
diff --git a/public/features/session-edit.png b/public/features/session-edit.png
new file mode 100644
index 00000000..ab8b2782
Binary files /dev/null and b/public/features/session-edit.png differ
diff --git a/public/features/sessions.png b/public/features/sessions.png
new file mode 100644
index 00000000..6699ed69
Binary files /dev/null and b/public/features/sessions.png differ
diff --git a/public/features/speaker-self-edit.png b/public/features/speaker-self-edit.png
new file mode 100644
index 00000000..ff60b6f8
Binary files /dev/null and b/public/features/speaker-self-edit.png differ
diff --git a/public/features/speakers.png b/public/features/speakers.png
new file mode 100644
index 00000000..911fad05
Binary files /dev/null and b/public/features/speakers.png differ
diff --git a/public/features/sponsors.png b/public/features/sponsors.png
new file mode 100644
index 00000000..ef64607a
Binary files /dev/null and b/public/features/sponsors.png differ
diff --git a/public/features/team.png b/public/features/team.png
new file mode 100644
index 00000000..a6f240d5
Binary files /dev/null and b/public/features/team.png differ
diff --git a/public/features/tickets.png b/public/features/tickets.png
new file mode 100644
index 00000000..52ee39e1
Binary files /dev/null and b/public/features/tickets.png differ
diff --git a/public/features/transcription.png b/public/features/transcription.png
new file mode 100644
index 00000000..069e8081
Binary files /dev/null and b/public/features/transcription.png differ
diff --git a/src/App.tsx b/src/App.tsx
index e60f72cc..d5b34e1a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -16,6 +16,9 @@ import { EventApp } from './events/page/EventApp'
import { lazyWithRetry } from './components/lazyWithRetry'
const PublicApp = lazyWithRetry(() => import('./public/PublicApp').then((module) => ({ default: module.PublicApp })))
+const FeaturesPage = lazyWithRetry(() =>
+ import('./public/features/FeaturesPage').then((module) => ({ default: module.FeaturesPage }))
+)
const EventsScreen = lazyWithRetry(() =>
import('./events/list/EventsScreen').then((module) => ({ default: module.EventsScreen }))
@@ -73,6 +76,11 @@ export const App = ({}) => {
+
+ }>
+
+
+
diff --git a/src/auth/LoginForm.tsx b/src/auth/LoginForm.tsx
index 6d50a539..d2421944 100644
--- a/src/auth/LoginForm.tsx
+++ b/src/auth/LoginForm.tsx
@@ -37,6 +37,9 @@ export const LoginForm = ({}) => {
height="200px"
/>
+
+ New here? Discover what OpenPlanner can do →
+
void }) => {
+ const [index, setIndex] = useState(0)
+ const image = images[index]
+
+ return (
+
+
+ onZoom(image)}
+ sx={{ width: '100%', display: 'block', cursor: 'zoom-in' }}
+ />
+
+ {images.length > 1 && (
+
+ setIndex((index - 1 + images.length) % images.length)}>
+
+
+ {images.map((dot, dotIndex) => (
+ setIndex(dotIndex)}
+ sx={{
+ width: 8,
+ height: 8,
+ borderRadius: '50%',
+ cursor: 'pointer',
+ backgroundColor: dotIndex === index ? 'primary.main' : 'action.disabled',
+ }}
+ />
+ ))}
+ setIndex((index + 1) % images.length)}>
+
+
+
+ )}
+
+ )
+}
+
+const FeatureSection = ({
+ section,
+ index,
+ onZoom,
+}: {
+ section: FeatureSectionContent
+ index: number
+ onZoom: (image: FeatureImage) => void
+}) => {
+ const imageFirst = index % 2 === 1
+ const hasImages = !!section.images?.length
+
+ return (
+
+
+
+ {section.title}
+
+
+ {section.tagline}
+
+
+ {section.bullets.map((bullet, bulletIndex) => (
+
+ {bullet}
+
+ ))}
+
+
+ {hasImages && (
+
+
+
+ )}
+
+ )
+}
+
+export const FeaturesPage = () => {
+ const theme = useTheme()
+ const [zoomedImage, setZoomedImage] = useState(null)
+
+ useEffect(() => {
+ document.title = 'OpenPlanner | Features'
+ }, [])
+
+ return (
+
+
+
+
+
+ Everything you need to run a conference
+
+
+ OpenPlanner is a free and open source platform to plan a conference and run the live show:
+ talks, speakers, sponsors, schedule, and day-of tooling.
+
+
+
+ }
+ href="https://github.com/HugoGresse/openplanner"
+ target="_blank"
+ rel="noopener">
+ Star on GitHub
+
+
+
+ {['Free & open source', 'ConferenceHall import', 'Static JSON API', 'Live transcription'].map(
+ (label) => (
+
+ )
+ )}
+
+
+
+ {FEATURE_SECTIONS.map((section, index) => (
+
+ ))}
+
+
+
+ Plan your next event with OpenPlanner
+
+
+ No pricing page — it is open source. Sign in and create your event.
+
+
+
+
+
+ Built by organizers, for organizers.{' '}
+
+ Contribute on GitHub
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/public/features/featuresContent.tsx b/src/public/features/featuresContent.tsx
new file mode 100644
index 00000000..66c67e62
--- /dev/null
+++ b/src/public/features/featuresContent.tsx
@@ -0,0 +1,198 @@
+import { ReactNode } from 'react'
+import { Link } from '@mui/material'
+
+export interface FeatureImage {
+ src: string
+ alt: string
+}
+
+export interface FeatureSectionContent {
+ key: string
+ title: string
+ tagline: string
+ bullets: ReactNode[]
+ images?: FeatureImage[]
+}
+
+const ExternalLink = ({ href, children }: { href: string; children: ReactNode }) => (
+
+ {children}
+
+)
+
+export const FEATURE_SECTIONS: FeatureSectionContent[] = [
+ {
+ key: 'schedule',
+ title: 'A real schedule builder',
+ tagline: 'Drag, drop, done — your program takes shape in minutes.',
+ bullets: [
+ 'Calendar view per day with your tracks and rooms side by side',
+ 'Formats with durations, categories with colors — sessions snap into place',
+ 'Schedule templates to prepare the grid before talks are picked',
+ 'Updated in realtime for every organizer, exportable as PDF',
+ ],
+ images: [
+ {
+ src: '/features/schedule.png',
+ alt: 'The OpenPlanner schedule calendar with sessions across three tracks',
+ },
+ ],
+ },
+ {
+ key: 'sessions',
+ title: 'Sessions, from CFP to stage',
+ tagline: 'Import accepted talks or add your own.',
+ bullets: [
+ <>
+ Pick accepted talks from ConferenceHall{' '}
+ without overwriting its data
+ >,
+ 'Filter, bulk-edit, and export sessions any way you need',
+ 'Categories, formats, languages, levels, private notes',
+ <>
+ AI-assisted teasing posts and session visuals generated with{' '}
+ ShortVid
+ >,
+ ],
+ images: [
+ { src: '/features/sessions.png', alt: 'The sessions list with filters and quick actions' },
+ { src: '/features/session-edit.png', alt: 'The session edit page with dates, speakers and media' },
+ ],
+ },
+ {
+ key: 'speakers',
+ title: 'Speakers who manage themselves',
+ tagline: 'Profiles, photos, socials — and a magic self-edit link.',
+ bullets: [
+ 'Speaker profiles with photo, company, socials and private contact info',
+ 'Self-edit via a magic link: speakers update their own bio and photo',
+ 'Every change goes through admin approval before it is published',
+ 'Sessions linked automatically, visible at a glance',
+ ],
+ images: [
+ { src: '/features/speakers.png', alt: 'The speakers list with linked sessions' },
+ {
+ src: '/features/speaker-self-edit.png',
+ alt: 'The public speaker self-edit form opened from a magic link',
+ },
+ ],
+ },
+ {
+ key: 'sponsors',
+ title: 'Sponsors and a public job board',
+ tagline: 'Categories, logos, and job posts your sponsors submit themselves.',
+ bullets: [
+ 'Sponsor categories with drag-and-drop ordering',
+ 'Each sponsor gets a private token to submit job offers',
+ 'You approve job posts before they reach the public site',
+ 'Everything ships in the exported JSON for your website',
+ ],
+ images: [
+ { src: '/features/sponsors.png', alt: 'Sponsor categories with logos' },
+ { src: '/features/jobs.png', alt: 'The job posts moderation page' },
+ ],
+ },
+ {
+ key: 'team',
+ title: 'Your team, on the website',
+ tagline: 'The people behind the event, grouped and ordered.',
+ bullets: [
+ 'Team members with photos, roles and socials',
+ 'Multiple teams with drag-and-drop ordering across and within groups',
+ 'Published in the exported JSON like everything else',
+ ],
+ images: [{ src: '/features/team.png', alt: 'The team management page' }],
+ },
+ {
+ key: 'tickets',
+ title: 'Tickets without the spreadsheet',
+ tagline: 'Tiers, prices, availability — ready for your site.',
+ bullets: [
+ 'Ticket tiers with price, currency, quantity and sale dates',
+ 'Highlight a tier, flag sold out, add a custom message',
+ 'Optional newsletter opt-in per tier, all exported to your website',
+ ],
+ images: [{ src: '/features/tickets.png', alt: 'The tickets management page' }],
+ },
+ {
+ key: 'blocks',
+ title: 'Building blocks for your website',
+ tagline: 'Describe any custom content — your site renders it.',
+ bullets: [
+ 'Markdown, images, links/CTAs or raw JSON, organized by page and group',
+ 'Single values, ordered lists, or keyed maps — your choice per block',
+ 'Multi-image drop upload, live preview, enable/disable per block',
+ 'Exported as blocks.. in the same JSON as the rest',
+ ],
+ images: [
+ { src: '/features/blocks.png', alt: 'The building blocks editor' },
+ { src: '/features/blocks-gallery.png', alt: 'An image gallery block with multi-image drop upload' },
+ ],
+ },
+ {
+ key: 'faq',
+ title: 'FAQ, public or private',
+ tagline: 'One editor, two audiences.',
+ bullets: [
+ 'Categories with drag-and-drop questions and markdown answers',
+ 'Public pages for attendees, private links for speakers or staff',
+ 'Share a whole category with a single URL, export as PDF',
+ ],
+ images: [{ src: '/features/faq.png', alt: 'The FAQ editor with categories' }],
+ },
+ {
+ key: 'live',
+ title: 'Run the live show',
+ tagline: 'Day-of tooling built from running real conferences.',
+ bullets: [
+ <>
+ Live transcription and on-screen subtitles powered by{' '}
+ Gladia
+ >,
+ 'Intermission screens between talks: next-session lower third, sponsor and media slideshow, driven by your schedule',
+ 'WhatsApp track management: poll each room "ready?", broadcast the GO, auto-remind on timing',
+ 'These screens run in any browser — no login needed in the room',
+ ],
+ images: [
+ {
+ src: '/features/intermission-1.jpg',
+ alt: 'Intermission screen at Sunny Tech with the next-session lower third',
+ },
+ {
+ src: '/features/transcription.png',
+ alt: 'The live transcription screen with the current and next talk',
+ },
+ {
+ src: '/features/intermission-2.jpg',
+ alt: 'Intermission screen rotating through the sponsor slideshow',
+ },
+ ],
+ },
+ {
+ key: 'publish',
+ title: 'Publish anywhere',
+ tagline: 'Your data, one JSON, any website.',
+ bullets: [
+ <>
+ One click deploys a static JSON with sessions, speakers, sponsors, team, FAQ, tickets and blocks —{' '}
+
+ see Sunny Tech 2026's real JSON
+
+ >,
+ 'Webhooks trigger your website build (GitHub repository_dispatch supported out of the box)',
+ <>
+ Built-in public schedule site if you do not want to build one —{' '}
+
+ see Sunny Tech 2026's live
+
+ >,
+ <>
+ OpenFeedback and Voxxrin exports, plus a full{' '}
+ REST API with per-event keys
+ >,
+ ],
+ images: [
+ { src: '/features/public-site.png', alt: "Sunny Tech 2026's public website built on the exported JSON" },
+ ],
+ },
+]