MeetMX-ai

resume-maker

"Generates a professional resume HTML, exports to PDF, and renders page-by-page PNG images. Invoke when user asks to create/make a resume, or wants HTML-to-PDF-to-image pipeline."

MeetMX-ai 0 Updated 1d ago

Resources

3
GitHub

Install

npx skillscat add meetmx-ai/resume-maker

Install via the SkillsCat registry.

SKILL.md

Resume Maker

This skill automates the full pipeline: content structuring → HTML generation → PDF export → page-by-page image rendering. It produces a single-page A4 resume in Chinese, optimized for print and screen.

Works with any AI coding assistant or IDE — no tool-specific dependencies.

Pipeline Overview

用户素材 → Step 1: 内容结构化 → Step 2: 生成 HTML → Step 3: 导出 PDF → Step 4: 逐页截图

Step 1: 收集素材 & 内容结构化

Ask the user for the following information. If they don't provide everything, generate realistic placeholder data and mark it clearly.

类别 必需字段
基本信息 姓名、电话、邮箱、求职意向、城市
教育背景 学校、专业、学历、时间
工作经历 公司、岗位、时间、3-4 条工作内容(量化成果优先)
项目经验 2-3 个:项目名、角色、技术栈、成果数据
技能清单 分类列出:编程语言、框架工具、工程化、语言能力

内容优化规则

Apply these transformations to every bullet point:

  1. 动词升级:把"负责"、"参与"、"协助"替换为"主导"、"独立完成"、"推动落地"
  2. 数据量化:每条工作内容必须有数字(百分比、用户量、时间缩短等)
  3. 核心成果标签:每段经历末尾加一个 result 标签,用一句话浓缩最大成果
  4. 一页原则:内容必须压缩到 A4 单页,必要时精简措辞而非删减经历

Step 2: 生成 HTML

Generate a complete, self-contained HTML file with the following design system.

Design Tokens

:root {
  --ink: #1a1a1a;
  --ink-soft: #4a4a4a;
  --ink-muted: #8a8a8a;
  --accent: #c45c3c;
  --accent-light: rgba(196, 92, 60, 0.08);
  --line: #e0dcd7;
  --bg: #faf9f7;
  --paper: #ffffff;
}

