Commit Graph

18 Commits

Author SHA1 Message Date
lewis 36ecd2cf30 fix(presenter): sync theme across audience + presenter iframes (T key)
Problem: pressing T in audience window only swapped the host page's
theme CSS link. Preview iframes in the presenter window stayed on the
theme that was active when the popup was opened (or the HTML default).

Fix: 3-hop theme propagation via message types
1. audience cycleTheme() → BroadcastChannel 'theme' message
2. presenter window receives BC msg → postMessage 'preview-theme'
   to both iframes
3. iframe preview mode listens for 'preview-theme' → swaps its own
   <link id='theme-link'> href

Also:
- Audience window listens for 'theme' BC events → applies theme
  (so pressing T in one window cycles theme in BOTH)
- Presenter window captures audience's current theme at open time
  (data-theme attr) and forwards it to each iframe on 'preview-ready'
  so previews match audience from frame 1, even if audience had
  already cycled theme before opening presenter
- preview mode auto-detects theme base path from existing
  theme-link href (same logic as audience cycleTheme)

Verified in headless Chrome: BC msg {type:theme, name:dracula} →
both audience and preview iframes show data-theme=dracula with
matching colors.
2026-04-17 23:34:09 +08:00
lewis b64ce0f832 perf(presenter): smooth navigation via postMessage (no reload, no flicker)
Problem: Switching slides reset iframe.src each time, causing visible
flicker (white flash → load → render) on every navigation.

Solution: load each preview iframe ONCE, then use postMessage for all
subsequent slide changes. The iframe stays mounted; only .is-active
class toggles between slides inside it.

Changes:
- runtime.js preview mode: now exposes a showSlide() function and
  listens for window.message events of type 'preview-goto'. Also
  posts 'preview-ready' to parent on init so the presenter window
  knows when each iframe is loaded.
- presenter window: tracks iframeReady state per iframe; first frame
  renders via iframe.src = ?preview=N (one-time), all subsequent
  navigation goes through postPreviewGoto() → postMessage. Notes,
  meta, and timer update directly without touching iframes.
- Init no longer calls update(idx) which used to reset iframe.src;
  instead inits notes/meta/count once and lets the load→ready flow
  populate previews.

Docs synced to match new architecture:
- SKILL.md: describes 4 magnetic cards, draggable/resizable, with
  the iframe ?preview=N pattern explained for AI consumers
- references/presenter-mode.md: updated ASCII diagram to show 4
  cards, removed old 58%/35% layout description, added explanation
  for why previews are pixel-perfect (iframe loads same HTML) and
  why navigation is flicker-free (postMessage, not reload)
- presenter-mode-reveal README: updated 4-card description
2026-04-17 23:27:05 +08:00
lewis 832f5be212 feat(presenter): magnetic-card UI with pixel-perfect iframe previews
Complete rewrite of presenter mode. Two-part solution:

1. Single-slide preview mode in runtime.js
   - Detect ?preview=N query param on page load
   - When present: show only slide N, hide all chrome (progress-bar,
     notes-overlay, overview), skip key handlers, skip hash/broadcast
   - This lets the presenter window load the deck file in iframes with
     specific slides — CSS/theme/colors 100% identical to audience view

2. Magnetic-card presenter window
   - 4 independent cards (CURRENT / NEXT / SCRIPT / TIMER)
   - Each card is position:absolute, draggable by header, resizable by
     bottom-right corner handle
   - Cards have colored indicator dots matching their role
   - Dragging shows blue outline; resizing shows green
   - Layout persists to localStorage per-deck, with 'Reset layout' button
   - Default layout: CURRENT big top-left, NEXT top-right, SCRIPT
     bottom-right, TIMER bottom-left

Previews use iframe.src = deckUrl + '?preview=N':
  - iframe loads THE SAME HTML file as the audience
  - runtime.js detects ?preview=N and renders only that slide
  - CSS transform:scale() fits 1920x1080 into card body, centered
  - Zero style injection / zero HTML escaping — can't break

Sync: BroadcastChannel keeps audience ↔ presenter in lockstep.

Verified with headless Chrome: tokyo-night theme, gradient headlines,
speaker avatars, agenda rows — all render identically between windows.
2026-04-17 23:21:45 +08:00
lewis 0fc41be493 feat(presenter): preserve slide layout + draggable splitters
Two user-reported issues fixed:

