presently 0.25.1 → 0.26.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/getting-started.md +30 -192
- data/context/index.yaml +4 -0
- data/context/templates.md +207 -0
- data/lib/presently/presentation_controller.rb +33 -7
- data/lib/presently/presenter_view.rb +15 -13
- data/lib/presently/recorder_view.rb +1 -1
- data/lib/presently/slide.rb +16 -2
- data/lib/presently/version.rb +1 -1
- data/readme.md +9 -5
- data/releases.md +7 -0
- data.tar.gz.sig +0 -0
- metadata +2 -1
- metadata.gz.sig +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fc69b4f81a2143dbbccc8d591c1fb675bb447057b77ffde4420f1ad1d7b3819a
|
|
4
|
+
data.tar.gz: b49c223f245c7949d72d8510d41d59f3e43efd6eb33b22bfe931bc84c0e1473d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '00686d6b384cdbbd81b27cc96e33e5301222c4b14a54c18f9221c2795f2b1eb0175ca4fbfc8caf10c3f2bb463df7ea85ba169b76b9b9e7c75049b419663b8be6'
|
|
7
|
+
data.tar.gz: d5348d5212bdde155fd4dcd7ea284606ff893716144fa8b04f202f3c18f0f18688431fe7ca59320c32c521baab047419b80170e31950fc57fe9dbcbaa545f95f
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/context/getting-started.md
CHANGED
|
@@ -188,173 +188,9 @@ The defaults are 1920×1080 at up to 30 frames per second. The exporter starts a
|
|
|
188
188
|
|
|
189
189
|
## Templates
|
|
190
190
|
|
|
191
|
-
Templates define the visual layout of each slide. Select
|
|
191
|
+
Templates define the visual layout of each slide. Select one with the `template` field in the frontmatter; slides without it use `default`. Common choices include `title` for an opening slide, `two_column` for comparisons, and `code` for code walkthroughs.
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
A general-purpose content slide. An H1 becomes the slide title and the remaining document becomes its body.
|
|
196
|
-
|
|
197
|
-
``` markdown
|
|
198
|
-
---
|
|
199
|
-
template: default
|
|
200
|
-
duration: 60
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
# Key points
|
|
204
|
-
|
|
205
|
-
- First point
|
|
206
|
-
- Second point
|
|
207
|
-
- Third point
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Title
|
|
211
|
-
|
|
212
|
-
A large title with a short body, centered on the slide.
|
|
213
|
-
|
|
214
|
-
``` markdown
|
|
215
|
-
---
|
|
216
|
-
template: title
|
|
217
|
-
duration: 30
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
# My Presentation Title
|
|
221
|
-
|
|
222
|
-
A subtitle or tagline
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Section
|
|
226
|
-
|
|
227
|
-
A section divider slide with a large heading, optional supporting body, and accent background.
|
|
228
|
-
|
|
229
|
-
``` markdown
|
|
230
|
-
---
|
|
231
|
-
template: section
|
|
232
|
-
duration: 15
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
# Part Two
|
|
236
|
-
|
|
237
|
-
Architecture and design
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Two Column
|
|
241
|
-
|
|
242
|
-
A side-by-side layout with `left` and `right` sections.
|
|
243
|
-
|
|
244
|
-
``` markdown
|
|
245
|
-
---
|
|
246
|
-
template: two_column
|
|
247
|
-
duration: 90
|
|
248
|
-
---
|
|
249
|
-
|
|
250
|
-
# Client and server responsibilities
|
|
251
|
-
|
|
252
|
-
The application is split across two cooperating environments.
|
|
253
|
-
|
|
254
|
-
## Left
|
|
255
|
-
|
|
256
|
-
**Server Side**
|
|
257
|
-
|
|
258
|
-
- Ruby + Lively
|
|
259
|
-
- WebSocket connections
|
|
260
|
-
|
|
261
|
-
## Right
|
|
262
|
-
|
|
263
|
-
**Client Side**
|
|
264
|
-
|
|
265
|
-
- Live DOM updates
|
|
266
|
-
- CSS animations
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Code
|
|
270
|
-
|
|
271
|
-
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.
|
|
272
|
-
|
|
273
|
-
``` markdown
|
|
274
|
-
---
|
|
275
|
-
template: code
|
|
276
|
-
duration: 60
|
|
277
|
-
focus: 2-8
|
|
278
|
-
---
|
|
279
|
-
|
|
280
|
-
# Constructor
|
|
281
|
-
|
|
282
|
-
```ruby
|
|
283
|
-
class Presentation
|
|
284
|
-
def initialize
|
|
285
|
-
@slides = []
|
|
286
|
-
@current_index = 0
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
def advance!
|
|
290
|
-
@current_index += 1
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
```
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
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.
|
|
297
|
-
|
|
298
|
-
### Statement
|
|
299
|
-
|
|
300
|
-
A prominent statement or quote, centered on the slide. Supports an optional `## Translation` placeholder.
|
|
301
|
-
|
|
302
|
-
``` markdown
|
|
303
|
-
---
|
|
304
|
-
template: statement
|
|
305
|
-
duration: 30
|
|
306
|
-
---
|
|
307
|
-
|
|
308
|
-
The best way to predict the future is to create it.
|
|
309
|
-
|
|
310
|
-
## Translation
|
|
311
|
-
|
|
312
|
-
未来を予測する最善の方法は、それを創ることである。
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### Translations
|
|
316
|
-
|
|
317
|
-
Templates can extract an optional `## Translation` section and position it independently from the main document. Every standard template displays it separately in a lighter style.
|
|
318
|
-
|
|
319
|
-
### Image
|
|
320
|
-
|
|
321
|
-
A centered image with an optional caption.
|
|
322
|
-
|
|
323
|
-
``` markdown
|
|
324
|
-
---
|
|
325
|
-
template: image
|
|
326
|
-
duration: 30
|
|
327
|
-
---
|
|
328
|
-
|
|
329
|
-

|
|
330
|
-
|
|
331
|
-
## Caption
|
|
332
|
-
|
|
333
|
-
System architecture overview
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
### Diagram
|
|
337
|
-
|
|
338
|
-
A centered canvas for diagrams and other custom visual layouts, with an optional title. A single grid or flex container is usually enough to create a diagram that remains centered as the slide scales:
|
|
339
|
-
|
|
340
|
-
``` markdown
|
|
341
|
-
---
|
|
342
|
-
template: diagram
|
|
343
|
-
duration: 60
|
|
344
|
-
---
|
|
345
|
-
|
|
346
|
-
# Request lifecycle
|
|
347
|
-
|
|
348
|
-
<div style="display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 2em; width: 80%;">
|
|
349
|
-
<div>Browser</div>
|
|
350
|
-
<div>→</div>
|
|
351
|
-
<div>Server</div>
|
|
352
|
-
</div>
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
For coordinate-based layouts, wrap the elements in `<div class="diagram-freeform">`. The wrapper fills the canvas and absolutely positions each direct child.
|
|
356
|
-
|
|
357
|
-
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.
|
|
193
|
+
See the [Templates guide](../templates/index) for built-in layouts, examples, translations, and custom templates.
|
|
358
194
|
|
|
359
195
|
## Transitions
|
|
360
196
|
|
|
@@ -400,35 +236,37 @@ The presenter view at `/presenter` provides:
|
|
|
400
236
|
- **Progress bar** — visual indicator of time consumed for the current slide.
|
|
401
237
|
- **Reload button** — reload slides from disk without restarting the server.
|
|
402
238
|
|
|
403
|
-
|
|
239
|
+
### Starting the Timer from a Title Slide
|
|
404
240
|
|
|
405
|
-
|
|
241
|
+
A title slide can stay on screen while the audience settles. Add `timer: start` to its frontmatter to start the presentation timer when you advance to the next slide:
|
|
406
242
|
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
243
|
+
``` markdown
|
|
244
|
+
---
|
|
245
|
+
template: title
|
|
246
|
+
duration: 0
|
|
247
|
+
timer: start
|
|
248
|
+
---
|
|
411
249
|
|
|
412
|
-
|
|
413
|
-
File.expand_path("templates", self.root)
|
|
414
|
-
end
|
|
415
|
-
end
|
|
416
|
-
```
|
|
250
|
+
# My Presentation
|
|
417
251
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
``` xrb
|
|
421
|
-
<?r translation = self.extract("Translation") ?>
|
|
422
|
-
#{self.slide_header}
|
|
423
|
-
<div class="slide-body">
|
|
424
|
-
#{self.document}
|
|
425
|
-
</div>
|
|
426
|
-
<?r if translation ?>
|
|
427
|
-
<div class="slide-translation">#{translation}</div>
|
|
428
|
-
<?r end ?>
|
|
252
|
+
We'll begin shortly.
|
|
429
253
|
```
|
|
430
254
|
|
|
431
|
-
|
|
255
|
+
The timer stays stopped while the title is displayed. Advancing from it in `/presenter` or `/display` starts the timer before showing the next slide. Setting `duration: 0` excludes the waiting slide from the expected presentation duration and pacing calculations. The `title` template itself does not control the timer.
|
|
256
|
+
|
|
257
|
+
Durations are read as floating-point seconds, including numeric strings. Negative, invalid, or non-finite values are treated as `0.0`. An unspecified or null duration defaults to `0.0` seconds, meaning no time has been allocated to that slide. Set explicit durations, or apply recorded narration durations, to establish a pacing schedule. When the total allocated duration is zero, the presenter shows elapsed time without pacing indicators, a progress bar, or a remaining-time estimate.
|
|
258
|
+
|
|
259
|
+
The `timer` field supports these actions:
|
|
260
|
+
|
|
261
|
+
| Value | Effect when advancing from this slide |
|
|
262
|
+
|---|---|
|
|
263
|
+
| `start` | Starts the timer only if it has never started. Revisiting the slide does not reset elapsed time or resume a manually paused timer. |
|
|
264
|
+
| `pause` | Pauses the timer, preserving elapsed time. Has no effect before the timer starts. |
|
|
265
|
+
| `resume` | Resumes a started timer, preserving elapsed time. Has no effect before the timer starts or while it is already running. |
|
|
266
|
+
|
|
267
|
+
For a break, put `timer: pause` on the slide immediately before the break slide, and `timer: resume` on the break slide itself. Give the break slide `duration: 0` to exclude the break from pacing calculations. Advancing into the break pauses timing; advancing out resumes it.
|
|
268
|
+
|
|
269
|
+
Timer actions run only when **Next** successfully moves to another slide. Going backwards, jumping directly to a slide, reloading, reconnecting, and restoring saved state do not trigger them. Neither does navigation in `/record`, or recorded playback. Slides without a recognized timer action leave the timer unchanged; the manual timer controls remain available.
|
|
432
270
|
|
|
433
271
|
## Customizing the Application
|
|
434
272
|
|
|
@@ -438,8 +276,8 @@ For advanced customization, create an `application.rb` and run with `presently a
|
|
|
438
276
|
#!/usr/bin/env presently
|
|
439
277
|
|
|
440
278
|
class Application < Presently::Application
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
279
|
+
def title
|
|
280
|
+
"My Conference Talk"
|
|
281
|
+
end
|
|
444
282
|
end
|
|
445
283
|
```
|
data/context/index.yaml
CHANGED
|
@@ -10,6 +10,10 @@ files:
|
|
|
10
10
|
title: Getting Started
|
|
11
11
|
description: This guide explains how to use `presently` to create and deliver web-based
|
|
12
12
|
presentations using Markdown slides.
|
|
13
|
+
- path: templates.md
|
|
14
|
+
title: Templates
|
|
15
|
+
description: This guide explains how to choose slide templates and create custom
|
|
16
|
+
layouts in Presently.
|
|
13
17
|
- path: animating-slides.md
|
|
14
18
|
title: Animating Slides
|
|
15
19
|
description: This guide explains how to animate content within slides using the
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Templates
|
|
2
|
+
|
|
3
|
+
This guide explains how to choose slide templates and create custom layouts in Presently.
|
|
4
|
+
|
|
5
|
+
## Built-in Templates
|
|
6
|
+
|
|
7
|
+
Templates define the visual layout of each slide. Select a template using the `template` field in the frontmatter.
|
|
8
|
+
|
|
9
|
+
### Default
|
|
10
|
+
|
|
11
|
+
A general-purpose content slide. An H1 becomes the slide title and the remaining document becomes its body.
|
|
12
|
+
|
|
13
|
+
``` markdown
|
|
14
|
+
---
|
|
15
|
+
template: default
|
|
16
|
+
duration: 60
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Key points
|
|
20
|
+
|
|
21
|
+
- First point
|
|
22
|
+
- Second point
|
|
23
|
+
- Third point
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Title
|
|
27
|
+
|
|
28
|
+
A large title with a short body, centered on the slide.
|
|
29
|
+
|
|
30
|
+
``` markdown
|
|
31
|
+
---
|
|
32
|
+
template: title
|
|
33
|
+
duration: 30
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
# My Presentation Title
|
|
37
|
+
|
|
38
|
+
A subtitle or tagline
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Section
|
|
42
|
+
|
|
43
|
+
A section divider slide with a large heading, optional supporting body, and accent background.
|
|
44
|
+
|
|
45
|
+
``` markdown
|
|
46
|
+
---
|
|
47
|
+
template: section
|
|
48
|
+
duration: 15
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
# Part Two
|
|
52
|
+
|
|
53
|
+
Architecture and design
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Two Column
|
|
57
|
+
|
|
58
|
+
A side-by-side layout with `left` and `right` sections.
|
|
59
|
+
|
|
60
|
+
``` markdown
|
|
61
|
+
---
|
|
62
|
+
template: two_column
|
|
63
|
+
duration: 90
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
# Client and server responsibilities
|
|
67
|
+
|
|
68
|
+
The application is split across two cooperating environments.
|
|
69
|
+
|
|
70
|
+
## Left
|
|
71
|
+
|
|
72
|
+
**Server Side**
|
|
73
|
+
|
|
74
|
+
- Ruby + Lively
|
|
75
|
+
- WebSocket connections
|
|
76
|
+
|
|
77
|
+
## Right
|
|
78
|
+
|
|
79
|
+
**Client Side**
|
|
80
|
+
|
|
81
|
+
- Live DOM updates
|
|
82
|
+
- CSS animations
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Code
|
|
86
|
+
|
|
87
|
+
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.
|
|
88
|
+
|
|
89
|
+
```` markdown
|
|
90
|
+
---
|
|
91
|
+
template: code
|
|
92
|
+
duration: 60
|
|
93
|
+
focus: 2-8
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
# Constructor
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
class Presentation
|
|
100
|
+
def initialize
|
|
101
|
+
@slides = []
|
|
102
|
+
@current_index = 0
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def advance!
|
|
106
|
+
@current_index += 1
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
````
|
|
111
|
+
|
|
112
|
+
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.
|
|
113
|
+
|
|
114
|
+
### Statement
|
|
115
|
+
|
|
116
|
+
A prominent statement or quote, centered on the slide. Supports an optional `## Translation` placeholder.
|
|
117
|
+
|
|
118
|
+
``` markdown
|
|
119
|
+
---
|
|
120
|
+
template: statement
|
|
121
|
+
duration: 30
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
The best way to predict the future is to create it.
|
|
125
|
+
|
|
126
|
+
## Translation
|
|
127
|
+
|
|
128
|
+
未来を予測する最善の方法は、それを創ることである。
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Image
|
|
132
|
+
|
|
133
|
+
A centered image with an optional caption.
|
|
134
|
+
|
|
135
|
+
``` markdown
|
|
136
|
+
---
|
|
137
|
+
template: image
|
|
138
|
+
duration: 30
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+

