@openpresentation/opf

中文文档
0.30.0发布于 2026/11/02MITTypeScriptES Module构建来源已验证

规范开放演示格式模式、TypeScript类型、本地验证和组合;在Node中,文件API和CLI默认注册pptx。@openpresentation/ Gallery的画廊目录。

中文使用文档
文档目录17 节
  1. 文件命名
  2. 安装
  3. 使用
  4. 事实,幻灯片上下文和字体处理
  5. 内容转换
  6. 标记和轮廓
  7. 读写任何形式的牌组
  8. OPF为YAML
  9. 源代码编辑:模式字段查询,文本寻址和语法恢复
  10. 验证(0.14.0)
  11. 补丁,diff,合并和格式化(0.12.0)
  12. id,文档散列和补丁范围(CE-04, CE-05)
  13. 布局预览
  14. 例子甲板
  15. 文档页面
  16. 上游的自述
  17. 开发

@openpresentation /消息

JavaScript和TypeScript的Canonical Open Presentation Format包。

发布OPF模式、目录预设、原始规范文件、生成的TypeScript类型、示例、文档和本地验证助手。模式是预稳定的(0。X -预计在1.0之前的小版本之间会有突破性的变化)。这个包不呈现PowerPoint文件,解析 .pptx,获取远程目录,调用托管api,提供遥测或使用AI。

规范的npm包仍然存在 @openpresentation/opf;一个单独的 @openpresentation/opf-spec 包不用于v0.2.0,因此现有的下游导入保持稳定。打包的npm工件包括包可寻址的OPF模式、目录、参考文件和一个可选的下游服务引用 openapi.yaml 下 spec/.

存储库: https://github.com/OpenPresentation/opf

文件命名

使用 *.opf.json 下载完整的开放演示格式文件,例如 deck.opf.json.

OPF文档是纯JSON,而 .opf.json Suffix使其对编辑器、验证器、代理和存储库工具可见。避免裸露的 *.opf 因为该扩展已经被其他文档和项目格式所使用。

安装

pnpm add @openpresentation/opf
# or: npm install @openpresentation/opf
# or: yarn add @openpresentation/opf

要求Node 22或更高版本(engines.node >=22),从0.12.1之后的版本。声明了0.10.0到0.12.1版本 24.x因此,npm在Node 22或26上静默地安装了一个匹配(RR-20)的旧版本。早期发布的版本保留了它们记录的运行时需求。

使用

对大多数应用程序代码使用通用的根API:

import { presentation, validate, embed } from "@openpresentation/opf";
import { gallery } from "@openpresentation/gallery";

import type { Presentation } from "@openpresentation/opf";

const deck: Presentation = {
  name: "Quarterly Review",
  slides: [{ title: "Quarterly Review", items: ["Revenue", "Product", "Hiring"] }],
};

console.log(presentation.$id);
// Register the catalogs your host trusts; core ships no records. In Node, validate, stats, paginate, embed and edit
// register the gallery (@openpresentation/gallery, a dependency of core) when a call names none.
const catalogs = [gallery];
console.log(validate({ ...deck, design: { theme: "classic" } }, { catalogs }).valid);
// Save with every record the deck uses embedded, so it renders the same with no catalog registered.
const saved = embed({ ...deck, design: { theme: "classic" } }, { catalogs }).document;
console.log(Object.keys(saved.catalogs.default.themes)); // ["classic"]
console.log(Object.keys(gallery.tones));

在Node(以及Bun和Deno)中,根目录添加文件: convert 将一个文件转换为另一个文件(将一个甲板转换为PDF, PNG, SVG或PPTX,将PowerPoint文件转换为甲板,将一个甲板形式转换为另一个甲板,或没有输出路径的字节), open 读取一个甲板文件或导入一个 .pptx, save 写一个。相同的导入在每个运行时都有效,所以一个命名空间导入涵盖了一个应用程序:

import * as opf from "@openpresentation/opf";

await opf.convert("deck.opf.md", "deck.pdf");
const deck = await opf.open("deck.opf.md");
deck.slides.push({ title: "Q4" });
await opf.save(deck, "deck.opf.md");
const { files } = await opf.convert(deck, { format: "pptx" }); // bytes, nothing written