Layout Rules

  • Page: width: 210mm; height: 297mm; with overflow: hidden to enforce single page
  • Top accent bar: 3px gradient linear-gradient(90deg, var(--accent), #d4845a, var(--accent))
  • Header: flex row — name left (Noto Serif SC, 28px, letter-spacing 4px), contact info right (11.5px, muted)
  • Sections: each has .section-head with dot + title + horizontal rule
  • Entries: left-border highlight on hover (2px, accent color), hidden in print
  • Bullet points: use character in accent color, NOT standard disc/circle
  • Result tags: inline pill with var(--accent-light) background, var(--accent) text
  • Skills: 2-column grid, tags use #f5f3f0 background
  • Footer: absolute positioned at bottom, centered, muted

Typography

  • Name: "Noto Serif SC", serif — 28px, weight 700
  • Body: "DM Sans", "Noto Sans SC", -apple-system, sans-serif
  • Section titles: 12px, letter-spacing 3px
  • Entry titles: 13px, weight 600
  • Body text: 11.5px, line-height 1.6
  • Result tags: 10.5px, weight 600

Print Styles

@media print {
  body { background: white; }
  .page { width: 100%; height: auto; margin: 0; padding: 28px 36px 24px; box-shadow: none; }
  .entry:hover { border-left-color: transparent; }
  .footer-line { position: static; }
}

Fonts Import

@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&family=Noto+Serif+SC:wght@600;700&family=DM+Sans:wght@400;500;600;700&display=swap');

HTML Structure Template

<div class="page">
  <header class="header">
    <div class="header-left">
      <h1>{姓名}</h1>
      <div class="title">{求职意向}</div>
    </div>
    <div class="header-right">
      {电话} · {邮箱}<br>
      {城市} · {GitHub/网站}<br>
      求职意向:{岗位}
    </div>
  </header>

  <section class="section">
    <div class="section-head">
      <span class="dot"></span>
      <h2>教育背景</h2>
      <span class="rule"></span>
    </div>
    <div class="entry">
      <div class="entry-top">
        <h3>{学校} · {专业}</h3>
        <span class="meta">{时间}</span>
      </div>
      <div class="subtitle">{学历} · GPA · 奖学金等</div>
    </div>
  </section>

  <section class="section">
    <div class="section-head">
      <span class="dot"></span>
      <h2>工作经历</h2>
      <span class="rule"></span>
    </div>
    <!-- 每段经历一个 .entry -->
    <div class="entry">
      <div class="entry-top">
        <h3>{公司} · {岗位}</h3>
        <span class="meta">{时间}</span>
      </div>
      <div class="subtitle">{部门} · {团队}</div>
      <ul>
        <li>{量化成果描述}</li>
      </ul>
      <span class="result">核心成果:{一句话浓缩}</span>
    </div>
  </section>

  <section class="section">
    <div class="section-head">
      <span class="dot"></span>
      <h2>项目经验</h2>
      <span class="rule"></span>
    </div>
    <!-- 同工作经历结构 -->
  </section>

  <section class="section">
    <div class="section-head">
      <span class="dot"></span>
      <h2>技能清单</h2>
      <span class="rule"></span>
    </div>
    <div class="skills-grid">
      <div class="skill-group">
        <h4>{分类名}</h4>
        <p>{技能内容或 tag 列表}</p>
      </div>
    </div>
  </section>

  <div class="footer-line">{姓名} · {岗位} · {年份}</div>
</div>

Save the HTML file as {姓名}_简历.html in the user's working directory.


Step 3: 导出 PDF

Use a headless Chromium-based browser to convert HTML to PDF. Detect the available browser on the current system:

Browser Detection (priority order)

  1. Google Chrome: C:\Program Files\Google\Chrome\Application\chrome.exe (Windows) / /Applications/Google Chrome.app/... (macOS) / google-chrome (Linux)
  2. Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe (Windows) / microsoft-edge (Linux)
  3. Chromium: chromium or chromium-browser (Linux)

Command

import subprocess, platform

def get_browser_cmd():
    """Detect available Chromium-based browser."""
    if platform.system() == "Windows":
        candidates = [
            r"C:\Program Files\Google\Chrome\Application\chrome.exe",
            r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
        ]
    elif platform.system() == "Darwin":
        candidates = [
            "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
            "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
        ]
    else:  # Linux
        candidates = ["google-chrome", "microsoft-edge", "chromium-browser", "chromium"]

    for cmd in candidates:
        try:
            subprocess.run([cmd, "--version"], capture_output=True, timeout=5)
            return cmd
        except (FileNotFoundError, subprocess.TimeoutExpired):
            continue
    raise RuntimeError("No Chromium-based browser found. Install Chrome or Edge.")

browser = get_browser_cmd()
subprocess.run([
    browser,
    "--headless", "--disable-gpu", "--no-pdf-header-footer",
    f"--print-to-pdf={pdf_path}",
    f"file:///{html_path.replace(os.sep, '/')}"
], capture_output=True)

Save as {姓名}_简历.pdf in the same directory.


Step 4: 逐页截图

Use PyMuPDF (fitz) + Pillow to render each page as a high-res PNG with a page-number pill overlay.

Dependencies

pip install PyMuPDF Pillow

Font Detection

import platform

def get_font_path():
    """Detect a suitable CJK font for the page-number pill."""
    system = platform.system()
    if system == "Windows":
        return r"C:\Windows\Fonts\msyh.ttc"  # Microsoft YaHei
    elif system == "Darwin":
        return "/System/Library/Fonts/PingFang.ttc"  # PingFang SC
    else:  # Linux
        candidates = [
            "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
            "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
            "/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
        ]
        for p in candidates:
            if os.path.exists(p):
                return p
        return None  # Will fall back to default font

Script Template

import fitz
import os
import shutil
import subprocess
import platform
from PIL import Image, ImageDraw, ImageFont

def get_browser_cmd():
    if platform.system() == "Windows":
        candidates = [
            r"C:\Program Files\Google\Chrome\Application\chrome.exe",
            r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
        ]
    elif platform.system() == "Darwin":
        candidates = [
            "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
            "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
        ]
    else:
        candidates = ["google-chrome", "microsoft-edge", "chromium-browser", "chromium"]
    for cmd in candidates:
        try:
            subprocess.run([cmd, "--version"], capture_output=True, timeout=5)
            return cmd
        except (FileNotFoundError, subprocess.TimeoutExpired):
            continue
    raise RuntimeError("No Chromium-based browser found.")

def get_font_path():
    system = platform.system()
    if system == "Windows":
        return r"C:\Windows\Fonts\msyh.ttc"
    elif system == "Darwin":
        return "/System/Library/Fonts/PingFang.ttc"
    else:
        for p in ["/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
                   "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"]:
            if os.path.exists(p):
                return p
    return None

label = "{姓名}"
html_path = r"{html_path}"
pdf_path = r"{pdf_path}"
output_dir = r"{output_dir}"

if os.path.exists(pdf_path):
    os.remove(pdf_path)
if os.path.exists(output_dir):
    shutil.rmtree(output_dir)
os.makedirs(output_dir, exist_ok=True)

# Step 3: HTML → PDF
browser = get_browser_cmd()
file_url = "file:///" + html_path.replace(os.sep, "/") if platform.system() == "Windows" else "file://" + html_path
subprocess.run([
    browser,
    "--headless", "--disable-gpu", "--no-pdf-header-footer",
    f"--print-to-pdf={pdf_path}",
    file_url
], capture_output=True)

# Step 4: PDF → 逐页 PNG
doc = fitz.open(pdf_path)
total = len(doc)
digits = len(str(total))
print(f"共 {total} 页")

font_path = get_font_path()

for i, page in enumerate(doc):
    img = page.get_pixmap(matrix=fitz.Matrix(4, 4))
    filename = f"page_{str(i+1).zfill(digits)}.png"
    filepath = os.path.join(output_dir, filename)
    img.save(filepath)

    # 添加页码胶囊标签
    pil_img = Image.open(filepath)
    w, h = pil_img.size
    draw = ImageDraw.Draw(pil_img)

    font_size = max(18, h // 50)
    if font_path:
        try:
            font = ImageFont.truetype(font_path, font_size)
        except:
            font = ImageFont.load_default()
    else:
        font = ImageFont.load_default()

    text = f"{label} · {i + 1}/{total}"
    bbox = draw.textbbox((0, 0), text, font=font)
    tw = bbox[2] - bbox[0]
    th = bbox[3] - bbox[1]

    pad_x = int(h * 0.02)
    pad_y = int(h * 0.008)
    pill_w = tw + pad_x * 2
    pill_h = th + pad_y * 2
    pill_x = (w - pill_w) // 2
    pill_y = h - pill_h - int(h * 0.03)

    draw.rounded_rectangle(
        [pill_x, pill_y, pill_x + pill_w, pill_y + pill_h],
        radius=pill_h // 2,
        fill=(250, 248, 245),
        outline=(235, 230, 222),
        width=1
    )

    text_x = (w - tw) // 2
    text_y = pill_y + pad_y
    draw.text((text_x, text_y), text, fill=(180, 175, 165), font=font)

    pil_img.save(filepath)
    print(f"  [{i+1}/{total}] {filename}")

doc.close()
print(f"完成!图片已保存到:{output_dir}")

Save this script as {姓名}_简历_to_img.py and execute it.


Output Checklist

After completing all steps, verify:

  • {姓名}_简历.html — 可在浏览器中打开,单页 A4
  • {姓名}_简历.pdf — PDF 导出成功
  • {姓名}_简历_pages/page_1.png — 逐页截图,底部有页码胶囊
  • 内容无 AI 编造的经历(所有数据来自用户或明确标注为模拟)
  • 每段经历有"核心成果"标签
  • 动词已升级(无"负责"、"参与"、"协助")
  • 打印样式正常(Ctrl+P / Cmd+P 无溢出)

Style Variants

If the user specifies a different style, adjust these tokens:

风格 accent 背景色 适用场景
简洁现代(默认) #c45c3c #faf9f7 互联网公司
经典专业 #2c3e50 #f8f9fa 外企、金融、咨询
个性创意 #6c5ce7 #fefefe 创业公司
视觉化 #e17055 #fff5f0 设计师、产品、运营

Categories