1. Slide layout broken in preview (content stuck to top, not centered)
   Root cause: iframe CSS was forcing .slide { display:block !important }
   which overrode base.css's .slide { display:flex; justify-content:center }
   Fix: Do NOT override .slide or .deck styling in iframe. Let host CSS
   (base.css + theme + scoped) handle flex centering, padding, etc.
   Only override .is-active visibility and hide notes/chrome.

2. Users can now resize preview regions
   - Horizontal splitter between current (left) and right column
   - Vertical splitter between next preview (top) and notes (bottom)
   - Splitters show blue hover state, drag updates flex sizes
   - reScale() called on every drag frame to keep iframe 1:1 accurate
   - Min sizes enforced (200px width, 80-100px height) to prevent collapse

Verified with headless Chrome: cover slide now correctly vertically
centered in the preview, matching audience view pixel-perfect.
2026-04-17 23:05:48 +08:00
lewis 647a908eab fix(presenter): use contentDocument.write() instead of srcdoc
Previous iframe srcdoc approach completely broke because .replace(/"/g, '&quot;')
mangled the stylesheet <link href="..."> into <link href=&quot;...&quot;>,
causing browser to treat the entire &quot;file://...&quot; as the attribute
value literal. All CSS failed to load → blank/unstyled preview.

New approach:
- iframe.contentDocument.write() takes raw HTML string, NO escaping needed
- All quotes (double and single) pass through untouched
- stylesheet href attributes remain valid
- body class and html attrs pass through cleanly
- Added initWhenReady() polling to ensure iframe contentDocument is available
  before first render (avoids race condition where document.write fires
  before iframe is fully initialized)

Verified with headless Chrome render — current/next slides now show correct
colors, fonts, layout matching audience view pixel-for-pixel.
2026-04-17 22:57:23 +08:00
lewis 06d6283ff7 fix(presenter): use iframe srcdoc for pixel-perfect slide preview
Root cause: CSS viewport units (vw/vh), clamp(), and percentage-based
layouts resolve against the actual viewport, not a fixed-size div.
DOM clones in a 1920x1080 container still render differently from the
audience view because the iframe-less context has the wrong viewport.

Fix: replace DOM clone approach with <iframe srcdoc='...'> for both
current and next slide previews. Each iframe:
- Is sized 1920x1080 (matching the design resolution)
- Creates its own viewport context (100vw=1920px, 100vh=1080px)
- Loads the full page CSS (absolute URLs) + body classes + html attrs
- Wraps the single slide in a .deck container
- CSS transform:scale() shrinks it to fit the preview area
- Result: pixel-perfect match with audience view

Also: srcdoc template carries the host page's body classes (e.g.
.tpl-presenter-mode-reveal) and html attributes (data-themes, lang)
so scoped CSS and theme variables work correctly inside the iframe.
2026-04-17 22:50:34 +08:00
lewis 0ce226f87c fix(presenter): theme path + popup slide rendering fidelity
3 bugs fixed:

1. T key theme path error (ERR_FILE_NOT_FOUND)
   - cycleTheme now auto-detects theme base path from existing
     <link id='theme-link'> href instead of hardcoding 'assets/themes/'
   - Works correctly from any subdirectory depth (e.g. templates/full-decks/xxx/)

2. Presenter popup colors wrong (gray/missing styles)
   - Popup <body> now inherits host page's body classes (e.g. .tpl-presenter-mode-reveal)
     so scoped CSS selectors like .tpl-xxx .slide work correctly
   - Popup <html> inherits all host attributes (lang, data-themes, data-theme, etc.)
   - Added .pv-body class with !important overrides to ensure presenter layout
     wins over any host CSS that might affect body

3. Presenter popup slide layout mismatch
   - Slides are now wrapped in a proper <div class='deck'> container at
     exactly 1920×1080px, matching the audience window's DOM structure
   - .pv-stage-inner .deck .slide forced to 1920×1080 with !important
   - Removed all manual style.xxx = overrides in renderSlide(); layout comes
     purely from CSS now, matching the audience view pixel-for-pixel
   - Hidden runtime chrome (.progress-bar, .notes-overlay, .overview, etc.)
     inside preview clones
2026-04-17 22:42:54 +08:00
lewis 23d9f5d369 fix(presenter): rewrite as popup window with CSS scale() rendering
BREAKING: S key no longer overlays on the same page. It now opens a
separate browser window (window.open) for the presenter.

Audience window (original page):
- Stays completely untouched — normal slide view
- S key opens the presenter popup
- ← → / T / F / O all work as before
- Navigation syncs to presenter via BroadcastChannel