绘图和ppt通过可选的同伴 @openpresentation/opf-render 和 @openpresentation/opf-pptx,哪个核心在调用第一次需要它们时加载;NPM不会为你安装它们。根有条件导出(OPF 0.18删除) /node): node, bun 和 deno 得到这个完整的构建,然后 browser, worker, workerd 和 default 获得具有相同名称和相同类型的浏览器安全构建,其中 open, save 和 convert 拒绝与 OPFApiError 代码 node-only. 其他所有子路径都在浏览器中运行。 parseSlideSelection(3 | "1-3" | [1, 3], total) 在两者中读取幻灯片选择。看到 OPF文件在Node.

在Cloudflare Workers、Vercel Edge和其他拒绝从字符串生成代码的主机上, validate 运行在构建时编译的验证器,而不是用Ajv编译模式。这个 workerd, worker 和 edge-light 条件选择它们,所以Worker不需要别名,也不需要选项;为在工作线程(以及严格的Content-Security-Policy下的页面)导入上运行的Node绑定的代码 @openpresentation/opf/precompiled 一次。结论和发现是相同的,并且CI通道在实际中运行包 workerd 运行时。看到 边缘运行时.

当你只需要一个表面时,使用聚焦导入:

import { presentation, audience } from "@openpresentation/opf/schemas";
import { specFileEntries } from "@openpresentation/opf/spec-files";
import { validate, assertValid, validationRules } from "@openpresentation/opf/validator";
import type { Presentation, Audience, Tone } from "@openpresentation/opf/types";

根条目保存应用程序级API:模式、目录引用及其解析(resolveReference, embed, copySlides, updateFromCatalog)、验证、变量、分页、数据助手、字体策略、 stats, resolveSlideContext 和 resolveSlideVariables. 发动机组成和绘制 context.slide 从 resolveSlideContext(deck, index, { slideNumber, slideCount }):带滑动范围的内置滑块 {{slide.number}}, {{slide.section}} 和 {{deck.slideCount}} 代入相同的数 options 带(resolveSlideVariables(slide, { slideNumber, slideCount }) 单独做替换)页眉和页脚文本由 layoutFurniture,它会记录每张幻灯片的编号 FurnitureTextPart.fields. 看到 模板和变量. 它不携带目录记录:pptx。画廊目录是包 @openpresentation/gallery (gallery, catalogDisplay的布局预览 @openpresentation/gallery/previews),在自己的版本行上发布的core依赖,当调用没有目录时,Node构建会注册它(OPF 0.19删除) @openpresentation/opf/catalog 和 defaultCatalog,没有别名)。解析引用的每个入口点都使用 { catalogs }、主机注册的目录;第一个是省略的文档的默认值 catalogs.default. 看到 目录和默认目录.

布局引擎的名称不在根目录上。 composeSlide, fitText, layoutQuote 另一个 layoutX/fitX 功能,编号,脚注和引用,颜色对比,代码语法,模式填充,度量趋势,图表选项,脚本字体和文本方向来自 @openpresentation/opf/composition;符号字体表来自 @openpresentation/opf/symbol-font-encodings.

事实,幻灯片上下文和字体处理

stats(presentation, options?) 报告关于桥牌的中立事实(结构、文字、注释、图像、图表、表格、数据集、引用、变量、资产、字体),而不进行构图、测量或验证;看到 统计指南. resolveSlideContext(presentation, index, { fonts, catalogs }) 将一张幻灯片的画布、布局、主题和字体系列(幻灯片设计,然后是甲板设计,然后是主题,然后是引擎默认值)解析为 ComposeSlideOptions 那 composeSlide 带一个 unresolved-reference 每个引用的诊断无法解析(strictReferences: true 抛出 OPFUnresolvedReferenceError 相反)。甲板级动词take { fonts }谁的手柄? textMeasurement 是主机的实际字体绘制文本的宽度(paginate(deck, { fonts }));渲染器的字体加载器返回一个扩展它的更丰富句柄。 composeSlide 它本身是发动机水平的 textMeasurement 和 fontFamilies ({ heading, body, code, accent? }直接)。

内容转换

@openpresentation/opf/convert 在文本、列表、引用、度量、代码、时间线、图表、表格和一组度量块之间转换一个有效负载(convertContent, contentConversionTargets)、嵌套列表项、分组块、在内容和幻灯片设计之间移动图像,以及拆分或合并幻灯片(splitSlide, splitSlideOnOverflow, mergeSlides, unpaginate). 每个函数都是纯粹的,从不虚构内容、报告 lossless 和 loss,有理由拒绝并验证其输出。看到 转换指南. 在变更日志中列出它之前的版本中不会。

标记和轮廓

