원클릭으로
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.
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.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| 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. |
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.