@openpresentation/opf 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{catalogs-HCTav5Wv.d.ts → catalogs-atkOF4Vy.d.ts} +7 -7
- package/dist/catalogs.d.ts +2 -2
- package/dist/catalogs.js +1 -1
- package/dist/{chunk-TWMRZ43O.js → chunk-6FU2KICU.js} +365 -327
- package/dist/{chunk-GCB6LGJM.js → chunk-CHKJ4QHQ.js} +225 -73
- package/dist/{chunk-NPOKUFEX.js → chunk-EQHZ3ZO4.js} +3 -3
- package/dist/{chunk-BAWLYSUN.js → chunk-FTWNWFIV.js} +180 -6
- package/dist/{chunk-TK3QHM3U.js → chunk-FWA5XB45.js} +54 -21
- package/dist/{chunk-GQSK3T7X.js → chunk-GN52EE3P.js} +146 -16
- package/dist/{chunk-OZULJBSG.js → chunk-RS5GZ5RW.js} +14 -0
- package/dist/composition-Tv9Wm3Oh.d.ts +691 -0
- package/dist/composition.d.ts +1 -624
- package/dist/composition.js +1 -1
- package/dist/docs.js +59 -11
- package/dist/examples.d.ts +1 -1
- package/dist/index.d.ts +65 -4
- package/dist/index.js +205 -7
- package/dist/lint.d.ts +3 -3
- package/dist/lint.js +5 -5
- package/dist/pagination.d.ts +4 -2
- package/dist/pagination.js +5 -5
- package/dist/{presentation-BMTdX6O1.d.ts → presentation-Ct42Mitb.d.ts} +51 -8
- package/dist/repo-readme.js +1 -1
- package/dist/{schemas-BYe5y8-i.d.ts → schemas-CiVmUT2p.d.ts} +6 -0
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +1 -1
- package/dist/spec/catalogs/layouts/extract/canonical.json +45 -21
- package/dist/spec/catalogs/layouts/index.json +10 -0
- package/dist/spec/catalogs/layouts/number-1x.json +1 -1
- package/dist/spec/catalogs/layouts/number-2x.json +2 -2
- package/dist/spec/catalogs/layouts/number-3x.json +3 -3
- package/dist/spec/catalogs/layouts/number-4x.json +4 -4
- package/dist/spec/catalogs/layouts/number-5x.json +5 -5
- package/dist/spec/catalogs/layouts/number-6x.json +6 -6
- package/dist/spec/catalogs/layouts/quote-1x.json +13 -0
- package/dist/spec/catalogs/layouts/timeline-1x.json +13 -0
- package/dist/spec/catalogs/narratives/board-meeting.json +21 -21
- package/dist/spec/catalogs/narratives/business-narrative.json +8 -8
- package/dist/spec/catalogs/narratives/business-review.json +12 -12
- package/dist/spec/catalogs/narratives/capacity-planning.json +8 -8
- package/dist/spec/catalogs/narratives/challenge-resolution.json +7 -7
- package/dist/spec/catalogs/narratives/classic-story.json +7 -7
- package/dist/spec/catalogs/narratives/company-intro.json +9 -9
- package/dist/spec/catalogs/narratives/conference-talk.json +1 -1
- package/dist/spec/catalogs/narratives/early-startup-pitch.json +12 -12
- package/dist/spec/catalogs/narratives/educate.json +9 -9
- package/dist/spec/catalogs/narratives/employee-review.json +8 -8
- package/dist/spec/catalogs/narratives/failure-analysis.json +10 -10
- package/dist/spec/catalogs/narratives/focus.json +12 -12
- package/dist/spec/catalogs/narratives/golden-circle.json +1 -1
- package/dist/spec/catalogs/narratives/innovation.json +9 -9
- package/dist/spec/catalogs/narratives/justice.json +11 -11
- package/dist/spec/catalogs/narratives/marketing-strategy.json +11 -11
- package/dist/spec/catalogs/narratives/performance-improvement-plan.json +8 -8
- package/dist/spec/catalogs/narratives/performance-review.json +11 -11
- package/dist/spec/catalogs/narratives/persuade.json +7 -7
- package/dist/spec/catalogs/narratives/persuasive-sales.json +8 -8
- package/dist/spec/catalogs/narratives/pitch-deck.json +3 -3
- package/dist/spec/catalogs/narratives/problem-solution.json +2 -2
- package/dist/spec/catalogs/narratives/product-launch.json +10 -10
- package/dist/spec/catalogs/narratives/project-proposal.json +10 -10
- package/dist/spec/catalogs/narratives/qbr.json +3 -3
- package/dist/spec/catalogs/narratives/rags-to-riches.json +7 -7
- package/dist/spec/catalogs/narratives/reveal.json +8 -8
- package/dist/spec/catalogs/narratives/scqa.json +1 -1
- package/dist/spec/catalogs/narratives/status-update.json +6 -6
- package/dist/spec/catalogs/narratives/strategic-advisory.json +7 -7
- package/dist/spec/catalogs/narratives/strategic-narrative.json +1 -1
- package/dist/spec/catalogs/narratives/survey-analysis.json +10 -10
- package/dist/spec/catalogs/narratives/survival-story.json +10 -10
- package/dist/spec/catalogs/narratives/transformation-arc.json +1 -1
- package/dist/spec/catalogs/narratives/trend-analysis.json +7 -7
- package/dist/spec/catalogs/narratives/underdog-victory.json +8 -8
- package/dist/spec/catalogs/narratives/venture-pitch.json +12 -12
- package/dist/spec/catalogs/narratives/weekly-progress.json +10 -10
- package/dist/spec/openapi.yaml +5 -0
- package/dist/spec/schemas/layout.schema.json +12 -3
- package/dist/spec/schemas/narrative.schema.json +1 -1
- package/dist/spec/schemas/opf.schema.json +83 -12
- package/dist/spec-files.d.ts +1 -1
- package/dist/spec-files.js +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/validator.d.ts +7 -4
- package/dist/validator.js +4 -4
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { assertValidPresentation } from './chunk-
|
|
2
|
-
import { resolveFontFamilies, resolveCanvasDimensions, composeSlide, tableRowBoundaries } from './chunk-
|
|
3
|
-
import { catalogs } from './chunk-
|
|
1
|
+
import { assertValidPresentation, visitContentPayloads } from './chunk-CHKJ4QHQ.js';
|
|
2
|
+
import { resolveFontFamilies, resolveCanvasDimensions, composeSlide, tableRowBoundaries } from './chunk-FTWNWFIV.js';
|
|
3
|
+
import { catalogs } from './chunk-6FU2KICU.js';
|
|
4
4
|
|
|
5
5
|
// src/pagination.ts
|
|
6
6
|
var OPFPaginationError = class extends Error {
|
|
@@ -16,6 +16,13 @@ var contentFields = /* @__PURE__ */ new Set(["text", "items", "bullets", "image"
|
|
|
16
16
|
var headingFields = /* @__PURE__ */ new Set(["title", "subtitle", "tag"]);
|
|
17
17
|
var isRecord = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
18
18
|
var clone = (value) => structuredClone(value);
|
|
19
|
+
var slideIds = (slide) => {
|
|
20
|
+
const ids = typeof slide.id === "string" ? [slide.id] : [];
|
|
21
|
+
visitContentPayloads(slide, "", (payload) => {
|
|
22
|
+
if (typeof payload.id === "string") ids.push(payload.id);
|
|
23
|
+
});
|
|
24
|
+
return ids;
|
|
25
|
+
};
|
|
19
26
|
var textOf = (value) => typeof value === "string" ? value : Array.isArray(value) ? value.map(textOf).join("") : value?.text ?? "";
|
|
20
27
|
var graphemes = new Intl.Segmenter("und", { granularity: "grapheme" });
|
|
21
28
|
function sliceRichText(value, start, end) {
|
|
@@ -83,20 +90,48 @@ function paginateSlide(input, options = {}) {
|
|
|
83
90
|
};
|
|
84
91
|
source = withReadability(source);
|
|
85
92
|
let evaluations = 0;
|
|
86
|
-
const geometry = (slide) => {
|
|
93
|
+
const geometry = (slide, pageIndex = 0) => {
|
|
87
94
|
if (++evaluations > 2e4) throw new OPFPaginationError("Pagination exceeded its layout evaluation limit. Split the input into smaller sections.");
|
|
88
|
-
return composeSlide(withReadability(slide, true), options);
|
|
95
|
+
return composeSlide(withReadability(slide, true), { ...options, slideNumber: (options.slideNumber ?? sourceIndex + 1) + pageIndex });
|
|
89
96
|
};
|
|
90
97
|
const initial = geometry(source);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
const repeatedMappings = (pageIndex) => {
|
|
99
|
+
if (!initial.furniture) return [];
|
|
100
|
+
const paths = new Set(initial.items.filter((item) => headingFields.has(item.field)).map((item) => item.path));
|
|
101
|
+
for (const part of initial.furniture?.parts ?? []) {
|
|
102
|
+
paths.add(part.path);
|
|
103
|
+
if (part.sourcePath) paths.add(part.sourcePath);
|
|
104
|
+
}
|
|
105
|
+
return [...paths].map((sourcePath) => ({ sourcePath, outputPath: sourcePath.startsWith(`${sourceBase}.`) ? `slides.${sourceIndex + pageIndex}${sourcePath.slice(sourceBase.length)}` : sourcePath }));
|
|
106
|
+
};
|
|
107
|
+
if (!initial.diagnostics.length) return { slides: [source], pages: [{ slideIndex: sourceIndex, mappings: initial.items.map((item) => ({ sourcePath: item.path, outputPath: item.path })), ...initial.furniture ? { repeatedMappings: repeatedMappings(0) } : {} }] };
|
|
108
|
+
const headerIssues = initial.diagnostics.filter((issue) => headingFields.has(issue.path.slice(sourceBase.length + 1)) || initial.furniture?.diagnostics.includes(issue));
|
|
109
|
+
if (headerIssues.length) throw new OPFPaginationError("Repeated headings or header/footer content cannot fit or resolve. Change the repeated content or slide design before pagination.", headerIssues);
|
|
94
110
|
const leaves = initial.items.filter((item) => !headingFields.has(item.field)).map((item) => leafFor(item.path, item.field, item.value));
|
|
95
111
|
const leafPaths = new Set(leaves.map((leaf) => leaf.path));
|
|
96
112
|
const slides = [], pages = [];
|
|
97
113
|
let selected = /* @__PURE__ */ new Map();
|
|
98
114
|
const reservedIds = new Set(options.reservedIds ?? []);
|
|
99
|
-
|
|
115
|
+
for (const id of slideIds(source)) reservedIds.add(id);
|
|
116
|
+
const emittedIds = /* @__PURE__ */ new Set();
|
|
117
|
+
const pageId = (base, pageIndex) => {
|
|
118
|
+
if (!emittedIds.has(base)) {
|
|
119
|
+
emittedIds.add(base);
|
|
120
|
+
return base;
|
|
121
|
+
}
|
|
122
|
+
let suffix = pageIndex + 1, id = `${base}--${suffix}`;
|
|
123
|
+
while (reservedIds.has(id)) id = `${base}--${++suffix}`;
|
|
124
|
+
reservedIds.add(id);
|
|
125
|
+
emittedIds.add(id);
|
|
126
|
+
return id;
|
|
127
|
+
};
|
|
128
|
+
const assignPageIds = (slide, pageIndex) => {
|
|
129
|
+
const assign = (node) => {
|
|
130
|
+
if (typeof node.id === "string") node.id = pageId(node.id, pageIndex);
|
|
131
|
+
};
|
|
132
|
+
assign(slide);
|
|
133
|
+
visitContentPayloads(slide, "", assign);
|
|
134
|
+
};
|
|
100
135
|
const project = (portions, pageIndex) => {
|
|
101
136
|
const mappings = [];
|
|
102
137
|
const visit = (node, path, out, root = false) => {
|
|
@@ -135,20 +170,17 @@ function paginateSlide(input, options = {}) {
|
|
|
135
170
|
if (pageIndex > 0) delete slide.notes;
|
|
136
171
|
return { slide, mappings };
|
|
137
172
|
};
|
|
138
|
-
const diagnosticsFor = (portions) => geometry(project(portions, slides.length).slide).diagnostics;
|
|
173
|
+
const diagnosticsFor = (portions) => geometry(project(portions, slides.length).slide, slides.length).diagnostics;
|
|
139
174
|
const finish = () => {
|
|
140
175
|
if (!selected.size) return;
|
|
141
176
|
if (slides.length >= maxSlides) throw new OPFPaginationError(`Pagination needs more than ${maxSlides} slides. No partial result was returned.`);
|
|
142
177
|
const { slide, mappings } = project(selected, slides.length);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
slide.id = id;
|
|
147
|
-
reservedIds.add(id);
|
|
148
|
-
}
|
|
178
|
+
const issues = geometry(slide, slides.length).diagnostics;
|
|
179
|
+
if (issues.length) throw new OPFPaginationError("A continuation page does not fit at its final page number. No partial result was returned.", issues);
|
|
180
|
+
assignPageIds(slide, slides.length);
|
|
149
181
|
assertValidPresentation({ slides: [slide] });
|
|
150
182
|
slides.push(slide);
|
|
151
|
-
pages.push({ slideIndex: sourceIndex + slides.length - 1, mappings });
|
|
183
|
+
pages.push({ slideIndex: sourceIndex + slides.length - 1, mappings, ...initial.furniture ? { repeatedMappings: repeatedMappings(slides.length - 1) } : {} });
|
|
152
184
|
selected = /* @__PURE__ */ new Map();
|
|
153
185
|
};
|
|
154
186
|
for (const leaf of leaves) {
|
|
@@ -204,7 +236,7 @@ function paginatePresentation(input, options = {}) {
|
|
|
204
236
|
const maxSlides = options.maxSlides ?? 100;
|
|
205
237
|
if (!Number.isInteger(maxSlides) || maxSlides < 1 || maxSlides > 1e4) throw new RangeError("maxSlides must be an integer between 1 and 10000.");
|
|
206
238
|
const output = [], pages = [];
|
|
207
|
-
const reservedIds = presentation.slides.
|
|
239
|
+
const reservedIds = presentation.slides.flatMap((slide) => slideIds(slide));
|
|
208
240
|
const resolve = (kind, id) => presentation.catalogs?.[kind]?.records?.find((record) => record.id === id) ?? catalogs[kind].find((record) => record.id === id);
|
|
209
241
|
presentation.slides.forEach((slide, index) => {
|
|
210
242
|
const overrides = options.slideOptions?.(slide, index) ?? {};
|
|
@@ -218,13 +250,14 @@ function paginatePresentation(input, options = {}) {
|
|
|
218
250
|
const fontReference = design.fontScheme ?? theme.fontScheme ?? "roboto";
|
|
219
251
|
const fontScheme = typeof fontReference === "string" ? resolve("fontSchemes", fontReference) : { ...resolve("fontSchemes", fontReference.id), ...fontReference };
|
|
220
252
|
const fonts = resolveFontFamilies(fontScheme);
|
|
221
|
-
const result = paginateSlide(slide, { ...resolveCanvasDimensions(design.dimensions ?? theme.dimensions), layout, fonts, contentAlignment: design.contentAlignment, titleAlignment: design.titleAlignment, contentBox: design.contentBox, textMeasurement: options.textMeasurement, textRasterPadding: options.textRasterPadding, ...overrides, slideIndex: index, maxSlides: maxSlides - output.length, minFontSize: options.minFontSize, reservedIds });
|
|
253
|
+
const result = paginateSlide(slide, { ...resolveCanvasDimensions(design.dimensions ?? theme.dimensions), layout, fonts, contentAlignment: design.contentAlignment, titleAlignment: design.titleAlignment, contentBox: design.contentBox, textMeasurement: options.textMeasurement, textRasterPadding: options.textRasterPadding, ...overrides, presentation, slideIndex: index, slideNumber: output.length + 1, maxSlides: maxSlides - output.length, minFontSize: options.minFontSize, reservedIds });
|
|
222
254
|
const outputStart = output.length;
|
|
223
255
|
result.pages.forEach((page, pageIndex) => {
|
|
224
|
-
|
|
256
|
+
const remap = (mapping) => ({ ...mapping, outputPath: mapping.outputPath.replace(/^slides\.\d+/, `slides.${outputStart + pageIndex}`) });
|
|
257
|
+
pages.push({ sourceSlideIndex: index, slideIndex: outputStart + pageIndex, mappings: page.mappings.map(remap), ...page.repeatedMappings ? { repeatedMappings: page.repeatedMappings.map(remap) } : {} });
|
|
225
258
|
});
|
|
226
259
|
output.push(...result.slides);
|
|
227
|
-
reservedIds.push(...result.slides.
|
|
260
|
+
reservedIds.push(...result.slides.flatMap((slide2) => slideIds(slide2)));
|
|
228
261
|
});
|
|
229
262
|
presentation.slides = output;
|
|
230
263
|
assertValidPresentation(presentation);
|
|
@@ -3,7 +3,7 @@ var presentation = {
|
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"$id": "https://openpresentation.org/schema/opf/v1",
|
|
5
5
|
"title": "Presentation",
|
|
6
|
-
"description": "Open-source JSON format for describing PowerPoint presentations. Agents describe narratives, content, audience, reusable assets, and design \u2014 the engine handles OOXML complexity.\n\nFields that reference catalog records (narrative, language, tone, audience, purpose, design.theme / design.theme.id, design.colorScheme / design.colorScheme.id, design.fontScheme / design.fontScheme.id, Slide.layout, Chart.type, Organization.socials / Speaker.socials) resolve through the catalog system: inline 'catalogs.<kind>.records[]' on the document \u2192 'catalogs.<kind>.source' on the document \u2192 engine defaults \u2192 the default catalog at https://www.pptx.gallery/<kind>. Every reference resolves to the catalog record's 'id' field. When an OPF document omits a reference entirely, the engine falls back to engine defaults (see /spec/reference/engine-defaults.json for a reference example). The defaults file is engine configuration; it is not part of the OPF document contract and has no JSON Schema.\n\nMost catalog references accept the bare 'id' as a string for the common case (e.g. narrative = 'classic-story', design.colorScheme = 'cool-horizon'). Audience, purpose, tone, design, and language object forms use 'id' as a base catalog reference plus inline overrides. Asset references use 'asset:<id>' strings that point into the top-level assets registry.",
|
|
6
|
+
"description": "Open-source JSON format for describing PowerPoint presentations. Agents describe narratives, content, audience, reusable assets, and design \u2014 the engine handles OOXML complexity.\n\nFields that reference catalog records (narrative, language, tone, audience, purpose, design.theme / design.theme.id, design.colorScheme / design.colorScheme.id, design.fontScheme / design.fontScheme.id, Slide.layout, Chart.type, Organization.socials / Speaker.socials) resolve through the catalog system: inline 'catalogs.<kind>.records[]' on the document \u2192 'catalogs.<kind>.source' on the document \u2192 engine defaults \u2192 the default catalog at https://www.pptx.gallery/<kind>. Every reference resolves to the catalog record's 'id' field. When an OPF document omits a reference entirely, the engine falls back to engine defaults (see /spec/reference/engine-defaults.json for a reference example). The defaults file is engine configuration; it is not part of the OPF document contract and has no JSON Schema.\n\nMost catalog references accept the bare 'id' as a string for the common case (e.g. narrative = 'classic-story', design.colorScheme = 'cool-horizon'). Audience, purpose, tone, design, and language object forms use 'id' as a base catalog reference plus inline overrides. Asset references use 'asset:<id>' strings that point into the top-level assets registry, and content color fields (rich-text runs, styled table cells) accept hex values, color-scheme slot/role names, or 'var:<id>' references into the top-level variables map.",
|
|
7
7
|
"type": "object",
|
|
8
8
|
"required": [
|
|
9
9
|
"slides"
|
|
@@ -284,6 +284,10 @@ var presentation = {
|
|
|
284
284
|
"$ref": "#/$defs/Design",
|
|
285
285
|
"description": "Optional design system covering theme, color scheme, font scheme, dimensions, background, logo, watermark, header, and footer applied to the deck. When omitted, engines use their default design configuration."
|
|
286
286
|
},
|
|
287
|
+
"variables": {
|
|
288
|
+
"$ref": "#/$defs/Variables",
|
|
289
|
+
"description": "Optional named color variables for values the deck uses in more than one place or wants to name for intent (e.g. a risk red, a brand highlight). Content color fields reference entries as 'var:<id>' strings. Variables complement the color scheme: scheme slots and roles stay the primary vocabulary; variables cover deck-specific named colors that have no scheme slot."
|
|
290
|
+
},
|
|
287
291
|
"narrative": {
|
|
288
292
|
"oneOf": [
|
|
289
293
|
{
|
|
@@ -1982,6 +1986,109 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
1982
1986
|
"#0F172AFF"
|
|
1983
1987
|
]
|
|
1984
1988
|
},
|
|
1989
|
+
"ColorRef": {
|
|
1990
|
+
"anyOf": [
|
|
1991
|
+
{
|
|
1992
|
+
"$ref": "#/$defs/HexColor"
|
|
1993
|
+
},
|
|
1994
|
+
{
|
|
1995
|
+
"type": "string",
|
|
1996
|
+
"enum": [
|
|
1997
|
+
"accent1",
|
|
1998
|
+
"accent2",
|
|
1999
|
+
"accent3",
|
|
2000
|
+
"accent4",
|
|
2001
|
+
"accent5",
|
|
2002
|
+
"accent6",
|
|
2003
|
+
"dark1",
|
|
2004
|
+
"dark2",
|
|
2005
|
+
"light1",
|
|
2006
|
+
"light2",
|
|
2007
|
+
"hyperlink",
|
|
2008
|
+
"followedHyperlink",
|
|
2009
|
+
"primary",
|
|
2010
|
+
"secondary",
|
|
2011
|
+
"accent",
|
|
2012
|
+
"background",
|
|
2013
|
+
"surface",
|
|
2014
|
+
"text",
|
|
2015
|
+
"textSecondary"
|
|
2016
|
+
]
|
|
2017
|
+
},
|
|
2018
|
+
{
|
|
2019
|
+
"type": "string",
|
|
2020
|
+
"pattern": "^var:[a-z][a-z0-9-]*$"
|
|
2021
|
+
}
|
|
2022
|
+
],
|
|
2023
|
+
"description": "A color value or reference, enforced on styled table cell fill and text colors and on cell border colors. Three forms:\n- Literal hex: '#RGB', '#RRGGBB', or '#RRGGBBAA'.\n- Color-scheme name, resolved through the effective color scheme after design resolution: an OOXML slot ('accent1'-'accent6', 'dark1', 'dark2', 'light1', 'light2', 'hyperlink', 'followedHyperlink') or an abstract role ('primary', 'secondary', 'accent', 'background', 'surface', 'text', 'textSecondary'). Roles resolve through the same role-to-slot mapping engines already apply to color schemes.\n- Variable reference: 'var:<id>' into the top-level variables map.\n\nNames keep content theme-portable: re-theming the deck updates every named reference, where a literal hex stays frozen. Unknown 'var:' ids produce a validation warning, never an error, and engines fall back to their default text color. TextRun.color documents the same three forms but remains an open string so imported decks with unrecognized run colors stay valid; validators warn there instead of erroring.",
|
|
2024
|
+
"examples": [
|
|
2025
|
+
"#0F4C81",
|
|
2026
|
+
"accent2",
|
|
2027
|
+
"text",
|
|
2028
|
+
"var:risk"
|
|
2029
|
+
]
|
|
2030
|
+
},
|
|
2031
|
+
"Variables": {
|
|
2032
|
+
"type": "object",
|
|
2033
|
+
"propertyNames": {
|
|
2034
|
+
"pattern": "^[a-z][a-z0-9-]*$"
|
|
2035
|
+
},
|
|
2036
|
+
"additionalProperties": {
|
|
2037
|
+
"$ref": "#/$defs/Variable"
|
|
2038
|
+
},
|
|
2039
|
+
"description": "Named color variables, keyed by stable kebab-case id. Content color fields reference entries as 'var:<id>' strings. Each value is a hex string shorthand or a Variable object.",
|
|
2040
|
+
"examples": [
|
|
2041
|
+
{
|
|
2042
|
+
"risk": "#B42318",
|
|
2043
|
+
"highlight": {
|
|
2044
|
+
"type": "color",
|
|
2045
|
+
"value": "#0F4C81",
|
|
2046
|
+
"description": "Brand highlight for emphasized runs."
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
]
|
|
2050
|
+
},
|
|
2051
|
+
"Variable": {
|
|
2052
|
+
"oneOf": [
|
|
2053
|
+
{
|
|
2054
|
+
"$ref": "#/$defs/HexColor"
|
|
2055
|
+
},
|
|
2056
|
+
{
|
|
2057
|
+
"type": "object",
|
|
2058
|
+
"required": [
|
|
2059
|
+
"type",
|
|
2060
|
+
"value"
|
|
2061
|
+
],
|
|
2062
|
+
"additionalProperties": false,
|
|
2063
|
+
"properties": {
|
|
2064
|
+
"type": {
|
|
2065
|
+
"type": "string",
|
|
2066
|
+
"enum": [
|
|
2067
|
+
"color"
|
|
2068
|
+
],
|
|
2069
|
+
"description": "Variable kind. Only 'color' is defined today; other kinds may be added when content surfaces exist to consume them."
|
|
2070
|
+
},
|
|
2071
|
+
"value": {
|
|
2072
|
+
"$ref": "#/$defs/HexColor",
|
|
2073
|
+
"description": "Hex color this variable resolves to."
|
|
2074
|
+
},
|
|
2075
|
+
"description": {
|
|
2076
|
+
"type": "string",
|
|
2077
|
+
"description": "Optional prose describing what the variable is for, surfaced by pickers and agents."
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
],
|
|
2082
|
+
"description": 'A single named variable. A hex string is shorthand for { "type": "color", "value": value }.',
|
|
2083
|
+
"examples": [
|
|
2084
|
+
"#B42318",
|
|
2085
|
+
{
|
|
2086
|
+
"type": "color",
|
|
2087
|
+
"value": "#B42318",
|
|
2088
|
+
"description": "Risk emphasis."
|
|
2089
|
+
}
|
|
2090
|
+
]
|
|
2091
|
+
},
|
|
1985
2092
|
"BackgroundShortcut": {
|
|
1986
2093
|
"oneOf": [
|
|
1987
2094
|
{
|
|
@@ -2713,6 +2820,10 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
2713
2820
|
},
|
|
2714
2821
|
"composition": {
|
|
2715
2822
|
"$ref": "#/$defs/Composition"
|
|
2823
|
+
},
|
|
2824
|
+
"extensions": {
|
|
2825
|
+
"type": "object",
|
|
2826
|
+
"description": 'Custom data passthrough for agent workflows at slide scope; ignored by the engine but preserved across read/write round-trips. Use for review state, generation provenance, or authoring conventions such as { "authoring": { "locked": true } }.'
|
|
2716
2827
|
}
|
|
2717
2828
|
}
|
|
2718
2829
|
},
|
|
@@ -2721,6 +2832,18 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
2721
2832
|
"description": "A content leaf or recursively composed group. A group contains blocks and optional composition; it cannot mix blocks with leaf payload fields. Groups may nest up to 32 levels.",
|
|
2722
2833
|
"additionalProperties": false,
|
|
2723
2834
|
"properties": {
|
|
2835
|
+
"id": {
|
|
2836
|
+
"type": "string",
|
|
2837
|
+
"description": "Optional stable identifier for this payload, unique among slide and payload ids in the document. Use when another system needs to address the payload across edits \u2014 patch-style agent edits, comments, review state, or generation provenance. Identity survives reordering where array indexes do not.",
|
|
2838
|
+
"examples": [
|
|
2839
|
+
"kpi-adoption",
|
|
2840
|
+
"churn-quote"
|
|
2841
|
+
]
|
|
2842
|
+
},
|
|
2843
|
+
"extensions": {
|
|
2844
|
+
"type": "object",
|
|
2845
|
+
"description": "Custom data passthrough for agent workflows at payload scope; ignored by the engine but preserved across read/write round-trips."
|
|
2846
|
+
},
|
|
2724
2847
|
"type": {
|
|
2725
2848
|
"type": "string",
|
|
2726
2849
|
"enum": [
|
|
@@ -3587,10 +3710,11 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
3587
3710
|
},
|
|
3588
3711
|
"color": {
|
|
3589
3712
|
"type": "string",
|
|
3590
|
-
"description": "Run text color
|
|
3713
|
+
"description": "Run text color. Documented forms: a hex string ('#RGB', '#RRGGBB', '#RRGGBBAA'), a color-scheme slot or role name resolved through the effective color scheme ('accent2', 'text'), or a 'var:<id>' reference into the top-level variables map. Prefer names over hex so runs survive re-theming. Any other string stays schema-valid so imported decks keep validating: validators warn and renderers fall back to the theme text color.",
|
|
3591
3714
|
"examples": [
|
|
3592
3715
|
"#0F172A",
|
|
3593
|
-
"
|
|
3716
|
+
"accent2",
|
|
3717
|
+
"var:risk"
|
|
3594
3718
|
]
|
|
3595
3719
|
},
|
|
3596
3720
|
"fontSize": {
|
|
@@ -3933,14 +4057,12 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
3933
4057
|
"additionalProperties": false,
|
|
3934
4058
|
"properties": {
|
|
3935
4059
|
"fill": {
|
|
3936
|
-
"
|
|
3937
|
-
"
|
|
3938
|
-
"description": "Explicit RGB or RGBA color. Eight-digit colors include alpha; #00000000 is transparent."
|
|
4060
|
+
"$ref": "#/$defs/ColorRef",
|
|
4061
|
+
"description": "Cell background: a hex color, a color-scheme slot or role name, or a 'var:<id>' variable reference. Eight-digit hex colors include alpha; #00000000 is transparent."
|
|
3939
4062
|
},
|
|
3940
4063
|
"color": {
|
|
3941
|
-
"
|
|
3942
|
-
"
|
|
3943
|
-
"description": "Default text color, overridden by individual rich run colors."
|
|
4064
|
+
"$ref": "#/$defs/ColorRef",
|
|
4065
|
+
"description": "Default text color, overridden by individual rich run colors. Accepts a hex color, a color-scheme slot or role name, or a 'var:<id>' variable reference."
|
|
3944
4066
|
},
|
|
3945
4067
|
"align": {
|
|
3946
4068
|
"type": "string",
|
|
@@ -4021,9 +4143,8 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
4021
4143
|
],
|
|
4022
4144
|
"properties": {
|
|
4023
4145
|
"color": {
|
|
4024
|
-
"
|
|
4025
|
-
"
|
|
4026
|
-
"description": "Explicit RGB or RGBA color. Eight-digit colors include alpha; #00000000 is transparent."
|
|
4146
|
+
"$ref": "#/$defs/ColorRef",
|
|
4147
|
+
"description": "Border color: a hex color, a color-scheme slot or role name, or a 'var:<id>' variable reference. Eight-digit hex colors include alpha; #00000000 is transparent."
|
|
4027
4148
|
},
|
|
4028
4149
|
"width": {
|
|
4029
4150
|
"type": "number",
|
|
@@ -4873,9 +4994,15 @@ var layout = {
|
|
|
4873
4994
|
"List",
|
|
4874
4995
|
"Image",
|
|
4875
4996
|
"Number",
|
|
4876
|
-
"
|
|
4997
|
+
"Metric",
|
|
4998
|
+
"Chart",
|
|
4999
|
+
"Table",
|
|
5000
|
+
"Code",
|
|
5001
|
+
"Video",
|
|
5002
|
+
"Quote",
|
|
5003
|
+
"Timeline"
|
|
4877
5004
|
],
|
|
4878
|
-
"description": "Primary kind of content the layout holds. Drives pickers and AI placement decisions."
|
|
5005
|
+
"description": "Primary kind of content the layout holds. Drives pickers and AI placement decisions. Metric is the canonical numeric/KPI category; Number remains an accepted legacy label."
|
|
4879
5006
|
},
|
|
4880
5007
|
"contentMultiple": {
|
|
4881
5008
|
"type": "string",
|
|
@@ -5083,6 +5210,9 @@ var layout = {
|
|
|
5083
5210
|
"subtitle",
|
|
5084
5211
|
"tag",
|
|
5085
5212
|
"text",
|
|
5213
|
+
"metric",
|
|
5214
|
+
"quote",
|
|
5215
|
+
"timeline",
|
|
5086
5216
|
"list",
|
|
5087
5217
|
"chart",
|
|
5088
5218
|
"picture",
|
|
@@ -5091,7 +5221,7 @@ var layout = {
|
|
|
5091
5221
|
"diagram",
|
|
5092
5222
|
"code"
|
|
5093
5223
|
],
|
|
5094
|
-
"description": "OPF placeholder kind. 'text' and 'list' are flexible textual content regions. The named kinds describe a specific content role used by pickers, AI generation, and engine defaulting."
|
|
5224
|
+
"description": "OPF placeholder kind. 'text' and 'list' are flexible textual content regions. 'metric' is a numeric/KPI content region filled by a metric payload, including its optional label, description, unit, delta, and trend. The named kinds describe a specific content role used by pickers, AI generation, and engine defaulting. 'picture' and legacy 'diagram' use image payloads; 'media' uses video. Quote and timeline use their corresponding payload fields."
|
|
5095
5225
|
}
|
|
5096
5226
|
}
|
|
5097
5227
|
},
|
|
@@ -5871,7 +6001,7 @@ var narrative = {
|
|
|
5871
6001
|
"quote",
|
|
5872
6002
|
"timeline"
|
|
5873
6003
|
],
|
|
5874
|
-
"description": "Default content kind for the beat's slide.
|
|
6004
|
+
"description": "Default content kind for the beat's slide. Uses ContentPayload.type names to help engines choose a layout. The legacy shape value is retained for compatibility and requests an image representation; it is not a native ContentPayload type."
|
|
5875
6005
|
},
|
|
5876
6006
|
"layoutHint": {
|
|
5877
6007
|
"type": "string",
|
|
@@ -1872,6 +1872,12 @@ var specFileEntries = [
|
|
|
1872
1872
|
"kind": "catalogRecord",
|
|
1873
1873
|
"mediaType": "application/json"
|
|
1874
1874
|
},
|
|
1875
|
+
{
|
|
1876
|
+
"path": "catalogs/layouts/quote-1x.json",
|
|
1877
|
+
"packagePath": "@openpresentation/opf/spec/catalogs/layouts/quote-1x.json",
|
|
1878
|
+
"kind": "catalogRecord",
|
|
1879
|
+
"mediaType": "application/json"
|
|
1880
|
+
},
|
|
1875
1881
|
{
|
|
1876
1882
|
"path": "catalogs/layouts/table-1x.json",
|
|
1877
1883
|
"packagePath": "@openpresentation/opf/spec/catalogs/layouts/table-1x.json",
|
|
@@ -1896,6 +1902,12 @@ var specFileEntries = [
|
|
|
1896
1902
|
"kind": "catalogRecord",
|
|
1897
1903
|
"mediaType": "application/json"
|
|
1898
1904
|
},
|
|
1905
|
+
{
|
|
1906
|
+
"path": "catalogs/layouts/timeline-1x.json",
|
|
1907
|
+
"packagePath": "@openpresentation/opf/spec/catalogs/layouts/timeline-1x.json",
|
|
1908
|
+
"kind": "catalogRecord",
|
|
1909
|
+
"mediaType": "application/json"
|
|
1910
|
+
},
|
|
1899
1911
|
{
|
|
1900
1912
|
"path": "catalogs/layouts/title-subtitle.json",
|
|
1901
1913
|
"packagePath": "@openpresentation/opf/spec/catalogs/layouts/title-subtitle.json",
|
|
@@ -3188,10 +3200,12 @@ var specFilePaths = [
|
|
|
3188
3200
|
"catalogs/layouts/number-4x.json",
|
|
3189
3201
|
"catalogs/layouts/number-5x.json",
|
|
3190
3202
|
"catalogs/layouts/number-6x.json",
|
|
3203
|
+
"catalogs/layouts/quote-1x.json",
|
|
3191
3204
|
"catalogs/layouts/table-1x.json",
|
|
3192
3205
|
"catalogs/layouts/text-1x.json",
|
|
3193
3206
|
"catalogs/layouts/text-2x.json",
|
|
3194
3207
|
"catalogs/layouts/text-3x.json",
|
|
3208
|
+
"catalogs/layouts/timeline-1x.json",
|
|
3195
3209
|
"catalogs/layouts/title-subtitle.json",
|
|
3196
3210
|
"catalogs/layouts/title.json",
|
|
3197
3211
|
"catalogs/narratives/board-meeting.json",
|