// ============================================================ // SLIDE CANVAS — Presentation Kit // Vanilla JS Slide Engine + Demo Slides // ============================================================ // ---------------------------------------------------------- // PRIMITIVE HELPERS — Generate HTML strings // ---------------------------------------------------------- const TYPE = { eyebrow: 24, micro: 24, body: 32, bodyLg: 38, small: 26, kicker: 44, title: 88, titleLg: 120, display: 200, mega: 280, }; const C = { orange: '#FF4D00', black: '#000000', white: '#FFFFFF', white20: 'rgba(255,255,255,0.20)', white10: 'rgba(255,255,255,0.10)', black20: 'rgba(0,0,0,0.20)', black10: 'rgba(0,0,0,0.10)', }; function metaBar(left, right, extraStyle = '') { return `
${left} ${right}
`; } function bottomMeta(left, right, fg = C.white) { return `
${left}${right}
`; } function display(text, size = 'title', color = 'inherit', extraStyle = '') { return `
${text}
`; } function bodyText(text, size = 'size-body', extraStyle = '') { return `

${text}

`; } function mono(text, size = 'size-eyebrow', extraStyle = '') { return `${text}`; } function idx(n, color = C.orange, size = TYPE.eyebrow) { return `${String(n).padStart(2,'0')}`; } function marquee(text, dir = 'left', bg = C.black, fg = C.white, skew = true, fontSize = '10vw') { const items = Array(6).fill(text); const itemsHtml = items.map(t => `${t}` ).join(''); return `
${itemsHtml}${itemsHtml}
`; } function badge(text, size = 180, fg = C.white, spinning = true) { const r = size / 2 - 18; const chars = text; const repeated = `${chars} · ${chars} · ${chars} · `; return `
${repeated}
`; } function arrowSvg(size = 40, color = 'currentColor', rotate = 0) { return ` `; } // ---------------------------------------------------------- // SLIDE DATA // ---------------------------------------------------------- const slides = [ // ---- SLIDE 0: Title / Cover ---- { bg: C.orange, fg: C.black, html: `
${metaBar('SLIDE CANVAS · 01', 'PRESENTATION KIT')}
${display('SLIDE', 'titleLg', C.black)}
${display('CANVAS', 'mega', C.black)}
${bodyText('A design system for building bold, high-impact presentation slides. Primitives, tokens, and animations — ready to compose.', 'size-bodyLg')}
${badge('SLIDE CANVAS · PRESENTATION KIT · ', 220, C.black, true)}
${bottomMeta('2024 · VANILLA JS', 'DESIGN TOKENS + PRIMITIVES', C.black)} ` }, // ---- SLIDE 1: Marquee Divider ---- { bg: C.black, fg: C.white, noPad: true, html: `
${display('DESIGN', 'display', C.white, 'margin-bottom:16px;')} ${display('TOKENS', 'mega', C.orange)}
${marquee('DESIGN TOKENS · TYPE · SPACE · COLOR · FONT', 'left', C.orange, C.black, true, '6vw')} ` }, // ---- SLIDE 2: Design Tokens Overview ---- { bg: C.black, fg: C.white, html: ` ${metaBar('TOKENS · 02', 'TYPOGRAPHY + SPACE + COLOR')}
${idx(1)} ${mono('TYPE SCALE')}
Typography
10-step type scale from eyebrow (24px) to mega (280px). Display faces for impact, body faces for readability.
24 32 44 88 120
${idx(2)} ${mono('SPACING')}
Space
Consistent spacing tokens for padding, gaps, and layout rhythm. Slide padding, item gaps, and title spacing all tokenized.
32px
56px
120px
${idx(3)} ${mono('COLOR')}
Color
Brand orange as the singular accent. Black, white, and transparency steps for layering and depth.
` }, // ---- SLIDE 3: Stats ---- { bg: C.black, fg: C.white, html: ` ${metaBar('IMPACT · 03', 'BY THE NUMBERS')}
10
Type Scale Steps
8
Spacing Tokens
6
Color Tokens
9
UI Primitives
Design Coverage92%
Token Adoption87%
${bottomMeta('03 · IMPACT', 'DATA-DRIVEN DESIGN')} ` }, // ---- SLIDE 4: Timeline ---- { bg: C.black, fg: C.white, html: ` ${metaBar('ROADMAP · 04', 'EVOLUTION')}
${display('THE', 'kicker')} ${display('ROAD-', 'titleLg')} ${display('MAP', 'titleLg', C.orange)} ${bodyText('A phased approach to building a complete design system for high-impact presentations.', 'size-body')}
PHASE 1
Tokens & Primitives
Define color, type, spacing, and build base UI components.
PHASE 2
Slide Templates
Compose primitives into reusable slide layouts: title, split, data, quote.
PHASE 3
Motion & Transitions
Add entrance animations, slide transitions, and micro-interactions.
PHASE 4
Export & Publish
Generate PDFs, share links, and present fullscreen from the browser.
` }, // ---- SLIDE 5: Primitives Showcase ---- { bg: C.orange, fg: C.black, html: ` ${metaBar('PRIMITIVES · 05', 'BUILDING BLOCKS', 'border-color:currentColor')}
METABAR
SECTION · 05STATUS
SECTION · 06META
DISPLAY
KICKER 44
TITLE 88
BIG 120
BADGE
${badge('PRIMITIVES · ', 140, C.black, true)} ${badge('DEMO · ', 110, C.black, true)}
BODY TEXT

