The club's slide decks, built with Slidev. You write slides in a Markdown file, and Slidev turns them into a presentation that runs in the browser and exports to PDF.
Every deck in this repo uses the club's "Sketchbook" template. It looks like a whiteboard after a good design meeting: wobbly pen outlines, lavender marker fills, handwritten notes, and photos stuck on with drawn frames. It's the template used for the 2026/27 AGM.
▶ View the AGM deck online: https://we-autopilot.github.io/Slides/
- What's in this repo
- Setup
- Everyday commands
- Making a new deck from the AGM template
- Option A: copy the whole AGM deck (next year's AGM, recruitment talks)
- Option B: start from the starter deck (workshops, project updates)
- Option C: copy individual AGM slides
- Option D: use the template in a different repo
- The AGM deck, slide by slide
- Slidev basics
- The Sketchbook style guide
- Layout reference
- Component reference
- Images, video and QR codes
- Presenting, exporting and hosting (live at we-autopilot.github.io/Slides)
- How the template works
- Troubleshooting
- Contributing
- Credits
| Path | What it is |
|---|---|
agm2026.md |
The 2026/27 AGM deck (17 slides). The best real example of the template. |
slides.md |
A short starter deck with one example of every layout, using placeholder text. |
layouts/ |
The slide layouts: cover, default, two-cols, section, highlights, flow, cards, team. |
components/ |
The building blocks: SketchBox, SketchFrame, Note, Num, SketchArrow, Bracket, Doodle, CartDiagram. |
styles/index.css |
The six colours, the fonts and all shared styles. |
global-top.vue |
The two SVG filters that make outlines look hand-drawn. |
setup/shiki.ts |
The light code-highlighting theme. |
public/ |
Images, logo, QR codes, sponsor logos and videos used by the decks. |
.github/workflows/deploy-pages.yml |
Publishes the AGM deck to GitHub Pages on every push to main. |
vite.config.ts |
A one-line build fix (see Troubleshooting). |
netlify.toml, vercel.json |
Settings for hosting on Netlify or Vercel instead, if you ever want to. |
docs/ |
Images used in this README. |
Any .md deck in the repo root gets the layouts, components and styles automatically. Nothing needs to be imported or copied.
- Node.js 22.12 or newer. Check with
node --version. Install the "LTS" version from nodejs.org if yours is older. - npm, which comes with Node.js.
- Git, plus a code editor. VS Code with the official Slidev extension is recommended: it shows a slide outline and a live preview.
Use npm, not pnpm or yarn. The repo is set up for npm: dependency versions are pinned in
package-lock.json. Slidev's own docs and project generator use pnpm, which is why you'll see it in tutorials, but don't use it here.
git clone <this repo's URL>
cd <repo folder>
npm install # one time; downloads Slidev into node_modules/
npm run dev # opens the AGM deck at http://localhost:3030Edit agm2026.md, save, and the browser updates straight away.
| I want to… | Command |
|---|---|
| Open the AGM deck | npm run dev |
| Open the starter deck | npm run template |
| Open any deck | npx slidev my-deck.md --open |
| Export the AGM deck to PDF | npm run export |
| Export any deck to PDF | npx slidev export my-deck.md |
| Export every slide as a PNG | npx slidev export my-deck.md --format png |
| Build a deck as a static website | npx slidev build my-deck.md (output goes to dist/) |
The first export asks for playwright-chromium, a headless browser that Slidev uses to take the PDF. Install it once with npm i -D playwright-chromium (about 150 MB).
Pick the option that matches what you're making. All four keep the same look as the AGM, because the look lives in layouts/, components/ and styles/, not in the deck file.
Best for next year's AGM, a recruitment or info-session talk, or a sponsor pitch, where most of the AGM's slides still make sense.
- Make a branch so
mainstays clean:git checkout -b agm2027
- Copy the deck:
cp agm2026.md agm2027.md
- Update the headmatter (the settings block at the very top). Change
title:andinfo:. LeavecolorSchema,fontsandtransitionas they are. - Point the npm scripts at the new file. In
package.json, changeagm2026.mdtoagm2027.mdin thedev,buildandexportscripts.buildis what Netlify/Vercel publish. - Run it:
npm run dev. - Go through it slide by slide using the AGM deck, slide by slide below. It lists what each slide is and what you'll need to replace.
- Delete what you don't need. Each slide is a self-contained block between
---lines, so delete the whole block. Add slides by copying an existing block and changing it. - Check every slide in fullscreen (
F11, orCtrl+Cmd+Fon a Mac) for anything cramped, cut off or out of date. Then export a PDF (npm run export) and look through it. - Commit and open a pull request into
main.
Best for workshops, project updates and team meetings, where you want the look but none of the AGM content.
- Copy the starter deck:
cp slides.md workshop-ros2.md
- Open it:
npx slidev workshop-ros2.md --open - The starter has eight slides: a title slide, a free-form slide, two columns with code and a table, a section break, a photo collage, a process flow, a card grid and a team slide. Keep the ones you need and delete the rest. Copy a block to get more of the same kind.
- Replace the placeholder text, and add your images to
public/(see Images, video and QR codes).
Every slide is the text between two --- lines, including its frontmatter: the layout: line and any settings under it. To reuse one AGM slide, for example the QNX sponsor slide or a team slide, copy that whole block into your deck and change the text and images.
---
layout: team ← copy from here…
icon: eye
steps:
- …
---
# Perception.
## The eyes and ears of the cart
← …to just before the next ---If your team wants its slides somewhere else:
- Easiest: a repo admin can tick Settings → General → Template repository on GitHub. Anyone can then press Use this template to get a fresh copy of this repo, delete the decks they don't need, and start their own.
- Into an existing Slidev project: copy these into the project root, then copy the headmatter from
slides.mdinto your deck:Check that the project's Slidev version is the same or newer (layouts/ components/ styles/ global-top.vue setup/ public/logo.svg@slidev/cli53 here).
The 2026/27 deck (agm2026.md), with what you'd change when reusing each slide. Bold layouts are custom Sketchbook layouts; the rest use default.
| # | Slide | Layout | What to update when reusing it |
|---|---|---|---|
| 1 | WE AutoPilot: Annual General Meeting | cover | Subtitle and cleaned cover illustration (public/photos/golf-cart-cover-signs-fixed.png). |
| 2 | Our club | default | Mission, values and vision. |
| 3 | Level 4 autonomy | default | Current-year target and autonomy levels. |
| 4 | 2024/25 highlights | highlights | Photos and notes, including the MNIST Workshop. |
| 5 | 2025/26 highlights | highlights | Photos and notes. |
| 6 | Sponsors | default | QNX, Notion, SOLIDWORKS and Roboshop. |
| 7 | What we've built so far | default | Perception images and planning video. |
| 8 | The road to Level 4 | flow | Four milestones and the current-year marker. |
| 9 | A self-driving golf cart | default | Vehicle and project overview. |
| 10 | How WEAP is built | section | Section break. |
| 11 | WEAP components | default | components/AutonomyStack.vue: ADCU, VCU and vehicle. |
| 12 | Technical team | cards | Hiring guide for five technical teams and non-tech teams. |
| 13–15 | Perception / Mapping & localization / Planning & control | team | Short recruitment overview of work, tools and skills. |
| 16 | Planned events | cards | Team Olympics, Development Showcase, and BBQ & Awards. |
| 17 | Join the ride | cards | Hiring invitation, socials and Discord QR. |
Common reuse jobs:
- New executives or leads: add their photo to
public/photos/leads/, updatesrc,nameandrolein thepeople:lists (slide 12). If a face is cut off, adjustpos:(for examplepos: center 25%). - A new year of highlights: copy slide 5's block and change the title,
photos:,notes:and thenext:teaser. - A new sponsor: put their logo in
public/sponsors/(SVG if possible), then copy slide 7 and update the points. Keep the logo in its real brand colours. - A new results video: see Looping videos for how to trim and crop it.
---
title: My talk # the first block is the "headmatter":
colorSchema: light # settings for the whole deck
fonts:
sans: Montserrat
provider: none
transition: fade
layout: cover # …and the first slide's layout
---
# First slide.
---
# Second slide.
## A purple subtitle
Some text, then **bold**, then a list:
- Lists render as handwritten notes
- <small>Put a caption under one with small</small>
<!-- Speaker notes: an HTML comment at the very end of a slide. -->
---
layout: section # a block right after --- sets this slide's options
doodle: wrench
---
# A section break.---on its own line starts a new slide. A YAML block right after it holds that slide's options ("frontmatter"), andlayout:picks the layout.- Copy the headmatter from
slides.mdwhen you start a deck. It sets the light colour scheme, the fonts and the fade transition. - Titles and subtitles:
# Title.is the slide title and## …the subtitle under it. - Markdown and HTML mix freely. Utility classes such as
flex,grid,grid-cols-2,gap-4,mt-3andtext-centerwork on any element (Slidev uses UnoCSS, which is Tailwind-compatible).
<v-click>…</v-click>reveals something on the next click, and<v-clicks>reveals a list item by item (docs).v-markdraws a purple underline, circle or highlight on a click. Use it for the one key phrase on a slide:<span v-mark="{ at: 1, type: 'underline', color: '#7C5CDB', strokeWidth: 3 }">key phrase</span>
typecan beunderline,circle,highlightorbox, andatis the click number.
| Key | Action |
|---|---|
→ or Space |
Next click or slide |
← |
Back |
O |
Overview of all slides (click one to jump to it) |
Esc |
Close the overview |
Presenter mode (speaker notes, the next slide and a timer) isn't a key: open http://localhost:3030/presenter/, or use the toolbar that appears when you hover over the bottom-left corner of a slide. For fullscreen, use the browser's own fullscreen (F11, or Ctrl+Cmd+F on a Mac) or the toolbar.
| G | Go to a slide number |
Full Slidev documentation: https://sli.dev/guide/.
Use only these six. They're CSS variables in styles/index.css, so in custom HTML write color: var(--purple) rather than a hex code.
| Token | Hex | Use for |
|---|---|---|
--paper |
#FFFFFF |
Background |
--ink |
#191919 |
Text and all pen outlines |
--purple |
#7C5CDB |
Annotations, arrows, marks, small labels, subtitles |
--lavender |
#EAE4FA |
The only fill colour (the "marker") |
--lilac |
#BEAEED |
Secondary lines, quiet dividers |
--muted |
#5D5A66 |
Small captions under notes |
Photos, videos and sponsor logos keep their real colours. Code blocks sit on a pale #F7F5FD with a thin lilac border.
- Montserrat: titles, body text, and anything people must read exactly, such as names, numbers and specs.
- Kalam: handwriting, for notes, asides, explanations and arrow labels. Add
class="hand"to any element, pluspurplefor an annotation (class="hand purple"). - Monospace: only inside code blocks.
Both fonts load from Google Fonts, so the presenting laptop needs internet. Without it they fall back to system fonts.
- 4–6 things to talk about per content slide. Only
sectionslides should be sparse. If a slide has one or two things on it, merge it with a neighbour. - Titles are sentence case and end with a full stop:
# Our club. - Only outlines and arrows wobble. Text, photos and code always stay crisp.
- Numbers (
Num, numbered notes, photo badges) are for real sequences, or to match a photo to its note. Don't use them as decoration. - Photos get a
SketchFrame, never rounded corners, shadows or filters, and alwaysalttext. - Avoid: dark backgrounds, gradients, glows, emoji icons, ALL-CAPS spaced-out labels and outlined text.
- Text size: body text 13–16 px, handwriting 16–20 px, captions no smaller than about 10.5 px.
Every layout except cover puts the logo top-left, with the # title and ## subtitle under it. slides.md has a working example of each one.
---
layout: cover
image: /photos/golf_cart_sketch-hd.jpg # the picture on the right
imageAlt: Describe the image
---
# WE<br>AutoPilot
## Annual General Meeting
<p class="hand">mapping, perception, and a golf cart that drives itself</p>This is used when a slide has no layout:. You get the logo, title and subtitle, then any Markdown or HTML. Most custom AGM slides (founders, sponsor, results) are default slides built with a grid and the components below.
Content before ::right:: goes in the left column, and content after it in the right.
---
layout: section
doodle: wrench # any Doodle name
---
# Section title.
One handwritten line.One big photo plus smaller ones (3–5 in total), each with a numbered badge. Matching numbered notes sit on the right, and an optional "next up" strip runs along the bottom.
layout: highlights
photos:
- { src: /photos/a.jpg, alt: What's in it, pos: center 30% } # the first one is the big one
- { src: /photos/b.jpg, alt: … }
notes:
- Note for photo 1
- { text: Note for photo 2, caption: small print }
next: "next up: … →" # optionalpos moves the crop (CSS object-position, for example center 30% or left center). Use it to keep faces in frame.
3–6 boxes joined by arrows. Each box has a plain-language label, the technical term under it, and a handwritten note below.
layout: flow
image: /photos/golf-cart.png # optional picture on the far left
imageNote: the vehicle # optional
steps:
- { label: Sense, term: Sensors, note: raw data }
- { label: Perceive, term: Perception, note: …, mark: true } # circled on click
- { label: Later, term: Next, note: …, fill: none, dashed: true } # a future step
loop: and round again # optional loop arrow back to step 1
brackets: # optional; steps are numbered from 1
- { from: 2, to: 2, label: Perception team }
rowTop: 186 # optional: move the row down (px)Content after ::extra:: is drawn on top of the slide. The roadmap slide uses it for its "you are here" arrow.
layout: cards
cols: 2 # columns (default 2)
face: 64 # headshot size in px
textSize: 16.5 # handwriting size in px
sideWidth: 230 # width of the ::side:: column
cards:
- icon: eye # a Doodle name
name: Perception
text: The handwritten description.
tools: A small purple line, e.g. tools
people:
- { src: /photos/leads/x.jpg, name: Full Name, role: Their role, pos: center 30% }Content after ::side:: goes in a column on the right, such as numbered notes, the operating-state boxes, or a QR code with "← scan me!".
layout: team
icon: eye
steps: # what the team builds (3 is the sweet spot)
- { label: Ingest, text: Camera frames and LiDAR into ROS 2 }
facts: # 2 key facts, each with a Doodle icon
- { icon: camera, label: Front camera, caption: small print }
tools: [ROS 2, OpenCV, TensorRT]
skills:
- Computer vision
- { text: Sensor fusion, caption: small print }
industry: { text: Where it shows up in industry., caption: small print }
handoff: "detections → the rest of the stack"You can use these in any slide. Sizes are px on Slidev's 980 × 552 canvas; it scales to the screen automatically.
A lavender box with a wobbly pen border. Use it for steps, callouts and stats.
<SketchBox :pad="'12px 16px'">…</SketchBox>
<SketchBox fill="none" dashed>…</SketchBox> <!-- white, dashed: e.g. a future step -->A photo with a drawn frame about 6 px outside it. Give it a size with style.
<SketchFrame src="/photos/team.jpg" alt="The team at the AGM" style="width: 240px; height: 160px" />
<SketchFrame src="/photos/team.jpg" alt="…" pos="center 25%" :n="1" corner="tr" style="…" />
<SketchFrame src="/sponsors/logo.svg" alt="…" fit="contain" style="…" /> <!-- show the whole image -->| Prop | Default | Meaning |
|---|---|---|
src, alt |
Image path and description | |
pos |
center |
Crop position (object-position) |
fit |
cover |
contain shows the whole image (logos, QR codes) |
n, corner |
Numbered badge (tl, tr, bl or br) |
You can also put your own media in its default slot, such as a <video> (see Looping videos).
<Note :n="1" caption="Small grey caption">A handwritten line</Note>
<Note color="purple">An annotation</Note>
<Num :n="2" /> <!-- just the hand-drawn numbered circle -->A curved pen arrow from (x1, y1) to (x2, y2), in px relative to the nearest parent with class="relative". bend curves it (negative bends the other way), and color="ink" makes it black.
<div class="relative" style="width: 200px; height: 80px">
<span class="hand purple absolute" style="left: 40px; top: 0">look here</span>
<SketchArrow :x1="60" :y1="30" :x2="0" :y2="70" :bend="12" />
</div>Use Slidev's built-in <Arrow> for plain straight arrows.
A hand-drawn bracket with a purple handwritten label, for "who owns what":
<Bracket label="Perception team" style="width: 200px" />Pen-drawn icons: <Doodle name="lidar" :size="32" />
eye · map-pin · steering-wheel · wrench · lidar · cone · camera · browser · coins · megaphone · calendar · briefcase · chat · shield · log · path · alert
To add a new icon, copy one of the <template v-else-if="name === '…'"> blocks in components/Doodle.vue. Icons are drawn on a 24 × 24 grid with an ink outline, a little purple, and a white or lavender fill.
A top-down sketch of the golf cart with LiDAR rings, the camera's view, detections and the planned path. It's used on the AGM's golf cart slide: <CartDiagram />.
- Where they go: put files in
public/and reference them with a leading slash, sopublic/photos/team.jpgbecomes/photos/team.jpg. Folders in use:photos/(withphotos/leads/for headshots),qr/,sponsors/andvideos/. - Formats: JPG for photos, SVG for logos, PNG for screenshots.
- Size: keep each file under about 1–1.5 MB, since everyone who clones the repo downloads every file. Around 1600 px on the long side is plenty for a projector.
- Blurry photos: a small headshot (under ~400 px) will look blurry when shown large. Ask for a bigger original, or upscale it with an AI upscaler; the AGM headshots ending in
-hd.jpgwere upscaled with Real-ESRGAN.
Videos should be short, silent and trimmed to the interesting part. With ffmpeg installed:
# Keep seconds 13–40, drop the audio, crop to a 500×650 region whose top-left corner
# is at x=484, y=150, and scale it down for the web:
ffmpeg -ss 13 -to 40 -i raw.mp4 -an \
-vf "crop=500:650:484:150,scale=750:-2" \
-c:v libx264 -crf 20 -pix_fmt yuv420p -movflags +faststart public/videos/clip.mp4
# A still frame to show in PDF/PNG exports, where video can't play:
ffmpeg -ss 2 -i public/videos/clip.mp4 -frames:v 1 public/videos/clip_poster.pngThen put it on a slide:
<SketchFrame style="width: 246px; height: 320px">
<video class="sk-frame-media" src="/videos/clip.mp4" poster="/videos/clip_poster.png"
autoplay loop muted playsinline aria-label="What the video shows" />
</SketchFrame>muted is required, because browsers won't autoplay a video with sound. Keep raw recordings out of the repo; commit only the trimmed clip.
Put them in a SketchFrame with fit="contain", at least about 200 px on the slide, and scan-test them from the back of the room. The Discord QR is public/qr/discord.png.
- Open the deck (
npm run dev) on the laptop that's plugged into the projector. - Open presenter mode on your laptop screen at
http://localhost:3030/presenter/. Open the normal view (http://localhost:3030) in a second window, drag it onto the projector screen and make it fullscreen (F11, orCtrl+Cmd+Fon a Mac). The two windows stay in sync. - Check the internet connection (the fonts come from Google Fonts), and click through every slide once beforehand so videos and images are loaded.
- PDF:
npx slidev export my-deck.mdwritesmy-deck-export.pdf. - PNG of each slide:
npx slidev export my-deck.md --format png - Missing browser: if export complains, run
npm i -D playwright-chromiumonce. - What doesn't export: videos show their
posterimage, and click animations appear in their final state. - Sharing: exports are git-ignored. Share PDFs through the club Drive or Discord.
The AGM deck is published at https://we-autopilot.github.io/Slides/. Anyone can open it in a browser, on any device, with nothing installed, and links to a single slide work (for example …/Slides/7, or presenter mode at …/Slides/presenter/).
How it works: .github/workflows/deploy-pages.yml runs on every push to main. It installs the dependencies, builds the deck with npx slidev build agm2026.md --base /Slides/, and publishes the result. It takes about a minute; follow it in the repo's Actions tab.
One-time setup (a repo admin does this once): Settings → Pages → Build and deployment → Source: GitHub Actions. Then push to main, or open Actions → Deploy slides to GitHub Pages → Run workflow.
To publish a different deck, change DECK: agm2026.md near the top of the workflow file. Pages hosts one deck per repo at this address. To host several, build each into its own subfolder (--base /Slides/workshop/ --out dist/workshop) in the same workflow.
To test a Pages build locally before pushing:
npx slidev build agm2026.md --base /Slides/The output in dist/ expects to be served from /Slides/, so test day-to-day changes with npm run dev instead.
Netlify or Vercel instead: netlify.toml and vercel.json are also configured. Connect the repo there and every push to main runs npm run build, which publishes the deck named in the build script in package.json.
You only need this section if you're changing the template itself.
- Automatic pickup: Slidev loads
layouts/*.vue,components/*.vue,styles/index.css,global-top.vueandsetup/*.tsfor every deck in the folder. Layout names that match Slidev's built-in ones (default,cover,section,two-cols) replace them. - The wobble:
global-top.vuedefines two SVG filters,#roughand#rough-sm. A filter would also distort any text inside the element it's applied to, so borders and fills are drawn on a::beforepseudo-element behind the content, and only that pseudo-element is filtered:Use.my-box { position: relative; isolation: isolate; } .my-box::before { content: ''; position: absolute; inset: 0; z-index: -1; border: 2px solid var(--ink); background: var(--lavender); filter: url(#rough); }
#rough-smon small things like icons and number circles. - Shared code: every layout and component is used by every deck. After changing one, open both
agm2026.mdandslides.mdand click through them before merging.
| Problem | Fix |
|---|---|
pnpm install or pnpm run dev fails |
Use npm: npm install, then npm run dev. |
Unsupported engine or Slidev won't start |
Update Node.js to 22.12 or newer (node --version). |
Port 3030 is in use |
npx slidev my-deck.md --port 3031, or close the other Slidev window. |
| Export says Playwright is missing | npm i -D playwright-chromium, then export again. |
| Fonts look wrong (Arial or Comic Sans) | No internet connection. The fonts load from Google Fonts. |
| A slide shows raw HTML or a stray code block | There's a blank line inside an HTML block. Remove blank lines between <div> tags. |
| SVG text is enormous | Don't use font-size="12" on SVG <text>; UnoCSS turns it into a class. Use style="font: 600 12px Montserrat". |
| Text looks wobbly or blurry | A wobble filter is on an element that contains text. Move the border to ::before (see above). |
| Speaker notes show up on the slide | The notes comment must be the last thing on the slide. |
| Image doesn't show | The path must start with / and the file must be inside public/; /photos/x.jpg means public/photos/x.jpg. Paths are case-sensitive. |
| Video doesn't autoplay | Add muted and playsinline. Use H.264 MP4 (the ffmpeg command above). |
| Something's cut off at the bottom | The slide is too full. Trim the text or split the slide; don't shrink text below ~12 px. |
slidev build fails with [lightningcss minify] Invalid token in pseudo element |
A bug in Slidev 53 combined with UnoCSS 66. vite.config.ts turns off CSS minification to get around it; don't delete that file unless a newer Slidev fixes it. |
| The GitHub Pages site is blank, or images are missing | The build needs --base /<repo name>/; the workflow sets this for you. Also check that Settings → Pages → Source is GitHub Actions. |
| The Pages site still shows an old version | Check that the latest run in the Actions tab finished, then hard-refresh (Ctrl+Shift+R). |
- One branch per deck or change:
Then open a pull request into
git checkout -b workshop-ros2 # …work… git add workshop-ros2.md public/photos/workshop/ git commit -m "Add ROS 2 workshop deck" git push -u origin workshop-ros2
main. - Name decks clearly: for example
agm2027.md,workshop-ros2.md,recruitment-fall2026.md. - Group a deck's images in a subfolder:
public/photos/workshop-ros2/. - Don't commit exported PDFs, raw screen recordings, or huge original photos.
- Template changes (layouts, components, styles) need a quick check of every deck, since they all share the template.
- Built with: Slidev. Fonts: Montserrat and Kalam, both under the SIL Open Font License.
- QNX logo: from Wikimedia Commons and a trademark of BlackBerry/QNX. It's used only to credit QNX as our sponsor.
- Waymo photo: used to illustrate Level 4 autonomy.
- Club material: the WE AutoPilot logo, the photos and the golf cart sketch belong to the club and its members. Ask before reusing them outside club material.