@openpresentation/opf/markdown 读取和写入一个甲板Markdown在一个小文档方言(YAML前端问题), --- 之间的幻灯片, # 标题, ## 副标题、列表、引用、表格、图片、 chart, metric 和 timeline 围栏, Note: 演讲者笔记)。 fromMarkdown(markdown, { split, defaults, validate }) 返回 { presentation, valid, findings, counts } 与发现(共享) Finding 格式),其中载有划线和列划线; toMarkdown(presentation, { unsupported }) 编写任何有效的deck,将该方言没有语法的内容嵌入到YAML中(或将其放入) report.loss),它写入的Markdown会转换回同一套牌。确定性和离线。阅读前面的事项与 yaml 包中。看到 减价指南. 在变更日志中列出它之前的版本中不会。

读写任何形式的牌组

parse(text, { format, filename, catalogs }) 和 stringify(presentation, { format | filename }) (根和 @openpresentation/opf/deck)读取和写入JSON (canonical), YAML或Markdown格式的deck。格式为 format 选项,否则为文件名(.opf.md 减价, .yaml 和 .yml 是YAML,其他都是JSON;一个普通 .md 不是套牌,更不是内容。 parse 返回表示并抛出 OPFValidationError 对于语法、模式或引用错误;错误的 report.findings 在文本中按行和列定位(opf/json-syntax, yaml/<rule> 或者 markdown/<rule> 语法错误)。警告不要抛出: validate(text) 返回完整的报表。两者都在浏览器中运行;文件是Node构建的任务(如上)。

OPF为YAML

@openpresentation/opf/yaml 以YAML(相同数据的创作形式)的形式读写一个deck (JSON保持规范)。 fromYaml(text, { aliases, validate }) 读取严格的json兼容的YAML 1.2(一个文档,根处的映射,没有自定义标记,重复的键或非有限的数字;锚定,别名和合并键只能与 aliases: true)和返回 { presentation, valid, findings, counts, schemaValid, checks }: validate 甲板报告,每一个发现(共享) Finding 格式,YAML语法错误为 yaml/<rule> 发现)位于YAML的行和列。 toYaml(presentation, { schemaComment }) 写入规范的YAML(模式键顺序、块样式、引用的模糊字符串),读取回同一套牌,并抛出 OPFYamlError 无效的。 parseYamlData 和 scanYamlComments 是帮助者。看到 YAML指南.

源代码编辑:模式字段查询,文本寻址和语法恢复

