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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46e3cc47613d0f667aeead379bdb8ed4c311ae9375c08ca32ceeeca4d57b5919
4
- data.tar.gz: d4bf90e706c3a358a30937a3589f493a9c42f70a87babf9cc976407714124b98
3
+ metadata.gz: de6eb2668cd67cd34eb8f02c51dce3bc3f823f71b8e553835d27c2476d3f793e
4
+ data.tar.gz: 37601886d71cc24f89510ed65d918dbb87bcd1de1d0c48718f96b15820790e23
5
5
  SHA512:
6
- metadata.gz: 07702bbfa6107d4ee4554015450a7008d09d69e6e2c7486a5b5aa6d94b7b15ba188557810634e8fca79bbadcc450793b7d36f01c6878cf04f9d0fe7a74f77de9
7
- data.tar.gz: 6b31a696453ce2a9d9adf6fe3b084a4aba9a20a23f4535b3582fab49af4999e62cebe41389cacc3ce7d9227bf0653365b2009892377cb09e20396bfa02a9d204
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
+ ![Architecture diagram](/images/architecture.png)
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
+ ```
@@ -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.
@@ -5,5 +5,5 @@
5
5
 
6
6
  # @namespace
7
7
  module Presently
8
- VERSION = "0.14.0"
8
+ VERSION = "0.14.1"
9
9
  end
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.0
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