Skip to content

Slide-deck template renders blank in no-JS viewers (QuickLook / iMessage previews): slides start opacity:0 and only JS reveals them #68

Description

@bradleyy

Summary

Slide decks generated from templates/slide-deck.html render as a blank page in any HTML viewer that disables JavaScript — most notably macOS/iOS QuickLook, which is what runs when someone taps an .html attachment forwarded over iMessage, previews it in Finder (space bar), or opens a downloaded attachment preview in Safari/Mail.

Scrollable pages from the other templates (e.g. architecture.html) render fine in the same viewers because their entrance animations are pure CSS (@keyframes fadeUp ... both). The slide template is the outlier.

Root cause

In templates/slide-deck.html (and the same pattern documented in references/slide-patterns.md under "Cinematic Transitions"), every slide and every .reveal child starts hidden in base CSS:

.slide {
  opacity: 0;
  transform: translateY(40px) scale(0.98);
  ...
}
.slide .reveal { opacity: 0; ... }

Visibility is only ever restored by JavaScript — the SlideEngine's IntersectionObserver adding .visible. With JS disabled, nothing ever adds the class, so the entire deck stays at opacity: 0. The content is all there; it's just invisible.

Repro

  1. Generate any deck from the template (or use the template file itself).
  2. AirDrop/iMessage it to yourself and tap the attachment, or select the file in Finder and press space (QuickLook).
  3. Blank page. The same file opens fine in a normal browser tab.

Suggested fix (progressive enhancement, ~4 lines)

Gate the hidden initial state on a js class that only exists when scripts run:

<head>
  <script>document.documentElement.classList.add('js');</script>
.js .slide { opacity: 0; transform: translateY(40px) scale(0.98); transition: ...; }
.js .slide.visible { opacity: 1; transform: none; }
.js .slide .reveal { opacity: 0; ... }
.js .slide.visible .reveal { opacity: 1; transform: none; }

With JS on, behavior is identical (animations, dots, keyboard nav). With JS off, the deck degrades to a fully readable scroll-snap document — nav chrome simply doesn't appear since it's built by JS anyway. This matches the graceful-degradation spirit the skill already applies elsewhere (e.g. prefers-reduced-motion forces everything visible with !important).

Two small adjacent hardening suggestions while in there:

  • height: 100vh; fallback line before each height: 100dvh; (older WebKit embedded views).
  • A note in slide-patterns.md that QuickLook also blocks network fetches in many contexts, so Google Fonts fall back to system fonts in previews — worth keeping font stacks with good fallbacks (the templates already do this).

I hit this on v0.8.1 (installed via the marketplace). Happy to open a PR with the template + docs change if you'd take one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions