@open-press/core
Press
One document. <Press> declares its title, page geometry, sources, and the React tree of Frames + helpers underneath. Always sits inside a <Workspace> root — even single-document projects.
<Workspace>, and every
document is one <Press> child under it (1 child for single-doc projects,
N for multi-doc). The v0.x shape — openpress.config.mjs + named config /
sources exports — is removed in v1.0; downstream workspaces should migrate via the
v0.10 codemod before upgrading.
One document. Declares title / page geometry / sources via props and the page tree via children. Lives as a child of <Workspace>. Display copy (subtitle, organization, author, etc.) lives in your own Cover JSX — Press does not carry rendering text beyond title.
import { Press } from "@open-press/core"; <Press
title="..."
page="a4" | "social-square" | "slide-16-9" | PageGeometry
sources={[ mdxSource({ id, preset, root }) ]}
slug? // optional in single-Press workspaces; required for multi-doc
theme? // default "./theme" (relative to the document file)
componentsDir? // default "./components"
>
{/* Frames + manuscript helpers */}
</Press> Document metadata
| Name | Type | Default | Description |
|---|---|---|---|
title required | string | Document title. Used for PDF metadata, HTML <title>, OG tags, and the workbench / tab-bar label. The only rendering text Press carries — subtitle / author / etc. belong in your Cover JSX. |
Page geometry
| Name | Type | Default | Description |
|---|---|---|---|
page | "a4" | "social-square" | "slide-16-9" | PageGeometry | Document-wide page size. Accepts a preset name or a custom geometry object ({ id, label, width, height }). Engine injects this as --openpress-page-* CSS variables. Individual <Frame> can override via its own page prop. |
Content sources
| Name | Type | Default | Description |
|---|---|---|---|
sources | SourceRegistration[] | Array of source registrations. Each entry is the return value of mdxSource({ id, preset, root }) from @open-press/core/mdx. id is what <MdxArea chainId>, <Sections source>, <Toc source> reference. |
Routing & paths
| Name | Type | Default | Description |
|---|---|---|---|
slug | string | URL segment and per-doc artifact directory (public/openpress/<slug>/document.json, reader route /<slug>). Required when the Workspace has more than one Press child. Optional for single-doc workspaces — defaults to /. | |
theme | string | Path to the theme directory, default "./theme" (relative to the document file). Inherits from workspace-level <Workspace theme> if not set. | |
componentsDir | string | Path to the React components directory, default "./components". |
Tree
| Name | Type | Default | Description |
|---|---|---|---|
children required | ReactNode | Your document body — typically <Frame> instances and / or manuscript helpers like <Sections>, <Toc>. |
// press/index.tsx
import { Workspace, Press, Frame, mdxSource } from "@open-press/core";
import { Sections, Toc } from "@open-press/core/manuscript";
export default function Project() {
return (
<Workspace>
<Press
title="Transport models in dense networks"
page="a4"
sources={[
mdxSource({ id: "story", preset: "section-folders", root: "chapters" }),
]}
>
<Frame frameKey="cover" role="document.cover">
<Cover /> {/* subtitle / organization / author all live here */}
</Frame>
<Toc source="story" maxLevel={2} />
<Sections source="story" />
<Frame frameKey="back-cover" role="document.back-cover">
<BackCover />
</Frame>
</Press>
</Workspace>
);
} // Need an A4 body AND a 16:9 cover in the same project?
// Use a multi-doc Workspace with one Press per geometry.
// (Per-Frame page override is not supported in 1.0 — one page
// size per Press.)
<Workspace name="Launch kit">
<Press slug="report" title="Launch report" page="a4" sources={[...]}>
{/* A4 cover + A4 body */}
</Press>
<Press slug="opener" title="Launch opener" page="slide-16-9" sources={[...]}>
{/* one 16:9 hero slide */}
</Press>
</Workspace> The legacy v0.x shape — <Press> took no metadata props; document/index.tsx exported config and sources alongside the component, with an openpress.config.mjs pointer at root. Removed in v1.0; the v0.10 codemod migrates automatically.
import { Press } from "@open-press/core"; <Press>
{/* tree only — metadata read from openpress.config.mjs */}
</Press> // document/index.tsx (v0.x — folder name and shape both removed)
import { Press, Frame } from "@open-press/core";
import { mdxSource } from "@open-press/core/mdx";
import { Sections } from "@open-press/core/manuscript";
export const config = { title: "Hello", page: "a4" };
export const sources = {
story: mdxSource({ preset: "section-folders", root: "chapters" }),
};
export default function Document() {
return (
<Press>
<Frame frameKey="cover">{/* ... */}</Frame>
<Sections source="story" />
</Press>
);
}
The v0.10 codemod produces the v1.0 shape in one step: rename document/ →
press/ (per-Press chapters move under press/<slug>/chapters/),
wrap in <Workspace>, move config fields onto
<Press> props, move deploy to package.json "openpress",
and delete the .mjs.
Runtime contract
You do not pass pagination state into <Press>. During export, OpenPress renders
the tree more than once: first to discover frames and content slots, then again after it knows where
each source block belongs. That runtime state is internal to the renderer.
What Press guarantees
| Name | Type | Default | Description |
|---|---|---|---|
Tree boundary | contract | Everything that should become part of the document must be rendered under the single <Press> root. | |
Single source of truth for metadata | contract | Title / page / sources live in <Press> props — there is no parallel config file in the v1.0 contract. | |
Page order | contract | Top-level frames and helpers render in document order. A cover before <Sections> appears before the generated content pages. | |
Renderer-owned pagination | contract | OpenPress may render the tree repeatedly to calculate page counts and content placement. Authors should describe pages declaratively and avoid render-time side effects. |
Authoring rules
- Every project's root is
<Workspace>.<Press>is always a child — never the top-level component. - One Workspace can hold 1 or N Press children. Single-doc projects have one; multi-doc projects (proposal + pitch + social) have several.
- Metadata lives on the
<Press>props — there is no parallel config file in the 1.0 contract. - Display copy beyond title (subtitle, organization, author bylines, version strings) goes into your own Cover JSX, not into Press props.
- Covers and back covers are ordinary
<Frame>components placed before / after the content helpers — no special API. - Do not fetch files, mutate globals, or depend on random values while rendering. The renderer may run the tree multiple times.
Related
- Workspace — multi-document projects.
- MDX sources — what
mdxSource()returns. - Frame — page surfaces inside the Press tree.
- Workspace config — package.json "openpress" field (operational settings) + Press props (document settings).