写作模板¶
新建写作项目时可以选空白项目或会议模板。会议模板是各会议公开的作者包,原样存放在 src/lib/writing/templates/vendor/<id>/,应用不改官方文件,也不向其中写入标题或作者。来源记录在同目录的 SOURCES.md。
模板清单¶
| id | 显示名 | 主文件 | 来源 |
|---|---|---|---|
blank |
空白 | main.tex(应用生成) |
— |
cvpr |
CVPR / ICCV | main.tex |
cvpr-org/author-kit |
icml |
ICML | example_paper.tex |
官方 icml2026.zip |
iclr |
ICLR | iclr2027_conference.tex |
ICLR 2027 官方样式文件 |
neurips |
NeurIPS | neurips_2026.tex |
NeurIPS 2026 官方格式说明包 |
acl |
ACL / EMNLP | acl_latex.tex |
acl-org/acl-style-files |
eccv |
ECCV | main.tex |
ECCV 2026 官方 LNCS 模板 |
空白项目的 main.tex 由 writingTemplateFiles("blank", 项目名) 生成:article 文档类,项目名写进 \title,其中的 \ & % $ # _ { } 会转义;文件里不写 % !TEX program。
打包¶
src/lib/writing/templates/index.ts 在构建时用 import.meta.glob 收集 vendor 文件:
- 文本文件:
./vendor/*/**/*.{tex,sty,bst,bib,cls,clo,eps},?raw+eager,内容直接打进前端 bundle。 - PDF:
./vendor/*/**/*.pdf,?url+eager,作为静态资源发布,新建项目时再fetch回来写入。
不匹配这两条 glob 的文件不会打包,新建的项目里也就没有它们。
新建项目¶
- 新建项目面板(
src/components/writing/new-project-form.tsx)按WRITING_TEMPLATE_IDS的顺序列出模板,显示名取src/i18n/locales/{en,zh-CN}/sidebar.json里的writing.templates.<id>。 createWritingProject(src/lib/writing/projects.ts)检查项目名,在thesis/<项目名>/下创建项目,目录或主文件已存在时不创建。先写入writingTemplateFiles返回的文本文件(保持官方包里的相对路径),再写入writingTemplateAssets返回的 PDF,然后刷新文件树,返回主文件路径。- 面板以文本模式打开这个主文件。
主文件与编译引擎¶
ROOTS 只决定新建后打开哪个文件,不会记到项目里。之后按通用规则识别:
- 项目主文件:
src/lib/writing/discover.ts的findTexRoot在项目目录顶层的.tex里依次选main.tex、thesis.tex、和目录同名的文件,都没有时按路径排序取第一个;顶层没有.tex时再看一层子目录。 - 编译根:编译、预览和 SyncTeX 用
resolveTexRoot。项目设置里显式选了主文件时用它;否则依次看% !TEX root、文件自身的\documentclass/\begin{document}、知识库里\input/\include了它的文件,都没有时用文件本身(详见 LaTeX)。
现有模板的编译根都会落到 ROOTS 写的文件上。CVPR 和 ECCV 的主文件就叫 main.tex;ICML 顶层只有一个 .tex;ICLR 的 math_commands.tex、ACL 的 acl_lualatex.tex 按路径排在主文件后面。NeurIPS 的 checklist.tex 排在 neurips_2026.tex 前面,会先被 findTexRoot 选中,但它没有 \documentclass,由 neurips_2026.tex \input,resolveTexRoot 会解析回 neurips_2026.tex。
引擎的选择顺序见 LaTeX。和模板有关的是 src/lib/tex/engine.ts 的 inferRequiredEngine,它只看主文件的导言区(\begin{document} 之前,去掉注释):
\babelfont/\babelprovide要求 LuaLaTeX,例如 ACL 包里的acl_lualatex.tex。fontspec、polyglossia、xeCJK或ctex系列文档类要求 XeLaTeX。\usepackage或\documentclass用到CONFERENCE_ENGINE里的名字时要求 pdfLaTeX:cvpr、iccv、iclr、icml、neurips、acl、eccv、eccvabbrv、llncs。其中iclr、icml、neurips可以带年份,如iclr2027_conference、icml2026、neurips_2026。
都不匹配,也没有 % !TEX program 和记住的选择时,用 XeLaTeX(没装时用第一个可用引擎)。
测试¶
test/writing-templates.test.ts:空白项目只生成main.tex,标题转义,不写% !TEX program;ICML、ACL 的主文件名,CVPR 主文件里的\usepackage[review]{cvpr},以及cvpr.sty、sec/1_intro.tex、icml2026.sty、iclr2027_conference.sty、neurips_2026.sty、acl.sty、llncs.cls都在。test/tex-engine.test.ts:CVPR、ICLR、ECCV(llncs)、NeurIPS、ICML 的包要求 pdfLaTeX,注释掉的\usepackage{cvpr}不算;\babelfont、fontspec、ctexart对应的引擎。
新增会议模板¶
以 <venue> 为例:
- 放官方包:把官方作者包解压到
vendor/<venue>/,保留目录结构,不改官方文件。编译好的示例 PDF、说明文档这类用不到的文件可以不放,ICML 和 ECCV 就是这样。在vendor/SOURCES.md加一行,写明来源和主文件。 - 注册:在
index.ts里把"<venue>"加进WRITING_TEMPLATE_IDS(下拉按这个顺序),并在ROOTS里填主文件在包内的路径。ROOTS的类型要求每个会议模板都有主文件,漏填时 typecheck 会报错。 - 核对文件类型:包里有扩展名不在
tex,sty,bst,bib,cls,clo,eps里的文本文件(如.def、.cfg、.fd)时,加进文本 glob;有 PDF 以外的二进制文件(如.png、.jpg)时,加进 PDF 那条?urlglob。否则新建的项目会缺文件。 - 核对主文件识别:主文件不叫
main.tex时,确认顶层按路径排在它前面的.tex都不是独立文档(自己带\documentclass)。否则findTexRoot会选中那个文件,编译根也会停在它上面。 - 显示名:在
en和zh-CN的sidebar.json里加writing.templates.<venue>。 - 引擎:确认主文件的导言区能被
inferRequiredEngine认出来。类名或宏包名不在CONFERENCE_ENGINE里时,把它加进去,否则会按 XeLaTeX 编译。 - 测试:在
test/writing-templates.test.ts断言主文件名和关键样式文件;改了CONFERENCE_ENGINE时,在test/tex-engine.test.ts加一条断言。 - 文档:更新本页的模板清单,以及 写作 里列出的会议名。
- 验证:
pnpm typecheck、pnpm lint:ts、pnpm vitest run test/writing-templates.test.ts test/tex-engine.test.ts;再在应用里用这个模板新建项目,确认文件齐全、能直接编译。
已知限制¶
- vendor 文本文件全部 eager 打进前端 bundle,模板越多,bundle 越大。
- 模板信息分散在
WRITING_TEMPLATE_IDS、ROOTS、两份sidebar.json、CONFERENCE_ENGINE和测试里,新增时要逐处改(见上面的步骤)。 - 官方包原样复制。换成新一年的包时要整体替换目录,并同步
ROOTS、SOURCES.md和测试里带年份的文件名;CONFERENCE_ENGINE已允许iclr、icml、neurips带年份,命名方式不变时不用改。应用不会在运行时下载或更新模板。 - 写入中途失败时不回滚:已经写入的文件留在
thesis/<项目名>/,再用同一个名字新建会提示已存在。