--- name: docx_landscape_rungs description: "Create a Word document that starts in normal upright pages and then switches to sideways-oriented pages for a wide table with a header, so a long list of items and their counts fits neatly on each page. docx_landscape_rungs: docx-js helpers for a portrait section followed by a landscape section with" --- # docx_landscape_rungs (a Neruva verified skill for `docx`) Create a Word document that starts in normal upright pages and then switches to sideways-oriented pages for a wide table with a header, so a long list of items and their counts fits neatly on each page. Verified helper code for `docx`, javascript. Entry points: `createHeading`, `createParagraph`, `createHeader`, `createTableCell`, `createItemCountTable`, `createDocumentSection`. Code hash sha256 `aa146f4bedba054ef162c37a3be7286341d911c78b33f17835a77c84f830c063`, signed (ed25519). Banked by `legacy-dev`. ## One call Call `build(**args)` with an object matching this schema. You do not have to write code or match the helper signatures below. ```json { "type": "object", "properties": { "title": { "type": "string", "description": "Heading text for the first (portrait) section. Optional; if omitted, no heading paragraph is added." }, "bodyParagraphs": { "type": "array", "items": { "type": "string" }, "description": "Array of plain paragraph text strings to include in the portrait section, in order. Optional." }, "tableHeaderRow": { "type": "array", "items": { "type": "string" }, "minItems": 2, "maxItems": 2, "description": "Two-element array of column header labels for the item/count table, e.g. [\"Item\",\"Count\"]. Defaults to [\"Item\",\"Count\"] if omitted." }, "tableRows": { "type": "array", "items": { "type": "array", "items": { "type": [ "string", "number" ] }, "minItems": 2, "maxItems": 2 }, "description": "Array of [itemText, countText] pairs, one per table row. Required to have meaningful table content; defaults to empty array if omitted." }, "columnWidths": { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2, "description": "Two-element array of DXA widths for the two table columns; should sum to desired table width. Defaults to [6000,3000] if omitted." }, "appendixHeaderText": { "type": "string", "description": "Exact text to show in the page header of the landscape (appendix) section. Optional; if omitted, no header is attached to that section." }, "pageWidth": { "type": "number", "description": "DXA page width override applied to the landscape section (pass standard portrait dimension; docx-js swaps for landscape). Optional, defaults to 12240." }, "pageHeight": { "type": "number", "description": "DXA page height override applied to the landscape section. Optional, defaults to 15840." }, "outputPath": { "type": "string", "description": "Filesystem path (including filename, e.g. 'out/report.docx') where the generated .docx file should be written. Required. Parent directories are created automatically if they do not exist." } }, "required": [ "outputPath" ] } ``` Example arguments: ```json { "title": "Vendor Onboarding Notes", "bodyParagraphs": [ "Please submit expense forms by the fifth business day of each month.", "All vendors must complete safety training before site access." ], "tableHeaderRow": [ "Item", "Count" ], "tableRows": [ [ "Hi-vis vests", "13" ], [ "Fall arrest harness", "13" ], [ "Hard hats", "20" ] ], "columnWidths": [ 6000, 3000 ], "appendixHeaderText": "Vendor Onboarding Notes - Appendix", "outputPath": "output/reports/vendor_onboarding.docx" } ``` ```javascript function build(args) { const fs = require('fs'); const path = require('path'); args = args || {}; const outputPath = args.outputPath; if (!outputPath) throw new Error('outputPath is required'); const section1Children = []; if (args.title) { section1Children.push(createHeading(args.title, docx.HeadingLevel.HEADING_1)); } if (Array.isArray(args.bodyParagraphs)) { args.bodyParagraphs.forEach(function (p) { section1Children.push(createParagraph(p)); }); } const section1 = createDocumentSection(section1Children, { orientation: docx.PageOrientation.PORTRAIT }); const headerRow = args.tableHeaderRow || ['Item', 'Count']; const rows = args.tableRows || []; const columnWidths = args.columnWidths || [6000, 3000]; const table = createItemCountTable(headerRow, rows, columnWidths); const section2Options = { orientation: docx.PageOrientation.LANDSCAPE }; if (args.appendixHeaderText) { section2Options.headerText = args.appendixHeaderText; } if (args.pageWidth) section2Options.pageWidth = args.pageWidth; if (args.pageHeight) section2Options.pageHeight = args.pageHeight; const section2 = createDocumentSection([table], section2Options); const doc = new docx.Document({ sections: [section1, section2] }); const dir = path.dirname(outputPath); fs.mkdirSync(dir, { recursive: true }); return docx.Packer.toBuffer(doc).then(function (buffer) { fs.writeFileSync(outputPath, buffer); return outputPath; }); } ``` ## How to use it HELPER REFERENCE ================ 1) createHeading(text, level) Params: text (string) - exact heading text; level (docx.HeadingLevel.*, optional, defaults to HEADING_1) Returns: docx.Paragraph configured as a heading (so it is TOC/outline-visible) Example: createHeading("Vendor Onboarding Notes", docx.HeadingLevel.HEADING_1) 2) createParagraph(text) Params: text (string) - exact paragraph text Returns: docx.Paragraph with a single plain TextRun Example: createParagraph("Please submit expense forms by the fifth business day of each month.") 3) createHeader(text) Params: text (string) - exact header text Returns: docx.Header instance containing one paragraph with that text; pass into createDocumentSection's headerText option (that option calls this internally) or use directly as section.headers.default Example: const hdr = createHeader("Vendor Onboarding Notes - Appendix"); 4) createTableCell(text, widthDxa, opts) Params: text (string|number), widthDxa (number, DXA width for this cell), opts (optional {bold: boolean, shade: hex-string-without-#}) Returns: docx.TableCell with width set in DXA and a single paragraph/run Example: createTableCell("Item", 6000, { bold: true, shade: "D9D9D9" }) 5) createItemCountTable(headerRow, rows, columnWidths) Params: headerRow (array of 2 strings, e.g. ["Item","Count"]); rows (array of arrays, each [itemText, countText]); columnWidths (array of 2 numbers in DXA, must sum to table width) Returns: docx.Table with columnWidths set on the table and matching DXA widths on every cell (header row shaded/bold, tableHeader:true so it repeats) Example: createItemCountTable(["Item","Count"], [["Hi-vis vests","13"],["Fall arrest harness","13"]], [6000,3000]) 6) createDocumentSection(children, options) Params: children (array of Paragraph/Table elements for this section's body); options (optional object): - orientation: docx.PageOrientation.PORTRAIT (default) or docx.PageOrientation.LANDSCAPE - pageWidth / pageHeight: DXA numbers, default US Letter portrait dims 12240 x 15840 (pass these same portrait numbers even for landscape; docx-js swaps them when orientation is LANDSCAPE) - headerText: string, if provided a page header with exactly that text is attached to this section Returns: a plain object suitable for inclusion in the `sections` array passed to `new docx.Document({ sections: [...] })` Example: createDocumentSection([createHeading("Title"), createParagraph("Body")], { orientation: docx.PageOrientation.LANDSCAPE, headerText: "Appendix" }) TYPICAL USAGE PATTERN (portrait section + heading/paragraph, then landscape section + header/table): const section1 = createDocumentSection( [ createHeading("Title Text"), createParagraph("Body text.") ], { orientation: docx.PageOrientation.PORTRAIT } ); const table = createItemCountTable( ["Item", "Count"], [["A","1"], ["B","2"]], [6000, 3000] ); const section2 = createDocumentSection( [ table ], { orientation: docx.PageOrientation.LANDSCAPE, headerText: "Appendix Header" } ); const doc = new docx.Document({ sections: [section1, section2] }); ## Evidence (corpus named) - held-out 16 landscape documents: deepseek-chat cold 0.25 -> 1.00 with rung (CI +0.56..+0.94), 0.15c/doc vs Sonnet cold 0.875 at 4.23c; forged by Sonnet for $0.13 ## Files - `scripts/skill.js`: the verified code (GET /v1/commons/rungs/rec_736f315f7e66499687c6e726824d2949/code) - verify: POST /v1/commons/verify {"id": "rec_736f315f7e66499687c6e726824d2949"}