|
|
142
|
+
|
|
143
|
+
## Caption
|
|
144
|
+
|
|
145
|
+
System architecture overview
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Diagram
|
|
149
|
+
|
|
150
|
+
A centered canvas for diagrams and other custom visual layouts, with an optional title. A single grid or flex container is usually enough to create a diagram that remains centered as the slide scales:
|
|
151
|
+
|
|
152
|
+
``` markdown
|
|
153
|
+
---
|
|
154
|
+
template: diagram
|
|
155
|
+
duration: 60
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
# Request lifecycle
|
|
159
|
+
|
|
160
|
+
<div style="display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 2em; width: 80%;">
|
|
161
|
+
<div>Browser</div>
|
|
162
|
+
<div>→</div>
|
|
163
|
+
<div>Server</div>
|
|
164
|
+
</div>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
For coordinate-based layouts, wrap the elements in `<div class="diagram-freeform">`. The wrapper fills the canvas and absolutely positions each direct child.
|
|
168
|
+
|
|
169
|
+
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.
|
|
170
|
+
|
|
171
|
+
## Translations
|
|
172
|
+
|
|
173
|
+
Templates can extract an optional `## Translation` section and position it independently from the main document. Every standard template displays it separately in a lighter style.
|
|
174
|
+
|
|
175
|
+
## Custom Templates
|
|
176
|
+
|
|
177
|
+
For layouts specific to your presentation, put `.xrb` files in a `templates/` directory alongside `slides/`. Presently searches this directory before its bundled templates, so you can add new layouts or override individual built-in templates.
|
|
178
|
+
|
|
179
|
+
To search additional directories, configure `templates_roots`, which returns an ordered array of paths:
|
|
180
|
+
|
|
181
|
+
``` ruby
|
|
182
|
+
# In your environment configuration:
|
|
183
|
+
service "presently" do
|
|
184
|
+
include Presently::Environment::Application
|
|
185
|
+
|
|
186
|
+
def templates_roots
|
|
187
|
+
[File.expand_path("shared-templates", self.root)] + super
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
For example, save the following template as `templates/custom.xrb` and select it with `template: custom` in a slide's frontmatter.
|
|
193
|
+
|
|
194
|
+
Templates receive a {ruby Presently::TemplateScope}. `self.slide_header` renders the semantic H1 title and optional section metadata, while `self.document` renders the remaining slide body. `self.extract(name)` removes an H2 placeholder with that exact heading text from the body and returns its rendered content. Extract placeholders before rendering the remaining document:
|
|
195
|
+
|
|
196
|
+
``` xrb
|
|
197
|
+
<?r translation = self.extract("Translation") ?>
|
|
198
|
+
#{self.slide_header}
|
|
199
|
+
<div class="slide-body">
|
|
200
|
+
#{self.document}
|
|
201
|
+
</div>
|
|
202
|
+
<?r if translation ?>
|
|
203
|
+
<div class="slide-translation">#{translation}</div>
|
|
204
|
+
<?r end ?>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Extraction stops at the next heading of the same or a higher level, so lower-level headings remain inside the extracted fragment. Placeholder names are case-sensitive and must match the heading text exactly. Only placeholders requested by the template are removed; other headings remain ordinary document content.
|
|
@@ -89,6 +89,7 @@ module Presently
|
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
# The progress through the current slide's allocated time.
|
|
92
|
+
# Slides with durations of zero or less are complete once their expected start time is reached.
|
|
92
93
|
# @returns [Float] A value between 0.0 and 1.0.
|
|
93
94
|
def slide_progress
|
|
94
95
|
return 0.0 unless @clock.started?
|
|
@@ -97,7 +98,11 @@ module Presently
|
|
|
97
98
|
return 0.0 unless slide
|
|
98
99
|
|
|
99
100
|
time_into_slide = @clock.elapsed - @presentation.expected_time_at(@current_index)
|
|
100
|
-
|
|
101
|
+
if slide.duration <= 0
|
|
102
|
+
time_into_slide.negative? ? 0.0 : 1.0
|
|
103
|
+
else
|
|
104
|
+
(time_into_slide / slide.duration).clamp(0.0, 1.0)
|
|
105
|
+
end
|
|
101
106
|
end
|
|
102
107
|
|
|
103
108
|
# Reset the timer so that elapsed time matches the expected time for the current slide.
|
|
@@ -107,8 +112,9 @@ module Presently
|
|
|
107
112
|
end
|
|
108
113
|
|
|
109
114
|
# The current pacing status relative to the slide timing.
|
|
110
|
-
# @returns [Symbol] One of `:on_time`, `:ahead`, or `:behind
|
|
115
|
+
# @returns [Symbol | Nil] One of `:on_time`, `:ahead`, or `:behind`, or `nil` when no presentation time is allocated.
|
|
111
116
|
def pacing
|
|
117
|
+
return unless total_duration.positive?
|
|
112
118
|
return :on_time unless @clock.started?
|
|
113
119
|
|
|
114
120
|
elapsed = @clock.elapsed
|
|
@@ -137,19 +143,27 @@ module Presently
|
|
|
137
143
|
# Navigate to a specific slide by index.
|
|
138
144
|
# Ignores out-of-bounds indices. Notifies listeners on change.
|
|
139
145
|
# @parameter index [Integer] The slide index to navigate to.
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
# @parameter timer [Boolean] Whether to apply the outgoing slide's timer action before notifying listeners.
|
|
147
|
+
# @returns [Boolean] Whether the destination index was valid.
|
|
148
|
+
def go_to(index, timer: false)
|
|
149
|
+
return false if index < 0 || index >= slide_count
|
|
142
150
|
|
|
151
|
+
advance_timer! if timer
|
|
143
152
|
@current_index = index
|
|
144
153
|
notify_listeners!
|
|
154
|
+
return true
|
|
145
155
|
end
|
|
146
156
|
|
|
147
|
-
# Advance to the next slide.
|
|
148
|
-
|
|
149
|
-
|
|
157
|
+
# Advance to the next slide, applying the current slide's timer action.
|
|
158
|
+
# Timer actions only run when there is a next slide.
|
|
159
|
+
# @parameter timer [Boolean] Whether to apply the outgoing slide's timer action.
|
|
160
|
+
# @returns [Boolean] Whether the presentation advanced to the next slide.
|
|
161
|
+
def advance!(timer: true)
|
|
162
|
+
go_to(@current_index + 1, timer: timer)
|
|
150
163
|
end
|
|
151
164
|
|
|
152
165
|
# Go back to the previous slide.
|
|
166
|
+
# @returns [Boolean] Whether the presentation moved to the previous slide.
|
|
153
167
|
def retreat!
|
|
154
168
|
go_to(@current_index - 1)
|
|
155
169
|
end
|
|
@@ -180,6 +194,18 @@ module Presently
|
|
|
180
194
|
|
|
181
195
|
private
|
|
182
196
|
|
|
197
|
+
# Apply the outgoing slide's timer action without resetting elapsed time.
|
|
198
|
+
def advance_timer!
|
|
199
|
+
case current_slide.timer
|
|
200
|
+
when "start"
|
|
201
|
+
@clock.start! unless @clock.started?
|
|
202
|
+
when "pause"
|
|
203
|
+
@clock.pause!
|
|
204
|
+
when "resume"
|
|
205
|
+
@clock.resume! if @clock.started?
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
183
209
|
# Notify all registered listeners that the slide has changed, and persist state.
|
|
184
210
|
def notify_listeners!
|
|
185
211
|
@state&.save(self)
|
|
@@ -100,14 +100,14 @@ module Presently
|
|
|
100
100
|
# @parameter builder [XRB::Builder] The HTML builder.
|
|
101
101
|
# @parameter slide [Slide | Nil] The current slide.
|
|
102
102
|
def render_timing(builder, slide)
|
|
103
|
-
|
|
103
|
+
pacing = @controller.pacing
|
|
104
|
+
progress = pacing ? (@controller.slide_progress * 100).round(1) : 0.0
|
|
104
105
|
next_slide = @controller.next_slide
|
|
105
106
|
builder.tag(:div, class: "timing", style: "--slide-progress: #{progress}%") do
|
|
106
|
-
pacing = @controller.pacing
|
|
107
107
|
pacing_class = case pacing
|
|
108
108
|
when :behind then "behind"
|
|
109
109
|
when :ahead then "ahead"
|
|
110
|
-
|
|
110
|
+
when :on_time then "on-time"
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
builder.tag(:div, class: "toolbar timing-info #{pacing_class}") do
|
|
@@ -136,17 +136,19 @@ module Presently
|
|
|
136
136
|
builder.text("Elapsed: #{format_duration(@controller.clock.elapsed)}")
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
builder.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
139
|
+
if pacing
|
|
140
|
+
builder.tag(:span, class: "remaining") do
|
|
141
|
+
builder.text("Remaining: #{format_duration(@controller.time_remaining)}")
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
builder.tag(:span, class: "pacing-indicator") do
|
|
145
|
+
indicator = case pacing
|
|
146
|
+
when :behind then "⏩ Speed up"
|
|
147
|
+
when :ahead then "⏪ Slow down"
|
|
148
|
+
else "✓ On time"
|
|
149
|
+
end
|
|
150
|
+
builder.text(indicator)
|
|
148
151
|
end
|
|
149
|
-
builder.text(indicator)
|
|
150
152
|
end
|
|
151
153
|
|
|
152
154
|
if slide
|
data/lib/presently/slide.rb
CHANGED
|
@@ -349,9 +349,23 @@ module Presently
|
|
|
349
349
|
end
|
|
350
350
|
|
|
351
351
|
# The expected duration of this slide in seconds.
|
|
352
|
-
#
|
|
352
|
+
# Negative, invalid, or non-finite values are treated as zero.
|
|
353
|
+
# @returns [Float] A finite duration of at least `0.0`, defaulting to `0.0` when unspecified or null.
|
|
353
354
|
def duration
|
|
354
|
-
@front_matter&.fetch("duration",
|
|
355
|
+
if value = @front_matter&.fetch("duration", nil)
|
|
356
|
+
duration = Float(value, exception: false)
|
|
357
|
+
if duration&.finite?
|
|
358
|
+
return duration.clamp(0.0, nil)
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
return 0.0
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# The timer action to apply when advancing from this slide.
|
|
366
|
+
# @returns [String | Nil] `"start"`, `"pause"`, `"resume"`, or `nil` when unspecified.
|
|
367
|
+
def timer
|
|
368
|
+
@front_matter&.fetch("timer", nil)
|
|
355
369
|
end
|
|
356
370
|
|
|
357
371
|
# Update the expected duration in the slide's YAML front matter.
|
data/lib/presently/version.rb
CHANGED
data/readme.md
CHANGED
|
@@ -26,6 +26,8 @@ Please see the [project documentation](https://socketry.github.io/presently/) fo
|
|
|
26
26
|
|
|
27
27
|
- [Getting Started](https://socketry.github.io/presently/guides/getting-started/index) - This guide explains how to use `presently` to create and deliver web-based presentations using Markdown slides.
|
|
28
28
|
|
|
29
|
+
- [Templates](https://socketry.github.io/presently/guides/templates/index) - This guide explains how to choose slide templates and create custom layouts in Presently.
|
|
30
|
+
|
|
29
31
|
- [Animating Slides](https://socketry.github.io/presently/guides/animating-slides/index) - This guide explains how to animate content within slides using the slide scripting system.
|
|
30
32
|
|
|
31
33
|
- [Animated Diagrams](https://socketry.github.io/presently/guides/animated-diagrams/index) - This guide explains how to design responsive, lifecycle-safe animated diagrams in Presently using semantic markup, slide-specific CSS, and Anime.js choreography.
|
|
@@ -67,6 +69,13 @@ The task records the presentation at 1920×1080 and 30 frames per second by defa
|
|
|
67
69
|
|
|
68
70
|
Please see the [project releases](https://socketry.github.io/presently/releases/index) for all releases.
|
|
69
71
|
|
|
72
|
+
### v0.26.0
|
|
73
|
+
|
|
74
|
+
- Add `timer: start`, `timer: pause`, and `timer: resume` slide metadata, applied when advancing away from a slide in the presenter or display.
|
|
75
|
+
- Normalize slide durations to finite, non-negative floating-point seconds. Missing or invalid durations now default to `0.0`, and negative durations are clamped to zero. Presentations relying on the previous 60-second default should set explicit durations.
|
|
76
|
+
- Handle zero-duration slide progress and hide pacing indicators, progress, and remaining-time estimates when a presentation has no allocated duration.
|
|
77
|
+
- Keep recorder navigation from changing the presentation timer.
|
|
78
|
+
|
|
70
79
|
### v0.24.1
|
|
71
80
|
|
|
72
81
|
- Use legible, customizable link colors on the default dark slide background.
|
|
@@ -117,11 +126,6 @@ Please see the [project releases](https://socketry.github.io/presently/releases/
|
|
|
117
126
|
|
|
118
127
|
- Fix slide rendering events for generated view identifiers that begin with a digit.
|
|
119
128
|
|
|
120
|
-
### v0.17.1
|
|
121
|
-
|
|
122
|
-
- Add slide-scoped resource cleanup with `Slide#defer`, `Slide#signal`, and idempotent `Slide#dispose`. Existing tracked timeouts now use the same disposal lifecycle.
|
|
123
|
-
- [Web Packages](https://socketry.github.io/presently/releases/index#web-packages)
|
|
124
|
-
|
|
125
129
|
## See Also
|
|
126
130
|
|
|
127
131
|
- [lively](https://github.com/socketry/lively) — The real-time application framework that powers Presently.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.26.0
|
|
4
|
+
|
|
5
|
+
- Add `timer: start`, `timer: pause`, and `timer: resume` slide metadata, applied when advancing away from a slide in the presenter or display.
|
|
6
|
+
- Normalize slide durations to finite, non-negative floating-point seconds. Missing or invalid durations now default to `0.0`, and negative durations are clamped to zero. Presentations relying on the previous 60-second default should set explicit durations.
|
|
7
|
+
- Handle zero-duration slide progress and hide pacing indicators, progress, and remaining-time estimates when a presentation has no allocated duration.
|
|
8
|
+
- Keep recorder navigation from changing the presentation timer.
|
|
9
|
+
|
|
3
10
|
## v0.24.1
|
|
4
11
|
|
|
5
12
|
- Use legible, customizable link colors on the default dark slide background.
|
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.
|
|
4
|
+
version: 0.26.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -122,6 +122,7 @@ files:
|
|
|
122
122
|
- context/animating-slides.md
|
|
123
123
|
- context/getting-started.md
|
|
124
124
|
- context/index.yaml
|
|
125
|
+
- context/templates.md
|
|
125
126
|
- lib/presently.rb
|
|
126
127
|
- lib/presently/application.rb
|
|
127
128
|
- lib/presently/clock.rb
|
metadata.gz.sig
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
4��繼=��h��R4-w4a�E�~9FOTuB��!xb1���u���Ι����y�)ҿ��a�)Ү�.���[Śb��K2��vE_�?�Rٝ�A�Q�6JV�]G8Wĩ��Zn�m��p�2���ݿ���#���o@3��n�t��&�*Z�#�˕d�G���'fZS$�Dc��}�N��1%� �'xJ��>�U��?TC���8�y[����r+U
|
|
2
|
-
�d�)??u�]���!��|����&��y@��]->[�?U���E�{*a�q�Uvp����s=_���
|
|
3
1
|
7St�ϫQ:��H�B�� M��8r\}�9Ҫ ��`e�w�
|
|
2
|
+
2���$ZD����?bD�l��*��!(M�c�~�%��`|��&M
|
|
3
|
+
@R�(K������}��X�\Ϯ,-sϺ{%����'ߊ�^���$����N��`�/�X���!=�hkݯ�HZ
|
|
4
|
+
^��#�<�h�h��A|��oe��G�B�ݕY��}s��+1z6���� �L�5�)̄�����5�t���X7��|ӳDi]>Y�w�aަ���qf-�X+h��@�FĜb<��V�6Ӟ�]�����t����I�d��R� ݛ���>�!y�/�|��$N�&ҫ:�
|