summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/site/casts/casts.toml2
-rw-r--r--docs/site/site.typ28
2 files changed, 24 insertions, 6 deletions
diff --git a/docs/site/casts/casts.toml b/docs/site/casts/casts.toml
index 67553089..5771e6be 100644
--- a/docs/site/casts/casts.toml
+++ b/docs/site/casts/casts.toml
@@ -1,5 +1,5 @@
# The landing page's terminal recordings (asciicast v2), in the order
-# shown: casts/<name>.cast for each. The first plays by itself; all loop
+# shown: casts/<name>.cast for each. Each plays by itself while on screen; all loop
# and fit the page's width. While `ready` is false the cast shows
# placeholder.svg, so the site builds before a recording exists.
# test/record_casts.py writes the casts and this file.
diff --git a/docs/site/site.typ b/docs/site/site.typ
index b308853d..e0cd9d4d 100644
--- a/docs/site/site.typ
+++ b/docs/site/site.typ
@@ -128,15 +128,17 @@
#doc-links.update(true)
-#let video(c) = el("video", (poster: "media/" + c.name + ".png", muted: "", loop: "", playsinline: "",
- controls: "", preload: "none"))[
+// Every recording plays by itself; the script below plays each only while
+// it is on screen. Without the script, `autoplay` still plays them.
+#let video(c) = el("video", (poster: "media/" + c.name + ".png", autoplay: "", muted: "", loop: "", playsinline: "",
+ controls: ""))[
#el("source", (src: "media/" + c.name + ".webm", type: "video/webm"))[]
#el("source", (src: "media/" + c.name + ".mp4", type: "video/mp4"))[]
]
#let placeholder = el("img", (src: "media/placeholder.svg", alt: "", width: "640", height: "400"))[]
/// A terminal recording: a box the player fills, its data inline (so it
-/// plays from file://), its caption under it. The first ready one plays.
+/// plays from file://), its caption under it.
#let ready-casts = casts.filter(c => c.ready)
#let cast(c, i) = el("figure", (class: if i == 0 { "clip cast first" } else { "clip cast" }))[
#if c.ready { el("div", (class: "player", id: "cast-" + c.name, "aria-label": c.title))[] } else { placeholder }
@@ -145,14 +147,29 @@
#let player-script = {
let list = ready-casts.enumerate().map(((i, c)) => (
id: "cast-" + c.name, data: read("casts/" + c.name + ".cast"),
- cols: c.cols, rows: c.rows, autoPlay: i == 0,
+ cols: c.cols, rows: c.rows,
))
// "</" may not appear inside a script element
let data = json.encode(list, pretty: false).replace("</", "<\\/")
el("script", (src: "player/asciinema-player.min.js"))[]
- el("script")[#("for (const c of " + data + ") AsciinemaPlayer.create({data: c.data}, document.getElementById(c.id), {cols: c.cols, rows: c.rows, autoPlay: c.autoPlay, loop: true, fit: 'width'});")]
+ el("script")[#("for (const c of " + data + ") { const el = document.getElementById(c.id); el.player = AsciinemaPlayer.create({data: c.data}, el, {cols: c.cols, rows: c.rows, autoPlay: true, loop: true, fit: 'width'}); }")]
}
+/// Plays a recording while it is on screen and pauses it once it leaves.
+#let in-view-script = el("script")[#(
+ "(() => { if (!('IntersectionObserver' in window)) return;
+" +
+ " const p = el => el.player || (el.tagName === 'VIDEO' ? el : null);
+" +
+ " const io = new IntersectionObserver(es => { for (const e of es) { const r = p(e.target); if (!r) continue;
+" +
+ " if (e.isIntersecting) Promise.resolve(r.play()).catch(() => {}); else r.pause(); } }, {threshold: 0.25});
+" +
+ " for (const el of document.querySelectorAll('.clip video, .cast .player')) io.observe(el);
+" +
+ "})();"
+)]
+
#document(href("index"), title: "pardes", shell("index", "pardes")[
#el("h1", (class: "masthead"))[pardes]
#el("p", (class: "lead"))[#landing.lead]
@@ -185,6 +202,7 @@
el("link", (rel: "stylesheet", href: "player/asciinema-player.css"))[]
player-script
}
+ #in-view-script
])
#for p in pages.slice(1, -1) {