Files
open-design/skills/html-ppt/scripts/render.sh
Tom HuangandGitHub f4ab52d9dd feat(skills): integrate lewislulu/html-ppt-skill + 15 per-template Examples cards (#193)
* feat(skills): integrate lewislulu/html-ppt-skill as html-ppt + 15 per-template Examples cards

Bring the MIT-licensed lewislulu/html-ppt-skill upstream into skills/html-ppt/
with its full asset tree (36 themes, 31 single-page layouts, 27 CSS + 20
canvas-FX animations, runtime + presenter mode, all 15 full-deck templates,
and the upstream LICENSE preserved verbatim).

Surface each full-deck template as its own Examples gallery card via thin
wrapper skills under skills/html-ppt-<template>/. Each wrapper ships:

- SKILL.md with `od.mode=deck`, scenario, `featured: 20-34` (slotting after
  the existing curated cards), an `od.example_prompt` tuned to the template,
  and `od.upstream` pointing at the upstream repo. Clicking "Use this prompt"
  on a card now wires up `kind=deck` + `speakerNotes=true` and seeds the
  composer with the upstream's authoring flow so the prompt -> output path
  matches the upstream demo.
- example.html baked self-contained (fonts/base/animations/style/theme CSS
  inlined, runtime <script> stripped) so the gallery srcdoc iframe renders
  the upstream look without external paths.

scripts/scaffold-html-ppt-skills.mjs and scripts/bake-html-ppt-examples.mjs
are idempotent generators — re-run after editing skills/html-ppt/ to re-sync
all per-template wrappers and their baked examples.

Add a Credits section + extend the License section in README.md /
README.zh-CN.md / README.ko.md to credit the upstream alongside the
already-cited op7418/guizang-ppt-skill.

* fix(scripts): allowlist html-ppt skill JS for residual-js check

Add scripts/bake-html-ppt-examples.mjs and scripts/scaffold-html-ppt-skills.mjs
to allowedExactPaths, and skills/html-ppt/assets/ to allowedPathPrefixes so
pnpm check:residual-js no longer flags the vendored upstream runtime JS or the
new maintainer-only .mjs scripts.

* fix(skills): keep all slides in baked html-ppt examples + correct asset guidance

The bake script's `STATIC_FALLBACK_CSS` set `.slide+.slide{display:none}`,
which silently truncated every baked `example.html` to slide 1. That artifact
is also served by `/api/skills/:id/example` and reused by the Examples
preview modal's share/export and print-to-PDF, so the rule dropped the rest
of the deck from those flows. Drop the rule — slides now stack in the
print-style flow the surrounding comment already described, the gallery
thumbnail iframe still naturally lands on slide 1 (each `.slide` is `100vh`),
and modal/share/export contains the full deck.

The wrapper SKILL.md authoring instructions told agents to copy
`index.html` + `style.css` into a project while keeping the upstream
`../../../assets/...` links, but those parent-relative URLs only resolve
in-tree (the template sits three folders deep). Once the file lives in a
project artifact, `base.css`, `animations.css`, and `runtime.js` 404 and
the deck never activates. Replace step 3 with two recipes — copy the
shared assets into a project-local `assets/` and rewrite the four tags,
or inline the CSS/JS directly — and re-emit all 15 wrapper SKILL.md
files via the scaffold generator.
2026-05-02 11:00:44 +08:00

72 lines
1.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# html-ppt :: render.sh — headless Chrome screenshot(s)
#
# Usage:
# render.sh <html-file> # one PNG, slide 1
# render.sh <html-file> <N> # N PNGs, slides 1..N, via #/k
# render.sh <html-file> all # autodetect .slide count
# render.sh <html-file> <N> <out-dir> # custom output dir
#
# Requires: Google Chrome at /Applications/Google Chrome.app (macOS).
set -euo pipefail
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
if [[ ! -x "$CHROME" ]]; then
echo "error: Chrome not found at $CHROME" >&2
exit 1
fi
FILE="${1:-}"
if [[ -z "$FILE" ]]; then
echo "usage: render.sh <html> [N|all] [out-dir]" >&2
exit 1
fi
if [[ ! -f "$FILE" ]]; then
echo "error: $FILE not found" >&2
exit 1
fi
COUNT="${2:-1}"
OUT="${3:-}"
ABS="$(cd "$(dirname "$FILE")" && pwd)/$(basename "$FILE")"
STEM="$(basename "${FILE%.*}")"
if [[ "$COUNT" == "all" ]]; then
COUNT="$(grep -c 'class="slide"' "$FILE" || true)"
[[ -z "$COUNT" || "$COUNT" -lt 1 ]] && COUNT=1
fi
if [[ -z "$OUT" ]]; then
if [[ "$COUNT" -gt 1 ]]; then
OUT="$(dirname "$FILE")/${STEM}-png"
mkdir -p "$OUT"
fi
fi
render_one() {
local url="$1" target="$2"
"$CHROME" \
--headless=new \
--disable-gpu \
--hide-scrollbars \
--no-sandbox \
--virtual-time-budget=4000 \
--window-size=1920,1080 \
--screenshot="$target" \
"$url" >/dev/null 2>&1
echo " ✔ $target"
}
if [[ "$COUNT" == "1" ]]; then
OUT_FILE="${OUT:-$(dirname "$FILE")/${STEM}.png}"
render_one "file://$ABS" "$OUT_FILE"
else
for i in $(seq 1 "$COUNT"); do
render_one "file://$ABS#/$i" "$OUT/${STEM}_$(printf '%02d' "$i").png"
done
fi
echo "done: rendered $COUNT slide(s) from $FILE"