一键导入
office-design-toolkit
Bộ kỹ năng Office (DOCX/PPTX/XLSX/PDF) và Design Toolkit tích hợp từ file người dùng cung cấp. Use when this capability is needed.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Bộ kỹ năng Office (DOCX/PPTX/XLSX/PDF) và Design Toolkit tích hợp từ file người dùng cung cấp. Use when this capability is needed.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Author or edit a Cate IDE theme — one data-driven theme covering app chrome colors, the terminal ANSI palette, and Monaco editor syntax tokens. Use when the user asks to create, customize, recolor, or generate a Cate theme, mentions a color scheme (Dracula, Nord, "make Cate look like X"), or wants a new light/dark theme. Use when this capability is needed.
Use when user invokes /wtc to work with Docker Compose worktree isolation, start/stop infra per worktree, or check worktree status
一键发布 Markdown 到微信公众号草稿箱。基于 wenyan-cli,支持多主题、代码高亮、图片自动上传。 Use when this capability is needed.
Apply this skill when reviewing code changes, scope, risks, or verification gaps. Use when this capability is needed.
Apply this skill when Flutter widgets, screens, routing, state management, async UI, platform channels, assets, responsive layout, accessibility, or Flutter tests are created or changed. Use when this capability is needed.
Apply this skill when Rust source, Cargo metadata, features, traits, errors, ownership, async runtime, unsafe code, tests, examples, benchmarks, release profiles, MSRV, toolchain declarations, standard-library APIs, or public crate APIs are created or changed. Use when this capability is needed.
| name | office-design-toolkit |
| description | Bộ kỹ năng Office (DOCX/PPTX/XLSX/PDF) và Design Toolkit tích hợp từ file người dùng cung cấp. Use when this capability is needed. |
| metadata | {"author":"0xAstroAlpha"} |
Path: /mnt/skills/public/docx/SKILL.md
File .docx là ZIP archive chứa XML files.
| Task | Approach |
|---|---|
| Read/analyze content | pandoc hoặc unpack raw XML |
| Create new document | Dùng docx-js |
| Edit existing document | Unpack → edit XML → repack |
python scripts/office/soffice.py --headless --convert-to docx document.doc
pandoc --track-changes=all document.docx -o output.md
python scripts/office/unpack.py document.docx unpacked/
python scripts/office/soffice.py --headless --convert-to pdf document.docx
pdftoppm -jpeg -r 150 document.pdf page
python scripts/accept_changes.py input.docx output.docx
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun,
Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink,
InternalHyperlink, Bookmark, FootnoteReferenceRun, PositionalTab,
PositionalTabAlignment, PositionalTabRelativeTo, PositionalTabLeader,
TabStopType, TabStopPosition, Column, SectionType,
TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType,
VerticalAlign, PageNumber, PageBreak } = require('docx');
const doc = new Document({ sections: [{ children: [/* content */] }] });
Packer.toBuffer(doc).then(buffer => fs.writeFileSync("doc.docx", buffer));
python scripts/office/validate.py doc.docx
// CRITICAL: docx-js defaults to A4, not US Letter
sections: [{
properties: {
page: {
size: { width: 12240, height: 15840 }, // US Letter in DXA
margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }
}
},
children: [/* content */]
}]
Common page sizes (DXA units, 1440 DXA = 1 inch):
| Paper | Width | Height | Content Width (1" margins) |
|---|---|---|---|
| US Letter | 12,240 | 15,840 | 9,360 |
| A4 (default) | 11,906 | 16,838 | 9,026 |
Landscape: Pass portrait dimensions, let docx-js swap:
size: {
width: 12240, // SHORT edge
height: 15840, // LONG edge
orientation: PageOrientation.LANDSCAPE
},
const doc = new Document({
styles: {
default: { document: { run: { font: "Arial", size: 24 } } },
paragraphStyles: [
{ id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 32, bold: true, font: "Arial" },
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } },
{ id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 28, bold: true, font: "Arial" },
paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },
]
},
sections: [{
children: [
new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun("Title")] }),
]
}]
});
// ❌ WRONG
new Paragraph({ children: [new TextRun("• Item")] })
// ✅ CORRECT
const doc = new Document({
numbering: {
config: [
{ reference: "bullets",
levels: [{ level: 0, format: LevelFormat.BULLET, text: "•", alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },
{ reference: "numbers",
levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },
]
},
sections: [{
children: [
new Paragraph({ numbering: { reference: "bullets", level: 0 },
children: [new TextRun("Bullet item")] }),
]
}]
});
// CRITICAL: Tables need dual widths - columnWidths on table AND width on each cell
const border = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" };
const borders = { top: border, bottom: border, left: border, right: border };
new Table({
width: { size: 9360, type: WidthType.DXA },
columnWidths: [4680, 4680],
rows: [
new TableRow({
children: [
new TableCell({
borders,
width: { size: 4680, type: WidthType.DXA },
shading: { fill: "D5E8F0", type: ShadingType.CLEAR },
margins: { top: 80, bottom: 80, left: 120, right: 120 },
children: [new Paragraph({ children: [new TextRun("Cell")] })]
})
]
})
]
})
new Paragraph({
children: [new ImageRun({
type: "png",
data: fs.readFileSync("image.png"),
transformation: { width: 200, height: 150 },
altText: { title: "Title", description: "Desc", name: "Name" }
})]
})
new Paragraph({ children: [new PageBreak()] })
new Paragraph({ pageBreakBefore: true, children: [new TextRun("New page")] })
// External
new Paragraph({
children: [new ExternalHyperlink({
children: [new TextRun({ text: "Click here", style: "Hyperlink" })],
link: "https://example.com",
})]
})
// Internal (bookmark + reference)
new Paragraph({ heading: HeadingLevel.HEADING_1, children: [
new Bookmark({ id: "chapter1", children: [new TextRun("Chapter 1")] }),
]})
new Paragraph({ children: [new InternalHyperlink({
children: [new TextRun({ text: "See Chapter 1", style: "Hyperlink" })],
anchor: "chapter1",
})]})
const doc = new Document({
footnotes: {
1: { children: [new Paragraph("Source: Annual Report 2024")] },
},
sections: [{
children: [new Paragraph({
children: [
new TextRun("Revenue grew 15%"),
new FootnoteReferenceRun(1),
],
})]
}]
});
new Paragraph({
children: [
new TextRun("Company Name"),
new TextRun("\tJanuary 2025"),
],
tabStops: [{ type: TabStopType.RIGHT, position: TabStopPosition.MAX }],
})
sections: [{
properties: {
column: { count: 2, space: 720, equalWidth: true, separate: true },
},
children: [/* content flows naturally */]
}]
new TableOfContents("Table of Contents", { hyperlink: true, headingStyleRange: "1-3" })
sections: [{
properties: {
page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } }
},
headers: {
default: new Header({ children: [new Paragraph({ children: [new TextRun("Header")] })] })
},
footers: {
default: new Footer({ children: [new Paragraph({
children: [new TextRun("Page "), new TextRun({ children: [PageNumber.CURRENT] })]
})] })
},
children: [/* content */]
}]
\n — use separate Paragraph elementsLevelFormat.BULLETtypewidth with DXA (never PERCENTAGE)columnWidths + cell widthShadingType.CLEAR (never SOLID)outlineLevel for TOCpython scripts/office/unpack.py document.docx unpacked/
’ (apostrophe), “/” (double quotes)python scripts/office/pack.py unpacked/ output.docx --original document.docx
<!-- Insertion -->
<w:ins w:id="1" w:author="Claude" w:date="2025-01-01T00:00:00Z">
<w:r><w:t>inserted text</w:t></w:r>
</w:ins>
<!-- Deletion -->
<w:del w:id="2" w:author="Claude" w:date="2025-01-01T00:00:00Z">
<w:r><w:delText>deleted text</w:delText></w:r>
</w:del>
npm install -g docx), LibreOffice, PopplerPath: /mnt/skills/public/pptx/SKILL.md
| Task | Guide |
|---|---|
| Read/analyze content | python -m markitdown presentation.pptx |
| Edit or create from template | Xem editing workflow |
| Create from scratch | Dùng PptxGenJS |
python -m markitdown presentation.pptx
python scripts/thumbnail.py presentation.pptx
python scripts/office/unpack.py presentation.pptx unpacked/
| Theme | Primary | Secondary | Accent |
|---|---|---|---|
| Midnight Executive | 1E2761 | CADCFC | FFFFFF |
| Forest & Moss | 2C5F2D | 97BC62 | F5F5F5 |
| Coral Energy | F96167 | F9E795 | 2F3C7E |
| Warm Terracotta | B85042 | E7E8D1 | A7BEAE |
| Ocean Gradient | 065A82 | 1C7293 | 21295C |
| Charcoal Minimal | 36454F | F2F2F2 | 212121 |
| Teal Trust | 028090 | 00A896 | 02C39A |
| Berry & Cream | 6D2E46 | A26769 | ECE2D0 |
| Sage Calm | 84B59F | 69A297 | 50808E |
| Cherry Bold | 990011 | FCF6F5 | 2F3C7E |
| Header Font | Body Font |
|---|---|
| Georgia | Calibri |
| Arial Black | Arial |
| Cambria | Calibri |
| Trebuchet MS | Calibri |
| Palatino | Garamond |
| Element | Size |
|---|---|
| Slide title | 36-44pt bold |
| Section header | 20-24pt bold |
| Body text | 14-16pt |
| Captions | 10-12pt muted |
const pptxgen = require("pptxgenjs");
let pres = new pptxgen();
pres.layout = 'LAYOUT_16x9';
let slide = pres.addSlide();
slide.addText("Hello World!", { x: 0.5, y: 0.5, fontSize: 36, color: "363636" });
pres.writeFile({ fileName: "Presentation.pptx" });
LAYOUT_16x9: 10" × 5.625" (default)LAYOUT_16x10: 10" × 6.25"LAYOUT_4x3: 10" × 7.5"LAYOUT_WIDE: 13.3" × 7.5"slide.addText("Simple Text", {
x: 1, y: 1, w: 8, h: 2, fontSize: 24, fontFace: "Arial",
color: "363636", bold: true, align: "center", valign: "middle"
});
// Rich text arrays
slide.addText([
{ text: "Bold ", options: { bold: true } },
{ text: "Italic ", options: { italic: true } }
], { x: 1, y: 3, w: 8, h: 1 });
// Multi-line (requires breakLine: true)
slide.addText([
{ text: "Line 1", options: { breakLine: true } },
{ text: "Line 2", options: { breakLine: true } },
{ text: "Line 3" }
], { x: 0.5, y: 0.5, w: 8, h: 2 });
// ✅ CORRECT
slide.addText([
{ text: "First item", options: { bullet: true, breakLine: true } },
{ text: "Second item", options: { bullet: true, breakLine: true } },
{ text: "Third item", options: { bullet: true } }
], { x: 0.5, y: 0.5, w: 8, h: 3 });
// ❌ NEVER use unicode bullets
slide.addShape(pres.shapes.RECTANGLE, {
x: 0.5, y: 0.8, w: 1.5, h: 3.0,
fill: { color: "FF0000" }, line: { color: "000000", width: 2 }
});
// Rounded rectangle
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
x: 1, y: 1, w: 3, h: 2,
fill: { color: "FFFFFF" }, rectRadius: 0.1
});
// With shadow
slide.addShape(pres.shapes.RECTANGLE, {
x: 1, y: 1, w: 3, h: 2,
fill: { color: "FFFFFF" },
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.15 }
});
slide.addImage({ path: "images/chart.png", x: 1, y: 1, w: 5, h: 3 });
// With options
slide.addImage({
path: "image.png", x: 1, y: 1, w: 5, h: 3,
rounding: true, transparency: 50,
sizing: { type: 'cover', w: 4, h: 3 }
});
const React = require("react");
const ReactDOMServer = require("react-dom/server");
const sharp = require("sharp");
const { FaCheckCircle } = require("react-icons/fa");
function renderIconSvg(IconComponent, color = "#000000", size = 256) {
return ReactDOMServer.renderToStaticMarkup(
React.createElement(IconComponent, { color, size: String(size) })
);
}
async function iconToBase64Png(IconComponent, color, size = 256) {
const svg = renderIconSvg(IconComponent, color, size);
const pngBuffer = await sharp(Buffer.from(svg)).png().toBuffer();
return "image/png;base64," + pngBuffer.toString("base64");
}
slide.addChart(pres.charts.BAR, [{
name: "Sales", labels: ["Q1", "Q2", "Q3", "Q4"], values: [4500, 5500, 6200, 7100]
}], {
x: 0.5, y: 0.6, w: 6, h: 3, barDir: 'col',
showTitle: true, title: 'Quarterly Sales',
chartColors: ["0D9488", "14B8A6", "5EEAD4"],
valGridLine: { color: "E2E8F0", size: 0.5 },
catGridLine: { style: "none" },
});
slide.background = { color: "F1F1F1" };
slide.background = { path: "https://example.com/bg.jpg" };
slide.background = { data: "image/png;base64,..." };
opacity propertybullet: true — NEVER unicode "•"breakLine: true between itemspython scripts/thumbnail.py template.pptxpython scripts/office/unpack.py template.pptx unpacked/python scripts/clean.py unpacked/python scripts/office/pack.py unpacked/ output.pptx --original template.pptx| Script | Purpose |
|---|---|
unpack.py | Extract and pretty-print |
add_slide.py | Duplicate slide or create from layout |
clean.py | Remove orphaned files |
pack.py | Repack with validation |
thumbnail.py | Visual grid of slides |
# Content QA
python -m markitdown output.pptx
# Visual QA — convert to images
python scripts/office/soffice.py --headless --convert-to pdf output.pptx
pdftoppm -jpeg -r 150 output.pdf slide
pip install "markitdown[pptx]" + Pillownpm install -g pptxgenjsPath: /mnt/skills/public/xlsx/SKILL.md
# ❌ WRONG
total = df['Sales'].sum()
sheet['B10'] = total
# ✅ CORRECT
sheet['B10'] = '=SUM(B2:B9)'
sheet['C5'] = '=(C4-C2)/C2'
sheet['D20'] = '=AVERAGE(D2:D19)'
python scripts/recalc.py output.xlsx
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
wb = Workbook()
sheet = wb.active
sheet['A1'] = 'Hello'
sheet['B2'] = '=SUM(A1:A10)'
sheet['A1'].font = Font(bold=True, color='FF0000')
sheet['A1'].fill = PatternFill('solid', start_color='FFFF00')
sheet.column_dimensions['A'].width = 20
wb.save('output.xlsx')
import pandas as pd
df = pd.read_excel('file.xlsx')
all_sheets = pd.read_excel('file.xlsx', sheet_name=None)
data_only=True reads values (WARNING: saving loses formulas)scripts/recalc.pyPath: /mnt/skills/public/pdf/SKILL.md
| Task | Best Tool |
|---|---|
| Merge PDFs | pypdf |
| Split PDFs | pypdf |
| Extract text | pdfplumber |
| Extract tables | pdfplumber |
| Create PDFs | reportlab |
| OCR scanned | pytesseract |
| Fill PDF forms | pdf-lib or pypdf (FORMS.md) |
from pypdf import PdfReader
reader = PdfReader("document.pdf")
text = ""
for page in reader.pages:
text += page.extract_text()
import pdfplumber
with pdfplumber.open("document.pdf") as pdf:
for page in pdf.pages:
tables = page.extract_tables()
for table in tables:
for row in table:
print(row)
from pypdf import PdfWriter, PdfReader
writer = PdfWriter()
for pdf_file in ["doc1.pdf", "doc2.pdf"]:
reader = PdfReader(pdf_file)
for page in reader.pages:
writer.add_page(page)
with open("merged.pdf", "wb") as output:
writer.write(output)
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet
doc = SimpleDocTemplate("report.pdf", pagesize=letter)
styles = getSampleStyleSheet()
story = []
story.append(Paragraph("Report Title", styles['Title']))
story.append(Spacer(1, 12))
story.append(Paragraph("Body text here.", styles['Normal']))
doc.build(story)
# ✅ CORRECT
chemical = Paragraph("H<sub>2</sub>O", styles['Normal'])
squared = Paragraph("x<super>2</super>", styles['Normal'])
# Extract text
pdftotext input.pdf output.txt
pdftotext -layout input.pdf output.txt
# Merge
qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf
# Split
qpdf input.pdf --pages . 1-5 -- pages1-5.pdf
# Rotate
qpdf input.pdf output.pdf --rotate=+90:1
import pytesseract
from pdf2image import convert_from_path
images = convert_from_path('scanned.pdf')
text = ""
for i, image in enumerate(images):
text += pytesseract.image_to_string(image)
# Watermark
for page in reader.pages:
page.merge_page(watermark)
writer.add_page(page)
# Encrypt
writer.encrypt("userpassword", "ownerpassword")
Path: /mnt/skills/public/frontend-design/SKILL.md
Path: /mnt/skills/examples/theme-factory/SKILL.md
#1a2332 | Teal #2d8b8b | Seafoam #a8dadc | Cream #f1faee#e76f51 | Coral #f4a261 | Warm Sand #e9c46a | Deep Purple #264653#2d4a2b | Sage #7d8471 | Olive #a4ac86 | Ivory #faf9f6#36454f | Slate Gray #708090 | Light Gray #d3d3d3 | White #ffffff#f4a900 | Terracotta #c1666b | Warm Beige #d4b896 | Chocolate #4a403a#d4e4f7 | Steel Blue #4a6fa5 | Silver #c0c0c0 | Crisp White #fafafa#d4a5a5 | Clay #b87d6d | Sand #e8d5c4 | Deep Burgundy #5d2e46#0066ff | Neon Cyan #00ffff | Dark Gray #1e1e1e | White #ffffff#4a7c59 | Marigold #f9a620 | Terracotta #b7472a | Cream #f5f3ed#2b1e3e | Cosmic Blue #4a4e8f | Lavender #a490c2 | Silver #e6e6fatheme-showcase.pdf to userthemes/ directoryPath: /mnt/skills/examples/canvas-design/SKILL.md
ArsenalSC, BigShoulders, Boldonse, BricolageGrotesque, CrimsonPro, DMMono, EricaOne, GeistMono, Gloock, IBMPlexMono, IBMPlexSerif, InstrumentSans, InstrumentSerif, Italiana, JetBrainsMono, Jura, LibreBaskerville, Lora, NationalPark, NothingYouCouldDo, Outfit, PixelifySans, PoiretOne, RedHatMono, Silkscreen, SmoochSans, Tektur, WorkSans, YoungSerif
| Need | Skill | Install |
|---|---|---|
| Create .docx | DOCX | npm install -g docx |
| Edit .docx | DOCX | unpack/edit XML/pack |
| Create .pptx | PPTX | npm install -g pptxgenjs |
| Edit .pptx | PPTX | unpack/edit XML/pack |
| Create .xlsx | XLSX | openpyxl (Python) |
| Edit .xlsx | XLSX | openpyxl + recalc.py |
| Create .pdf | reportlab (Python) | |
| Edit .pdf | pypdf / pdfplumber | |
| Beautiful web UI | Frontend Design | HTML/CSS/JS/React |
| Apply themes | Theme Factory | 10 preset themes |
| Art/poster/visual | Canvas Design | reportlab + fonts |
Use this as default style system when creating professional DOCX plans/proposals unless user asks otherwise.
size: 22 in docx half-points)1A23322D8B8B1F2937475569CBD5E1F4F8FAUse when user asks for the same visual language as approved sample files.
2A7A788B6B4A1F4D782D2D2D / 33333376C893, FF9E8A, 5B4FA0 (use sparingly)FFFFFF12240 x 15840 DXA) unless user requests A41080 DXA each side (≈0.75")\n for layout; split into separate Paragraph elementswidth with WidthType.DXAcolumnWidths on tablewidth on each TableCellCBD5E1)1A2332)FFFFFF / F4F8FA)Use the following references for every Office task:
references/workflow-policy.mdreferences/design-system-docx.mdreferences/qa-checklists.mdMandatory operating mode:
If user asks for speed, still preserve the phase order with reduced depth.
Definition of done for Office output:
Brand handling:
#ABDF00 gradient-first aesthetic.Source: 0xAstroAlpha/office-design-toolkit — distributed by TomeVault.