Skill: mtdnot/presentation-agent (version 1.0.0)

--- name: presentation-agent description: "Convert Markdown documents to presentation slides (PDF/PPTX/HTML) using Marp. Supports Mermaid diagrams (gantt, flowchart, etc.) and data graphs. Use when a user asks to create slides, presentations, or decks from Markdown files or text content." --- # Presentation Agent Convert Markdown to slides via Marp CLI with Mermaid diagram support. ## Quick Start ```bash bash scripts/md2slide.sh <input.md> [pdf|pptx|html] [output_dir] ``` ## Markdown Format Use standard Marp syntax. `---` separates slides. Add frontmatter: ```markdown --- marp: true theme: default paginate: true --- # Title Slide --- ## Content Slide - Point 1 - Point 2 ``` ## Mermaid Diagrams Include mermaid code blocks directly. They are auto-rendered to PNG and embedded: ````markdown ```mermaid gantt title Schedule dateFormat YYYY-MM-DD section Phase1 Task A :a1, 2026-01-01, 14d ``` ```` Supported: gantt, flowchart, sequence, pie, class, state, er diagrams. ## Data Graphs For matplotlib/plotly graphs, generate PNG first via `exec`, then embed as `![](path.png)` in the Markdown. ## Workflow 1. Receive Markdown content (or generate from user's data/request) 2. Ensure `marp: true` is in frontmatter 3. Run `bash scripts/md2slide.sh input.md pdf ./output` 4. Deliver the output file to the user ## デザインルール（必須） 以下はオーナーからの指示に基づく。全プレゼンで必ず守ること。 ### フォント - **明朝体を使う**（IPAex明朝等）。ゴシック体はデフォルトで使わない。 - Google Fontsなどのリモートフォントはmarp PDF変換時に読み込めない。**ローカルにインストール済みのフォントのみ使用**すること。 - フォントサイズは十分に大きくする（本文30px以上、h1は50px以上、h2は40px以上）。 ### 絵文字 - **スライド内で絵文字を使わない。** タイトル・見出し・本文すべて。 ### ロゴ - `theme/logo.jpg` を全スライド右上に表示する（frexida.cssのsection::before）。 - ロゴサイズは**120px以上**にする。小さすぎると見えない。 - PDF変換時にロゴが読み込まれるよう、CSSの`background-image: url()`には**絶対パス**を使うこと。 ### テーマ - `theme/frexida.css` を基本テーマとして使う（ネイビー＋ゴールド）。 - PDF変換時は `--theme` オプションでCSSを指定し、`--allow-local-files` を付ける。 - frexida.cssのfont-familyをローカル明朝体に差し替えたCSS（絶対パス版）を `/tmp/` に生成して使う。 ### データの可視化 - 具体的な日付・金額・数値がある場合は**できる限り図で可視化する**。 - Mermaidのガントチャート、フローチャート、円グラフ、遷移図などを積極的に使う。 - テーブルだけで済ませず、視覚的にわかるようにすること。 ### Mermaidプリプロセス - Mermaidブロックを含むMarkdownは、必ず `scripts/mermaid_preprocess.py` でPNGに変換してからmarpに渡す。 - 出力先ディレクトリは事前に `mkdir -p` すること（スクリプト内で作成されない）。 ### md2slide.sh使用時の注意 - stdinを読もうとしてハングするため、直接marpコマンドを `--no-stdin` 付きで実行するか、`< /dev/null` を付けること。 ## Dependencies - `@marp-team/marp-cli` (npm global) - `@mermaid-js/mermaid-cli` (npm global) - Both already installed on this host.

path: scripts/md2slide.sh
content: #!/usr/bin/env bash
# md2slide.sh — Markdown → Marp スライド変換（Mermaid + Tailwind CSS対応）
# Usage: md2slide.sh <input.md> [format: pdf|pptx|html] [output_dir]
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
THEME_DIR="$(cd "${SCRIPT_DIR}/../theme" && pwd)"
INPUT="${1:?Usage: md2slide.sh <input.md> [pdf|pptx|html] [output_dir]}"
FORMAT="${2:-pdf}"
OUTDIR="${3:-.}"
BASENAME="$(basename "${INPUT}" .md)"
OUTPUT="${OUTDIR}/${BASENAME}.${FORMAT}"

mkdir -p "${OUTDIR}"

TMPMD="$(mktemp /tmp/marp_XXXXXX.md)"
IMGDIR="$(mktemp -d /tmp/marp_img_XXXXXX)"

# Pre-process: mermaid blocks → PNG
python3 "${SCRIPT_DIR}/mermaid_preprocess.py" "${INPUT}" "${TMPMD}" "${IMGDIR}"

# Inject Tailwind CSS script tags after frontmatter (if not already present)
if ! grep -q 'tailwindcss' "${TMPMD}"; then
  python3 -c "