Body text at 32px for comfortable reading on large canvases.

Small body at 26px for secondary content and captions.

INDEX + ARROW
01 ${arrowSvg(40, C.black, 0)}
02 ${arrowSvg(40, C.black, 0)}
MONO LABEL
UPPERCASE MONO 24
MICRO LABEL 24
${bottomMeta('05 · PRIMITIVES', '9 COMPONENTS', C.black)} ` }, // ---- SLIDE 6: Quote ---- { bg: C.black, fg: C.white, html: `
"
DESIGN IS
NOT JUST WHAT
IT LOOKS LIKE.
— STEVE JOBS · QUOTE SLIDE PRIMITIVE
${bottomMeta('06 · PHILOSOPHY', 'QUOTE PRIMITIVE')} ` }, // ---- SLIDE 7: Image + Text Split ---- { bg: C.black, fg: C.white, html: ` ${metaBar('SHOWCASE · 07', 'IMAGE + TEXT')}
${display('VISUAL', 'titleLg')} ${display('IMPACT', 'titleLg', C.orange)}
${bodyText('Full-bleed images paired with bold typography create slides that command attention and communicate with clarity.', 'size-body')}
${mono('EXPLORE MORE')} ${arrowSvg(24, C.orange, 0)}
Abstract visual
${bottomMeta('07 · SHOWCASE', 'SPLIT LAYOUT')} ` }, // ---- SLIDE 8: Marquee + End ---- { bg: C.orange, fg: C.black, noPad: true, html: ` ${marquee('SLIDE CANVAS · PRESENTATION KIT · DESIGN SYSTEM · ', 'right', C.black, C.orange, true, '8vw')}
${badge('END · SLIDE CANVAS · PRESENTATION KIT · FIN · ', 260, C.black, true)}
${display('THANK YOU', 'titleLg', C.black)}
BUILT WITH DESIGN TOKENS + PRIMITIVES
${marquee('THANK YOU · GRAZIE · MERCI · DANKE · ARIGATO · ', 'left', C.black, C.orange, true, '6vw')} ` }, ]; // ---------------------------------------------------------- // SLIDE ENGINE // ---------------------------------------------------------- let currentSlide = 0; let isTransitioning = false; let overviewOpen = false; function renderSlides() { const container = document.getElementById('slide-container'); container.innerHTML = slides.map((s, i) => { const padClass = s.noPad ? 'no-pad' : ''; return `
${s.html}
`; }).join(''); } function goToSlide(n, animate = true) { if (isTransitioning || n < 0 || n >= slides.length) return; isTransitioning = true; const allSlides = document.querySelectorAll('.slide'); const prev = allSlides[currentSlide]; const next = allSlides[n]; if (prev) prev.classList.remove('active'); if (next) next.classList.add('active'); currentSlide = n; updateIndicator(); setTimeout(() => { isTransitioning = false; }, animate ? 500 : 0); } function nextSlide() { goToSlide(currentSlide + 1); } function prevSlide() { goToSlide(currentSlide - 1); } function updateIndicator() { const el = document.getElementById('slide-indicator'); el.textContent = `${String(currentSlide + 1).padStart(2, '0')} / ${String(slides.length).padStart(2, '0')}`; } // ---------------------------------------------------------- // OVERVIEW // ---------------------------------------------------------- function toggleOverview() { overviewOpen = !overviewOpen; const modal = document.getElementById('overview-modal'); if (overviewOpen) { buildOverview(); modal.classList.remove('hidden'); modal.classList.add('flex'); } else { modal.classList.add('hidden'); modal.classList.remove('flex'); } } function buildOverview() { const grid = document.getElementById('overview-grid'); grid.innerHTML = slides.map((s, i) => { const padClass = s.noPad ? 'no-pad' : ''; return `
${s.html}
${String(i+1).padStart(2,'0')}
`; }).join(''); } function overviewGo(n) { toggleOverview(); setTimeout(() => goToSlide(n), 200); } // ---------------------------------------------------------- // FULLSCREEN // ---------------------------------------------------------- function toggleFullscreen() { if (!document.fullscreenElement) { document.documentElement.requestFullscreen().catch(() => {}); } else { document.exitFullscreen().catch(() => {}); } } // ---------------------------------------------------------- // KEYBOARD // ---------------------------------------------------------- document.addEventListener('keydown', (e) => { if (overviewOpen) { if (e.key === 'Escape') toggleOverview(); return; } switch (e.key) { case 'ArrowRight': case 'ArrowDown': case ' ': case 'PageDown': e.preventDefault(); nextSlide(); break; case 'ArrowLeft': case 'ArrowUp': case 'PageUp': e.preventDefault(); prevSlide(); break; case 'Home': e.preventDefault(); goToSlide(0); break; case 'End': e.preventDefault(); goToSlide(slides.length - 1); break; case 'f': case 'F': toggleFullscreen(); break; case 'Escape': if (document.fullscreenElement) toggleFullscreen(); break; case 'o': case 'O': toggleOverview(); break; } }); // Touch support let touchStartX = 0; let touchStartY = 0; document.addEventListener('touchstart', (e) => { touchStartX = e.changedTouches[0].screenX; touchStartY = e.changedTouches[0].screenY; }, { passive: true }); document.addEventListener('touchend', (e) => { const dx = e.changedTouches[0].screenX - touchStartX; const dy = e.changedTouches[0].screenY - touchStartY; if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 50) { if (dx < 0) nextSlide(); else prevSlide(); } }, { passive: true }); // Hide key hint after first navigation let hintHidden = false; function hideHint() { if (hintHidden) return; hintHidden = true; const hint = document.getElementById('key-hint'); if (hint) hint.style.opacity = '0'; } const origNext = nextSlide; const origPrev = prevSlide; // Override to also hide hint window.nextSlide = function() { hideHint(); origNext(); }; window.prevSlide = function() { hideHint(); origPrev(); }; // ---------------------------------------------------------- // INIT // ---------------------------------------------------------- function init() { renderSlides(); updateIndicator(); // Auto-hide hint after 6s setTimeout(() => { hideHint(); }, 6000); } document.addEventListener('DOMContentLoaded', init);