Sn Ppt Doctor
OpenSenseNova/SenseNova-Skills
A skill your agent uses when diagnosing PPT Skill setup or failures involving source parsing, Playwright or Chromium rendering, HTML-to-PPTX export, Workbench startup, or bundled search and…
Convert Kami HTML templates to production-grade PDF via Chromium/Playwright.
$ npx skills add EliasOulkadi/shokunin --skill kagen -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install EliasOulkadi/shokunin kagen --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.pack/skills/kagen .claude/skills/kagen && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "kagen" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/kagen into .claude/skills/kagen/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "kagen", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/kagenType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add EliasOulkadi/shokunin --skill kagen -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install EliasOulkadi/shokunin kagen --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.pack/skills/kagen .agents/skills/kagen && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "kagen" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/kagen into .agents/skills/kagen/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "kagen", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add EliasOulkadi/shokunin --skill kagen -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install EliasOulkadi/shokunin kagen --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.pack/skills/kagen .cursor/skills/kagen && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "kagen" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/kagen into .cursor/skills/kagen/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "kagen", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/EliasOulkadi/shokunin.git --path .pack/skills/kagen--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add EliasOulkadi/shokunin --skill kagen -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install EliasOulkadi/shokunin kagen --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.pack/skills/kagen .gemini/skills/kagen && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "kagen" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/kagen into .gemini/skills/kagen/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "kagen", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install EliasOulkadi/shokunin kagenInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add EliasOulkadi/shokunin --skill kagen -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .github/skills && cp -r skills-src/.pack/skills/kagen .github/skills/kagen && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "kagen" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/kagen into .github/skills/kagen/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "kagen", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add EliasOulkadi/shokunin --skill kagen -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install EliasOulkadi/shokunin kagen --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.pack/skills/kagen .opencode/skills/kagen && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "kagen" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/kagen into .opencode/skills/kagen/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "kagen", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
kagenConvert Kami HTML templates to production-grade PDF via Chromium/Playwright.
Kagen is an agent skill from EliasOulkadi/shokunin. Convert Kami HTML templates to production-grade PDF via Chromium/Playwright. Complements Kami (design) with PDF rendering. Use when user asks to generate PDF files, render HTML to PDF, or export documents.
Its SKILL.md is about 6.4k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts. Compatibility notes: opencode
It sits in Documents & Office, covering PDF and Browser testing. It works with Playwright. The repository describes itself as: 職人 Shokunin 62 AI agent skills for OpenCode, Claude Code, Cursor, Windsurf. ChromaDB memory, MCP servers, declarative self-updates. Multi-model, open source, zero cost. The licence is MIT.
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 4c68e5b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npxblackFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
playwright.devpdf4.devbrowserstack.comprint-css.rocksdocupotion.comw3.orgblog.rasc.chnews.ycombinator.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
opencode
From compatibility in the SKILL.md frontmatter.
Kagen loads about 6.4k tokens when it runs. Until then it costs about 53 tokens; SKILL.md has 2,224 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from EliasOulkadi/shokunin at commit 4c68e5b, republished under its MIT licence (© EliasOulkadi). 2,224 words, ~6,368 tokens.
.claude/skills/kagen/SKILL.md (or your agent's skills folder).紙源 · かげん - paper source. PDF generation companion to Kami.
Kami designs, Kagen ships. Converts Kami HTML templates to production-grade PDF using Chromium (Playwright), bypassing WeasyPrint's Windows limitations.
| Problem | Solution |
|---|---|
| WeasyPrint doesn't work on Windows (no GTK) | Kagen uses Playwright/Chromium — works everywhere |
| WeasyPrint cold-start ~630ms per render | Playwright warm ~13ms per render |
| WeasyPrint can't execute JS | Chromium renders fully (charts, dynamic content) |
| wkhtmltopdf is deprecated and unmaintained | Playwright is actively maintained by Microsoft |
Based on benchmarks (pdf4.dev 2026), engineering discussions (HN, Stack Overflow, BrowserStack), and production experience from DocRaptor, customjs.space, and print-css.rocks.
npx playwright auto-installs on first use)npx playwright install chromium)npx playwright pdf "file:///path/to/doc.html" "output.pdf"Or from Node.js:
const { chromium } = require('playwright');
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('file:///path/to/doc.html', { waitUntil: 'networkidle' });
await page.pdf({
path: 'output.pdf',
format: 'A4',
printBackground: true,
margin: { top: '0', bottom: '0', left: '0', right: '0' }
});
await browser.close();await page.pdf({
path: 'output.pdf',
format: 'A4', // or 'Letter', 'A3'
printBackground: true, // always true — renders parchment bg
margin: { top: '0', bottom: '0', left: '0', right: '0' },
// For screen media (not print):
// await page.emulateMedia({ media: 'screen' });
});/* Always include in your HTML template header */
@page {
size: A4;
margin: 24mm 26mm 26mm 26mm;
background: #f5f4ed;
widows: 4;
orphans: 4;
}
/* Force background colors in Chromium */
* {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
/* Avoid orphan text lines — high widows/orphans prevents single-line splits */
body { widows: 4; orphans: 4; }
p { widows: 3; orphans: 3; }
li { widows: 2; orphans: 2; }
/* Page break control — only on chapters with heavy content */
.chapter { }
.chapter.break { break-before: page; }
/* Never let a heading sit alone at page bottom */
h1, h2, h3, h4 { break-after: avoid; }
/* Keep these blocks intact — never split across pages */
table, pre, figure, .callout, .card,
blockquote, .finding-header, .takeaway {
break-inside: avoid;
}
/* Avoid code blocks getting orphaned from their preceding paragraph */
pre {
margin-top: 6pt;
page-break-before: avoid;
}
/* Tables should not break rows across pages */
table tr {
break-inside: avoid;
}Each document type needs its own set of visual patterns. Apply accordingly:
| Type | Required patterns | Optional patterns |
|---|---|---|
| Pentest / Security report | Severity badges (red/orange/green), risk bar, code blocks with left border, impact/remediation boxes | Finding-header with metadata, findings table with badges |
| One-pager / Executive summary | Glance grid (4 metrics), lead paragraph, takeaway box, cover with large title + decorative line | Callout for key data point, footer with contact |
| White paper / Long doc | Chapter breaks in dense sections, table of contents, callouts, keep-together on critical blocks | Quotes, diagrams, appendix |
| Letter | Wide margins (25mm), formal greeting and closing, no columns, no tables | Letterhead, signature |
| Resume | Dense body (9.2pt), metric row, project bullets with action + result | Timeline, skills grid |
| Slides | Assertion-evidence titles, one idea per slide, one-line bullets, pinned callout | Code cards, 2x2 table |
Rule: if the document type isn't in the table, choose the closest one and adapt.
Nothing looks more amateur than a page with 2 lines. Causes and solutions:
| Cause | Solution | Auto-detection |
|---|---|---|
| Heading with 1 short paragraph at the end | Merge with previous section | If a chapter has only 1 h2 + 1 p, it doesn't deserve its own page |
break-before: page on every section | Only use on chapters with >1/3 page of content | Count paragraphs + tables + lists. If they add up to less than 5 elements, don't force a break |
break-inside: avoid on large block that doesn't fit | Relax break-inside or split the block | If a keep-together measures more than 1 page, don't force it |
| Source list at the end spilling onto a separate page | Move to consolidated sources chapter | Sources go in one place, not repeated in each chapter |
Validate that content inherited from Kami doesn't have these marks:
| Anti-pattern | Problem | Fix |
|---|---|---|
Repeated em dash — as label/value separator | Black Box — no credentials, multiple lines in a row | Parentheses, comma, colon. The dash is for genuine asides, not for separating labels |
| Uniform tables without color | All rows identical, no visual indication of severity or priority | Color badges, subtle zebra rows, highlighted first column |
| Code blocks without contrast | They blend with the body, don't look like code | Left blue border, ivory background, monospace, generous padding |
| Same structure on every page | Every page is title + table or title + list | Vary: finding box, risk bar, flowchart, callout. Alternate rhythm |
| Claims without source | "LLMs hallucinate 15-20%" without attribution | "According to Vectara HHEM 2026, LLMs..." |
| Practice | Source | Why |
|---|---|---|
Always set printBackground: true | BrowserStack, Playwright docs | Kami uses parchment bg #f5f4ed — Chromium strips it by default |
Use file:// protocol | Stack Overflow, DocuPotion | Avoids auth/CORS issues with local files |
Set waitUntil: 'networkidle' | BrowserStack | Ensures fonts, CSS fully loaded |
| Lock browser version in CI | BrowserStack, blog.rasc.ch | Chromium updates can change rendering |
Use @page margins, not Playwright margins | print-css.rocks, CSS Paged Media spec | CSS margins are more predictable for paged media |
-webkit-print-color-adjust: exact | MDN, Chromium docs | Critical for parchment backgrounds and brand colors |
| Reuse browser instance (warm) | pdf4.dev benchmark | 42ms → 3ms speedup (14x) |
| Validate PDF visually in CI | BrowserStack | Page count, whitespace, font check |
const { chromium } = require('playwright');
class PDFRenderer {
constructor() {
this.browser = null;
}
async start() {
this.browser = await chromium.launch();
}
async render(htmlPath, outputPath) {
const page = await this.browser.newPage();
await page.goto('file:///' + htmlPath.replace(/\\/g, '/'), {
waitUntil: 'networkidle'
});
await page.pdf({
path: outputPath,
format: 'A4',
printBackground: true,
margin: { top: '0', bottom: '0', left: '0', right: '0' }
});
await page.close();
}
async stop() {
await this.browser.close();
}
}Chromium embeds system fonts by default. For custom fonts (like TsangerJinKai02 in Kami):
@font-face {
font-family: "CustomFont";
src: url("fonts/CustomFont.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}Place font files relative to the HTML and use relative src paths. Chromium resolves them from the HTML file's directory.
| Problem | Fix |
|---|---|
| White background instead of parchment | Add printColorAdjust: exact in CSS and printBackground: true in JS |
| Fonts not rendering | Use relative paths in @font-face, check font file exists |
| Page breaks wrong | Check break-inside: avoid on tables, pre, callout |
| Near-empty page (2 lines alone) | Merge short section with previous; avoid break-before: page on light chapters |
| Content overflow | Use page-break-inside: avoid on large blocks |
| Chinese chars as boxes | Include CJK font in @font-face or use system CJK fallback |
| PDF too large | Remove unnecessary images, compress embedded fonts |
| Slow first render | Keep browser instance alive (warm mode) |
Concrete patterns to include in the HTML by document type:
/* Severity badges (pentest, security) */
.badge-high { background: #f5e8e8; color: #a83030; display: inline-block; padding: 2pt 7pt; border-radius: 3pt; font-size: 8pt; font-weight: 500; text-transform: uppercase; }
.badge-medium { background: #f5ede2; color: #b86a25; display: inline-block; padding: 2pt 7pt; border-radius: 3pt; font-size: 8pt; font-weight: 500; text-transform: uppercase; }
.badge-ok { background: #e8f2ec; color: #2a7a4a; display: inline-block; padding: 2pt 7pt; border-radius: 3pt; font-size: 8pt; font-weight: 500; text-transform: uppercase; }
/* Risk bar (pentest exec summary) */
.risk-bar { display: flex; gap: 2pt; margin: 8pt 0 14pt 0; height: 12pt; }
.risk-bar .seg { border-radius: 2pt; display: flex; align-items: center; justify-content: center; font-size: 7pt; color: #fff; font-weight: 500; }
/* Code blocks with left border (pentest, technical) */
pre { border-left: 2.5pt solid #1B365D; border-radius: 3pt; background: #faf9f5; padding: 10pt 14pt; font-family: Consolas, monospace; font-size: 9pt; line-height: 1.5; break-inside: avoid; }
/* Impact/Remediation boxes (pentest) */
.impact-box, .remediation-box { border-left: 2pt solid #e8e6dc; padding-left: 12pt; margin: 10pt 0 14pt 0; break-inside: avoid; }
.impact-box .label, .remediation-box .label { font-size: 8.5pt; letter-spacing: 0.8pt; text-transform: uppercase; font-weight: 500; color: #1B365D; margin-bottom: 4pt; }
/* Cover accent line */
.cover-line { width: 60pt; height: 2pt; background: #1B365D; margin: 20pt 0; border-radius: 1pt; }
/* Pipeline flow (4 step horizontal) */
.pipeline-flow { display: flex; gap: 0; margin: 18pt 0; break-inside: avoid; }
.pipeline-step { flex: 1; text-align: center; padding: 10pt 8pt; }
.pipeline-step .dot { width: 6pt; height: 6pt; border-radius: 50%; background: #1B365D; margin: 0 auto 5pt auto; }
.pipeline-step + .pipeline-step { border-left: 0.5pt dotted #e8e6dc; }
.pipeline-step .name { font-size: 9pt; font-weight: 500; color: #141413; margin-bottom: 3pt; }
.pipeline-step .desc { font-size: 7.5pt; color: #6b6a64; line-height: 1.35; }
/* Keep-together wrapper */
.keep-together { break-inside: avoid; }Don't generate the PDF without passing this checklist. Each item is a real failure documented in previous iterations.
break-before: page only on chapters with dense content— used as label/value separatorsprintBackground: true in Playwright configuration-webkit-print-color-adjust: exact in CSSwidows: 4; orphans: 4 in @page and bodybreak-inside: avoid on pre, table, blockquote, callouttable tr { break-inside: avoid } so tables don't split rowsMinimum functional template that includes all essential patterns. Copy and adapt:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document Title</title>
<style>
@page { size: A4; margin: 24mm 26mm 26mm 26mm; background: #f5f4ed; widows: 4; orphans: 4; }
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-print-color-adjust: exact; }
:root {
--parchment: #f5f4ed; --ivory: #faf9f5; --near-black: #141413;
--dark-warm: #3d3d3a; --olive: #504e49; --stone: #6b6a64;
--brand: #1B365D; --border: #e8e6dc; --border-soft: #e5e3d8;
--serif: Charter, Georgia, Palatino, "Times New Roman", serif;
--mono: Consolas, "Courier New", monospace;
}
body { font-family: var(--serif); font-size: 10.5pt; line-height: 1.65; color: var(--near-black); background: var(--parchment); widows: 4; orphans: 4; }
h1 { font-size: 24pt; border-left: 2.5pt solid var(--brand); padding-left: 8pt; margin: 0 0 10pt 0; break-after: avoid; }
h2 { font-size: 16pt; margin: 24pt 0 8pt 0; break-after: avoid; }
p { margin: 0 0 10pt 0; widows: 3; orphans: 3; }
table { width: 100%; border-collapse: collapse; font-size: 9.5pt; margin: 12pt 0; break-inside: avoid; }
table th { text-align: left; padding: 6pt 8pt; border-bottom: 1pt solid var(--border); background: var(--ivory); }
table td { padding: 5pt 8pt; border-bottom: 0.3pt solid var(--border-soft); }
table tr { break-inside: avoid; }
pre { border-left: 2.5pt solid var(--brand); border-radius: 3pt; background: var(--ivory); padding: 10pt 14pt; font-size: 9pt; font-family: var(--mono); break-inside: avoid; margin: 6pt 0 10pt 0; }
.callout { background: var(--ivory); border-left: 2pt solid var(--brand); padding: 10pt 14pt; border-radius: 3pt; margin: 12pt 0; break-inside: avoid; }
.keep-together { break-inside: avoid; }
.break { break-before: page; }
/* Add visual patterns by document type (badges, risk bar, etc.) */
</style>
</head>
<body>
<!-- Cover -->
<section style="min-height:240mm;display:flex;flex-direction:column;justify-content:space-between;padding:40mm 0 0 0;break-after:page;">
<div>
<div style="font-size:10pt;color:var(--brand);letter-spacing:2pt;text-transform:uppercase;margin-bottom:18pt;">Document Type</div>
<div style="font-size:40pt;font-weight:500;line-height:1.12;margin-bottom:16pt;">Main Title</div>
<div style="width:60pt;height:2pt;background:var(--brand);margin:20pt 0;border-radius:1pt;"></div>
<div style="font-size:14pt;color:var(--olive);max-width:85%;">Subtitle or description</div>
</div>
<div style="font-size:10pt;color:var(--stone);">Author · Date</div>
</section>
<!-- Chapter -->
<section class="break">
<h1>Chapter Title</h1>
<p>Document content. Verify sources (research), humanize text (humanize), design with Kami.</p>
<!-- Tables, lists, callouts as needed -->
</section>
</body>
</html># One-liner from Kami HTML to PDF
npx playwright pdf "file:///path/to/kami-output.html" "final.pdf"Before rendering, verify the template is production-ready:
@page rules specify explicit size (A4, Letter) and margins-webkit-print-color-adjust: exact and print-color-adjust: exact are set on *@font-face declarations use relative paths, not absolute filesystem pathsformat (A4, Letter, A3) to match the template's @page { size: } declarationprintBackground: true — always. Never skip this. Chromium strips backgrounds by defaultmargin: { top: '0', bottom: '0', left: '0', right: '0' } — use CSS @page margins insteadwaitUntil: 'networkidle' to ensure fonts, CSS, and images are fully loaded before renderingfile:// protocol to avoid CORS and authentication issues with local filespage.pdf() with configured optionsComplete ALL four checklist categories before final output: Structural (blocking), Visual (high priority), Content (high priority), Technical (blocking). Every item in the self-review protocol is a real failure mode documented from previous iterations.
| Cause | Fix |
|---|---|
| PDF renders with stark white background instead of parchment (#f5f4ed) | Chromium strips all backgrounds in print mode. Ensure BOTH printBackground: true in Playwright JS config AND -webkit-print-color-adjust: exact on * in CSS |
| Custom fonts render as fallback system serif in the PDF output | Use relative paths in @font-face src: url("fonts/CustomFont.woff2"). Place font files in same directory as HTML or a subdirectory. Chromium resolves relative to the HTML file's location |
| CJK characters (Chinese, Japanese, Korean) render as empty boxes or tofu | Include a CJK-capable font via @font-face or add system CJK fallback stack: font-family: "TsangerJinKai02", "SimSun", "MS Mincho", serif. Test before batch rendering |
| Near-empty page at end of section (2 lines of text floating alone) | Merge the short section with the previous one. Only apply break-before: page to chapters with > 1/3 page of content. Count elements: if heading + paragraph count < 5 total, don't force a page break |
| Table rows split awkwardly across consecutive pages | Add table tr { break-inside: avoid; } in CSS. For large spanning tables, add table { break-inside: avoid; } so the entire table moves as a block |
| Page break leaves an isolated heading at the very bottom of a page | Add h1, h2, h3, h4 { break-after: avoid; } to ensure at least the first content element after a heading stays with it on the same page |
| PDF file size is excessive (10MB+ for a text-heavy document) | Remove unnecessary raster images. Subset and compress embedded fonts to only used glyphs. Reduce DPI of any embedded raster content. Check for duplicated embedded resources |
page.pdf() call hangs indefinitely on networkidle with dynamic/JS-rendered content | Switch to waitUntil: 'load' or add explicit page.waitForTimeout(3000). For charts and JS-rendered content, use waitForSelector() on a known rendered element |
| Chromium version mismatch between local dev and CI causes visual output differences | Lock Chromium version explicitly: note the version npx playwright install chromium installs. Document it in CI config. Re-baseline visual checks on every Chromium version bump |
| Multiple documents rendered in bulk — browser crashes after N documents due to memory | Implement page pooling: close and reopen pages every 10-20 documents. Or restart browser every 50 documents. Memory leak in Chromium PDF rendering is a known issue |
| Pattern | Problem | Fix |
|---|---|---|
Setting margins via Playwright margin parameter instead of CSS @page | Playwright margin rendering is inconsistent across Chromium versions. CSS @page margins produce predictable, standards-compliant output | Always use @page { margin: 24mm 26mm 26mm 26mm; } in CSS. Set Playwright margin: { top: '0', bottom: '0', left: '0', right: '0' } |
break-before: page applied to every section/chapter unconditionally | Creates near-empty pages when a section has little content. Reader sees a page with 2 lines. Looks unprofessional and amateur | Only force page breaks on chapters with > 1/3 page of content. Count paragraph + table + list elements. If < 5 total content elements, skip the forced break |
| All pages share identical visual structure (title → table → title → table) | Monotonous reading experience. Reader disengages after page 3. Document fails to sustain attention through key findings | Vary rhythm: finding box, then risk bar, then callout, then table, then narrative paragraph. Alternate between data-dense and commentary pages |
| Repeated em dashes used as label/value separator in tables and lists | "Black Box — no credentials" repeated 15 times in a pentest report. Jarring, lazy, reads like raw data dump | Use colon separator (Black Box: no credentials), parentheses, or proper table columns with distinct header and value styling |
| Code blocks visually indistinguishable from surrounding body text | Reader skims past code assuming it's prose. Reduces document credibility. Technical content loses all impact | Style every code block: 2.5pt left border, ivory/tinted background, monospace font (Consolas/Courier), generous padding (10-14pt), slight border-radius |
printBackground: false anywhere in the production rendering pipeline | Chrome strips all background colors, including parchment. Document renders on stark white default. Destroys the Kami visual design | Always printBackground: true. Add CI assertion: if PDF renders with white background, fail the build |
| Launching a new browser instance per PDF document | Cold start ~630ms vs warm ~13ms. 48x slower per document. Wastes CI minutes on multi-document projects | Use warm mode (PDFRenderer class pattern): launch browser once, render all documents, close browser once. Keep-alive between renders |
Font files referenced with absolute Windows paths (C:\Users\swagger\fonts\...) | PDF generated on a different machine or in CI won't find fonts. Paths break across environments. Not portable | Always use relative paths in @font-face: src: url("fonts/CustomFont.woff2"). Place font files in same directory or subdirectory as the HTML template |
| Skipping the self-review protocol because "it looks fine in the browser" | Browser rendering != PDF output. Chrome applies different print stylesheet rules. Many issues only visible in the final PDF | Always open the actual PDF output and run through all 4 checklist categories. Visual inspection is mandatory, not optional |
© EliasOulkadi, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .pack/skills/kagen of EliasOulkadi/shokunin.
Open the folder on GitHubat commit 4c68e5b
Kagen next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Kagen this skillEliasOulkadi/shokunin | 114 | — | ~6.4k | Automated safety check: Pass | MIT | |
| Sn Ppt DoctorOpenSenseNova/SenseNova-Skills | 5.7k | — | ~884 | Automated safety check: Notes | MIT | |
| Browser Automationynulihao/AgentSkillOS | 618 | — | ~2.2k | Automated safety check: Pass | None | |
| Cloudflare Browser Renderingeinverne/dotfiles | 121 | — | ~4.9k | Automated safety check: Pass | GPL-3.0 | |
| Playwright CLImizchi/skills | 360 | — | ~625 | Automated safety check: Pass | None | |
| Publish Zsxq Articlesugarforever/01coder-agent-skills | 137 | — | ~3.2k | Automated safety check: Pass | MIT |
OpenSenseNova/SenseNova-Skills
A skill your agent uses when diagnosing PPT Skill setup or failures involving source parsing, Playwright or Chromium rendering, HTML-to-PPTX export, Workbench startup, or bundled search and…
ynulihao/AgentSkillOS
Non-testing browser automation - web scraping, form filling, screenshot capture, PDF generation, workflow automation.
einverne/dotfiles
Guide for implementing Cloudflare Browser Rendering - a headless browser automation API for screenshots, PDFs, web scraping, and testing.
mizchi/skills
A skill your agent uses when running Playwright via terminal CLI — npx playwright test (test runner), codegen (interactive recording), screenshot / pdf (one-off captures), and CI sharding.
sugarforever/01coder-agent-skills
Publish Markdown articles to Zsxq (知识星球) as drafts. An agent skill from sugarforever/01coder-agent-skills.
sanity-io/sanity
Automates browser interactions for web testing, form filling, screenshots, and data extraction.
EliasOulkadi/shokunin
Design CI/CD pipelines for GitHub Actions, GitLab CI, and CircleCI with matrix builds, test sharding, caching, Docker layer caching, OIDC auth, deployment strategies (rolling, blue-green, canary)…
EliasOulkadi/shokunin
Build production-grade components for React, Vue 3, and Svelte 5 with all states (loading, empty, error, success, idle), TypeScript strict, WCAG 2.2 accessibility, server components (RSC), and…
EliasOulkadi/shokunin
PostgreSQL database administration — backup/restore (pgdump, PITR, WAL archiving), health monitoring (connections, bloat, cache hit ratio, dead tuples), connection pooling (PgBouncer), replication…
EliasOulkadi/shokunin
Design database schemas with Prisma/Drizzle, PostgreSQL index strategy (B-tree, GIN, GiST, BRIN, Hash), query optimization (EXPLAIN ANALYZE), migration safety (expand/contract, zero-downtime), and…
EliasOulkadi/shokunin
Optimize Docker images with multi-stage builds, distroless bases, BuildKit cache mounts, multi-arch builds, compose watch, security hardening (non-root, seccomp, capabilities drop), and…
EliasOulkadi/shokunin
Design error handling, structured logging, and observability with OpenTelemetry (traces, metrics, logs), error classification, recovery patterns (retry with jitter, circuit breaker, bulkhead…
Works with
Categories
Convert Kami HTML templates to production-grade PDF via Chromium/Playwright. Kagen is an agent skill from EliasOulkadi/shokunin. Convert Kami HTML templates to production-grade PDF via Chromium/Playwright.
Kagen fits situations like: user asks to generate PDF files; render HTML to PDF; export documents.
Run `npx skills add EliasOulkadi/shokunin --skill kagen -a claude-code`. Or copy the skill folder (.pack/skills/kagen in EliasOulkadi/shokunin) into .claude/skills/kagen in your project. Claude Code loads it when a task matches its description.
Run `npx skills add EliasOulkadi/shokunin --skill kagen -a codex`. Or copy the skill folder (.pack/skills/kagen in EliasOulkadi/shokunin) into .agents/skills/kagen in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add EliasOulkadi/shokunin --skill kagen -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/kagen, .gemini/skills/kagen, .github/skills/kagen and .opencode/skills/kagen in your project.
Going by SKILL.md and its folder, Kagen needs the command-line tools its instructions call (npx and black). Our summary lists: Node.js. Compatibility (from SKILL.md): opencode.
SKILL.md names 8 domains. As links in the text: playwright.dev, pdf4.dev, browserstack.com, print-css.rocks, docupotion.com, w3.org, blog.rasc.ch and news.ycombinator.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Kagen is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.4k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Kagen: Sn Ppt Doctor (OpenSenseNova/SenseNova-Skills, 5.7k stars), Browser Automation (ynulihao/AgentSkillOS, 618 stars), Cloudflare Browser Rendering (einverne/dotfiles, 121 stars) and Playwright CLI (mizchi/skills, 360 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
EliasOulkadi (a GitHub user) maintains it in EliasOulkadi/shokunin, which has 114 GitHub stars. The repository holds 49 skills in this directory. The repository was last updated on October 5, 2026.
Source: EliasOulkadi/shokunin on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.