import re
content = open('${TMPMD}').read()
tailwind_tags = '''<script src=\"${THEME_DIR}/js/tailwindcss-3.0.16.js\"></script>
<script src=\"${THEME_DIR}/js/tailwind.config.js\"></script>
'''
# Insert after frontmatter closing ---
match = re.match(r'(---\n.*?\n---\n)', content, re.DOTALL)
if match:
    pos = match.end()
    content = content[:pos] + '\n' + tailwind_tags + '\n' + content[pos:]
else:
    content = tailwind_tags + '\n' + content
open('${TMPMD}', 'w').write(content)
"
fi

# Convert with Marp
case "${FORMAT}" in
  pdf)  marp "${TMPMD}" --pdf -o "${OUTPUT}" --allow-local-files --html --theme-set "${THEME_DIR}/frexida.css" < /dev/null ;;
  pptx) marp "${TMPMD}" --pptx -o "${OUTPUT}" --allow-local-files --html --theme-set "${THEME_DIR}/frexida.css" < /dev/null ;;
  html) marp "${TMPMD}" -o "${OUTPUT}" --allow-local-files --html --theme-set "${THEME_DIR}/frexida.css" < /dev/null ;;
  *)    echo "Unknown format: ${FORMAT}"; exit 1 ;;
esac

rm -rf "${TMPMD}" "${IMGDIR}"
echo "✅ ${OUTPUT}"


path: scripts/mermaid_preprocess.py
content: #!/usr/bin/env python3
"""Extract mermaid blocks from markdown, render to PNG, replace with image refs."""
import sys, re, subprocess, os

infile, outfile, imgdir = sys.argv[1], sys.argv[2], sys.argv[3]
content = open(infile).read()
idx = 0

def replace_mermaid(m):
    global idx
    mmd = os.path.join(imgdir, f"mermaid_{idx}.mmd")
    png = os.path.join(imgdir, f"mermaid_{idx}.png")
    with open(mmd, 'w') as f:
        f.write(m.group(1))
    subprocess.run(
        ["mmdc", "-i", mmd, "-o", png, "-b", "transparent", "--width", "1200"],
        stdin=subprocess.DEVNULL, capture_output=True, timeout=30
    )
    idx += 1
    if os.path.exists(png):
        return f"![mermaid]({png})"
    return m.group(0)

content = re.sub(r'```mermaid\n(.*?)```', replace_mermaid, content, flags=re.DOTALL)
open(outfile, 'w').write(content)


path: theme/frexida.css
content: /* @theme frexida */
@import 'default';

:root {
  /* Brand Colors */
  --brand-navy: #162033;
  --brand-gold: #C9A227;
  --deep-accent: #0E1624;
  --bg-light: #F4F1EA;
  --bg-white: #FAFAF8;
  /* UI Colors */
  --color-success: #1F7A5C;
  --color-warning: #C97A00;
  --color-error: #A83232;
  --color-border: #D6D3CC;
  --color-text-muted: #5C6370;
}

section {
  background-color: var(--bg-white);
  color: var(--brand-navy);
  font-family: 'Noto Sans JP', 'Helvetica Neue', Arial, sans-serif;
}

section::after {
  /* Page number styling */
  color: var(--color-text-muted);
}

/* Logo in top-right of every slide */
section::before {
  content: '';
  position: absolute;
  top: 20px;
  right: 24px;
  width: 48px;
  height: 48px;
  background-image: url('./logo.png');
  background-size: contain;
  background-repeat: no-repeat;
  z-index: 10;
}

h1, h2, h3, h4, h5, h6 {
  color: var(--brand-navy);
}

h1 {
  border-bottom: 3px solid var(--brand-gold);
  padding-bottom: 8px;
}

a {
  color: var(--brand-gold);
}

strong {
  color: var(--deep-accent);
}

blockquote {
  border-left: 4px solid var(--brand-gold);
  background-color: var(--bg-light);
  color: var(--brand-navy);
}

table th {
  background-color: var(--brand-navy);
  color: var(--bg-white);
}

table td {
  border-color: var(--color-border);
}

code {
  background-color: var(--bg-light);
  color: var(--deep-accent);
}

/* Typography - em-based */
.text-em-3xl { font-size: 1.875em; line-height: 1.2; }
.text-em-2xl { font-size: 1.5em; line-height: 1.25; }
.text-em-xl { font-size: 1.25em; line-height: 1.3; }
.text-em-lg { font-size: 1.125em; line-height: 1.4; }
.text-em-base { font-size: 1em; line-height: 1.5; }

/* Primary Gradient */
.bg-gradient-primary {
  background: linear-gradient(to right, #1B4565, #3E9BA4);
}


path: theme/js/tailwind.config.js
content: tailwind.config = {
  corePlugins: {
    preflight: false,
  },
};


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)