源代码编辑器(CLI和代理)的两个浏览器安全子路径。 @openpresentation/opf/schema 从JSON模式中读取文档的字段模型: describeField(path, document?) 返回类型、描述、枚举值、默认值、示例、父节点是否需要 oneOf 变异(和 primary(表单模板应该使用),排名 children 一个对象(首先需要,然后是策展) COMMON_KEYS 顺序,然后按字母顺序;提升区域, extensions 和 $schema 是 advanced),数组的项模式(itemInfo)或地图(entryInfo), requiredChildren 和 freeText, { known: false } 对于模式没有描述的路径; catalogKindAt(path, document?) 将参考字段指向的目录命名为(layouts, themes, colorSchemes, fontSchemes, narratives, audiences, purposes, tones) schemaCatalogKinds (也可以导出),核心端元数据由模式名称和JSON指针键;发布的模式不携带供应商关键字,并在严格的ajax下编译,因此新的引用字段是其中的一个条目,不需要更改编辑器。它所基于的导航帮助器也被导出(resolveSchema, schemaVariants, activeSchema, schemaAtPath, createSchemaValue, listSchemaFields, splitOpfPath)。 @openpresentation/opf/source 将文本转换为位置和返回: locate(text, format, pointer, { part }) 是JSON、YAML或Markdown (value, key, entry, open 或者 colon;最近的祖先 exact: false 节点缺失时;按其查找结果使用的相同范围来定位标记下滑幻灯片字段 layout= 选项注释的标记,后面的文本 # 或者 - ), pathAt(text, format, offset) 插入符号下的路径, scanMarkdown(text) 带有方言词汇的Markdown deck(前部内容,幻灯片,选项注释,围栏,注释)的区域(SLIDE_OPTION_KEYS, BLOCK_OPTION_KEYS, FENCE_KINDS, METRIC_KEYS), analyzeJsonSyntax(text, { limit }) 每个JSON语法错误的根本原因,一次,按位置顺序(最多五个),包括范围,消息,提示和修复它的修复程序(Insert comma, Add { }, Remove "design", Insert }, Use double quotes,……); validate(text) 报告相同的原因 opf/json-syntax 发现。看到 验证.

验证(0.14.0)

validate(input, options?) 是一个检查器,从根和从 @openpresentation/opf/validator. input 是经过解析的表示或严格的JSON文本;结果是 ValidationReport 谁的 findings (共享 Finding 格式, spec/schemas/finding.schema.json每个人都有一个马厩 opf/<rule> Id,严重程度,六个类别之一: format (JSON语法,重复键,模式) references (目录参考,资产,引文,数据集), policy (主机 contracts), accessibility (对比,Alt文本,阅读顺序,链接), layout (溢出,字体大小,图像分辨率,字体)和 content (占位符、空幻灯片、非数字图表单元格)。 valid 意味着没有严重的发现 error,默认情况下只有 format, references 和 policy 发现可以有。文本输入添加行和列; only, ignore 和 severity 挑选和推广规则或类别;作文是懒惰的,所以 validate(deck, { only: ["format"] }) 成本与模式检查的成本相同。只读且确定性:不获取远程资源。看到 验证指南. 干净的报告不证明布局、字体或本机导出保真度。

describeFinding(finding, { document }) 和 explain(ruleId) 把发现用通俗易懂的语言表达出来。 describeFinding (从 @openpresentation/opf/source)返回 { message, next } 对于任何发现:反引号中的字段有什么问题,接下来可能会发生什么(“你的意思是?” center?”),根据调查结果本身的数据和文件编写;每一个 opf/* 规则有它的文本。 explain (也在包的根目录上)返回规则的摘要、基本原理、 fix 还有一个小的before/after example. 看到 明文文本和 explain.

补丁,diff,合并和格式化(0.12.0)

在0.12.0添加(未在0.11.4或更早版本中添加): @openpresentation/opf/patch 是CLI和编辑器共享的RFC 6902实现(applyPatch, applyPatchWithInverse, invertPatch(严格的指针帮助器,可选的结果模式验证); @openpresentation/opf/diff 有 diff (幻灯片匹配的id,内容和相似性,移动,可读的报告和JSON补丁)和 merge (三向合并与冲突对象,永远不会放弃一方); @openpresentation/opf/format 有 format (规范键顺序和布局,幂等)。看到 该指南.

id,文档散列和补丁范围(CE-04, CE-05)

@openpresentation/opf/ids (所有的都放在包的根上,指针和哈希部分也放在上面 /patch)使编辑可寻址和可检查。 assignIds(document, { generate? }) 填补缺失 id 幻灯片和内容有效载荷的确定性({ document, patch, assigned };现有的id永远不会改变)。在数组中,指针标记 @intro 元素的名称 id 是 intro,所以 /slides/@intro/blocks/@kpi/text 幸存重新排序: applyPatch 和 readPointer 解决它, resolveIdPointer 和 toIdPointer 转换指针, resolveIdPatch 和 toIdPatch 一整块。 documentHash(document) 是 sha256: 和SHA-256的键排序JSON(纯JavaScript,在Node,浏览器和edge运行时相同); applyPatch(document, patch, { expectHash }) 和 edit(deck, patch, { expectHash }) 只应用于获取哈希值的文档,否则抛出 OPFPatchHashError 什么也改变不了。 touches(patch, document?) 返回指针(索引和id形式)、id、幻灯片id和补丁读取和写入的类型,用于冲突检测和权限检查。看到 该指南.

布局预览

@openpresentation/gallery/previews 提供预渲染的SVG缩略图 幻灯片布局目录在pptx.画廊。每个预览都是一个自包含的SVG 大小为16:9的容器,颜色和布局已经渲染。

import { getLayoutPreview } from "@openpresentation/gallery/previews";

export function LayoutThumbnail({ slug }: { slug: string }) {
  const html = getLayoutPreview(slug);
  if (!html) return null;
  return (
    <div
      className="aspect-[16/9] overflow-hidden rounded-lg border border-border bg-card"
      dangerouslySetInnerHTML={{ __html: html }}
    />
  );
}

预览源存在于 packages/gallery 检查所读取的存储库的。

例子甲板

@openpresentation/opf/examples 船每 .opf.json 文件从 examples/ 在上游回购中,已经针对表示进行了解析和验证 构建时的模式。

import {
  examples,
  galleries,
  getExample,
  getExamplesByGallery,
} from "@openpresentation/opf/examples";

const compliance = getExample("compliance-readiness-review");
const businessDecks = getExamplesByGallery("business-functions");

console.log(`${examples.length} example decks across ${galleries.length} galleries`);

每一个 ExampleRecord 包括已解析的 Presentation 对象及其 repo-相对路径,顶级类别(gallery, technical,……),以及 如适用,廊塞。

文档页面

@openpresentation/opf/docs 运顶层 docs/*.md 参考页面 (schema-reference, catalog-schema-reference, content-payloads, content-item-design-overrides, examples). 子目录等 docs/migrations 和 docs/plans 是故意排除的吗 在固定的NPM发布中快速发布。

import { docs, getDoc } from "@openpresentation/opf/docs";

for (const doc of docs) {
  console.log(`${doc.title} — ${doc.file}`);
}

const schemaRef = getDoc("schema-reference");
console.log(schemaRef?.markdown.slice(0, 200));

上游的自述

@openpresentation/opf/repo-readme 暴露上游的原始降价 OpenPresentation/opf 自述文件。在此版本固定在此发布。使用它 当你想在另一个网站或应用程序中镜像规范的README时 不需要进行网络获取。

import { repoReadme } from "@openpresentation/opf/repo-readme";

console.log(repoReadme.split("\n").slice(0, 3).join("\n"));

验证报告包含 findings. 一个严重的发现 error 是一个 结构性问题 valid 虚假的; warning 和 info 发现是 咨询的,如 narrative, design 或者 layout 解析的引用 地方(opf/unresolved-reference)或缺少Alt文本。引用解析 在文件所嵌入的记录中(catalogs.custom, catalogs.default,名叫 组),然后在主机注册的目录中 { catalogs }.

const report = validate(deck, { catalogs: [gallery] });
if (!report.valid) console.error(report.findings.filter((finding) => finding.severity === "error"));
for (const finding of report.findings) console.warn(finding.ruleId, finding.path, finding.message);

本地验证目录记录:

import { validateCatalogRecord } from "@openpresentation/opf";
import { gallery } from "@openpresentation/gallery";

for (const [id, record] of Object.entries(gallery.audiences)) {
  // A published record file carries its $schema and id; the gallery keys records by id without them.
  const result = validateCatalogRecord("audiences", { $schema: "https://openpresentation.org/schema/opf-audience/v1", id, ...record });
  if (!result.valid) {
    console.error(result.findings);
  }
}

原始规范JSON发布于 spec/:

import presentationSchema from "@openpresentation/opf/spec/schemas/opf.schema.json" with {
  type: "json",
};

原始规范清单显示了应该从npm而不是GitHub解析的文件的类型化包路径。 openapi.yaml 是选择通过HTTP公开OPF的下游服务的参考契约;OpenPresentation不承载该API。

import { specFileEntries } from "@openpresentation/opf/spec-files";

const openApi = specFileEntries.find((entry) => entry.path === "openapi.yaml");
console.log(openApi?.packagePath);

核心船没有目录记录文件(RR-78):记录是 @openpresentation/gallery’s,和pptx。库为每个已发布的记录文件提供服务 https://www.pptx.gallery/<kind>/<id>.json. 文件从来没有指向他们。主机转而注册目录:

import { gallery } from "@openpresentation/gallery";
validate(deck, { catalogs: [gallery] });

开发

pnpm --filter @openpresentation/opf typecheck
pnpm --filter @openpresentation/opf test
pnpm --filter @openpresentation/opf pack:dry-run

src/generated/ 和 dist/ 是从根目录生成的 spec/ 目录和被git有意忽略。

版本与发布记录

@openpresentation/opf 共发布 60 个版本,首次发布于 2026/05/06;过去 12 个月发布了 60 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.30.0latest2026/11/021 天前
0.29.12026/10/276 天前
0.29.02026/10/276 天前
0.28.02026/10/277 天前
0.27.02026/10/267 天前
0.26.102026/10/258 天前

其他发布通道:next → 0.26.0-rc.0。

关于 @openpresentation/opf 的常见问题

@openpresentation/opf 是什么?

规范开放演示格式模式、TypeScript类型、本地验证和组合;在Node中,文件API和CLI默认注册pptx。@openpresentation/ Gallery的画廊目录。

如何安装 @openpresentation/opf?

在项目目录运行 npm install @openpresentation/opf,或使用 pnpm add / yarn add / bun add。

@openpresentation/opf 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@openpresentation/opf 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@openpresentation/opf 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@openpresentation/opf 可以商用吗?

@openpresentation/opf 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@openpresentation/opf 还在维护吗?

最新版本 0.30.0 发布于 2026/11/02(1 天前);至今共发布 60 个版本,其中过去 12 个月发布了 60 个;首次发布于 2026/05/06。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。