Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when generating a Word (.docx) file with the docx JavaScript library (docx-js): emit the library's real API idioms — DXA table widths, LevelFormat list numbering, ShadingType.CLEAR, an explicit US Letter page size, a required ImageRun type, PageNumber fields, and Packer output — which cheaper models do not produce by default.
.claude/skills/docx-js-authoring/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 100% | 18 |
| Model | Lift | Δ tokens | Δ turns | Cases | Verified |
|---|---|---|---|---|---|
| gemini-3.6-flashbest | +45% | +67% | 0% | 22 | 54d ago |
| gemini-3.5-flash | pending re-run | — | |||
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-11 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-15 | ✗→✓ | ▲ Improved | — | — |
| case-19 | ✗→✓ | ▲ Improved | — | — |
| case-14 | ✗→✓ | ▲ Improved | — | — |
Enforces the current public API of the docx npm package (docx-js) when building a .docx in JavaScript/TypeScript. Apply to any code that constructs a Document from require("docx") / import {...} from "docx". The rules below are the exact tokens the library expects; the model's natural defaults diverge from most of them.
properties.page.size, thelibrary uses its A4 default. For US documents pass US Letter in twips: width: 12240, height: 15840 (1 inch = 1440 DXA). Use 1440 for each margin.
width: 12240 (short edge) andheight: 15840 (long edge) and add orientation: PageOrientation.LANDSCAPE. The library swaps them in the XML — do not pre-swap width and height yourself.
WidthType.DXA, never WidthType.PERCENTAGE. Percentage widthsbreak in Google Docs. Set the table width as { size, type: WidthType.DXA }, give the table a columnWidths array, AND repeat width: { size, type: WidthType.DXA } on every cell. The table's size must equal the sum of columnWidths, and each cell's size must match its column.
ShadingType.CLEAR, never ShadingType.SOLID. Shade a cell withshading: { fill: "RRGGBB", type: ShadingType.CLEAR }. SOLID renders as a black fill.
LevelFormat, never a literal glyph. Define bullets withLevelFormat.BULLET and ordered lists with LevelFormat.DECIMAL under numbering.config, then attach each paragraph via numbering: { reference, level }. Never put a •, •, -, or 1. character into a TextRun to fake a list.
HeadingLevel.HEADING_1 … HEADING_6 (or TITLE). Set heading:HeadingLevel.HEADING_1 on the paragraph. When overriding built-in styles, use the exact style IDs "Heading1", "Heading2", … and give each an outlineLevel so a table of contents can see it.
ImageRun with a REQUIRED type. new ImageRun({ type: "png", data,transformation: { width, height } }). type is mandatory in the current API and must be one of "png" | "jpg" | "jpeg" | "gif" | "bmp" | "svg".
PageNumber.CURRENT / PageNumber.TOTAL_PAGES. Put them in a footer run'schildren, e.g. new TextRun({ children: [PageNumber.CURRENT] }). There is no "{PAGE}" string field.
new PageBreak() inside a Paragraph. A standalone PageBreak is invalidXML: new Paragraph({ children: [new PageBreak()] }), or pageBreakBefore: true.
Packer.toBuffer(doc) (a Promise), or Packer.toBlob in the browser. There isno doc.save() / doc.write() method.
"\n" in a TextRun. Each visual line is its own Paragraph.Each pair shows the model's wrong default (BEFORE) and the docx-js form (AFTER).
Bullet list
javascript// BEFORE — literal glyphs in text runs new Paragraph({ children: [new TextRun("• First point")] }) // AFTER — numbering config drives the bullet numbering: { config: [{ reference: "pts", levels: [{ level: 0, format: LevelFormat.BULLET, text: "•", alignment: AlignmentType.LEFT }] }] } new Paragraph({ numbering: { reference: "pts", level: 0 }, children: [new TextRun("First point")] })
Table width
javascript// BEFORE — percentage width (breaks in Google Docs), no cell width new Table({ width: { size: 100, type: WidthType.PERCENTAGE }, rows: [...] }) // AFTER — DXA on the table AND each cell, columnWidths sum to the table width new Table({ width: { size: 9360, type: WidthType.DXA }, columnWidths: [4680, 4680], rows: [ new TableRow({ children: [ new TableCell({ width: { size: 4680, type: WidthType.DXA }, children: [new Paragraph("Cell")] }) ] }) ] })
Cell shading
javascript// BEFORE — SOLID renders black shading: { fill: "D5E8F0", type: ShadingType.SOLID } // AFTER shading: { fill: "D5E8F0", type: ShadingType.CLEAR }
Image
javascript// BEFORE — pre-v8 API, now throws (no type) new ImageRun({ data: fs.readFileSync("logo.png"), transformation: { width: 120, height: 60 } }) // AFTER — type is required new ImageRun({ type: "png", data: fs.readFileSync("logo.png"), transformation: { width: 120, height: 60 } })
Page setup + output
javascript// BEFORE — implicit A4, and a save() that does not exist const doc = new Document({ sections: [{ children }] }); doc.save("out.docx"); // AFTER — explicit US Letter in DXA, Packer output const doc = new Document({ sections: [{ properties: { page: { size: { width: 12240, height: 15840 }, margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } }, children }] }); Packer.toBuffer(doc).then(buf => fs.writeFileSync("out.docx", buf));
width: 11906,height: 16838) rather than relying on the default — be explicit either way.
12240 − 2880 = 9360DXA; the table size and the sum of columnWidths both equal 9360.
reference continues the count;a different reference restarts at 1.
new TableOfContents(...) only sees paragraphs styled withHeadingLevel; custom run styles are ignored by the TOC.
type: WidthType.DXA on the table and every cell. DON'T use WidthType.PERCENTAGE.LevelFormat numbering config. DON'T hand-type •, •, or 1..ShadingType.CLEAR. DON'T use ShadingType.SOLID.ImageRun a type. DON'T omit it.Packer.toBuffer. DON'T call doc.save().PageBreak inside a Paragraph. DON'T emit it as a top-level child.TextRuns instead of a LevelFormat numbering config.WidthType.PERCENTAGE (or omitting width) so the table collapses in Google Docs.ShadingType.SOLID, producing black cells.ImageRun type.doc.save() instead of Packer.toBuffer."\n" inside a run instead of separate paragraphs.PageOrientation.LANDSCAPE (no manual swap).WidthType.DXA on table + cells; size = sum of columnWidths.ShadingType.CLEAR.LevelFormat.BULLET / LevelFormat.DECIMAL numbering config.HeadingLevel; ImageRun has type.PageNumber.CURRENT in the footer; PageBreak inside a Paragraph.Packer.toBuffer.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +45 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.5-flash | verified | 7/9/2026 | +26% |
Other measured skills in the registry, with their headline benchmark lift.