import { Presentation, PresentationFile } from "@oai/artifact-tool";const OUTPUT = "lesson-design-demo.pptx";// 修改这里,就能换成自己的课程内容。const lesson = { subject: "八年级物理", topic: "压强", duration: 40, objectives: [ "解释压力、受力面积与压强之间的关系", "用压强规律解释陌生生活情境", ], slides: [ { title: "为什么雪地靴的鞋底更宽?", prompt: "先独立判断,再用一句话写下理由。", action: "预测并解释", evidence: "带理由的初始判断", minutes: 3, }, { title: "同样重,陷入程度为什么不同?", prompt: "比较两张实验现象图,圈出发生变化的条件。", action: "观察与比较", evidence: "变量识别记录", minutes: 4, }, { title: "保持压力不变,只改变受力面积", prompt: "小组讨论:受力面积变小时,作用效果怎样变化?", action: "控制变量讨论", evidence: "小组关系判断", minutes: 5, }, { title: "保持受力面积不变,只改变压力", prompt: "根据现象补全:压力越大,压力的作用效果越____。", action: "归纳规律", evidence: "完整规律表述", minutes: 4, }, { title: "用一个量描述压力的作用效果", prompt: "压强 = 压力 ÷ 受力面积;说出公式中每个量的含义。", action: "建立概念", evidence: "口头解释与符号对应", minutes: 5, }, { title: "计算不是代数字,而是解释关系", prompt: "先判断压强变化方向,再代入数据验证。", action: "先推理后计算", evidence: "方向判断+计算过程", minutes: 5, }, { title: "图钉为什么一头尖、一头宽?", prompt: "分别解释尖端和帽端的设计目的。", action: "迁移到生活用品", evidence: "双变量因果解释", minutes: 4, }, { title: "履带车为什么不容易陷进松软地面?", prompt: "不使用“更稳”这个词,用压强关系重新解释。", action: "修正日常语言", evidence: "规范科学解释", minutes: 4, }, { title: "给临时舞台设计更安全的支撑脚", prompt: "画出方案,并说明你改变了哪个变量。", action: "设计与论证", evidence: "草图+设计理由", minutes: 4, }, { title: "现在,你会怎样重新回答开场问题?", prompt: "对比课前答案:哪一点改变了?哪条证据促成了改变?", action: "回看与反思", evidence: "课前—课后解释对照", minutes: 2, }, ],};const C = { ink: "#0B1220", navy: "#111B2E", white: "#F7FAFC", muted: "#9AA8BF", teal: "#26D9B3", orange: "#FF8A55", line: "#263650",};functionaddText(slide, text, x, y, w, h, style = {}) { const box = slide.shapes.add({ geometry: "textbox", position: { left: x, top: y, width: w, height: h }, fill: "none", line: { fill: "none", width: 0 }, }); box.text = text; box.text.style = { fontFamily: "Microsoft YaHei", fontSize: 24, color: C.white, ...style, }; return box;}functionaddBase(slide, index) { slide.background.fill = C.ink; addText(slide, `LESSON DESIGN / ${lesson.subject}`, 64, 38, 600, 24, { fontSize: 13, bold: true, color: C.teal, }); addText(slide, String(index).padStart(2, "0"), 1160, 38, 56, 24, { fontSize: 13, bold: true, color: C.muted, textAlign: "right", });}functionaddTitleSlide(deck) { const slide = deck.slides.add(); addBase(slide, 0); addText(slide, lesson.topic, 72, 162, 700, 108, { fontSize: 66, bold: true, }); addText(slide, "从生活现象出发,理解压力的作用效果", 76, 282, 760, 50, { fontSize: 27, color: C.teal, }); addText( slide, `${lesson.duration} 分钟 · ${lesson.objectives.length} 个学习目标 · ${lesson.slides.length} 个学习动作`, 76, 388, 850, 34, { fontSize: 18, color: C.muted }, ); addText(slide, "先预测,再观察;先解释,再计算。", 76, 528, 920, 60, { fontSize: 34, bold: true, color: C.orange, });}functionaddLearningSlide(deck, item, index) { const slide = deck.slides.add(); addBase(slide, index); addText(slide, item.title, 72, 112, 1080, 92, { fontSize: 42, bold: true, }); addText(slide, item.prompt, 76, 252, 1080, 84, { fontSize: 28, color: C.white, }); const line = slide.shapes.add({ geometry: "rect", position: { left: 76, top: 382, width: 1080, height: 2 }, fill: C.line, line: { fill: "none", width: 0 }, }); line.name = "section-divider"; addText(slide, "学生动作", 76, 422, 180, 32, { fontSize: 16, bold: true, color: C.teal, }); addText(slide, item.action, 76, 462, 430, 54, { fontSize: 25, bold: true, }); addText(slide, "学习证据", 576, 422, 180, 32, { fontSize: 16, bold: true, color: C.orange, }); addText(slide, item.evidence, 576, 462, 510, 54, { fontSize: 25, bold: true, }); addText(slide, `${item.minutes} MIN`, 1060, 620, 100, 28, { fontSize: 14, bold: true, color: C.muted, textAlign: "right", });}functionaddClosingSlide(deck) { const slide = deck.slides.add(); addBase(slide, lesson.slides.length + 1); addText(slide, "这节课结束时,学生带走什么?", 72, 118, 1040, 72, { fontSize: 43, bold: true, }); lesson.objectives.forEach((objective, i) => { addText(slide, `0${i + 1}`, 78, 266 + i * 112, 64, 48, { fontSize: 25, bold: true, color: C.teal, }); addText(slide, objective, 156, 264 + i * 112, 910, 64, { fontSize: 27, bold: true, }); }); addText(slide, "课后请保留最后一页的回答,作为下一轮教学调整的依据。", 78, 560, 1040, 46, { fontSize: 21, color: C.orange, });}async function main() { const deck = Presentation.create({ slideSize: { width: 1280, height: 720 }, }); addTitleSlide(deck); lesson.slides.forEach((item, i) => addLearningSlide(deck, item, i + 1)); addClosingSlide(deck); const pptx = await PresentationFile.exportPptx(deck); await pptx.save(OUTPUT); console.log(`已生成:${OUTPUT}`);}main().catch((error) => { console.error(error); process.exitCode = 1;});