presently 0.14.0 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/context/animating-slides.md +266 -0
- data/context/getting-started.md +324 -0
- data/context/index.yaml +16 -0
- data/lib/presently/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -1
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de6eb2668cd67cd34eb8f02c51dce3bc3f823f71b8e553835d27c2476d3f793e
|
|
4
|
+
data.tar.gz: 37601886d71cc24f89510ed65d918dbb87bcd1de1d0c48718f96b15820790e23
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5d272168a8f3de208c69e56fb44083c2417987d5178afc6e021f9ae4c9c2ddd5985f3251637581e21aea109e9698778c147865baece48bd8a6cb7dd652c7c888
|
|
7
|
+
data.tar.gz: 1d30ea352a266fcf97def9fdba931adb9cec25933f74bebbac85ecb53e35ceaee46c2faebdcbde473bb853c2959e135a6a2b0b5309eaff91646a632f50ddc043
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Animating Slides
|
|
2
|
+
|
|
3
|
+
This guide explains how to animate content within slides using the `morph` transition and the slide scripting system.
|
|
4
|
+
|
|
5
|
+
## How Morph Works
|
|
6
|
+
|
|
7
|
+
The `morph` transition uses the browser's View Transitions API. When navigating between two slides, any element that has a `view-transition-name` style on both the old and new slide is matched — the browser captures its position and appearance in both states and animates between them.
|
|
8
|
+
|
|
9
|
+
Elements without a matching name crossfade. The slide background stays completely still (no container animation).
|
|
10
|
+
|
|
11
|
+
This is the mechanism that makes build sequences possible: the same element appears on consecutive slides with the same name, so it stays pinned in place while hidden elements appear around it.
|
|
12
|
+
|
|
13
|
+
## Slide Scripts
|
|
14
|
+
|
|
15
|
+
Any slide can include a JavaScript block at the end of its presenter notes section. The script runs in the browser immediately after the slide renders.
|
|
16
|
+
|
|
17
|
+
~~~ markdown
|
|
18
|
+
---
|
|
19
|
+
template: default
|
|
20
|
+
duration: 30
|
|
21
|
+
transition: morph
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
- First point
|
|
25
|
+
- Second point
|
|
26
|
+
- Third point
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
Your presenter notes here.
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
slide.find("li").show(1, {group: "bullet"})
|
|
34
|
+
```
|
|
35
|
+
~~~
|
|
36
|
+
|
|
37
|
+
The script receives a `slide` object — an instance of the `Slide` class from `slide.js` — scoped to the current slide's body.
|
|
38
|
+
|
|
39
|
+
If the script contains a syntax error or throws an exception, the error is logged to the browser console and the presentation continues unaffected.
|
|
40
|
+
|
|
41
|
+
## The Slide API
|
|
42
|
+
|
|
43
|
+
### `slide.find(selector)`
|
|
44
|
+
|
|
45
|
+
Queries elements within the slide body matching the given CSS selector. Returns a `SlideElements` collection. This is a pure query with no side effects.
|
|
46
|
+
|
|
47
|
+
``` javascript
|
|
48
|
+
slide.find("li") // all list items
|
|
49
|
+
slide.find("h2, li") // headings and list items in document order
|
|
50
|
+
slide.find(".callout") // elements with a specific class
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `elements.show(n, options)`
|
|
54
|
+
|
|
55
|
+
Shows the first `n` elements in the collection and hides the rest. Assigns `view-transition-name` to each element so the morph transition can match them across consecutive slides. Returns a `Promise` that resolves when any reveal animation completes.
|
|
56
|
+
|
|
57
|
+
``` javascript
|
|
58
|
+
slide.find("li").show(0) // all hidden
|
|
59
|
+
slide.find("li").show(1) // first visible, rest hidden
|
|
60
|
+
slide.find("li").show(3) // first three visible, rest hidden
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Options:
|
|
64
|
+
|
|
65
|
+
| Option | Description |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `group` | Name prefix for `view-transition-name` — must be consistent across slides for morph to match elements. Defaults to `"build"`. |
|
|
68
|
+
| `effect` | Entry animation for the newly revealed element. See effects below. |
|
|
69
|
+
|
|
70
|
+
### `elements.builder(options)`
|
|
71
|
+
|
|
72
|
+
Creates a `SlideBuilder` with default options and a cached position. Use this instead of calling `show()` manually when you want to reveal elements one at a time from a script.
|
|
73
|
+
|
|
74
|
+
``` javascript
|
|
75
|
+
const bullets = slide.find("li").builder({group: "bullet", effect: "fly-up"})
|
|
76
|
+
bullets.show(0) // hide all initially
|
|
77
|
+
bullets.next() // reveal first, plays fly-up
|
|
78
|
+
bullets.next() // reveal second, plays fly-up
|
|
79
|
+
bullets.finished // true when all revealed
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `SlideBuilder#next(overrides)`
|
|
83
|
+
|
|
84
|
+
Reveals the next element using the builder's default effect. Only touches the single newly revealed element — O(1). Returns a `Promise`. Accepts optional overrides for this step.
|
|
85
|
+
|
|
86
|
+
### `SlideBuilder#show(n, overrides)`
|
|
87
|
+
|
|
88
|
+
Sets the builder to an arbitrary position. Useful for initialization and jumping. Iterates all elements for correctness.
|
|
89
|
+
|
|
90
|
+
### `SlideBuilder#play(interval, callback)`
|
|
91
|
+
|
|
92
|
+
Reveals all remaining elements in sequence, with `interval` milliseconds between each step. An optional callback is invoked after each `next()` — return `false` to stop playback early. Requires the builder to be created via `slide.find(...).builder()` so that timeouts are tracked and cancelled when the slide changes.
|
|
93
|
+
|
|
94
|
+
``` javascript
|
|
95
|
+
// Play all elements at 400ms intervals:
|
|
96
|
+
boxes.play(400)
|
|
97
|
+
|
|
98
|
+
// Stop early based on a condition:
|
|
99
|
+
boxes.play(400, () => !paused)
|
|
100
|
+
|
|
101
|
+
// Inspect the builder after each step:
|
|
102
|
+
boxes.play(400, (builder) => !builder.finished)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `SlideBuilder#finished`
|
|
106
|
+
|
|
107
|
+
Returns `true` when all elements have been revealed.
|
|
108
|
+
|
|
109
|
+
## Build Sequences
|
|
110
|
+
|
|
111
|
+
A build sequence is a series of consecutive slides with the same content, each revealing one more element. Because the slides are real files, each has its own duration and presenter notes — you can write exactly what to say when each element appears.
|
|
112
|
+
|
|
113
|
+
~~~ markdown
|
|
114
|
+
<!-- 030-overview.md -->
|
|
115
|
+
---
|
|
116
|
+
template: default
|
|
117
|
+
duration: 20
|
|
118
|
+
transition: morph
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
- Real-time synchronization
|
|
122
|
+
- Markdown-based slides
|
|
123
|
+
- Multiple templates
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
Let's walk through the key features.
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
slide.find("li").show(0, {group: "bullet"})
|
|
131
|
+
```
|
|
132
|
+
~~~
|
|
133
|
+
|
|
134
|
+
~~~ markdown
|
|
135
|
+
<!-- 031-overview.md -->
|
|
136
|
+
---
|
|
137
|
+
template: default
|
|
138
|
+
duration: 20
|
|
139
|
+
transition: morph
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
- Real-time synchronization
|
|
143
|
+
- Markdown-based slides
|
|
144
|
+
- Multiple templates
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
The display and presenter stay in sync over a WebSocket connection.
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
slide.find("li").show(1, {group: "bullet"})
|
|
152
|
+
```
|
|
153
|
+
~~~
|
|
154
|
+
|
|
155
|
+
The `group` option must be identical across all slides in the sequence so the browser matches the same elements. Without it, each slide uses the default `"build"` prefix — which is fine as long as only one build sequence is active per slide.
|
|
156
|
+
|
|
157
|
+
Because all elements are in the DOM from the start (just hidden), the vertical layout stays consistent throughout the sequence — there is no shift as elements appear.
|
|
158
|
+
|
|
159
|
+
## Build Effects
|
|
160
|
+
|
|
161
|
+
Pass an `effect` option to animate the newly revealed element as it appears. The effect plays as a CSS animation on the element and is removed automatically once it completes.
|
|
162
|
+
|
|
163
|
+
``` javascript
|
|
164
|
+
slide.find("li").show(2, {group: "bullet", effect: "fly-up"})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Available effects:
|
|
168
|
+
|
|
169
|
+
| Effect | Animation |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `fade` | Fades in |
|
|
172
|
+
| `fly-left` | Slides in from the left |
|
|
173
|
+
| `fly-right` | Slides in from the right |
|
|
174
|
+
| `fly-up` | Rises in from below |
|
|
175
|
+
| `fly-down` | Drops in from above |
|
|
176
|
+
| `scale` | Scales up from 80% |
|
|
177
|
+
|
|
178
|
+
## Multiple Build Groups
|
|
179
|
+
|
|
180
|
+
A slide can have multiple independent build groups. Each `find().show()` call is self-contained:
|
|
181
|
+
|
|
182
|
+
``` javascript
|
|
183
|
+
// Reveal list items as one group, callout div as another
|
|
184
|
+
slide.find("li").show(3, {group: "bullet"})
|
|
185
|
+
slide.find(".callout").show(1, {group: "callout", effect: "fly-up"})
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## In-Slide Animation with `slide.after()`
|
|
189
|
+
|
|
190
|
+
For sequential reveals within a single slide (without navigating to the next slide), use `slide.after()`. Each step fires a delay in milliseconds relative to the previous step. Returns a `SlideContext` so subsequent `.after()` calls chain naturally.
|
|
191
|
+
|
|
192
|
+
``` javascript
|
|
193
|
+
const panes = slide.find(".pane").builder({group: "pane", effect: "fade"})
|
|
194
|
+
const items = slide.find(".item").builder({group: "item", effect: "fly-up"})
|
|
195
|
+
panes.show(0)
|
|
196
|
+
items.show(0)
|
|
197
|
+
|
|
198
|
+
slide
|
|
199
|
+
.after(400, () => panes.next())
|
|
200
|
+
.after(400, () => items.next())
|
|
201
|
+
.after(300, () => items.next())
|
|
202
|
+
.after(400, () => panes.next())
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
All timeouts registered via `slide.after()` (and the underlying `slide.setTimeout()`) are automatically cancelled when the user navigates to another slide, so stale callbacks never fire.
|
|
206
|
+
|
|
207
|
+
The global `setTimeout` in slide scripts is also automatically tracked — you can use it directly and it will be cancelled on slide change.
|
|
208
|
+
|
|
209
|
+
## Looping Animations with `slide.loop()`
|
|
210
|
+
|
|
211
|
+
To repeat an animation indefinitely, use `slide.loop()`. The callback receives a fresh `SlideContext` each iteration and can use `after()` to schedule steps in the same way as a regular chain. The loop waits for all steps to complete and then restarts, with an optional extra pause between iterations.
|
|
212
|
+
|
|
213
|
+
``` javascript
|
|
214
|
+
const steps = slide.find(".step").builder({effect: "fly-up"})
|
|
215
|
+
steps.show(0)
|
|
216
|
+
|
|
217
|
+
slide.loop((context) => {
|
|
218
|
+
steps.show(0) // reset at the start of each iteration
|
|
219
|
+
context
|
|
220
|
+
.after(800, () => steps.next())
|
|
221
|
+
.after(800, () => steps.next())
|
|
222
|
+
.after(800, () => steps.next())
|
|
223
|
+
}, { delay: 1500 })
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The `delay` option adds extra time after the last step before the next iteration begins — useful for giving the audience a moment to read the fully-revealed state before it resets.
|
|
227
|
+
|
|
228
|
+
The callback is responsible for resetting any state (such as calling `builder.show(0)`) at the start of each iteration. This keeps the loop body self-contained and makes the reset timing explicit.
|
|
229
|
+
|
|
230
|
+
All timeouts are tracked through the parent slide, so the loop stops automatically when the user navigates away — no cleanup needed.
|
|
231
|
+
|
|
232
|
+
## Absolutely Positioned Elements
|
|
233
|
+
|
|
234
|
+
All slide templates support absolutely positioned elements since the slide container is `position: relative`. You can overlay any element on top of normal slide content:
|
|
235
|
+
|
|
236
|
+
~~~ markdown
|
|
237
|
+
<div style="position: absolute; bottom: 2rem; right: 2rem; background: var(--accent); color: white; padding: 0.5rem 1rem; border-radius: 6px;">
|
|
238
|
+
Callout text
|
|
239
|
+
</div>
|
|
240
|
+
~~~
|
|
241
|
+
|
|
242
|
+
In the `diagram` template, all direct `<div>` children are `position: absolute` by default, so you can build free-form layouts without repeating the positioning declaration:
|
|
243
|
+
|
|
244
|
+
~~~ markdown
|
|
245
|
+
---
|
|
246
|
+
template: diagram
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
<div style="left: 10%; top: 20%; width: 35%; height: 30%; background: var(--surface-light);">
|
|
250
|
+
Node A
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<div style="left: 55%; top: 20%; width: 35%; height: 30%; background: var(--surface-light);">
|
|
254
|
+
Node B
|
|
255
|
+
</div>
|
|
256
|
+
~~~
|
|
257
|
+
|
|
258
|
+
Combine with the scripting system to animate diagram elements into place:
|
|
259
|
+
|
|
260
|
+
``` javascript
|
|
261
|
+
const nodes = slide.find("div").builder({group: "node", effect: "fade"})
|
|
262
|
+
nodes.show(0)
|
|
263
|
+
slide
|
|
264
|
+
.after(400, () => nodes.next())
|
|
265
|
+
.after(400, () => nodes.next())
|
|
266
|
+
```
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide explains how to use `presently` to create and deliver web-based presentations using Markdown slides.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add the gem to your project:
|
|
8
|
+
|
|
9
|
+
``` bash
|
|
10
|
+
$ gem install presently
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Core Concepts
|
|
14
|
+
|
|
15
|
+
Presently has several core concepts:
|
|
16
|
+
|
|
17
|
+
- A {ruby Presently::Presentation} which loads and manages slide content from Markdown files.
|
|
18
|
+
- A {ruby Presently::PresentationController} which manages the mutable state of a presentation: current slide, clock, and listeners.
|
|
19
|
+
- A {ruby Presently::Slide} which represents a single slide parsed from a Markdown file with YAML frontmatter.
|
|
20
|
+
- A {ruby Presently::DisplayView} which renders the audience-facing full-screen display.
|
|
21
|
+
- A {ruby Presently::PresenterView} which renders the presenter console with notes, timing, and slide previews.
|
|
22
|
+
|
|
23
|
+
## Creating Your First Presentation
|
|
24
|
+
|
|
25
|
+
Create a new directory for your presentation:
|
|
26
|
+
|
|
27
|
+
``` bash
|
|
28
|
+
$ mkdir my-talk
|
|
29
|
+
$ cd my-talk
|
|
30
|
+
$ mkdir slides
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Writing Slides
|
|
34
|
+
|
|
35
|
+
Each slide is a Markdown file in the `slides/` directory. Files are ordered alphabetically, so prefix them with numbers:
|
|
36
|
+
|
|
37
|
+
``` markdown
|
|
38
|
+
---
|
|
39
|
+
template: title
|
|
40
|
+
duration: 30
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
# Title
|
|
44
|
+
|
|
45
|
+
Welcome to My Talk
|
|
46
|
+
|
|
47
|
+
# Subtitle
|
|
48
|
+
|
|
49
|
+
A presentation built with Presently
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
These are presenter notes — only visible in the presenter view.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Each slide has three parts:
|
|
57
|
+
|
|
58
|
+
1. **YAML frontmatter** between `---` markers at the top, specifying the template, duration, and other metadata.
|
|
59
|
+
2. **Content** with Markdown headings that become named sections for the template.
|
|
60
|
+
3. **Presenter notes** after a `---` separator in the body (optional).
|
|
61
|
+
|
|
62
|
+
### Running the Presentation
|
|
63
|
+
|
|
64
|
+
Start the server from your presentation directory:
|
|
65
|
+
|
|
66
|
+
``` bash
|
|
67
|
+
$ presently
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Then open two browser windows:
|
|
71
|
+
|
|
72
|
+
- `http://localhost:9292/` — the audience display.
|
|
73
|
+
- `http://localhost:9292/presenter` — the presenter console.
|
|
74
|
+
|
|
75
|
+
Advancing slides in either window updates both in real-time via WebSockets.
|
|
76
|
+
|
|
77
|
+
### Keyboard Controls
|
|
78
|
+
|
|
79
|
+
- **Arrow Right / Space / Page Down** — next slide.
|
|
80
|
+
- **Arrow Left / Page Up** — previous slide.
|
|
81
|
+
- **F** — toggle full-screen (display view).
|
|
82
|
+
|
|
83
|
+
## Templates
|
|
84
|
+
|
|
85
|
+
Templates define the visual layout of each slide. Select a template using the `template` field in the frontmatter.
|
|
86
|
+
|
|
87
|
+
### Default
|
|
88
|
+
|
|
89
|
+
A general-purpose content slide. All content without a heading goes into the `body` section.
|
|
90
|
+
|
|
91
|
+
``` markdown
|
|
92
|
+
---
|
|
93
|
+
template: default
|
|
94
|
+
duration: 60
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
- First point
|
|
98
|
+
- Second point
|
|
99
|
+
- Third point
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Title
|
|
103
|
+
|
|
104
|
+
A large title with a subtitle, centered on the slide.
|
|
105
|
+
|
|
106
|
+
``` markdown
|
|
107
|
+
---
|
|
108
|
+
template: title
|
|
109
|
+
duration: 30
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
# Title
|
|
113
|
+
|
|
114
|
+
My Presentation Title
|
|
115
|
+
|
|
116
|
+
# Subtitle
|
|
117
|
+
|
|
118
|
+
A subtitle or tagline
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Section
|
|
122
|
+
|
|
123
|
+
A section divider slide with a large heading and accent background.
|
|
124
|
+
|
|
125
|
+
``` markdown
|
|
126
|
+
---
|
|
127
|
+
template: section
|
|
128
|
+
duration: 15
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
# Heading
|
|
132
|
+
|
|
133
|
+
Part Two
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Two Column
|
|
137
|
+
|
|
138
|
+
A side-by-side layout with `left` and `right` sections.
|
|
139
|
+
|
|
140
|
+
``` markdown
|
|
141
|
+
---
|
|
142
|
+
template: two_column
|
|
143
|
+
duration: 90
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
# Left
|
|
147
|
+
|
|
148
|
+
**Server Side**
|
|
149
|
+
|
|
150
|
+
- Ruby + Lively
|
|
151
|
+
- WebSocket connections
|
|
152
|
+
|
|
153
|
+
# Right
|
|
154
|
+
|
|
155
|
+
**Client Side**
|
|
156
|
+
|
|
157
|
+
- Live DOM updates
|
|
158
|
+
- CSS animations
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Code
|
|
162
|
+
|
|
163
|
+
A syntax-highlighted code slide with optional focus regions for code walkthroughs. Use the `focus` frontmatter to specify which lines to highlight (1-based). Lines outside the focus range are dimmed, and the code scrolls to center the focused region.
|
|
164
|
+
|
|
165
|
+
``` markdown
|
|
166
|
+
---
|
|
167
|
+
template: code
|
|
168
|
+
duration: 60
|
|
169
|
+
focus: 2-8
|
|
170
|
+
title: Constructor
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
class Presentation
|
|
175
|
+
def initialize
|
|
176
|
+
@slides = []
|
|
177
|
+
@current_index = 0
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def advance!
|
|
181
|
+
@current_index += 1
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
```
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Create animated walkthroughs by using multiple slides with the same code but different `focus` ranges. The transition between them smoothly scrolls and shifts the dim overlays.
|
|
188
|
+
|
|
189
|
+
### Statement
|
|
190
|
+
|
|
191
|
+
A prominent statement or quote, centered on the slide. Supports an optional `# Translation` section.
|
|
192
|
+
|
|
193
|
+
``` markdown
|
|
194
|
+
---
|
|
195
|
+
template: statement
|
|
196
|
+
duration: 30
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
The best way to predict the future is to create it.
|
|
200
|
+
|
|
201
|
+
# Translation
|
|
202
|
+
|
|
203
|
+
未来を予測する最善の方法は、それを創ることである。
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Translations
|
|
207
|
+
|
|
208
|
+
All templates support an optional `# Translation` section. When present, the translation is displayed below the main content in a lighter style. This works with `title`, `section`, `statement`, and `image` templates.
|
|
209
|
+
|
|
210
|
+
### Image
|
|
211
|
+
|
|
212
|
+
A centered image with an optional caption.
|
|
213
|
+
|
|
214
|
+
``` markdown
|
|
215
|
+
---
|
|
216
|
+
template: image
|
|
217
|
+
duration: 30
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+

|
|
221
|
+
|
|
222
|
+
# Caption
|
|
223
|
+
|
|
224
|
+
System architecture overview
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Diagram
|
|
228
|
+
|
|
229
|
+
A free-form layout slide with a `position: relative` container. Direct `<div>` children are `position: absolute` by default, so you can place elements precisely using inline styles. Use this for custom diagrams, annotated layouts, or any slide that doesn't fit a standard template.
|
|
230
|
+
|
|
231
|
+
``` markdown
|
|
232
|
+
---
|
|
233
|
+
template: diagram
|
|
234
|
+
duration: 60
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
<div style="left: 10%; top: 20%; width: 35%; height: 25%;">
|
|
238
|
+
Browser
|
|
239
|
+
</div>
|
|
240
|
+
|
|
241
|
+
<div style="left: 55%; top: 20%; width: 35%; height: 25%;">
|
|
242
|
+
Server
|
|
243
|
+
</div>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
All other templates also support absolutely positioned overlays since the slide container is `position: relative`. This lets you add callouts, badges, or annotations on top of any template's normal content.
|
|
247
|
+
|
|
248
|
+
## Transitions
|
|
249
|
+
|
|
250
|
+
Slides transition instantly by default. Add a `transition` key to the frontmatter to animate between slides:
|
|
251
|
+
|
|
252
|
+
``` markdown
|
|
253
|
+
---
|
|
254
|
+
template: default
|
|
255
|
+
transition: fade
|
|
256
|
+
---
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Available transitions:
|
|
260
|
+
|
|
261
|
+
| Transition | Effect |
|
|
262
|
+
|---|---|
|
|
263
|
+
| `fade` | Crossfade between slides |
|
|
264
|
+
| `slide-left` | Current slide exits left, next enters from right |
|
|
265
|
+
| `slide-right` | Current slide exits right, next enters from left |
|
|
266
|
+
| `morph` | Matched elements animate between positions; everything else crossfades |
|
|
267
|
+
|
|
268
|
+
The `morph` transition uses the browser's View Transitions API to smoothly animate individual elements between slides. Elements with the same `view-transition-name` across two consecutive slides are matched and interpolated.
|
|
269
|
+
|
|
270
|
+
## Presenter Notes
|
|
271
|
+
|
|
272
|
+
Presenter notes appear after a `---` separator in the slide body. They support standard Markdown including **bold** and *italic*. Italic text is styled as a stage direction — use it for cues that shouldn't be spoken aloud:
|
|
273
|
+
|
|
274
|
+
``` markdown
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
*Take a breath and wait for the room to settle.*
|
|
278
|
+
|
|
279
|
+
Hi everyone, thanks for being here.
|
|
280
|
+
|
|
281
|
+
*Make eye contact with the front row.*
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Presenter Console
|
|
285
|
+
|
|
286
|
+
The presenter view at `/presenter` provides:
|
|
287
|
+
|
|
288
|
+
- **Current and next slide previews** — see what's coming without switching windows.
|
|
289
|
+
- **Presenter notes** — notes from the slide's `---` separator section.
|
|
290
|
+
- **Timer controls** — Start, Pause, Resume, and Reset buttons.
|
|
291
|
+
- **Pacing indicator** — shows whether you're on time, ahead, or behind based on per-slide `duration` metadata.
|
|
292
|
+
- **Progress bar** — visual indicator of time consumed for the current slide.
|
|
293
|
+
- **Reload button** — reload slides from disk without restarting the server.
|
|
294
|
+
|
|
295
|
+
## Custom Templates
|
|
296
|
+
|
|
297
|
+
You can provide your own `.xrb` template files by configuring the templates root:
|
|
298
|
+
|
|
299
|
+
``` ruby
|
|
300
|
+
# In your environment configuration:
|
|
301
|
+
service "presently" do
|
|
302
|
+
include Presently::Environment::Application
|
|
303
|
+
|
|
304
|
+
def templates_root
|
|
305
|
+
File.expand_path("templates", self.root)
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Templates receive a {ruby Presently::TemplateScope} with access to `self.slide` (the {ruby Presently::Slide} instance) and `self.section(name)` for retrieving named content sections.
|
|
311
|
+
|
|
312
|
+
## Customizing the Application
|
|
313
|
+
|
|
314
|
+
For advanced customization, create an `application.rb` and run with `presently application.rb`:
|
|
315
|
+
|
|
316
|
+
``` ruby
|
|
317
|
+
#!/usr/bin/env presently
|
|
318
|
+
|
|
319
|
+
class Application < Presently::Application
|
|
320
|
+
def title
|
|
321
|
+
"My Conference Talk"
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
```
|
data/context/index.yaml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Automatically generated context index for Utopia::Project guides.
|
|
2
|
+
# Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
|
|
3
|
+
---
|
|
4
|
+
description: A web-based presentation tool built with Lively.
|
|
5
|
+
metadata:
|
|
6
|
+
documentation_uri: https://socketry.github.io/presently/
|
|
7
|
+
source_code_uri: https://github.com/socketry/presently.git
|
|
8
|
+
files:
|
|
9
|
+
- path: getting-started.md
|
|
10
|
+
title: Getting Started
|
|
11
|
+
description: This guide explains how to use `presently` to create and deliver web-based
|
|
12
|
+
presentations using Markdown slides.
|
|
13
|
+
- path: animating-slides.md
|
|
14
|
+
title: Animating Slides
|
|
15
|
+
description: This guide explains how to animate content within slides using the
|
|
16
|
+
`morph` transition and the slide scripting system.
|
data/lib/presently/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: presently
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.14.
|
|
4
|
+
version: 0.14.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -90,6 +90,9 @@ files:
|
|
|
90
90
|
- bake/presently/rehearse.rb
|
|
91
91
|
- bake/presently/slides.rb
|
|
92
92
|
- bin/presently
|
|
93
|
+
- context/animating-slides.md
|
|
94
|
+
- context/getting-started.md
|
|
95
|
+
- context/index.yaml
|
|
93
96
|
- lib/presently.rb
|
|
94
97
|
- lib/presently/application.rb
|
|
95
98
|
- lib/presently/clock.rb
|
metadata.gz.sig
CHANGED
|
Binary file
|