presently 0.17.2 → 0.19.0

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.
@@ -13,6 +13,7 @@
13
13
  --on-time: #2ed573;
14
14
  --behind: #ff4757;
15
15
  --ahead: #ffa502;
16
+ --control-height: 2.25rem;
16
17
  --font-sans: "Inter", "Helvetica Neue", Arial, sans-serif;
17
18
  --font-mono: "JetBrains Mono", "Fira Code", monospace;
18
19
  }
@@ -31,12 +32,48 @@ html, body {
31
32
  SLIDE STYLES (shared)
32
33
  ======================== */
33
34
 
34
- .slide {
35
+ .slide-viewport {
36
+ position: relative;
37
+ display: grid;
38
+ place-items: center;
39
+ overflow: hidden;
40
+ container-type: size;
41
+ }
42
+
43
+ .slide-surface {
35
44
  width: 100%;
36
45
  height: 100%;
37
- display: flex;
38
- align-items: center;
39
- justify-content: center;
46
+ display: grid;
47
+ place-items: center;
48
+ container-type: size;
49
+ background: var(--slide-bg);
50
+ }
51
+
52
+ .slide {
53
+ --slide-font-size: 2.2cqi;
54
+ --slide-font-body: 1em;
55
+ --slide-font-title: 1.8em;
56
+ --slide-font-heading: 1.6em;
57
+ --slide-font-statement: 1.5em;
58
+ --slide-font-secondary: 0.8em;
59
+ --slide-font-column: 0.84em;
60
+ --slide-font-code: 0.75em;
61
+ --slide-gutter: 3.333cqi;
62
+ --slide-gap: 1.667cqi;
63
+ --slide-radius: 0.417cqi;
64
+
65
+ flex: none;
66
+ width: 100cqw;
67
+ height: auto;
68
+ aspect-ratio: 16 / 9;
69
+ container-type: size;
70
+ }
71
+
72
+ @container (min-aspect-ratio: 16 / 9) {
73
+ .slide {
74
+ width: auto;
75
+ height: 100cqh;
76
+ }
40
77
  }
41
78
 
42
79
  .slide-inner {
@@ -47,13 +84,15 @@ html, body {
47
84
  flex-direction: column;
48
85
  align-items: center;
49
86
  justify-content: center;
50
- padding: 4rem;
87
+ padding: var(--slide-gutter);
88
+ font-size: var(--slide-font-size);
89
+ line-height: 1.5;
51
90
  }
52
91
 
53
92
  /* Default template */
54
93
  .default-template .slide-body {
55
- font-size: 1.8rem;
56
- line-height: 1.6;
94
+ font-size: var(--slide-font-body);
95
+ line-height: 1.5;
57
96
  width: 100%;
58
97
  }
59
98
 
@@ -80,9 +119,9 @@ html, body {
80
119
  }
81
120
 
82
121
  .title-template .slide-title {
83
- font-size: 3.5rem;
122
+ font-size: var(--slide-font-title);
84
123
  font-weight: 700;
85
- margin-bottom: 1rem;
124
+ margin-bottom: calc(var(--slide-gap) * 0.75);
86
125
  }
87
126
 
88
127
  .title-template .slide-title p {
@@ -90,7 +129,7 @@ html, body {
90
129
  }
91
130
 
92
131
  .title-template .slide-subtitle {
93
- font-size: 1.8rem;
132
+ font-size: var(--slide-font-body);
94
133
  opacity: 0.7;
95
134
  }
96
135
 
@@ -99,13 +138,16 @@ html, body {
99
138
  }
100
139
 
101
140
  /* Section template */
102
- .section-template {
141
+ .slide-surface[data-template="section"] {
103
142
  background: linear-gradient(135deg, var(--accent), var(--surface-light));
143
+ }
144
+
145
+ .section-template {
104
146
  text-align: center;
105
147
  }
106
148
 
107
149
  .section-template .slide-heading {
108
- font-size: 3rem;
150
+ font-size: var(--slide-font-heading);
109
151
  font-weight: 700;
110
152
  }
111
153
 
@@ -116,14 +158,15 @@ html, body {
116
158
  /* Two column template */
117
159
  .two-column-template {
118
160
  flex-direction: row;
119
- gap: 3rem;
120
- padding: 3rem 4rem;
161
+ gap: calc(var(--slide-gap) * 1.5);
162
+ padding: calc(var(--slide-gutter) * 0.75) var(--slide-gutter);
121
163
  }
122
164
 
123
165
  .two-column-template .column {
124
166
  flex: 1;
125
- font-size: 1.4rem;
126
- line-height: 1.6;
167
+ min-width: 0;
168
+ font-size: var(--slide-font-column);
169
+ line-height: 1.5;
127
170
  }
128
171
 
129
172
  .two-column-template .column ul {
@@ -136,30 +179,60 @@ html, body {
136
179
 
137
180
  /* Diagram template */
138
181
  .diagram-template {
139
- padding: 0;
182
+ padding: var(--slide-gutter);
140
183
  }
141
184
 
142
- .diagram-template .slide-body > div {
185
+ .diagram-template .slide-title {
186
+ flex: none;
187
+ width: 100%;
188
+ margin-bottom: var(--slide-gap);
189
+ font-size: var(--slide-font-body);
190
+ font-weight: 700;
191
+ text-align: center;
192
+ }
193
+
194
+ .diagram-template .slide-title p {
195
+ margin: 0;
196
+ }
197
+
198
+ .diagram-template .slide-body {
199
+ display: grid;
200
+ flex: 1;
201
+ place-items: center;
202
+ width: 100%;
203
+ min-height: 0;
204
+ }
205
+
206
+ .diagram-template .diagram-freeform {
207
+ position: relative;
208
+ width: 100%;
209
+ height: 100%;
210
+ }
211
+
212
+ .diagram-template .diagram-freeform > * {
143
213
  position: absolute;
144
214
  box-sizing: border-box;
145
215
  }
146
216
 
147
217
  /* Image template */
148
218
  .image-template .slide-caption {
149
- font-size: 1.6rem;
150
- margin-bottom: 2rem;
219
+ font-size: var(--slide-font-secondary);
220
+ margin-bottom: var(--slide-gap);
151
221
  text-align: center;
152
222
  }
153
223
 
154
224
  .image-template .slide-image {
155
- max-width: 80%;
225
+ display: grid;
226
+ place-items: center;
227
+ width: min(80cqi, 100%);
228
+ max-height: 65cqb;
156
229
  text-align: center;
157
230
  }
158
231
 
159
- .image-template .slide-image img {
232
+ .image-template .slide-image :is(img, video, svg, iframe) {
160
233
  max-width: 100%;
161
- max-height: 60vh;
162
- border-radius: 8px;
234
+ max-height: 65cqb;
235
+ border-radius: var(--slide-radius);
163
236
  }
164
237
 
165
238
  /* Hide raw code blocks until syntax-js upgrades them */
@@ -273,11 +346,11 @@ pre > syntax-code {
273
346
  /* Statement template */
274
347
  .statement-template {
275
348
  text-align: center;
276
- gap: 2rem;
349
+ gap: var(--slide-gap);
277
350
  }
278
351
 
279
352
  .statement-template .slide-statement {
280
- font-size: 2.5rem;
353
+ font-size: var(--slide-font-statement);
281
354
  font-weight: 600;
282
355
  line-height: 1.4;
283
356
  width: 100%;
@@ -293,9 +366,9 @@ pre > syntax-code {
293
366
 
294
367
  /* Shared translation style — works in any template */
295
368
  .slide-translation {
296
- font-size: 1.6rem;
369
+ font-size: var(--slide-font-secondary);
297
370
  opacity: 0.7;
298
- margin-top: 1rem;
371
+ margin-top: calc(var(--slide-gap) * 0.5);
299
372
  }
300
373
 
301
374
  .slide-translation p {
@@ -337,14 +410,14 @@ mermaid-diagram {
337
410
 
338
411
  /* Code template */
339
412
  .code-template {
340
- padding: 2rem 3rem;
413
+ padding: var(--slide-gap) calc(var(--slide-gutter) * 0.75);
341
414
  align-items: stretch;
342
415
  }
343
416
 
344
417
  .code-template .code-title {
345
- font-size: 1.6rem;
418
+ font-size: var(--slide-font-secondary);
346
419
  font-weight: 600;
347
- margin-bottom: 1rem;
420
+ margin-bottom: calc(var(--slide-gap) * 0.5);
348
421
  }
349
422
 
350
423
  .code-template .code-title p {
@@ -355,21 +428,21 @@ mermaid-diagram {
355
428
  position: relative;
356
429
  flex: 1;
357
430
  overflow: hidden;
358
- border-radius: 8px;
431
+ border-radius: var(--slide-radius);
359
432
  background: rgba(0, 0, 0, 0.3);
360
433
  }
361
434
 
362
435
  .code-scroll {
363
436
  transition: transform 0.6s ease-in-out;
364
- padding: 1rem;
437
+ padding: calc(var(--slide-gap) * 0.5);
365
438
  }
366
439
 
367
440
  .code-scroll pre {
368
441
  margin: 0;
369
442
  background: none;
370
443
  padding: 0;
371
- line-height: 1.6;
372
- font-size: 1.5rem;
444
+ line-height: 1.5;
445
+ font-size: var(--slide-font-code);
373
446
  }
374
447
 
375
448
  /* Dim overlays */
@@ -441,29 +514,26 @@ live-view:has(.display) {
441
514
 
442
515
  /* Fade */
443
516
  html[data-transition="fade"]::view-transition-old(slide-container) {
444
- animation: vt-fade-out 0.4s ease-in-out;
445
- }
446
-
447
- html[data-transition="fade"]::view-transition-new(slide-container) {
448
- animation: vt-fade-in 0.4s ease-in-out;
517
+ animation: vt-fade-out 0.4s ease-in-out both;
518
+ z-index: 1;
449
519
  }
450
520
 
451
521
  /* Slide left */
452
522
  html[data-transition="slide-left"]::view-transition-old(slide-container) {
453
- animation: vt-slide-out-left 0.4s ease-in-out;
523
+ animation: vt-slide-out-left 0.4s ease-in-out both;
454
524
  }
455
525
 
456
526
  html[data-transition="slide-left"]::view-transition-new(slide-container) {
457
- animation: vt-slide-in-right 0.4s ease-in-out;
527
+ animation: vt-slide-in-right 0.4s ease-in-out both;
458
528
  }
459
529
 
460
530
  /* Slide right */
461
531
  html[data-transition="slide-right"]::view-transition-old(slide-container) {
462
- animation: vt-slide-out-right 0.4s ease-in-out;
532
+ animation: vt-slide-out-right 0.4s ease-in-out both;
463
533
  }
464
534
 
465
535
  html[data-transition="slide-right"]::view-transition-new(slide-container) {
466
- animation: vt-slide-in-left 0.4s ease-in-out;
536
+ animation: vt-slide-in-left 0.4s ease-in-out both;
467
537
  }
468
538
 
469
539
  /* ========================
@@ -472,8 +542,7 @@ html[data-transition="slide-right"]::view-transition-new(slide-container) {
472
542
 
473
543
  body.playback,
474
544
  .playback-stage,
475
- .playback-frame,
476
- .playback-frame > .slide {
545
+ .playback-frame {
477
546
  width: 100vw;
478
547
  height: 100vh;
479
548
  }
@@ -687,21 +756,33 @@ body.playback[data-controls="false"] .playback-start-screen {
687
756
  }
688
757
 
689
758
  /* Controls */
690
- .controls {
759
+ .toolbar {
691
760
  display: flex;
692
761
  align-items: center;
693
762
  gap: 1rem;
763
+ }
764
+
765
+ .toolbar > button,
766
+ .toolbar > select,
767
+ .toolbar > .slide-info {
768
+ height: var(--control-height);
769
+ background: var(--surface-light);
770
+ border: 1px solid rgba(255,255,255,0.1);
771
+ border-radius: 6px;
772
+ }
773
+
774
+ .controls {
694
775
  padding: 0.5rem 1rem;
695
776
  background: var(--surface);
696
777
  border-radius: 8px;
697
778
  }
698
779
 
699
780
  .controls button {
700
- background: var(--surface-light);
781
+ display: inline-flex;
782
+ align-items: center;
783
+ justify-content: center;
701
784
  color: var(--slide-text);
702
- border: 1px solid rgba(255,255,255,0.1);
703
- padding: 0.5rem 1rem;
704
- border-radius: 6px;
785
+ padding: 0 1rem;
705
786
  cursor: pointer;
706
787
  font-size: 0.9rem;
707
788
  font-family: var(--font-sans);
@@ -713,11 +794,8 @@ body.playback[data-controls="false"] .playback-start-screen {
713
794
  }
714
795
 
715
796
  .controls .jump-to {
716
- background: var(--surface-light);
717
797
  color: var(--slide-text);
718
- border: 1px solid rgba(255,255,255,0.1);
719
- padding: 0.5rem 0.75rem;
720
- border-radius: 6px;
798
+ padding: 0 0.75rem;
721
799
  font-size: 0.9rem;
722
800
  font-family: var(--font-sans);
723
801
  cursor: pointer;
@@ -728,22 +806,61 @@ body.playback[data-controls="false"] .playback-start-screen {
728
806
  background: var(--accent);
729
807
  }
730
808
 
731
- .controls button.reload {
732
- margin-left: auto;
733
- }
734
-
735
809
  .controls .slide-info {
736
810
  font-size: 1rem;
811
+ display: flex;
812
+ align-items: stretch;
813
+ flex: 1 1 0;
814
+ min-width: 0;
815
+ white-space: nowrap;
816
+ overflow: hidden;
817
+ }
818
+
819
+ .controls .slide-position,
820
+ .controls .edit-link {
821
+ flex: 0 0 auto;
822
+ }
823
+
824
+ .controls .slide-position {
825
+ display: flex;
826
+ align-items: center;
827
+ padding: 0 0.75rem;
828
+ font-size: 0.9rem;
737
829
  opacity: 0.8;
738
830
  }
739
831
 
740
832
  .controls .slide-path {
741
833
  font-size: 0.8rem;
742
834
  opacity: 0.6;
835
+ display: inline-flex;
836
+ align-items: center;
837
+ flex: 0 1 auto;
838
+ min-width: 0;
839
+ padding: 0 0.6rem;
840
+ border-left: 1px solid rgba(255,255,255,0.1);
841
+ }
842
+
843
+ .controls .slide-path-directory,
844
+ .controls .slide-path-filename {
845
+ overflow: hidden;
846
+ text-overflow: ellipsis;
847
+ white-space: nowrap;
848
+ }
849
+
850
+ .controls .slide-path-directory {
851
+ flex: 1 1 0;
852
+ }
853
+
854
+ .controls .slide-path-filename {
855
+ flex: 0 1 auto;
743
856
  }
744
857
 
745
858
  .controls .edit-link {
746
- margin-left: 0.3rem;
859
+ display: flex;
860
+ align-items: center;
861
+ margin-left: 0;
862
+ padding: 0 0.5rem;
863
+ border-left: 1px solid rgba(255,255,255,0.1);
747
864
  text-decoration: none;
748
865
  opacity: 0.6;
749
866
  transition: opacity 0.2s;
@@ -784,10 +901,6 @@ body.playback[data-controls="false"] .playback-start-screen {
784
901
  min-height: 0;
785
902
  }
786
903
 
787
- .preview-frame .slide {
788
- zoom: 0.5;
789
- }
790
-
791
904
  .preview-frame .no-slide {
792
905
  display: flex;
793
906
  align-items: center;
@@ -814,9 +927,6 @@ body.playback[data-controls="false"] .playback-start-screen {
814
927
  }
815
928
 
816
929
  .timing-info {
817
- display: flex;
818
- gap: 2rem;
819
- align-items: center;
820
930
  font-size: 1rem;
821
931
  }
822
932
 
@@ -840,11 +950,8 @@ body.playback[data-controls="false"] .playback-start-screen {
840
950
  }
841
951
 
842
952
  .timing-info .pause-button {
843
- background: var(--surface-light);
844
953
  color: var(--slide-text);
845
- border: 1px solid rgba(255,255,255,0.1);
846
954
  padding: 0.3rem 0.75rem;
847
- border-radius: 6px;
848
955
  cursor: pointer;
849
956
  font-size: 0.9rem;
850
957
  font-family: var(--font-sans);
@@ -1140,12 +1247,6 @@ body.export {
1140
1247
  overflow: hidden;
1141
1248
  }
1142
1249
 
1143
- /* Slide fills its container, which is sized by inline style. */
1144
- .export-slide-area .slide {
1145
- width: 100%;
1146
- height: 100%;
1147
- }
1148
-
1149
1250
  /* Notes panel below the slide. */
1150
1251
  .export-notes-area {
1151
1252
  padding: 0.5rem 2rem 0.5rem;
data/readme.md CHANGED
@@ -28,6 +28,8 @@ Please see the [project documentation](https://socketry.github.io/presently/) fo
28
28
 
29
29
  - [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
30
 
31
+ - [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.
32
+
31
33
  ### Recording Narration
32
34
 
33
35
  Open `http://localhost:9292/record` to record narration separately from the live presenter interface. Presently stores one WebM/Opus recording per slide under `audio/`, mirroring the slide's relative path:
@@ -65,6 +67,20 @@ The task records the presentation at 1920×1080 and 30 frames per second by defa
65
67
 
66
68
  Please see the [project releases](https://socketry.github.io/presently/releases/index) for all releases.
67
69
 
70
+ ### v0.19.0
71
+
72
+ - Support language-prefixed inline code such as `ruby:` for syntax highlighting.
73
+ - Preserve blank lines within consistently indented HTML blocks in slide Markdown.
74
+
75
+ ### v0.18.0
76
+
77
+ - Render slides on a responsive 16:9 canvas across the display, presenter, recording, playback, and export interfaces.
78
+ - Center diagram content by default, add optional diagram titles, and make free-form absolute positioning explicit with `.diagram-freeform`.
79
+ - Prevent slide backgrounds and content from flickering during view transitions.
80
+ - Add lifecycle-managed Anime.js animation scopes, reusable diagram setup scripts, and guidance for authoring animated diagrams.
81
+ - Truncate long slide paths responsively while preserving their filenames in presenter controls.
82
+ - Preserve the complete saved presentation state when restoring the controller.
83
+
68
84
  ### v0.17.2
69
85
 
70
86
  - Fix slide rendering events for generated view identifiers that begin with a digit.
@@ -103,15 +119,6 @@ q
103
119
 
104
120
  - Add `Slide#element` and `SlideContext#element` getters — expose the slide body DOM element directly for cases where `find()` is not sufficient, such as measuring dimensions, attaching event listeners, or integrating third-party libraries.
105
121
 
106
- ### v0.10.0
107
-
108
- - Replace internal `SlideChain` with an exported `SlideContext` class. `SlideContext` accumulates elapsed time across `after()` calls exactly as `SlideChain` did, but also exposes `find()`, `setTimeout()`, and a `get elapsed()` getter. `Slide#after()` now returns a `SlideContext` — existing slide scripts are unaffected.
109
- - Add `Slide#loop(callback, {delay})` — runs a callback in a repeating loop until the slide changes. The callback receives a fresh `SlideContext` each iteration so it can schedule steps with `after()`. The loop waits for all steps to complete (`context.elapsed`) plus an optional extra `delay` before starting the next iteration. All timeouts flow through the slide's existing tracked `setTimeout`, so they are cancelled automatically on slide change.
110
-
111
- ### v0.9.0
112
-
113
- - `SlideBuilder#show` and `SlideBuilder#next` no longer overwrite `view-transition-name` on elements that already have one set. This allows elements with explicit names (for morph transitions to other slides) to coexist with the build system — they still get `visibility` and `viewTransitionClass` managed, but keep their own name.
114
-
115
122
  ## See Also
116
123
 
117
124
  - [lively](https://github.com/socketry/lively) — The real-time application framework that powers Presently.
data/releases.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Releases
2
2
 
3
+ ## v0.19.0
4
+
5
+ - Support language-prefixed inline code such as `ruby:` for syntax highlighting.
6
+ - Preserve blank lines within consistently indented HTML blocks in slide Markdown.
7
+
8
+ ## v0.18.0
9
+
10
+ - Render slides on a responsive 16:9 canvas across the display, presenter, recording, playback, and export interfaces.
11
+ - Center diagram content by default, add optional diagram titles, and make free-form absolute positioning explicit with `.diagram-freeform`.
12
+ - Prevent slide backgrounds and content from flickering during view transitions.
13
+ - Add lifecycle-managed Anime.js animation scopes, reusable diagram setup scripts, and guidance for authoring animated diagrams.
14
+ - Truncate long slide paths responsively while preserving their filenames in presenter controls.
15
+ - Preserve the complete saved presentation state when restoring the controller.
16
+
3
17
  ## v0.17.2
4
18
 
5
19
  - Fix slide rendering events for generated view identifiers that begin with a digit.
@@ -1,4 +1,9 @@
1
1
  <div class="slide-inner diagram-template">
2
+ <?r if self.section?("title") ?>
3
+ <div class="slide-title">
4
+ #{self.section("title")}
5
+ </div>
6
+ <?r end ?>
2
7
  <div class="slide-body">
3
8
  #{self.section("body")}
4
9
  </div>
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.17.2
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0.16'
75
+ version: '0.19'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0.16'
82
+ version: '0.19'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: async-webdriver
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -118,6 +118,7 @@ files:
118
118
  - bake/presently/rehearse.rb
119
119
  - bake/presently/slides.rb
120
120
  - bin/presently
121
+ - context/animated-diagrams.md
121
122
  - context/animating-slides.md
122
123
  - context/getting-started.md
123
124
  - context/index.yaml
@@ -246,6 +247,8 @@ files:
246
247
  - public/_components/@socketry/syntax/themes/base/xrb.css
247
248
  - public/_components/@socketry/syntax/themes/base/yaml.css
248
249
  - public/_components/@socketry/syntax/themes/theming.md
250
+ - public/_components/animejs/LICENSE.md
251
+ - public/_components/animejs/dist/bundles/anime.esm.min.js
249
252
  - public/_static/custom.css
250
253
  - public/_static/index.css
251
254
  - public/application.js
metadata.gz.sig CHANGED
Binary file