Coordinates may be fractions of the slide (0–1) or pixels in a 1280×720 space. Values ≤ 1 are treated as fractions.
| Cmd/Ctrl + B / I / U | Make the highlighted editor text bold, italic, or underlined. |
| Cmd/Ctrl + S | Download the current presentation. |
| Cmd/Ctrl + Z / Y | Undo or redo. Copy, cut, paste, and browser Find keep their standard shortcuts. |
| Cmd/Ctrl + 1…9 | Apply the correspondingly numbered document-palette color while the editor has focus. |
| --- | Start a new slide. |
| !--- | Start a pocket slide: rendered in the editor and reachable by direct navigation (overview, thumbnails, ?slide=N), but skipped when advancing with space/n. It still executes, so !set and \${…} math there affect later slides. Built-in slide_hidden is 1 on these slides. |
| !if expr … !else … !endif | Conditional lines (nestable). Truthy = non-zero number or non-empty string; combine with comparisons, e.g. !if slide_num > 3 or !if \${x*2} == 10. |
| !import(theme.psl) | Splice a PSL template into this slide. Use !import("shared files/theme.psl") for spaces. Imports resolve relative to the declaring file; imported images/media/backgrounds use the template folder. Imports may nest but cannot add slides; cycles warn. Template palette declarations join the document palette. Browser imports require reachable URLs (CORS applies); the VS Code extension reads local files. |
| [shown text](https://…) [](https://…) | Inline link, opens in a new tab. Leave the shown text blank to display the URL. Balanced parentheses are allowed inside the URL. |
| first line{{br}}second line | Force a line break without starting a new text item or bullet. Other safe inline controls: {{wbr}}, {{nbsp}}, and {{sub|text}}, {{sup|text}}, {{mark|text}}, {{u|text}}, {{s|text}}, {{small|text}}, {{nobr|text}}. |
| {{color=#d33|red text}} {{color=warning|named color}} | Color part of a line with any CSS color or a document-palette name. Use Insert ▸ Text Color… to apply a color to highlighted editor text. |
| Normal {{size=44px|large}} normal | Change font size within a line. Units may be px, pt, em, rem, or %; a number without a unit means pixels. Other inline markup works inside the resized text. |
| !foreach i 1 6 [step] … !endfor | Repeat the body once per value (inclusive; step may be fractional or negative; nestable). \${i} works everywhere in the body — labels, coordinates, durations — so one loop can build and animate a whole family of elements. Use \${…} for computed bounds. |
| # Title / ## Subtitle | Big centered title and subtitle (title slides). |
| ### Slide title | Heading at the top of a regular slide. |
| - item / - sub-item | Bullets; indent 2 spaces per level. **bold**, *italic*, `code` work in any text. |
| $e^{i\pi} + 1 = 0$ · $$\frac{dN}{dt} = rN$$ | LaTeX math (KaTeX) in any text — headings, bullets, table cells, shape text. $…$ is inline, $$…$$ is display (centered, on its own line). Currency is left alone ($5 and $10 stays text); write \$ for a literal dollar sign next to math. \${…} variables substitute first, so computed values work inside formulas. Invalid LaTeX shows its source in red with the error as a tooltip. |
| % a comment | Ignored. |
| ... | Pause point — wait for spacebar before revealing what follows. |
| >>> >>> 1.5s | Chain — run what follows automatically when the previous animations finish. Add a duration to wait before starting the next group. |
| ```cpp … ``` | Fenced code block with syntax highlighting (cpp, python, javascript, bash, and other common languages; omit the language for plain code). A --- inside a fence does not start a new slide. Size with {w=…, size=…}. |
| | a | b | |:--|--:| | 1 | 2 | | Markdown table. The |---| row makes the first row a header; :--/--:/:-: set column alignment. Cells take inline markdown and \${…}. |
| !set test 5 | Define any variable. Numeric values become numbers; anything else is a string. Reserved style names configure the deck: bg dim tint color accent linkcolor visitedlinkcolor font headfont size size1 size2 size3 headsize headsize1 headsize2 headsize3. size is the shared body default; size1 targets body text and top-level bullets, while size2/size3 target nested bullet levels. headsize is the shared heading default; headsize1/2/3 target #/##/###. Specific settings and an element's {size=…} win in that order. |
| !set palette ocean #A0B3C9 !set palette warning #d33 | Define reusable document colors. Names work anywhere a color is accepted; declaration order assigns Cmd/Ctrl+1 through 9 and fixes the palette colors at the front of the color picker. |
| The value is \${test} | \${…} anywhere in slide text substitutes an expression: variables, numbers, strings, + - * / % ( ). + concatenates strings. |
| \${test*2 + 1} | Math works, with normal precedence. |
| \${test = test + 1} | Assignment: prints the new value and updates the variable. Expressions run at parse time, top to bottom, so results are deterministic. |
| \${slide_num} · \${num_slides} · \${slide_hidden} | Built-ins: current slide number, total slide count (pocket slides included), and whether this slide is hidden. |
| — → 😀 · \${nbsp} · \${chr(8594)} | Special characters: HTML entities work in any text (never tags — markup stays escaped), emojis paste straight in, \${nbsp} is a non-breaking space, and chr(n) gives any code point. |
| \${min(3,7)} · \${sin(pi/2)} · \${test > 4} | Functions: min max sin cos tan exp log log2 sqrt abs floor ceil round (with built-in pi). Comparisons < <= > >= == != return 1 or 0. |
| \${pic.x} · \${box.cy} · \${arr.x2} | Members of any [label]ed element (values as declared, in px): all elements have x y (+ w h cx cy when known); lines/arrows add x1 y1 x2 y2; circles r; ellipses rx ry. Great for attaching one element to another. |
| !all …lines… | Everything after !all (to the end of that slide) is pasted at the top of every slide, then evaluated per slide — so \${slide_num} is correct. Build footers, headers, watermarks, running counters. One block per deck. |
| !set coords absolute | Undistorted geometry: fractions on both axes map to the slide height (one unit = 720px), so !rect (…)(0.3,0.3) is a true square. The slide is aspect (≈1.778) units wide; pixels (values > 1) are always undistorted. !set coords fraction restores the default (x → width, y → height). Built-ins: slide_w slide_h aspect. |
| @(0.55, 0.1) text or element | Absolute position: top-left anchor at 55% across, 10% down. Add {anchor=center} to center on the point. |
| [mylabel] element [lex:phase,front_end] element | Name an element so animations and expressions can target it; add reusable tags after a colon. Use [:tag1,tag2] when no unique label is needed. |
| !style block {fill=#09e, round=20} {$block, size=48} element | Define and reuse a named style. Named styles and explicit properties compose left to right, so later entries override earlier ones. Declarations may span multiple lines. |
| {size=44px, color=crimson} text | Style overrides. Keys: size color font fill stroke w h thick align valign anchor opacity rotate z · shapes/boxes also: textcolor pad round tint dim. |
| {rotate=25} !rect (…)(…) | Give an element a starting rotation, in degrees, about its own center. |
Put a style prefix before the first pipe row, or use a named style. Example: [results] {w=900px, headerfill=#1f6f6b, headertext=white, colwidths=(40%,60%)} | Group | Result |
| outer / thick / stroke | Outer border width, interior rule width, and shared line color. Bare border widths are pixels; zero removes them independently. |
| rules=all|rows|columns|none | Which interior rules are drawn. The outer border is independent. |
| headerfill / headertext bodyfill / bodytext / stripe | Header colors, body colors, and fill for even body rows. CSS colors and document-palette names work. |
| pad / valign / w / size / font | Cell padding and vertical alignment; table width and typography. Use explicit px for lengths. |
| colwidths=(40%,60%) colalign=(left,right) | One entry per column. Widths accept percentages, pixels, or auto. Column alignment overrides align, which overrides Markdown alignment. |
| !anim results headerfill blue 0.5s !anim results rules rows | Colors and lengths interpolate; font, align, valign, rules, colwidths, and colalign change instantly with no duration (or 0s). |
Explicit textcolor works on ordinary text as well as shape text. Rectangles retain 6px corners and text boxes 12px; round=0 makes square corners. Use !anim target w 400px for width, h for image/video/embed height, and textsize for font size. Chart data/palette and media sources/playback flags remain creation-time properties; unsupported animations produce warnings.
|  | Image. Size with {w=0.3} (fraction of slide width) or pixels. |
| !bg(url) · !bg(#123456) | Slide background image (covers slide) or color. |
| {dim=0.5, tint=#000} !bg(url) · !dim 0.5 | Darken (or tint) the background so text on top stays readable. dim is 0–1. |
| !embed(https://your.app) | Embed a live web app as a sandboxed iframe. Position with @(), size with {w=, h=}. Scripts, forms, pop-ups, fullscreen, autoplay, presentations, and downloads are available; SlideDown does not grant camera, microphone, or clipboard permission. Thumbnails show a placeholder. |
| !video(clip.mp4) !audio(voice.mp3) | Native video / audio. Position with @(), size video with {w=, h=} (defaults to 16:9). Style flags: autoplay (starts when the element is revealed — browsers require muted for videos to autoplay reliably), loop, muted, controls=0, and poster=url for a video cover frame. Playback pauses automatically when the element is hidden or you leave the slide. Thumbnails and print show the poster or a placeholder. |
| !chart bar (0.2, 0.3) (0.6, 0.5) Q1:14, Q2:22, Q3:19 !chart line (x, y) (w, h) 2023:4, 2024:9 !chart pie (0.5, 0.5) 0.25 A:40, B:35, C:25 | Native charts from label:value pairs. Bar and line take a top-left corner and size; pie takes a center and radius. Styling: colors=(#1f6f6b, #d97b4a, …) sets the series palette (or fill= for one color), color= the axis/label ink, size= the label text size, thick= the line-chart stroke, and values=0 hides the numeric labels. Values can be computed with \${…}. Charts are shapes, so !anim enter/exit, scale, rotate, hide and show all work on them. |
| !set transition fade 0.4 !transition slide | Slide-to-slide transitions during presentation: fade, slide (direction follows travel), slideleft, slideright, or none, with an optional duration in seconds. !set transition … applies from that slide onward; a !transition … line overrides it for its own slide only (it applies when entering that slide). Editor preview, thumbnails, and print always cut; the transition is skipped for users with reduced-motion enabled. |
| !line (x1,y1) (x2,y2) | Line. Style with {color=…, thick=…}. |
| !arrow (x1,y1) (x2,y2) | Arrow (head at second point). |
| !circle (cx,cy) r | Circle; r is a fraction of slide height or pixels. |
| !ellipse (cx,cy) (rx,ry) | Ellipse. |
| !rect (x,y) (w,h) | Rectangle, top-left at (x,y). |
| !textbox (x,y) (w,h) Your text | A rectangle with wrapped text inside. Style: fill, textcolor, size, align, valign, pad, round, thick (border). |
| !rect (x,y) (w,h) Some text | Any closed shape (rect, circle, ellipse, polygon, diamond, star) can carry inner text — just type it after the geometry. |
| !polygon (x,y) (x,y) (x,y) … | Closed polygon, any number of vertices. !triangle = 3-point shorthand; !polyline is the open version. |
| !diamond (cx,cy) (w,h) · !star (cx,cy) n r [r_in] | Centered diamond; n-pointed star with outer radius r (inner defaults to 0.45·r). |
| !curve (x1,y1) (cx,cy) (x2,y2) | Quadratic Bézier — ideal for diagram connectors; the middle pair is the control point. |
| !anim poly point 4 (x,y) 1s | point now animates any vertex of any multi-point shape. Members: polygons expose x y w h cx cy n plus per-vertex x1 y1 x2 y2 …. |
| !anim pic hide 0.5s · !anim pic show | Fade out / fade in. |
| !anim pic move (0.6, 0.2) 1s | Move to a new position. Shapes move by their first-listed point; a tag selection moves its bounding-box top-left to the destination. |
| !anim @front_end translate (80, 0) 0.5s | Move every current member by the same relative offset. Tag selections are resolved when the phase begins. |
| !anim arrow1 point 2 (0.8, 0.5) 1s | Move just point 1 or 2 of a line/arrow. |
| !anim pic size 0.45 1s | Animate an image to a new width. |
| !anim pic scale 1.6 0.5s | Scale any element about its center. |
| !anim pic rotate 180 1s | Rotate an element to an absolute angle (degrees), pivoting on its own center. |
| !anim @front_end scale 1.2 0.5s !anim @front_end rotate 15 0.5s | Transform a tag selection as one temporary unit around its shared center. Tag scale and rotation are relative and may run simultaneously with movement when they select the exact same members. |
| !anim hand rotate 90 around (0.5, 0.5) 1s | Rotate around any point in the slide, not just the element's own center — e.g. a clock hand around the clock face, or one shape orbiting another. |
| !anim word color #cc2244 0.5s | Animate text color / shape stroke. |
| !anim @nodes fill white 0.5s !anim @nodes stroke black 0.5s | Animate fill, stroke, textcolor, opacity, thick, or round across a selection. |
| !anim word textsize 54px 0.7s | Animate font size. |
| !anim box text **New label** !anim timer text Remaining: 0.5s | Instantly replace an element's Markdown text. Everything after text is content, including duration-like text. Works on headings, paragraphs, bullets, and shapes that already contain text. |
| !tag parser remove front_end !tag optimizer add front_end | Change later tag membership. Put >>> or ... between membership changes and dependent animations. |
| !anim @nodes front !anim node z 20 | Discrete layering: z, front, back, forward, and backward. Tag selections move as a layer block and retain internal source order. |
| {ease=bounce} !anim pic move … | Easing on any animation: linear easein easeout back bounce elastic (default is ease in-out). |
| !anim pic path (cx,cy) (x,y) 1s | Move along a quadratic Bézier from the current position via a control point. |
| !anim pic enter drop !anim pic exit slideleft 0.4s | Entrance / exit effects: fade slideleft slideright slideup slidedown grow drop spin (exit also shrink). For an entrance, declare the element and its enter in the same step — it appears with the effect. drop defaults to a bounce. |
Use Wrap text above the editor to fit long lines to the pane. The preference is remembered in this browser and does not insert line breaks or change the presentation.
Consecutive !anim lines run simultaneously. Geometric selections in one phase must be disjoint or contain exactly the same members; use >>> between partial overlaps. Separate with ... to wait for a keypress, or >>> to auto-run in sequence. The Insert ▸ Animation… menu builds these lines for you.
| space / → / click | Advance one step (past a … or on to the next slide). Pressing during an animation finishes it instantly. |
| ← | Back one step. |
| phone ‹ / › · swipe | Touch controls appear automatically in presentation mode: beside the slide in landscape, or below it in portrait. Swipe left/right on the slide to advance/go back. |
| Backspace | Back one whole slide. |
| n / p | Next / previous slide (skipping remaining steps). |
| v | Slide overview sidebar; click a slide to jump — including pocket (!---) slides, shown dashed. |
| ⧉ Presenter view | Opens the slides in a separate window — drag it to the projector and press F (or click once) there for fullscreen. This window becomes your console: the script is your notes, auto-scrolled to the current slide, with thumbnails as a click-to-jump overview. Both windows' keyboards drive the show. |
| b · f / ⛶ · home / end · esc | Blackout · fullscreen · first/last slide · exit. The play button and Present ▸ Present start at the current editor slide; use Present from Beginning to start over. Present commands enter fullscreen automatically. "▶ 2nd screen" (shown when an extended display is detected, Chromium browsers) presents fullscreen on your other monitor. |
File ▸ Print / Save as PDF lays out one slide per page, fully advanced (all reveal steps shown), with pocket slides omitted and embeds shown as placeholders. The print stylesheet requests full-bleed 16:9 landscape pages. Enable “background graphics” if slide backgrounds look washed out; for physical paper, use “Fit to printable area” if your printer cannot print borderlessly.
Host this HTML file and your .psl script anywhere (e.g. GitHub Pages), then share a link like slidedown.html?present=my_talk.psl — visitors land directly in the slideshow and can step through with space. Add &slide=5 to start on a specific slide. Cross-origin script URLs work if the host sends CORS headers; same-site files always work.
Editor ↔ preview. Moving the caret in the script selects the slide you're editing and advances its preview through the current ... section. Clicking a thumbnail moves the caret to that slide's end so its full state is shown. Drag the divider between the panes to resize them; the ◂/▸ buttons on it collapse one side, and double-clicking it (or Ctrl/Cmd + \) toggles a full-width editor. The thin strip beside the thumbnails hides the rail. The layout is remembered between sessions.