Presenter window (popup):
- Current slide rendered at 1920×1080 then CSS transform:scale() to fit
- Next slide preview also at 1920×1080 scale() — layout never breaks
- Large-font speaker script (18px, scrollable)
- Elapsed timer + page counter + current slide title
- ← → navigates (syncs back to audience window)
- R resets timer, Esc closes popup

Technical:
- runtime.js builds presenter HTML dynamically (buildPresenterHTML)
- Collects all slide outerHTML + notes + all stylesheets from host page
- Injects into popup via document.write()
- BroadcastChannel keyed by pathname for multi-deck isolation
- base.css: removed all old inline .pv-* / .presenter-view styles
  (presenter styles now self-contained in popup HTML)

Docs updated:
- SKILL.md: describes popup behavior, separate keyboard sections
- references/presenter-mode.md: new dual-window diagram, updated flow
- presenter-mode-reveal/README.md: updated S key and dual-screen guide
2026-04-17 22:36:04 +08:00
lewis 43c4a74f63 feat(presenter): add true presenter view (S) with speaker script + timer
Runtime (assets/runtime.js):
- S key now opens a split-view presenter mode: current slide (left 55%) +
  next-slide preview + large-font speaker script (150-300 words, scrollable)
  + elapsed timer + page counter
- Legacy bottom notes drawer moved to N key (keeps backward compat)
- R key resets timer (only active inside presenter view)
- Esc closes all overlays (overview / notes / presenter)
- Auto-picks up <aside class="notes">, <div class="notes">, or .speaker-notes

