# Scene: Exam Paper ## Overview Exam papers are among the most critical document types in education. Unlike general documents, they require high precision in layout, print compatibility, and subject-specific formatting. This specification covers the complete workflow from page framework to subject-specific features. → Universal prohibitions — see `references/common-rules.md` → **Note:** Exam papers use their OWN font/layout specs (not Profile A defaults). All text is pure black/white/grey for photocopy clarity. --- ## 1. Page Setup & Framework ### Paper Specifications | Type | Paper | Orientation | Use Case | |------|-------|-------------|----------| | Practice / Unit quiz | A4 | Portrait | Daily practice, homework, quizzes | | Formal exam | A3 | Landscape + 2-column | Midterm / final / standardized (requires OOXML) | | Answer sheet | A4 | Portrait | Standalone answer card | ### Margins ```js // A4 portrait — no seal line page: { size: { width: 11906, height: 16838 }, margin: { top: 850, bottom: 850, left: 1200, right: 1200 } } // A4 portrait — with seal line (left binding area reserved) page: { size: { width: 11906, height: 16838 }, margin: { top: 850, bottom: 850, left: 2200, right: 850 } } // A3 landscape dual-column (requires OOXML) // ⚠️ A3 dual-column may render slightly differently in WPS vs Word. Test in both before batch printing. page: { size: { width: 23812, height: 16838, orientation: PageOrientation.LANDSCAPE }, margin: { top: 850, bottom: 850, left: 2200, right: 850 } } ``` ### Section Handling Different parts should use section breaks (`SectionType.NEXT_PAGE`): - **Header area (full-width):** Title, instructions, score table (no columns) - **Content area:** Questions (may use columns) - **Composition / answer sheet:** Independent section, independent format - **Attachment pages:** Large maps/diagrams for geography/biology can be separate pages ```js sections: [ { properties: { /* Header section — no columns */ }, children: [...] }, { properties: { type: SectionType.CONTINUOUS, column: { count: 2, space: 720 } }, children: [...] }, { properties: { type: SectionType.NEXT_PAGE }, children: [...] }, // Composition ] ``` ### Template-First Principle ⚠️ **Build framework first, fill content second.** Before writing questions, determine: 1. Paper size + margins 2. Whether seal line is needed 3. Whether columns are used 4. Question type structure and point allocation 5. Whether composition grid / answer sheet is needed --- ## 2. Seal Line & Student Information Area ### When to Use Seal Line | Scenario | Seal Line | Student Info Position | |----------|-----------|---------------------| | Formal standardized exam | ✅ Required | Left vertical info column | | Midterm / Final | ✅ Recommended | Left vertical info column | | Unit quiz | ❌ Optional | Header horizontal info row | | Daily practice | ❌ Skip | Header horizontal info row | ### Seal Line Implementation #### Method 1: Header horizontal prompt (simple) ```js headers: { default: new Header({ children: [ new Paragraph({ alignment: AlignmentType.CENTER, children: [new TextRun({ text: ".............. Seal ...... Line ...... Do ...... Not ...... Answer ...... Inside ..............", size: 16, color: "999999", font: "SimSun" })] }) ] }) } ``` #### Method 2: Vertical text box (OOXML advanced) ```xml Name:________ Class:________ ID:________ - - - - - - - - - Seal Line - - - - - - - - - ``` ### Student Info Row ```js // Horizontal info row (when no seal line) — borderless 3-column table new Table({ alignment: AlignmentType.CENTER, columnWidths: [2800, 2800, 2800], rows: [new TableRow({ children: [ cell("Name: ______________"), cell("Class: ______________", AlignmentType.CENTER), cell("ID: ______________", AlignmentType.RIGHT), ] })] }) ``` Fill lines should be moderate length (10–14 underscore chars). Label order: Name → Class → Student ID. --- ## 3. Paper Header & Title Area ### Structure ``` School name (16pt SimHei, centered) Exam title (14pt SimHei, centered) — e.g., "2025–2026 Academic Year Second Semester Midterm" Subject title (14pt SimHei, centered) — e.g., "Grade 7 Mathematics" Student info row Instructions (10pt SimSun, centered, grey) Score table (as needed) ``` ### Font Specifications | Element | Font | Size | Style | |---------|------|------|-------| | School name | SimHei | 16pt (size:32) | Bold, centered | | Exam title | SimHei | 14pt (size:28) | Bold, centered | | Subject title | SimHei | 14pt (size:28) | Bold, centered | | Instructions | SimSun | 10pt (size:20) | Grey 333333, centered | | Student info | SimSun | 10.5pt (size:21) | Normal | ### Instructions Content Should include: total score, exam duration, answer method, special requirements (e.g., calculator allowed). ### Score Table - Header row: light grey background F0F0F0, centered - Columns: Question type | Section names... | Total - Rows: Points | Section points... | Total points - Row: Score | blank... | blank - Table centered, 80% page width ⚠️ **Header area should not be too full** — title + info + instructions + score table should not exceed 1/3 of the page. --- ## 4. Content Layout Rules ### Color Palette ```js // Exam papers use only black/white/grey for clear photocopying const C = { title: "000000", body: "000000", section: "333333", seal: "999999", answerLine: "CCCCCC", headerBg: "F0F0F0", gridLine: "DDDDDD", }; ``` ### Column Usage | Subject / Question Type | Recommendation | |------------------------|----------------| | Math multiple choice + fill-in | ✅ Suitable for columns | | Physics multiple choice | ✅ Suitable for columns | | Chinese reading / composition | ❌ Not suitable | | English cloze / reading | ❌ Not suitable | | History source-based | ❌ Not suitable | | Geography map reading | ❌ Not suitable | ### Question Numbering Entire paper uses consistent three-level numbering: - **Major sections:** I, II, III, IV... (Chinese: 一、二、三、四…) - **Questions:** 1. 2. 3. ... (Arabic + period) - **Sub-questions:** (1) (2) (3) ... (parenthesized) ⚠️ **No extra symbols before question numbers** (no `•`, `▸`, `▪`, `-`, `*`). The number itself is the only marker. **Never use docx numbering/bullet list styles** for question numbers — must use plain TextRun manual numbering. ```js // ✅ Correct — plain TextRun manual numbering new Paragraph({ spacing: { before: 120, after: 60, line: 360 }, children: [new TextRun({ text: `${i+1}. ${question}`, size: 21, font: { eastAsia: "SimSun" } })] }) // ❌ Wrong — numbering causes Word to add bullets new Paragraph({ numbering: { reference: "xxx", level: 0 }, // ← Forbidden! children: [new TextRun({ text: question })] }) ``` ### Question Spacing ```js sectionTitle: { before: 300, after: 150 } // Major section headers question: { before: 120, after: 80 } // Between questions subQuestion: { before: 60, after: 40 } // Between sub-questions ``` ### Page Break Control ⚠️ Key principles: - **Question stem and answer area must not split** across pages - **Source material and questions on same page** - **Figures adjacent to their questions** - **Avoid orphan lines** — question stem, options, answer area appear as a group ```js new Paragraph({ keepNext: true, keepLines: true, children: [...] }) ``` ⚠️ **Answer question page break rule (mandatory):** Complete combination (stem + figure + answer lines) must be considered as a unit. If remaining space cannot fit stem + figure + at least 3 answer lines, push entire question to next page. Use `keepNext: true` to chain: stem → figure → first 3 answer lines. --- ## 5. Font & Paragraph Standards ### Underline Formatting for "Underlined Parts" (Mandatory) When a question references "underlined part" (划线部分), the relevant text MUST use actual underline formatting (`underline: { type: UnderlineType.SINGLE }`). **Never** show "划线部分为 XXX" as plain text annotation — the underline must be visually rendered. ```js // ✅ Correct — actual underline on the referenced text new Paragraph({ children: [ new TextRun({ text: "1. It is ", size: 21, font: { ascii: "Times New Roman" } }), new TextRun({ text: "a butterfly", size: 21, font: { ascii: "Times New Roman" }, underline: { type: UnderlineType.SINGLE, color: "000000" } }), new TextRun({ text: ". (Ask about the underlined part)", size: 21, font: { ascii: "Times New Roman" } }), ]}) // ❌ Wrong — underlined part described as annotation text new TextRun({ text: "1. It is a butterfly. (对划线部分提问) 注:划线部分为 a butterfly" }) ``` ### Font Hierarchy | Element | Font | Size | Style | |---------|------|------|-------| | Section title | SimHei | 11pt (size:22) | Bold | | Question content | SimSun | 10.5pt (size:21) | Normal | | Points annotation | SimSun | 10pt (size:20) | In parentheses | | Reading material | KaiTi/SimSun | 10.5pt (size:21) | KaiTi to differentiate | | Notes/source | SimSun | 9pt (size:18) | Grey 666666 | | Seal line | SimSun | 8pt (size:16) | Grey 999999 | | Page number | SimSun | 9pt (size:18) | Centered | ### Line Spacing ```js line: 360 // ~1.5x for readability answerLine: 500 // Answer line spacing for writing room ``` ### Paragraph Rules - ⚠️ **Never use consecutive returns for whitespace** — use `spacing.before/after` - Chinese questions use Chinese punctuation; English materials use English punctuation - Mixed CN/EN: use Times New Roman or Calibri for English text --- ## 6. Multiple Choice Layout ### Core Rule ⚠️ **Options must NEVER be aligned with spaces!** Must use borderless tables. ### Option Layout — Borderless Table ```js // Short options: 4 columns in 1 row new Table({ columnWidths: [2200, 2200, 2200, 2200], rows: [new TableRow({ children: ["A","B","C","D"].map((label, i) => new TableCell({ borders: NBs, width: { size: 2200, type: WidthType.DXA }, margins: { top: 0, bottom: 0, left: 60, right: 60 }, children: [new Paragraph({ spacing: { before: 0, after: 0 }, children: [new TextRun({ text: `${label}. ${options[i]}`, size: 21, font: "SimSun" })] })] }) ) })] }) // Medium options: 2 columns, 2 rows // Long options: 1 column, 4 rows ``` ### Option Length Detection ```js function getOptionLayout(options) { const maxLen = Math.max(...options.map(o => o.length)); if (maxLen <= 6) return "4col"; if (maxLen <= 15) return "2col"; return "1col"; } ``` --- ## 7. Fill-in-the-Blank Layout ```js // Blank line length matches expected answer: // Short answer (number/word): 8 underscores // Medium (phrase): 14 underscores // Long (sentence): 20 underscores new Paragraph({ spacing: { before: 140, after: 80, line: 400 }, children: [new TextRun({ text: `${num}. Question text ________________.`, size: 21, font: "SimSun" })] }) ``` ⚠️ Fill-in lines must not break across lines — if line is too long, put the blank on the next line. --- ## 8. Short Answer / Problem-Solving Layout ### Question + Points ```js new Paragraph({ spacing: { before: 200, after: 60, line: 360 }, keepNext: true, children: [new TextRun({ text: `${num}. (${points} pts) ${question}`, size: 21, font: "SimSun" })] }) ``` ### Answer Lines ```js // Light grey answer lines (CCCCCC), NOT black // ⚠️ Answer lines are ONLY for writing space within each question — never as dividers between questions function answerLines(count) { return Array(count).fill(null).map(() => new Paragraph({ spacing: { before: 0, after: 0, line: 500 }, borders: { bottom: { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" } }, children: [new TextRun({ text: " ", size: 21 })] }) ); } ``` ⚠️ **Separation between questions:** Use **only spacing** (`spacing.before: 200`) for visual separation between questions. **Forbidden:** - ❌ Grey horizontal lines (borders) - ❌ Color block dividers (Table-simulated separators) - ❌ Symbol dividers (e.g., `───────`) - ❌ Any visual separator decoration ### Answer Space vs. Points | Points | Suggested Lines | Description | |--------|----------------|-------------| | 2–4 | 3–4 lines | Simple calculation / short answer | | 5–8 | 6–8 lines | Medium problem | | 10–12 | 8–10 lines | Complex problem | | 14–20 | 10–14 lines | Comprehensive / essay question | --- ## 9. Source-Based / Reading Question Layout ### Material vs. Question Separation ```js // Material area — indented + KaiTi to differentiate new Paragraph({ indent: { left: 420, right: 420 }, spacing: { before: 100, after: 100, line: 380 }, children: [new TextRun({ text: materialText, size: 21, font: "KaiTi" })] }) // Source attribution new Paragraph({ alignment: AlignmentType.RIGHT, indent: { right: 420 }, children: [new TextRun({ text: "— from \"XXX\"", size: 18, color: "666666", font: "SimSun" })] }) ``` ### Key Principles - Material title, source, body, and notes use different fonts - Long materials: increase line spacing (line: 380–400) - Material and corresponding questions on same page - Sub-question numbers (1)(2)(3) clearly correspond to material - **Data tables in materials MUST use proper docx `Table` objects** — never render tabular data as Markdown plain text (`| col | col |`). This includes statistics tables, climate data tables, comparison tables, and any structured data within question materials. Use bordered tables (see § 13 Table Usage Standards) with appropriate header row styling. --- ## 10. Composition / Writing Area ### Grid Count Calculation ⚠️ **Grid count must exceed required word count by 20–30%** (for title, paragraph indents, line breaks). | Required Words | Min Grid Count | Recommended Layout | |---------------|---------------|-------------------| | 400 | 500 | 25 rows × 20 cols | | 600 | 750 | 38 rows × 20 cols | | 800 | 1000 | 50 rows × 20 cols | | 1000 | 1250 | 63 rows × 20 cols | ```js function calcGridSize(requiredWords, colsPerRow = 20) { const totalCells = Math.ceil(requiredWords * 1.25); const rows = Math.ceil(totalCells / colsPerRow); return { rows, colsPerRow, totalCells: rows * colsPerRow }; } ``` ### Chinese Composition Grid ```js function compositionGrid(rows, colsPerRow) { const cellSize = Math.floor(8800 / colsPerRow); return new Table({ columnWidths: Array(colsPerRow).fill(cellSize), rows: Array(rows).fill(null).map(() => new TableRow({ height: { value: cellSize, rule: HeightRule.EXACT }, children: Array(colsPerRow).fill(null).map(() => new TableCell({ borders: thinBs("DDDDDD"), width: { size: cellSize, type: WidthType.DXA }, children: [new Paragraph({ children: [] })] }) ) }) ) }); } ``` ### English Writing Area (Horizontal Lines) — MANDATORY for English Writing Questions ⚠️ **Every English writing/composition question MUST include ruled horizontal lines.** A blank area without lines is FORBIDDEN — students need lines to write on. ```js function writingLines(count) { return Array(count).fill(null).map(() => new Paragraph({ spacing: { before: 0, after: 0, line: 560 }, borders: { bottom: { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" } }, children: [new TextRun({ text: " ", size: 21 })] }) ); } ``` **Line count by word requirement:** | Required Words | Lines | |---------------|-------| | ≤50 | 8 | | 50–80 | 10 | | 80–120 | 12 | | 120+ | 15 | **Rules:** 1. Lines must appear immediately after the writing prompt paragraph 2. Line color: light grey `CCCCCC` (print-friendly, not visually heavy) 3. Line spacing: `line: 560` (provides adequate writing room) 4. Chinese composition uses grid (`compositionGrid`), English uses lines (`writingLines`) — never mix them up ``` ### Composition Area Requirements - Independent section or clear separation - Title space reserved (for self-chosen topics) - Word count prompt visible ("No fewer than 800 words" / "About 120 words") - Grid/line colors light — must not interfere with writing - Pages continuous, not split --- ## 11. Answer Key (参考答案) ### Output Rules 1. **Default (user does not request answers in the same file):** Generate the answer key as a **separate .docx file** (e.g., `exam.docx` + `exam_answers.docx`). This prevents students from accidentally seeing answers. 2. **User explicitly requests answers in the same file:** Place the answer key on an **independent page** using `SectionType.NEXT_PAGE`. Answer key MUST NOT appear on the same page as any exam question. ### Separate File Format (Default) The answer key file should include: - Title: "《{exam title}》参考答案" (SimHei, 14pt/size:28, bold, centered) - Same question numbering as the exam - Concise answers (letter choices, key words, short solutions) - Font: SimSun 10.5pt (size: 21) ### Same File Format (When User Requests) ```js // Answer key as a separate section — MUST use SectionType.NEXT_PAGE { properties: { type: SectionType.NEXT_PAGE, page: { margin: { top: 850, bottom: 850, left: 1200, right: 1200 } } }, children: [ new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 300 }, children: [new TextRun({ text: "参考答案", size: 28, bold: true, font: { eastAsia: "SimHei" } })], }), // ... answer content paragraphs ], } ``` ### Rules 1. ⚠️ **Never place answer content directly after the last question without a page/section break** 2. Answer content should be concise — no answer lines, no grid, plain text only 3. Calculation/proof questions: show key steps, not just final answer 4. If the exam has figures, answers may reference "see Figure X" without re-embedding --- ## 12. Figures & Illustrations ### Image Insertion ```js new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 100, after: 60 }, children: [new ImageRun({ data: imageBuffer, transformation: { width: 300, height: 200 }, type: "png" })] }) new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 100 }, children: [new TextRun({ text: "(Figure 1)", size: 18, color: "666666", font: "SimSun" })] }) ``` ### Key Principles - Images set as inline (default) to prevent floating - Resolution sufficient for print clarity - **B&W print compatible:** images must remain distinguishable when printed in grayscale - Figure numbers and captions complete - Figures adjacent to corresponding questions - Maps must have: scale bar, north arrow, legend - Coordinate graphs must have: axis labels, tick marks, units ### ⚠️ Figure-Text Order (Strictly Enforced) **For questions with figures, element order must be:** ``` 1. Question stem (keepNext: true) 2. Figure (centered, keepNext: true) 3. Answer lines / answer area ``` **Forbidden:** answer lines between stem and figure, or figure after answer lines. ### Figure Content Matching - **Figures must be semantically consistent with question stem:** if question says "triangle ABC", figure must label vertices A, B, C - Geometry annotations must match described angles, side lengths - Function graphs must mark key points mentioned in the question - Physics experiment diagrams must match described apparatus - Figure width: geometry ≤ 50% page width, data/experiment ≤ 70% ### ⚠️ Figure Diversity Rule (Mandatory) **No duplicate figures in the entire paper.** Even if two questions involve the same type (e.g., both triangles), each must have a distinct figure: 1. Different labels (different vertex letters, angles, side lengths) 2. Different shapes (acute vs. right vs. obtuse triangle) 3. Different styling (if applicable) If using matplotlib, each call must use **different parameters and data** — never copy the same generation code. ### Subject-Specific Figure Requirements | Subject | Common Types | Special Requirements | |---------|-------------|---------------------| | Math | Geometry, functions, coordinates | No distortion, clear labels | | Physics | Circuits, mechanics, apparatus | Standard symbols, correct arrows | | Chemistry | Apparatus, molecular structures | Reagent names labeled | | Biology | Cell, organ, ecosystem diagrams | Labels not too small | | Geography | Maps, contour lines, statistics | Legend + scale + north arrow | --- ## 13. Formulas & Special Symbols ### Formulas Math/physics/chemistry formulas use **LaTeX → docx-js Math mapping** (see `references/math-formulas.md`): - Basic (fractions, sub/superscript, roots) → docx-js Math components - Complex (3+ nesting, matrices) → matplotlib PNG fallback - Never hand-type Unicode formula approximations ### Common Unicode Math Symbols ``` × ÷ ± ∓ ≠ ≈ ≤ ≥ ∞ √ ∑ ∏ ∫ ∂ ∆ ∇ α β γ δ ε θ λ μ π σ φ ω ⊂ ⊃ ∈ ∉ ∪ ∩ ∅ ∀ ∃ → ← ↑ ↓ ⇒ ⇔ ° ′ ″ ‰ ² ³ ⁴ ⁿ ₁ ₂ ₃ ``` ### Chemical Formulas Subscripts/superscripts must be correct: H₂O, CO₂, Fe₂O₃, Ca(OH)₂ Reaction arrows: → ⇌ ↑ ↓ --- ## 14. Table Usage Standards ### Borderless Tables (for alignment) For: option alignment, info rows, question number + points alignment ```js const NB = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" }; const NBs = { top: NB, bottom: NB, left: NB, right: NB }; ``` ### Bordered Tables (for data display) For: score tables, data tables, statistics ```js const thinB = (c="000000") => ({ style: BorderStyle.SINGLE, size: 1, color: c }); const thinBs = (c="000000") => ({ top: thinB(c), bottom: thinB(c), left: thinB(c), right: thinB(c) }); ``` ### Table Standards - Cell padding moderate (margins: top/bottom 40–60, left/right 60–80) - Consistent border thickness - Header row: light grey F0F0F0 background - Avoid cross-page tables - Tables centered (`alignment: AlignmentType.CENTER`) --- ## 15. Headers & Footers ### Page Numbers ```js footers: { default: new Footer({ children: [ new Paragraph({ alignment: AlignmentType.CENTER, children: [ new TextRun({ children: [PageNumber.CURRENT], size: 18, font: "SimSun" }), ] }) ] }) } ``` ⚠️ **Denominator FORBIDDEN** — never use `PageNumber.TOTAL_PAGES` or "Page X of Y". Show only current page number. ### Headers - May contain seal line prompt or subject name - Small font (8–9pt), grey color (999999) - Should not be visually heavy — must not compete with content --- ## 16. Subject-Specific Standards ### Chinese Language - Reading, classical poetry, composition: **no columns** - Poetry preserves original line breaks - Classical text needs annotation area (smaller font, indented) - Composition grid in independent section, grid count via `calcGridSize` (800 words → 50×20 = 1000 cells) - Dictation questions: horizontal lines, moderate length - Reading materials: use KaiTi to differentiate ### Mathematics - Multiple choice, fill-in: suitable for neat layout - Formulas: Unicode symbols or OOXML - Geometry/function graphs must be clear, undistorted - Problem-solving: sufficient working space - Coordinate graphs: labeled axes, tick marks ### English - English font: Times New Roman, moderate character spacing - Cloze: numbers in text, options after passage - Reading comprehension: material + questions as groups - Writing area: horizontal lines, not grid - Listening (if any): numbers aligned with options ### Physics / Chemistry / Biology - Experiment/apparatus diagrams must be clear and accurate - Unit symbols standardized (m/s, kg, mol/L, etc.) - Chemical formula subscripts correct - Calculation and experiment analysis: sufficient answer space - Biology structure diagrams: labels not too small ### History / Politics - Source-based questions are lengthy — **no columns** - Dates, figures, events clearly labeled - Essay questions: more whitespace than multiple choice - Historical sources cite provenance - Chart materials in logical order ### Geography - Maps are the focus — must be clear - Legend, scale bar, north arrow required - Map and question close together — avoid page turns - Map reading questions: balance figure and text space - Contour line values clearly labeled --- ## Final Review Checklist After generating an exam paper, check every item: - [ ] Question numbers sequential, points correct, total correct - [ ] Question stems match options / materials / illustrations one-to-one - [ ] **Figures come after stem, before answer area** (strict order) - [ ] **Figure content matches question semantics** (labels, symbols match) - [ ] **Composition grid count ≥ required words × 1.25** (800 words → at least 1000 cells) - [ ] Options aligned with borderless tables (not spaces) - [ ] No wrong pages, missing pages, **no extra blank pages** - [ ] Images / tables / formulas positioned correctly - [ ] **No Markdown table syntax in document** — all data tables use proper docx Table objects - [ ] Fonts, sizes, line spacing consistent - [ ] Answer space matches difficulty and point value - [ ] Clear when printed in B&W - [ ] Subject-specific layout handled properly - [ ] Seal line / page numbers / headers formatted correctly - [ ] Header info complete (school, subject, duration, total score) - [ ] **No extra PageBreak at end of last section** - [ ] **Answer key is either a separate file (default) or on a separate page (if user requested in same file)** — never on the same page as questions