Packt Content Format
Content within the Content Lake is stored in Packt Content Format (PCF), a JSON-based rich text specification designed for modern publishing. PCF provides a structured, serialisable representation of content that can be rendered into any output format -- HTML, Markdown, SSML, ePub, PDF, and beyond.
PCF is heavily influenced by Portable Text by Sanity.io. Any valid Portable Text document is a valid PCF document.
PCF has two complementary layers:
- The Content Layer -- A JSON structure representing the document content (this page).
- The Entity Overlay -- A separate JSON document that annotates the content with knowledge graph references (see Entities).
Output Format Comparison
The same content expressed in each supported output format:
{
"style": "h1",
"_type": "block",
"_key": "f4a901bc12e7",
"children": [
{
"_type": "span",
"_key": "a1b2c3d4e5f6",
"text": "Introduction"
}
]
},
{
"_type": "block",
"_key": "9a85015a4de8",
"style": "normal",
"markDefs": [
{
"_type": "link",
"_key": "c233e5cbac18",
"href": "https://www.packtpub.com"
}
],
"children": [
{
"_type": "span",
"_key": "37c3818c5d6b",
"text": "Introducing the ",
"marks": []
},
{
"_type": "span",
"_key": "b086edb3fed9",
"marks": [
"c233e5cbac18"
],
"text": "Packt"
},
{
"_type": "span",
"_key": "aa3ef773326d",
"marks": [],
"text": " content format to enhance publishing flows and integrate context to content."
}
]
}
Document Structure
A PCF document is a JSON array of blocks:
[
{ "_type": "block", "_key": "abc123" },
{ "_type": "image", "_key": "def456" },
{ "_type": "block", "_key": "ghi789" }
]
Every element in the root array must have:
| Field | Type | Required | Description |
|---|---|---|---|
_type |
string | Yes | The block type identifier |
_key |
string | Yes | A document-unique key for this block |
Text Blocks
A text block represents a paragraph, heading, list item, or blockquote.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
_type |
string | Yes | "block" |
Always "block" for text blocks |
_key |
string | Yes | -- | Document-unique identifier |
style |
string | Yes | "normal" |
"normal", "h1" -- "h6", "blockquote" |
markDefs |
array | No | [] |
Annotation definitions for child spans |
children |
array | Yes | -- | Array of spans and inline objects |
listItem |
string | No | null |
List type: "bullet", "number", "square", "letter" |
level |
integer | No | null |
Nesting depth for list items (1-based) |
Spans
A span is the inline text unit within a block.
| Field | Type | Required | Description |
|---|---|---|---|
_type |
string | Yes | Always "span" |
_key |
string | Yes | Block-unique identifier |
text |
string | Yes | The text content |
marks |
array | Yes | Decorator names or markDef keys |
Marks
Marks annotate spans with formatting or data. There are two kinds:
decorators (simple string values) and annotations (references
to structured definitions in markDefs).
Decorators
Simple string values in the marks array:
| Decorator | Meaning |
|---|---|
"strong" |
Bold |
"em" |
Italic |
"underline" |
Underline |
"strike" |
Strikethrough |
"code" |
Inline code |
"superscript" |
Superscript |
"subscript" |
Subscript |
Annotations
Annotations reference entries in the block's markDefs array and
carry structured data. A span references an annotation by including
the annotation's _key in its marks array.
{
"_type": "block",
"_key": "9a85015a4de8",
"style": "normal",
"markDefs": [
{
"_type": "link",
"_key": "c233e5cbac18",
"href": "https://www.packtpub.com",
"title": "Packt Publishing"
}
],
"children": [
{
"_type": "span",
"_key": "37c3818c5d6b",
"text": "Visit ",
"marks": []
},
{
"_type": "span",
"_key": "b086edb3fed9",
"marks": ["c233e5cbac18"],
"text": "Packt Publishing"
},
{
"_type": "span",
"_key": "aa3ef773326d",
"marks": [],
"text": " for more."
}
]
}
In this example, the span containing "Packt Publishing" includes
"c233e5cbac18" in its marks array. That key matches the link
definition in markDefs, so the span is rendered as a hyperlink.
Standard Annotation Types
| Type | Purpose | Rendered? |
|---|---|---|
link |
External hyperlink | Yes |
internalLink |
Cross-document content link (contentlake:// URI) |
Yes |
footnote |
Page-level note with rich text body | Yes |
endnote |
Document-level note with rich text body | Yes |
citation |
Structured bibliographic reference | Yes |
crossRef |
Intra-document block reference | Yes |
comment |
Editorial workflow annotation | No |
Links
{
"_type": "link",
"_key": "lnk1",
"href": "https://www.packtpub.com",
"title": "Packt Publishing"
}
Internal Links
Internal links use the contentlake:// URI scheme to reference
other documents within the Content Lake:
Footnotes and Endnotes
Footnotes and endnotes carry a rich text body as a nested PCF block array. Serialisers auto-number footnotes sequentially within the page or document.
{
"_type": "footnote",
"_key": "fn1",
"body": [
{
"_type": "block",
"_key": "fnb1",
"style": "normal",
"children": [
{
"_type": "span",
"_key": "fns1",
"text": "See the original paper for details.",
"marks": []
}
]
}
]
}
Citations
Citations carry structured bibliographic data:
{
"_type": "citation",
"_key": "cit1",
"citationKey": "knuth1997",
"authors": ["Donald E. Knuth"],
"title": "The Art of Computer Programming",
"year": 1997,
"publisher": "Addison-Wesley",
"isbn": "978-0201896831"
}
Supported fields: authors, title, year, publisher, venue,
doi, url, isbn, pages, citationKey.
Lists
Lists are consecutive blocks with a listItem property. There is
no wrapper element -- list structure is derived from sequence and
level values.
[
{
"_type": "block",
"_key": "li1",
"style": "normal",
"listItem": "bullet",
"level": 1,
"children": [
{
"_type": "span",
"_key": "lis1",
"text": "First item",
"marks": []
}
]
},
{
"_type": "block",
"_key": "li2",
"style": "normal",
"listItem": "bullet",
"level": 2,
"children": [
{
"_type": "span",
"_key": "lis2",
"text": "Nested item",
"marks": []
}
]
},
{
"_type": "block",
"_key": "li3",
"style": "normal",
"listItem": "bullet",
"level": 1,
"children": [
{
"_type": "span",
"_key": "lis3",
"text": "Second item",
"marks": []
}
]
}
]
Serialisers group consecutive blocks sharing the same listItem
type into list containers. A change in level opens or closes
nested lists accordingly.
Custom Block Types
| Type | Description |
|---|---|
image |
Static images with captions, alt text, and asset refs |
video |
Embedded video with provider metadata |
codeBlock |
Syntax-highlighted code listings |
aside |
Callouts, tips, warnings with a semantic tone value |
formula |
Mathematical expressions (LaTeX/KaTeX) |
table |
Structured tabular data with rich-text cells |
Custom types beyond these are permitted. A serialiser that
encounters an unrecognised _type should skip the block gracefully
-- it must not fail.
Images
Image blocks store the image source, accessibility text, display
properties, and responsive size variants. The children array
provides a rich text description that can be used for extended alt
text or audio descriptions.
{
"_key": "79973aed956a",
"_type": "image",
"src": "/images/portable-text-logo.png",
"alt": "Portable Text Editor logo",
"props": {
"type": "png",
"height": 800,
"width": 800,
"resolution": "2x",
"dpi": 1200
},
"sizes": [
{ "original": "/images/portable-text-logo.png" },
{ "1.5x": "/images/portable-text-logo.png 1.5x" },
{ "2x": "/images/portable-text-logo.png 2x" },
{ "4x": "/images/portable-text-logo.png 4x" }
],
"children": [
{
"_type": "span",
"_key": "37c3818c5d6b",
"text": "This is a detailed alt text by ",
"marks": []
},
{
"_type": "span",
"_key": "b086edb3fed9",
"marks": ["strong"],
"text": "the Content Lake"
},
{
"_type": "span",
"_key": "aa3ef773326d",
"marks": [],
"text": " which can contain lists and other formatting to enhance use-cases like audio descriptions."
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
_type |
string | Yes | Always "image" |
_key |
string | Yes | Document-unique identifier |
src |
string | Yes | Path or URL to the default image asset |
alt |
string | Yes | Short accessibility text |
props |
object | No | Image metadata (type, dimensions, DPI) |
sizes |
array | No | Responsive variants keyed by resolution |
children |
array | No | Rich text description for extended alt text |
Serialisation
PCF is designed to be serialised to any target format:
- For
"block"types, render children spans applying marks and styles. - For custom types, render the type-specific structure.
- For unknown types, skip gracefully or render a placeholder.
Serialisers should walk the root array in order, maintaining state
for list grouping (consecutive listItem blocks) and footnote
numbering. Each block is self-contained apart from those two
concerns, so parallel or partial rendering is straightforward.
Compatibility with Portable Text
PCF is a superset of Portable Text. The block, span,
markDefs, and marks system works identically. PCF extends
Portable Text in three ways:
_keyis required on all blocks and spans (Portable Text treats it as optional).- Additional standard types such as
aside,formula, andtableare defined. - The Entity Overlay system annotates content with knowledge graph references without modifying the content layer (see Entities).
Any Portable Text serialiser can render PCF content. Custom block types and annotations will be skipped by serialisers that do not recognise them, which is the expected behaviour.