Styles (assets/base.css):
- New .presenter-view grid layout with pv-main / pv-side / pv-notes / pv-bar
- body.presenter-mode hides deck chrome from the operator's eye
- Timer styled with JetBrains Mono green (#3fb950)

New template (templates/full-decks/presenter-mode-reveal/):
- 6-slide demo deck designed around the S key presenter flow
- 5 presets via T key: tokyo-night, dracula, catppuccin-mocha, nord, corporate-clean
- Every slide ships a complete 150-300 word <aside class="notes"> example
  written in the "3 rules of speaker script" style
- Scoped .tpl-presenter-mode-reveal CSS with rule-row, feature-row, code-block
- README explains the full authoring flow

Docs:
- New references/presenter-mode.md — when to use, 3 rules of \u9010\u5b57\u7a3f writing
  (\u63d0\u793a\u4fe1\u53f7 / 150-300 \u5b57 / \u53e3\u8bed), required HTML structure, common mistakes,
  standard AI prompt for generating speaker scripts
- SKILL.md: upgraded template count 14 -> 15, added Presenter Mode section
  in 'When to use' with trigger keywords
- full-decks.md: row 15 added with \ud83c\udfa4 marker
- full-decks-index.html gallery now lists presenter-mode-reveal
2026-04-17 22:19:53 +08:00
lewis c52acbff47 fix: resolve DANGEROUS scan warnings on install
- HTML-encode destructive command text in testing-safety-alert template
  to avoid false positive CRITICAL destructive scan hits
- Add .clawscan-allow allowlist for path traversal false positives
  (templates correctly reference root assets via ../../../)

Closes #3
2026-04-17 21:47:11 +08:00
lewis 376dfe5e77 fix: hide .notes from slides + add explicit no-presenter-text rule
- base.css: add .notes{display:none!important} so speaker notes are never
  visible on the rendered slide (only in S overlay)
- SKILL.md: add NEVER-put-presenter-text rule in authoring rules
- authoring-guide.md: add same rule in What to NOT do section

Fixes issue where AI would put small descriptive/presenter-only text
directly on slide markup instead of inside <div class='notes'>.
2026-04-16 11:27:32 +08:00
lewis 9f99b12b12 docs(readme): add hero GIF (cover with live previews) + layouts cycling GIF
- hero.gif (~2.4 MB): intro-deck cover page captured live showing the
  3 preview strips all running (full decks / canvas FX / cycling layouts)
- layouts-live.gif (~570 KB): the 31-layout auto-rotator cycling through
  kpi-grid -> chart-line -> timeline in real templates/single-page files
- README: hero GIF moved to the very top as the opening visual,
  layouts-live.gif inserted below the 31-layout section next to layouts.png
2026-04-15 22:36:33 +08:00
lewis 0824d3648b docs(readme): embed themes / layouts / animations / templates showcase screenshots
- add docs/readme/montage-{themes,layouts,animations,templates}.html
- pre-render each montage to a 1920x1080 PNG via headless Chrome
- embed all 4 hero screenshots into README.md
- themes.png shows 8 live theme previews
- layouts.png shows 8 real single-page layouts
- animations.png shows 8 canvas FX tiles with running particles
- templates.png shows 6 full-deck iframes
2026-04-15 22:32:28 +08:00
lewis 9bbca1697e docs: audit README + SKILL — accurate counts, install command, pre-author checklist
- README fully rewritten: correct 36 themes / 31 layouts / 27 CSS + 20 FX anims / 14 full decks
- Add one-line install: npx skills add https://github.com/lewislulu/html-ppt-skill
- List all 36 theme names, 14 full-deck names, and the animation catalogs
- SKILL.md: fix 30 → 31 layouts, 25 → 27 CSS animations
- SKILL.md: add 'Before you author anything' section — always ask user about
  content/style/starting-point, or recommend themes based on audience
- SKILL.md: fix duplicate '5.' in Quick start numbering
2026-04-15 17:08:58 +08:00
lewis 3f6558d11e chore: drop fix-brief 2026-04-15 16:38:23 +08:00
lewis db0f0cee33 fix: v2 — iframe theme isolation, 8 full-deck templates from source decks, 20 FX animations (particles/graph/fireworks), +12 themes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 16:29:08 +08:00
lewis a93138e1bf feat: html-ppt AgentSkill — 24 themes, 31 layouts, 20+ animations
World-class HTML presentation skill with keyboard navigation, theme/animation
switching, headless Chrome rendering, and showcase decks for themes/layouts/animations.

- 24 themes (minimal-white, dracula, catppuccin, tokyo-night, xiaohongshu-white, …)
- 31 single-page layouts (cover, code, charts, timeline, gantt, mindmap, …)
- 20+ named animations (rise-in, typewriter, confetti-burst, card-flip-3d, …)
- theme/layout/animation showcase decks
- runtime.js: arrow/space/F/S/O/T/A keybinds, hash routing, progress bar
- render.sh headless Chrome PNG export
- MIT, author lewis <sudolewis@gmail.com>
2026-04-15 15:36:16 +08:00
lewis 5554a11c85 feat: html-ppt AgentSkill — HTML PPT Studio
Token-driven static HTML presentation system. One skill directory under
html-ppt/ implementing the full AgentSkills spec.

- 24 themes (assets/themes/*.css): minimal-white, editorial-serif,
  soft-pastel, sharp-mono, arctic-cool, sunset-warm, catppuccin-latte/mocha,
  dracula, tokyo-night, nord, solarized-light, gruvbox-dark, rose-pine,
  neo-brutalism, glassmorphism, bauhaus, swiss-grid, terminal-green,
  xiaohongshu-white, rainbow-gradient, aurora, blueprint, memphis-pop.
  Each overrides only CSS custom properties consumed by base.css.
- 31 single-page layout templates (templates/single-page/) with realistic
  demo data: cover, toc, section-divider, bullets, two/three-column,
  big-quote, stat-highlight, kpi-grid, table, code (highlight.js), diff,
  terminal, flow/arch/mindmap diagrams, timeline, roadmap, gantt,
  comparison, pros-cons, checklist, image-hero/grid, chart-bar/line/pie/
  radar (chart.js), process-steps, cta, thanks.
- 27 named animations (assets/animations/animations.css) applied via
  class="anim-<name>" or data-anim="<name>"; runtime re-triggers on slide
  enter. Respects prefers-reduced-motion.
- Runtime (assets/runtime.js): ←/→/Space/PgUp/PgDn/Home/End nav, F
  fullscreen, S speaker notes overlay, O overview grid, T cycle themes,
  A cycle animations, #/N deep-link, progress bar, counter-up tick-up.
- Showcase decks: theme-showcase.html (24), animation-showcase.html (27),
  layout-showcase.html (iframe tour of 30 layouts), deck.html starter.
- Scripts: render.sh (headless Chrome at /Applications/Google Chrome.app,
  1920×1080, multi-slide via #/N) and new-deck.sh (scaffold from deck.html).
- References: themes.md, layouts.md, animations.md, authoring-guide.md.
- examples/demo-deck/ — complete 8-slide deck using aurora theme + chart.js.
- SKILL.md with trigger keywords (presentation, PPT, slides, keynote, deck,
  幻灯片, 演讲稿, reveal, 小红书图文) and authoring rules.
- MIT LICENSE, README.md.

Author: lewis <sudolewis@gmail.com>
2026-04-15 15:35:03 +08:00