# impress.js User Guide

impress.js is a presentation framework that turns ordinary HTML into a single, infinite canvas you can zoom, pan, and rotate through in 3D. Instead of a stack of flat slides, you place your content anywhere on a boundless space and let the browser fly the "camera" from one point to the next using CSS3 transforms and transitions. It was inspired by the idea behind [prezi.com](https://prezi.com), and it uses no jQuery and no runtime dependencies — just modern browser features.

You author a presentation entirely in HTML and CSS. Each slide is a `<div class="step">` positioned with `data-*` attributes (`data-x`, `data-y`, `data-z`, `data-rotate`, `data-scale`). One line of JavaScript — `impress().init()` — starts the show.

> [!NOTE]
> impress.js is a **framework you build presentations with**, not an application you run. There is nothing to "launch." You write an HTML file, include the `impress.js` script, and open it in a browser.

---

## Table of Contents

1. [Quick Start](#1-quick-start)
2. [Requirements](#2-requirements)
3. [Installation](#3-installation)
4. [Building Your First Presentation](#4-building-your-first-presentation)
5. [Positioning Slides (the data-* attributes)](#5-positioning-slides-the-data--attributes)
6. [Presentation Settings (the root element)](#6-presentation-settings-the-root-element)
7. [Navigating a Presentation (keyboard, mouse, touch)](#7-navigating-a-presentation-keyboard-mouse-touch)
8. [Styling with impress.js State Classes](#8-styling-with-impressjs-state-classes)
9. [Plugin Catalog](#9-plugin-catalog)
10. [Extra Add-ons (Markdown, Mermaid, syntax highlighting)](#10-extra-add-ons-markdown-mermaid-syntax-highlighting)
11. [The JavaScript API](#11-the-javascript-api)
12. [Common Tasks (recipes)](#12-common-tasks-recipes)
13. [How It Works (concepts)](#13-how-it-works-concepts)
14. [Troubleshooting](#14-troubleshooting)
15. [FAQ](#15-faq)
16. [Reference](#16-reference)

---

## 1. Quick Start

Create a file called `index.html`, paste this in, and open it in Chrome or Firefox. Use the **arrow keys** or **spacebar** to move between slides.

```html
<!DOCTYPE html>
<html>
<head>
    <title>My first presentation</title>
</head>
<body class="impress-not-supported">
    <div id="impress">

        <div class="step" data-x="0" data-y="0">
            <h1>Hello, impress.js</h1>
        </div>

        <div class="step" data-x="1000" data-y="0" data-rotate="90">
            <h1>This slide is rotated 90&deg;</h1>
        </div>

        <div class="step" data-x="2000" data-y="0" data-scale="3">
            <h1>And this one is zoomed in</h1>
        </div>

    </div>

    <!-- Load impress.js, falling back to the CDN if no local copy exists -->
    <script src="js/impress.js"></script>
    <script>
        window.impress ||
        document.write('<script src="https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js"><\/script>');
    </script>
    <script>impress().init();</script>
</body>
</html>
```

```text
A full-screen presentation opens on the first slide. Press the Right arrow or
Space to fly to the rotated slide, then again to zoom into the third.
```

> [!TIP]
> That's the entire model: a `#impress` container, one `<div class="step">` per slide positioned with `data-*` attributes, and `impress().init()`. Everything else in this guide builds on these three ideas.

---

## 2. Requirements

impress.js runs in the **viewer's browser** — there is no server, build step, or account required to *present*. The only requirement is a reasonably modern browser.

| Feature used | Why | Browser support |
|---|---|---|
| CSS 3D Transforms | The core 3D positioning/camera | Modern Chrome, Firefox, Safari, Edge |
| CSS Transitions | The animated movement between steps | Modern Chrome, Firefox, Safari, Edge |
| `dataset` (DataSet API) | Reads `data-*` attributes from your HTML | Modern browsers |
| `classList` (ClassList API) | Adds/removes state classes | Modern browsers |

> [!IMPORTANT]
> The typical and recommended use case is presenting **from your own laptop** with a browser version you have tested. If you embed an impress.js presentation in a public web page, some visitors on older browsers may see only the fallback message (see [Section 8](#8-styling-with-impressjs-state-classes)).

> [!NOTE]
> impress.js deliberately uses **no jQuery and no other JavaScript libraries**, and does not polyfill older browsers. Recent Firefox and Chrome are known to work well; recent versions of other major browsers generally work too.

---

## 3. Installation

There are two ways to get impress.js into your presentation. Pick based on whether you'll have a reliable internet connection when you present.

> [!CAUTION]
> If you are **not certain you'll have WiFi** during your talk, download a local copy (Method B). A CDN-only setup will fail to load with no network.

=== "From a CDN (no download)"

    Include one `<script>` tag in your HTML. impress.js loads automatically — nothing to download.

    ```html
    <script src="https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js"></script>
    <script>impress().init();</script>
    ```

    Pinned version links:

    | Version | jsDelivr URL |
    |---|---|
    | v2.0.0 | `https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js` |
    | v1.1.0 | `https://cdn.jsdelivr.net/gh/impress/impress.js@1.1.0/js/impress.js` |
    | latest source | `https://cdn.jsdelivr.net/gh/impress/impress.js/js/impress.js` |

=== "Download a local copy"

    1. Go to the [GitHub Releases page](https://github.com/impress/impress.js/releases) and download the source as a `.zip` or `.tar`.
    2. Unzip it.
    3. Copy the `js/` folder into your project directory.
    4. (Optional) Copy the `css/` folder too, if you want the sample plugin styling in `impress-common.css`.

    ```html
    <script src="js/impress.js"></script>
    <script>impress().init();</script>
    ```

=== "Belt-and-suspenders (local + CDN fallback)"

    Use a local file but fall back to the CDN automatically if it's missing:

    ```html
    <script src="js/impress.js"></script>
    <script>
        window.impress ||
        document.write('<script src="https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js"><\/script>');
    </script>
    <script>impress().init();</script>
    ```

### About `impress-common.css`

impress.js **does not require any CSS file** — it generates the positioning CSS it needs dynamically. However, the bundled `css/impress-common.css` provides sample styling that several plugins need to look right (the help popup, toolbar, progress bar, speaker-notes hiding, and the mouse-timeout cursor hiding). Link it if you use those plugins:

```html
<link rel="stylesheet" href="./css/impress-common.css">
```

> [!NOTE]
> impress.js is **not currently published to npm**. The `package.json` in the repo exists mainly to run the build and test tooling. Install it by downloading a release or linking the CDN, not via `npm install`.

> [!WARNING]
> The file you link in the browser is `js/impress.js` — a generated bundle that concatenates the core and **all default plugins**. The files under `src/` are the authored source and are not meant to be linked individually in a presentation.

---

## 4. Building Your First Presentation

A presentation has three required pieces.

### 4.1 The fallback message (recommended)

Put a class of `impress-not-supported` on the `<body>` and include a fallback block. If the browser can't run impress.js, the visitor sees this message instead of a broken page. impress.js removes the class automatically when it detects support.

```html
<body class="impress-not-supported">
    <div class="fallback-message">
        <p>Your browser <b>doesn't support the features required</b> by impress.js,
           so you are presented with a simplified version of this presentation.</p>
        <p>For the best experience please use the latest
           <b>Chrome</b>, <b>Safari</b> or <b>Firefox</b> browser.</p>
    </div>
    ...
</body>
```

### 4.2 The root element

All presentation content lives inside a single root element, by default the one with `id="impress"`. Anything outside it is **not** animated by impress.js.

```html
<div id="impress">
    <!-- all your steps go here -->
</div>
```

### 4.3 The steps

Each slide is a `<div class="step">`. Give it an `id` if you want a friendly URL hash and easy navigation targets (otherwise impress.js auto-assigns `step-1`, `step-2`, …).

```html
<div id="intro" class="step" data-x="0" data-y="0">
    <h1>Welcome</h1>
</div>
```

> [!WARNING]
> Do **not** apply your own CSS `transform`, `position`, `width`, or `height` directly to a `.step` element — impress.js controls those. If you need custom styling or layout, put a child `<div>` inside the step and style that instead.

```html
<div class="step" data-x="1000" data-y="1000" data-scale="2">
    <div class="my-content">
        <h1>Powerful, yet still simple</h1>
    </div>
</div>
```

> [!TIP]
> Because every step is wrapped in a zero-size box, you **cannot** use percentage widths/heights (`width: 100%`) for step content. Use pixel values that correspond to your target `data-width`/`data-height` (see [Section 6](#6-presentation-settings-the-root-element)).

---

## 5. Positioning Slides (the data-* attributes)

You place each step on the infinite canvas by setting `data-*` attributes. The values position the **center** of the step. All values are strings, so quote your numbers. Negative numbers are allowed everywhere.

| Attribute | Default | What it does |
|---|---|---|
| `data-x` | `0` | X position (left ↔ right), in pixels |
| `data-y` | `0` | Y position (top ↔ bottom), in pixels |
| `data-z` | `0` | Z position (depth toward/away from camera), in pixels |
| `data-scale` | `1` | Size multiplier relative to other steps (e.g. `4` = 4× larger) |
| `data-rotate` | `0` | Clockwise rotation in degrees (alias for `data-rotate-z`) |
| `data-rotate-x` | `0` | Rotation around the X axis, in degrees |
| `data-rotate-y` | `0` | Rotation around the Y axis, in degrees |
| `data-rotate-z` | `0` | Rotation around the Z axis, in degrees |
| `data-rotate-order` | `xyz` | Order the X/Y/Z rotations are applied |
| `data-transition-duration` | inherits root | Per-step transition time in ms (overrides the global setting) |

### Examples

A step moved left and up:

```html
<div class="step" data-x="-1000" data-y="-1500">
    <q>Aren't you just <b>bored</b> with slides-based presentations?</q>
</div>
```

A zoomed-in title:

```html
<div id="title" class="step" data-x="0" data-y="0" data-scale="4">
    <h1>impress.js</h1>
</div>
```

A step pushed deep into the background on the Z axis:

```html
<div id="tiny" class="step" data-x="2825" data-y="2325" data-z="-3000" data-rotate="300" data-scale="1">
    <p>and <b>tiny</b> ideas</p>
</div>
```

Full 3D rotation around multiple axes:

```html
<div class="step" data-x="6200" data-y="4300" data-z="-100"
     data-rotate-x="-40" data-rotate-y="10" data-scale="2">
    <p>have you noticed it's in <b>3D</b>?</p>
</div>
```

> [!TIP]
> `data-rotate` and `data-rotate-z` are exact aliases — both rotate around the Z axis (the one facing the viewer).

> [!NOTE]
> `data-rotate-order` matters because each rotation is applied relative to the element's *current* orientation. The default `xyz` works for almost everything; change it only for advanced poses that the default order can't reach. See the bundled `examples/3D-rotations/` demo.

### Relative positioning (the `rel` plugin)

Typing absolute coordinates for dozens of slides gets tedious. The built-in **rel** plugin lets you position a step *relative to the previous step*, which means inserting or moving slides rarely forces you to re-do coordinates.

```html
<!-- 1000px right and 500px up from the previous step -->
<div class="step" data-rel-x="1000" data-rel-y="500">...</div>

<!-- relative to a specific earlier step by id -->
<div class="step" data-rel-x="-1000" data-rel-y="750" data-rel-to="title">...</div>
```

You can express relative values as multiples of screen width/height with `w`/`h` units:

```html
<div class="step" data-rel-x="1.5w" data-rel-y="1.5h">...</div>
```

See the [rel plugin](#rel--relative-positioning) entry for the full attribute list and an important compatibility note.

---

## 6. Presentation Settings (the root element)

Global settings go as `data-*` attributes on the `#impress` root element. They define your **target screen size** — author your CSS as if the screen is exactly this size, and impress.js will scale the whole presentation up or down to fit whatever screen it's shown on.

| Attribute | Default | Explanation |
|---|---|---|
| `data-width` | `1920` | Width of the target screen, in px. Content scales automatically on other sizes. |
| `data-height` | `1080` | Height of the target screen, in px. |
| `data-max-scale` | `3` | Maximum scale-up factor on larger screens. |
| `data-min-scale` | `0` | Minimum scale-down factor on smaller screens. |
| `data-perspective` | `1000` | 3D perspective in px. Set to `0` to disable 3D effects. |
| `data-transition-duration` | `1000` | Default transition time between steps, in ms (1 s). |

```html
<div id="impress"
     data-transition-duration="1000"
     data-width="1024"
     data-height="768"
     data-max-scale="3"
     data-min-scale="0"
     data-perspective="1000">
    ...
</div>
```

> [!IMPORTANT]
> The default target resolution is **HD (1920×1080)**. If your presentation was authored for the older 1024×768 default, set it explicitly or your layout will look off:
> ```html
> <div id="impress" data-width="1024" data-height="768" data-max-scale="1" data-min-scale="0">
> ```

> [!NOTE]
> A `data-max-scale` of `1` will *not* enlarge content on screens bigger than your target size — it will only ever shrink. Use a value above `1` (the default is `3`) if you want content to grow on big displays.

---

## 7. Navigating a Presentation (keyboard, mouse, touch)

These controls come from the built-in **navigation**, **help**, **blackout**, **fullscreen**, and **impressConsole** plugins, which are all included in `js/impress.js` by default.

### Keyboard

| Key | Action |
|---|---|
| <kbd>→</kbd> Right / <kbd>↓</kbd> Down / <kbd>Space</kbd> / <kbd>Tab</kbd> / <kbd>Page Down</kbd> | Next step |
| <kbd>←</kbd> Left / <kbd>↑</kbd> Up / <kbd>Page Up</kbd> / <kbd>Shift</kbd>+<kbd>Tab</kbd> | Previous step |
| <kbd>H</kbd> or <kbd>?</kbd> | Toggle the on-screen help popup |
| <kbd>B</kbd> or <kbd>.</kbd> | Blackout — blank/unblank the screen |
| <kbd>F5</kbd> | Enter fullscreen (plugin) |
| <kbd>Esc</kbd> | Exit fullscreen |
| <kbd>P</kbd> | Open the speaker console (impressConsole) |

> [!NOTE]
> <kbd>Tab</kbd> moves to the **next** step on purpose. impress.js needs to control the Tab key because the browser's default Tab behavior (focusing links/buttons) can scroll the viewport and break the careful 3D positioning. <kbd>Shift</kbd>+<kbd>Tab</kbd> goes back.

> [!TIP]
> Modifier combinations like <kbd>Alt</kbd>+<kbd>Tab</kbd>, <kbd>Ctrl</kbd>+…, and <kbd>Cmd</kbd>+… are ignored, so switching windows won't accidentally advance your slides.

### Mouse

- **Click any non-active step** to fly to it.
- **Click a link** whose `href` is `#some-step-id` to navigate to that step.

### Touch

The built-in **touch** plugin lets you **swipe** left/right to move between steps on touch devices. Transitions may look slightly different from the keyboard experience.

### The help popup

To show the help overlay (and let viewers press <kbd>H</kbd> for it), add an empty div anywhere in your page:

```html
<div id="impress-help"></div>
```

The popup appears for 7 seconds when the presentation loads, and toggles on <kbd>H</kbd>/<kbd>?</kbd>. Plugins automatically add their own keys to it (for example, the navigation plugin adds the "Left & Right → Previous & Next step" line).

> [!TIP]
> Style the help popup yourself, or link `impress-common.css` which includes a ready-made style for `#impress-help`.

---

## 8. Styling with impress.js State Classes

impress.js adds CSS classes to your elements as the presentation runs. You hook into these classes to style slides and trigger per-slide animations.

### Step state classes

Every step is always in exactly one of three states:

| Class | Applied to | Meaning |
|---|---|---|
| `.future` | Steps not visited yet | Style or hide upcoming slides |
| `.present` | The step at the center of the camera right now | Trigger in-slide animations |
| `.past` | Steps already visited | Style or hide previous slides |
| `.active` | The currently visible step (same as present, available for convenience) | Highlight the current slide |

```css
/* Fade non-active steps */
.step {
    opacity: 0.3;
    transition: opacity 1s;
}
.step.active {
    opacity: 1;
}

/* Animate something only while its slide is centered */
.present .rotating {
    transform: rotate(-10deg);
    transition-delay: 0.25s;
}
```

### The `impress-on-*` body class

When a step becomes active, impress.js adds a class to the `<body>` named after the step's id, e.g. `impress-on-overview`. This lets you style globally based on which slide is showing (something you can't do by matching upward from the step to the body):

```css
.impress-on-overview .step {
    opacity: 1;
    cursor: pointer;
}
.impress-on-step-1 { background: LightBlue; }
```

### The `impress-not-supported` / `impress-supported` classes

If the browser lacks required features, impress.js adds `impress-not-supported` to the `<body>`; otherwise it adds `impress-supported`. Author your fallback styles against `.impress-not-supported`:

```css
.impress-not-supported .step {
    display: inline-block; /* show steps as a simple stacked list */
}
```

> [!TIP]
> Add `class="impress-not-supported"` to the `<body>` yourself in the HTML. That way visitors **with JavaScript disabled** also get the fallback styling — impress.js will remove the class at runtime when it confirms support.

---

## 9. Plugin Catalog

Almost every feature beyond positioning is a **plugin**. All of the plugins below are *default plugins* — they are already bundled in `js/impress.js`, so you don't load them separately. Most do nothing until you opt in, usually by adding an HTML attribute, a specific `<div>`, or a CSS class.

| Plugin | How you enable it | What it does |
|---|---|---|
| [navigation](#navigation) | automatic | Keyboard + mouse navigation between steps |
| [navigation-ui](#navigation-ui) | toolbar present | Back/Forward buttons + a slide-picker dropdown |
| [touch](#touch) | automatic | Swipe gestures on touch devices |
| [rel](#rel--relative-positioning) | `data-rel-*` attributes | Position steps relative to other steps |
| [goto](#goto) | `data-goto*` attributes | Non-linear jumps (out-links) |
| [bookmark](#bookmark) | `data-bookmark-key-list` | Non-linear jumps via global hotkeys (in-links) |
| [skip](#skip) | `class="skip"` | Skip a step during normal next/prev |
| [stop](#stop) | `class="stop"` | Stop next() from wrapping past this step |
| [substep](#substep) | `class="substep"` | Reveal bullet points one at a time |
| [autoplay](#autoplay) | `data-autoplay` | Auto-advance after a timeout |
| [progress](#progress) | `.impress-progressbar` / `.impress-progress` divs | Progress bar + slide counter |
| [help](#help) | `#impress-help` div | On-screen keyboard help popup |
| [blackout](#blackout) | automatic (<kbd>B</kbd>/<kbd>.</kbd>) | Blank the screen |
| [fullscreen](#fullscreen) | automatic (<kbd>F5</kbd>) | Enter fullscreen |
| [impressConsole](#impressconsole) | automatic (<kbd>P</kbd>) | Speaker console with notes + preview |
| [mobile](#mobile) | CSS you provide | Hide far-away slides to save resources on phones |
| [resize](#resize) | automatic | Re-fit the presentation when the window resizes |
| [mouse-timeout](#mouse-timeout) | CSS you provide | Add a body class after 3 s of mouse inactivity |
| [toolbar](#toolbar) | `#impress-toolbar` div | A shared GUI toolbar other plugins add widgets to |
| [form](#form) | automatic | Make form fields usable inside slides |
| [media](#media) | `data-media-*` attributes | Auto play/pause/stop audio & video per step |
| [extras](#extras) | extra `<script>` tags | Auto-initialize 3rd-party add-ons |

---

### navigation

Automatic. Listens for the keyboard and mouse events described in [Section 7](#7-navigating-a-presentation-keyboard-mouse-touch). No setup needed.

### navigation-ui

Provides **Back**, **Forward**, and a **slide-selector dropdown**. These controls appear inside the toolbar, so you must also enable the [toolbar](#toolbar) plugin (add a `<div id="impress-toolbar"></div>`). The dropdown labels each step by its `title` attribute, or its `id` if no title is set.

### touch

Automatic. Enables swipe navigation on touch devices.

### rel — Relative positioning

Position a step relative to the previous step (or to a named earlier step) instead of with absolute coordinates.

Supported step attributes:

```text
data-rel-x   data-rel-y   data-rel-z   data-rel-to
data-rel-rotate-x   data-rel-rotate-y   data-rel-rotate-z
data-rel-position    data-rel-reset
```

- Non-zero `data-rel-*` values are **inherited** from the previous step, so a deck where every slide shifts by the same amount needs the value set only once.
- A relative value is ignored if the matching absolute value (`data-x`, etc.) is also set on the same step.
- `data-rel-to="some-id"` references an earlier step (only *previous* steps, to avoid circular positioning).
- Use `w`/`h` units for screen-relative offsets: `data-rel-x="1.5w"`.
- `data-rel-position="relative"` makes offsets relative to the previous slide's *rotated* frame, so you can build circles and complex layouts without manual trigonometry. It is inherited, so set it once on the first slide.
- `data-rel-reset` resets all `data-rel-*` to zero for that step; `data-rel-reset="all"` also resets `data-rotate-*`.

> [!WARNING]
> Enabling `rel` introduces one backward-incompatible change: when a step **omits** `data-x`/`data-y`/`data-z`, the value is **inherited from the previous step** rather than defaulting to `0`. If you have an older deck that relied on the old "missing means 0" behavior, add explicit `data-z="0"` (etc.) where needed, or remove the plugin. (This is the *only* compatibility caveat in the framework, and it exists precisely because relative positioning is so much more convenient.)

### goto

A non-linear navigation plugin. It defines *out-links* on a step — where to jump when leaving it.

```html
<!-- When leaving this step, always go to "step-5" -->
<div class="step" data-goto="step-5">

<!-- Different targets for next() vs prev() -->
<div class="step" data-goto-next="step-5" data-goto-prev="step-1">

<!-- Bind specific keys to specific destinations -->
<div class="step"
     data-goto-key-list="ArrowUp ArrowDown ArrowRight ArrowLeft"
     data-goto-next-list="step-4 step-3 step-2 step-5">
```

Key names follow the [MDN KeyboardEvent key values](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values).

### bookmark

Like goto, but defines *in-links* — global hotkeys that jump **to** a step from anywhere.

```html
<div id="agenda" class="step" data-bookmark-key-list="Digit1 KeyA 1 2 3 a b c">
```

- An `id` is required on the step.
- Assigning the same key to multiple steps cycles among them.

> [!WARNING]
> It's up to you to avoid keys already reserved by other plugins (<kbd>H</kbd>, <kbd>B</kbd>, <kbd>P</kbd>, <kbd>?</kbd>, etc.).

### skip

Add `class="skip"` to a step to skip it during normal `next()`/`prev()` navigation. You can still reach it directly (e.g. via a URL hash or `goto()`).

```html
<div class="step skip">This won't appear in the normal flow</div>
```

### stop

Add `class="stop"` to a step to prevent `next()` from advancing past it — handy on a final slide so the deck doesn't wrap back to the start.

```html
<div class="step stop">Last slide — stays put</div>
```

### substep

Reveal parts of a slide one at a time, like PowerPoint bullet animations. Give child elements `class="substep"`; `next()`/`prev()` will reveal/hide them before moving on to the next step.

```html
<style>
    .substep { opacity: 0; }
    .substep.substep-visible { opacity: 1; transition: opacity 1s; }
</style>

<div class="step">
    <h1>Fruits</h1>
    <p class="substep">Orange</p>
    <p class="substep">Apple</p>
</div>
```

- Control order with `data-substep-order="N"` (integers, ascending; unordered substeps reveal last).
- The plugin adds `substep-visible` to revealed substeps and `substep-active` to the most recent one — you supply the CSS to show/hide them.
- `goto()` ignores substeps and jumps straight to the target step.

### autoplay

Auto-advance the presentation after a timeout. Enable it globally on the root, then override per step.

```html
<div id="impress" data-autoplay="5">         <!-- 5 s default -->
    <div class="step" data-autoplay="0">...</div>   <!-- never auto-advance -->
    <div class="step">...</div>                     <!-- uses global 5 s -->
    <div class="step" data-autoplay="10">...</div>  <!-- 10 s -->
</div>
```

The value is the wait time in **seconds**; `0` disables auto-advance on that step. You can also trigger autoplay via a URL parameter: append `?impress-autoplay=5` to the page URL.

### progress

Shows a progress bar and/or a slide counter. Add the divs where you want them:

```html
<div class="impress-progressbar"><div></div></div>
<div class="impress-progress"></div>
```

Style them yourself, or link `impress-common.css` for the sample styling.

### help

Shows the keyboard-shortcut popup. Add `<div id="impress-help"></div>` to your page (see [Section 7](#the-help-popup)).

### blackout

Automatic. Press <kbd>B</kbd> or <kbd>.</kbd> to blank the screen (and again to restore it) — useful to draw attention away from the slides.

### fullscreen

Automatic. Press <kbd>F5</kbd> to enter fullscreen, <kbd>Esc</kbd> to leave.

> [!NOTE]
> impress.js works fine with your browser's normal fullscreen (usually <kbd>F11</kbd>). The fullscreen plugin is mainly useful when combined with the impressConsole plugin.

### impressConsole

Press <kbd>P</kbd> to open a **speaker console** in a separate window: current slide, preview of the next slide, your speaker notes, and navigation.

Add notes inside any step with a `notes` div:

```html
<div class="step">
    Visible slide content
    <div class="notes">Speaker notes — only shown in the console.</div>
</div>
```

Hide notes from the actual presentation with CSS:

```css
.notes { display: none; }
```

### mobile

Detects mobile OSes and adds a `body.impress-mobile` class, plus `div.next`/`div.prev` classes to the steps adjacent to the current one. Combined with your CSS, this lets you hide all but the current/next/previous slides to save resources on phones.

```css
body.impress-mobile .step { display: none; }
body.impress-mobile .step.active,
body.impress-mobile .step.present,
body.impress-mobile .step.next,
body.impress-mobile .step.prev { display: block; }
```

### resize

Automatic. Re-fits the presentation when the browser window changes size. No configuration.

### mouse-timeout

After 3 seconds of mouse inactivity, adds `body.impress-mouse-timeout`; removes it on the next move, click, or touch. Use it to hide UI (or the cursor itself) until the mouse moves:

```css
body.impress-mouse-timeout { cursor: none; }
body.impress-mouse-timeout div#impress-toolbar { display: none; }
```

### toolbar

A shared on-screen toolbar that other plugins (like navigation-ui) hang their widgets on. Enable it by adding:

```html
<div id="impress-toolbar"></div>
```

Style it yourself; `impress-common.css` includes a sample position (bottom-right). Combine with mouse-timeout to auto-hide it.

### form

Automatic. Improves the use of `<input>`, `<textarea>`, `<button>`, etc. inside slides: it stops keypresses in form fields from triggering navigation (so typing "P" in a text box won't open the console), and de-focuses fields when you leave a step.

> [!NOTE]
> The form plugin notes that <kbd>Tab</kbd> navigation *between* form fields is not currently possible, because the navigation plugin must fully control the Tab key. This is a known limitation flagged in the plugin itself.

### media

Auto play/pause/stop `<audio>` and `<video>` based on which step is showing. Set attributes on a step (inherited by media inside it) or on individual media elements:

| Attribute | Effect |
|---|---|
| `data-media-autoplay="true"` | Start the media when its step is entered |
| `data-media-autostop="true"` | Stop and reset media when leaving the step |
| `data-media-autopause="true"` | Pause (keep position) when leaving the step |

```html
<div class="step" data-media-autoplay="true" data-media-autopause="true">
    <video src="demo.mp4" controls></video>
</div>
```

The plugin also toggles body classes while media plays/pauses (e.g. `body.impress-media-video-playing`) so you can dim the background.

> [!TIP]
> To auto-advance when a clip finishes: `<video onended="impress().next()">`.

### extras

Automatically initializes any 3rd-party "extra add-ons" you've included (see the next section). If you haven't added any, it does nothing.

---

## 10. Extra Add-ons (Markdown, Mermaid, syntax highlighting)

Beyond the default plugins, impress.js can use **extra add-ons** — 3rd-party plugins collected in the separate [impress-extras](https://github.com/impress/impress-extras) repository. They are not part of impress.js core and are **not active by default**; you must include each one with its own `<script>` tag. The built-in `extras` plugin then auto-initializes them.

To get the extras when cloning:

```bash
git clone --recursive https://github.com/impress/impress.js.git
```

Typical add-ons and how you'd reference them:

```html
<head>
    <!-- e.g. syntax highlighting and diagram styling -->
    <link rel="stylesheet" href="../../extras/highlight/styles/github.css">
    <link rel="stylesheet" href="../../extras/mermaid/mermaid.forest.css">
</head>
```

The plugins README documents one extra-specific attribute: for the Markdown add-on you can choose a dialect with `data-markdown-dialect="..."`.

> [!NOTE]
> Because extras live in a submodule, a plain (non-`--recursive`) checkout will not include them. They're optional — your presentation works without any of them.

---

## 11. The JavaScript API

For most presentations you never write JavaScript beyond `impress().init()`. The API is there for custom controls, integrations, and programmatic navigation.

### `impress( [id] )`

A factory that returns the presentation's API object. Pass the root element's id; omit it to use the default `"impress"`.

```javascript
var api = impress();          // uses #impress
var api2 = impress("root");   // uses #root
```

### API methods

| Method | Description |
|---|---|
| `.init()` | Initialize and start the presentation. Call once. |
| `.next()` | Go to the next step (in document order). |
| `.prev()` | Go to the previous step. |
| `.goto(target [, duration])` | Go to a step by index (number), id (string), or element. Optional transition duration in ms. |
| `.tear()` | Reset the DOM to its pre-`init()` state ("unload" impress.js). |

```javascript
var api = impress();
api.init();
api.goto(7);          // by index
api.goto("overview"); // by id
api.next();
```

> [!NOTE]
> Only **one** impress.js instance per document is supported in practice.

### Events

impress.js fires custom DOM events on the root element. Listen with `addEventListener`.

| Event | Fired when |
|---|---|
| `impress:init` | The presentation has finished initializing. `event.detail.api` gives you the API. |
| `impress:stepenter` | A step has finished transitioning in. `event.target` is the step. |
| `impress:stepleave` | A step is being left. `event.detail.next` is the incoming step. |
| `impress:steprefresh` | A step is (re)drawn, e.g. after a resize. |

```javascript
var root = document.getElementById("impress");

root.addEventListener("impress:stepenter", function (event) {
    console.log("Entered step:", event.target.id);
});

root.addEventListener("impress:stepleave", function (event) {
    console.log("Leaving", event.target.id, "for", event.detail.next.id);
});

impress().init();
```

> [!TIP]
> The `impress:stepenter`/`impress:stepleave` events are the supported way to run your own code (analytics, animations, syncing) as the audience moves through the deck.

---

## 12. Common Tasks (recipes)

### Make a simple, PowerPoint-style linear deck

Use the **classic-slides** approach: lay steps out in a row and rely on the default next/prev navigation. The bundled `examples/classic-slides/` demo is a ready-made template.

```html
<div id="impress" data-width="1024" data-height="768" data-max-scale="1">
    <div class="step" data-x="0">Slide 1</div>
    <div class="step" data-x="1024">Slide 2</div>
    <div class="step" data-x="2048">Slide 3</div>
</div>
```

### Reveal bullets one at a time

See the [substep plugin](#substep) — add `class="substep"` to each bullet and supply show/hide CSS.

### Add speaker notes and use the presenter console

Add `<div class="notes">…</div>` inside steps, hide them with `.notes { display:none }`, and press <kbd>P</kbd> while presenting. See [impressConsole](#impressconsole).

### Auto-run a kiosk presentation

Enable [autoplay](#autoplay) on the root (`data-autoplay="10"`) and combine with the [stop](#stop) plugin if you don't want it to loop.

### Jump to any slide from a menu

Give steps ids and link to them; the navigation plugin intercepts `href="#step-id"` clicks:

```html
<a href="#summary">Skip to summary</a>
...
<div id="summary" class="step" data-x="...">...</div>
```

### Show a progress bar

Add the [progress](#progress) divs and (optionally) link `impress-common.css`.

### Reload a presentation after editing the DOM

Call `impress().tear()`, modify your steps, then `impress().init()` again. impress.js re-reads the `data-*` attributes on each transition, so you can also change coordinates dynamically and have them apply on the next `goto()`.

---

## 13. How It Works (concepts)

You don't need this section to use impress.js, but it clarifies the mental model.

**One canvas, many steps.** All your steps live on a single, boundless canvas. impress.js doesn't move the slides — it moves the *camera*. When you go to a step, impress.js computes the inverse of that step's position/rotation/scale and applies it to the canvas, so the chosen step ends up centered and upright in front of the viewer.

**Two animated elements.** impress.js wraps your steps in a `canvas` element inside the `root`. The `root` handles **scaling** (zoom), and the `canvas` handles **translation and rotation**. They animate with slightly different delays so zooming in/out looks natural.

**Window scaling.** Your `data-width`/`data-height` define a target size. impress.js measures the real window and scales everything to fit (bounded by `data-min-scale`/`data-max-scale`), which is why one deck looks right on a laptop and a projector.

**State as CSS classes.** Navigation is expressed as classes (`.future`/`.present`/`.past`/`.active`, `impress-on-*`) so all visual behavior is yours to define in CSS.

**Plugins via events.** Most plugins simply listen for `impress:init`, `impress:stepenter`, or `impress:stepleave` and use the public API. *Pre-init* plugins (like `rel`) run before init to rewrite attributes; *pre-stepleave* plugins (like `goto`, `skip`, `stop`, `substep`) run before a transition and can redirect or cancel it.

**The URL hash.** impress.js keeps the location hash in sync (`#/step-id`) so you can deep-link to and reload on a specific slide.

---

## 14. Troubleshooting

### Error: presentation shows the "browser doesn't support" fallback message

**Cause:** The browser lacks CSS 3D Transforms, CSS Transitions, the DataSet API, or the ClassList API — or you're viewing in a very old browser.
**Solution:** Use a current version of Chrome, Firefox, Safari, or Edge.
**Prevention:** Test on the exact browser/version you'll present with; present from your own laptop when possible.

### My slides are all stacked on top of each other

**Cause:** Steps have no positioning attributes, so they all sit at `0,0`.
**Solution:** Give each step distinct `data-x`/`data-y` (and optionally `data-z`, `data-rotate`, `data-scale`) values.
**Prevention:** Remember that quotes are required (`data-x="1000"`), since attribute values are strings.

### Nothing happens / `impress is not defined`

**Cause:** The `js/impress.js` script didn't load (wrong path or no network for the CDN), or `impress().init()` ran before the script loaded.
**Solution:** Check the script `src` path; use the local+CDN fallback snippet; ensure `impress().init()` runs **after** the impress.js `<script>` tag.
**Prevention:** Download a local copy if you might present without WiFi.

### My custom CSS on `.step` (size/transform) is ignored or breaks layout

**Cause:** impress.js controls `position`, `transform`, `width`, and `height` on step elements.
**Solution:** Wrap your content in a child `<div>` and style that instead of the `.step` div.
**Prevention:** Treat `.step` as a positioning container only; never set its transform/size directly.

### Percentage widths/heights don't work inside a step

**Cause:** Each step is wrapped in a zero-size box, so `%` units resolve to zero.
**Solution:** Use pixel values that match your `data-width`/`data-height` target.

### After upgrading, slide positions shifted

**Cause:** The `rel` plugin changed the default for missing `data-x`/`data-y`/`data-z` from `0` to "inherit from previous step."
**Solution:** Add explicit `data-z="0"` (and `data-x`/`data-y` as needed) to the affected steps, or remove the `rel` plugin.
**Prevention:** When authoring against a build that includes `rel`, set coordinates explicitly where you mean zero.

### Typing in a form field triggers navigation (e.g. opens the console)

**Cause:** Without the `form` plugin, keypresses in fields bubble up to the navigation/console plugins.
**Solution:** The default build already includes the `form` plugin; make sure you're using `js/impress.js`, not a custom build that omitted it.

### The presentation re-fits with a slight delay after resizing the window

**Cause:** The resize transition is set to a fixed duration.
**Solution:** This is expected behavior; the presentation re-scales after the window settles.

### Speaker notes appear on the actual slides

**Cause:** You added `<div class="notes">` but didn't hide it.
**Solution:** Add `.notes { display: none; }` to your CSS (the notes still show in the <kbd>P</kbd> console).

### 3D-positioned content isn't clickable

**Cause:** Elements pushed back on the Z axis can fall "behind" the body element in some browsers (notably Chrome).
**Solution:** Use the `pointer-events` workaround from `impress-common.css`, which makes everything except `#impress` non-clickable so clicks reach your steps.

### A rotated slide ends up in an unexpected orientation

**Cause:** Multiple-axis rotations are order-dependent and the default `xyz` order can't reach every pose.
**Solution:** Set `data-rotate-order` (e.g. `"zyx"`) on that step; see the `examples/3D-rotations/` demo.

---

## 15. FAQ

**Q: Do I need Node.js or npm to make a presentation?**
No. You only need a browser and a text editor. Node/npm are required solely if you want to *build* impress.js from source or run its tests.

**Q: Can I install it with `npm install impress.js`?**
Not currently — impress.js isn't published to npm. Download a release or use the jsDelivr CDN.

**Q: Which file do I include — `src/impress.js` or `js/impress.js`?**
`js/impress.js`. It's the generated bundle of the core plus all default plugins. `src/impress.js` is just the core, without plugins.

**Q: Do I have to use `impress-common.css`?**
No. impress.js generates the positioning CSS it needs. `impress-common.css` only adds sample styling for plugins like help, toolbar, and progress.

**Q: How many slides can a presentation have?**
There's no fixed limit. On low-powered/mobile devices, very 3D-heavy decks can get sluggish — the `mobile` plugin helps by hiding far-away slides.

**Q: Can I have more than one impress.js presentation on a single page?**
The code technically supports multiple roots, but in practice one instance per document is what's supported and recommended.

**Q: How do I deep-link to a specific slide?**
Give the step an `id` and link to `#/step-id` (or `#step-id`). The URL hash stays in sync as you navigate, so reloading returns to the same slide.

**Q: Can I auto-advance slides for a kiosk?**
Yes — use the `autoplay` plugin (`data-autoplay="N"` seconds), optionally with `?impress-autoplay=N` in the URL.

**Q: How do I add presenter notes?**
Put `<div class="notes">…</div>` inside a step, hide it with CSS, and press <kbd>P</kbd> to open the speaker console.

**Q: Will it work when embedded in a public web page?**
It can, but visitors on older/unsupported browsers may see only the fallback message. impress.js is designed primarily for presenting from your own (tested) browser.

**Q: Is there a visual editor?**
There's a sibling project, [Impressionist](https://github.com/henrikingo/impressionist), a 3D GUI editor for building impress.js presentations.

**Q: Where can I see a full-featured example?**
The repo's `index.html` is the official, heavily-commented demo. The `examples/` folder has more demos (classic-slides, cube, 3D-rotations, 3D-positions, 2D-navigation, markdown).

---

## 16. Reference

### Root element attributes

| Attribute | Default | Purpose |
|---|---|---|
| `data-width` | `1920` | Target screen width (px) |
| `data-height` | `1080` | Target screen height (px) |
| `data-max-scale` | `3` | Max scale factor |
| `data-min-scale` | `0` | Min scale factor |
| `data-perspective` | `1000` | 3D perspective (px); `0` disables 3D |
| `data-transition-duration` | `1000` | Default transition time (ms) |
| `data-autoplay` | — | Global auto-advance time (seconds), via autoplay plugin |

### Step element attributes (core)

| Attribute | Default | Purpose |
|---|---|---|
| `data-x` / `data-y` / `data-z` | `0` | Position of step center (px) |
| `data-scale` | `1` | Size multiplier |
| `data-rotate` / `data-rotate-z` | `0` | Z-axis rotation (deg) |
| `data-rotate-x` / `data-rotate-y` | `0` | X/Y-axis rotation (deg) |
| `data-rotate-order` | `xyz` | Rotation application order |
| `data-transition-duration` | inherits root | Per-step transition time (ms) |

### Plugin-specific step attributes & classes (selected)

| Attribute / class | Plugin | Purpose |
|---|---|---|
| `data-rel-x/y/z`, `data-rel-to`, `data-rel-rotate-*`, `data-rel-position`, `data-rel-reset` | rel | Relative positioning |
| `data-goto`, `data-goto-next`, `data-goto-prev`, `data-goto-key-list`, `data-goto-next-list` | goto | Out-link jumps |
| `data-bookmark-key-list` | bookmark | In-link hotkeys |
| `data-autoplay` | autoplay | Per-step auto-advance (seconds; `0` = off) |
| `data-substep-order` + `class="substep"` | substep | Ordered bullet reveals |
| `data-media-autoplay/autostop/autopause` | media | Per-step media control |
| `class="skip"` | skip | Skip in normal navigation |
| `class="stop"` | stop | Block next() past this step |
| `class="notes"` | impressConsole | Speaker notes |

### CSS classes impress.js applies

| Class | Applied to | Meaning |
|---|---|---|
| `.future` / `.present` / `.past` | steps | Visit state |
| `.active` | step | Currently centered step |
| `.impress-on-{id}` | `<body>` | Active step's id |
| `.impress-supported` / `.impress-not-supported` | `<body>` | Feature-support state |
| `.impress-enabled` / `.impress-disabled` | `<body>` | Init state |
| `.impress-mobile` | `<body>` | Mobile device detected (mobile plugin) |
| `.impress-mouse-timeout` | `<body>` | Mouse idle >3 s (mouse-timeout plugin) |
| `.substep` / `.substep-visible` / `.substep-active` | substep elements | Reveal state |

### Keyboard shortcuts

| Key | Action |
|---|---|
| Right / Down / Space / Tab / Page Down | Next |
| Left / Up / Page Up / Shift+Tab | Previous |
| H or ? | Toggle help |
| B or . | Blackout |
| F5 / Esc | Fullscreen / exit |
| P | Speaker console |

### JavaScript API

| Call | Purpose |
|---|---|
| `impress([id])` | Get the API for a root element |
| `.init()` | Start the presentation |
| `.next()` / `.prev()` | Navigate sequentially |
| `.goto(idx \| id \| el [, ms])` | Navigate to a specific step |
| `.tear()` | Reset the DOM |
| `impress.supported` | Boolean: browser support check |

### Events

`impress:init`, `impress:stepenter`, `impress:stepleave`, `impress:steprefresh` (all on the root element).

---

_Generated June 2026 from impress/impress.js at c9f6c67. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
