Wittern, Christian. “Bunkankun: Digital Text as distributed layers.” Presented at Balisage: The Markup Conference 2026, Washington, DC, August 3 - 7, 2026. In Proceedings of Balisage: The Markup Conference 2026. Balisage Series on Markup Technologies, vol. 31 (2026). https://doi.org/10.4242/BalisageVol31.Wittern01.
Balisage: The Markup Conference 2026 August 3 - 7, 2026
Balisage Paper: Bunkankun: Digital Text as distributed layers
Christian Wittern
Christian Wittern is Professor at the Center for Innovative Informatics of the Humanities,
Institute for Research in Humanities, Kyoto University. He was Chair of the TEI Technical
Council from 2003 to 2007 and chaired the TEI Character Encoding Workgroup.
CC-BY 4.0 Creative Commons Attribution 4.0 International
Abstract
Markup in XML can be impractical for certain users, and for certain texts. In the
case of premodern Chinese texts, TEI has produced mixed results, and alternatives
are needed. The notion of the ancient scroll, juan in Chinese, provides a catalyst for a more suitable approach to the markup task:
An archival format, which like the scroll, contains the normalized text without space
or formatting, complemented by metadata assets that can be added in distributed layers.
In practice, this is expanded by recipe formats, which pin a set of requests for text
locations or types and combine it with formatting templates to produce a text for
consumption by the user or further processing. This approach to markup, conceptually
patterned after Docker compose files, and realized mostly in YAML, is what seems to
be more suitable for the markup of premodern Chinese texts.
As a Sinologist, my main interest for the past 35 years lay in the digital representation
of premodern Chinese texts for use in research environments. Encountering the TEI
and SGML at
that time was a life changing experience and has shaped my activities for many years;
one of
the outcomes is a large corpus of Buddhist texts[1]. Among colleagues the uptake was mixed, and looking for
more approachable ways to encode text, I embraced an approach of
making the markup as implicit as possible with a simple data format
derived from Emacs org-mode, called the Kanseki Repository[2]. This went on for a dozen years, then a different
project brought me back to TEI – by this time I had given up the
idea of having researchers edit the source directly and concentrated
on the creation of a collaborative platform, hiding the technical
complexity and angled brackets[3]. Ten years into this project, out of an attempt to bring the Kanseki Repository
and the TLS on the same page, I happened on the idea to stop trying to contain all
features of
a text in one container and instead embracing an approach which bears some similarity
to
Docker images: Composable layers of a text as separate components, drawn together
according to
a recipe (think Docker file) by a composer that performs the steps outlined in
the recipe and produces the fleeting shape of a text according to the wishes of the
reader:
with or without annotations, translations or facsimile images, and in the format needed
at the
moment: PDF for printing, HTML for the web, ePub for a ebook reader.
As always, getting the details right is where the rubber hits the
road. JSON is the native language of most modern communication, but
not really usable as an archival file format; YAML fits this bill
better. A few weeks of experimenting resulted in a shape of data
that is both fit for the purpose and has interesting properties
inherited from thousands of years of writing Chinese: Texts written
on scrolls, kept in bundles with minimal metadata attached. So in
this presentation, I would like to introduce this text format, which
is specialized for this specific use of premodern Chinese texts, and
probably not for much else, but might still contain some ideas that
inspire imitation. A first realization of an interface is now
online[4], and a first version of the texts is published.
A short look at the shape of Chinese texts
Before we dive in, I will give a very short introduction to
premodern Chinese texts. The earliest surfaces used for writing in
China have been bones of cattle or turtle plastrons, followed by
bronze vessels. These could only be used for short inscriptions, so
bamboo strips and silk came also to be used. Before woodblock
printing started in the 9th century (see Fig 1), texts have been
written on paper since the Eastern Han period (25 - 220 AD). To make
handling of longer texts convenient, sheets of paper were glued
together to form a long surface of several meters (ready to hold
several thousand characters), these were rolled for storage and put
in boxes. For convenience, the outside usually had the title and
sequential number and the beginning would start with some metadata
for housekeeping, including a table of contents if there were
several shorter texts on a scroll.
Figure 1: Woodblock print of the Diamond Sutra, ca 868
The beginning section of a woodblock print, discovered in Central Asia, now held
in the British Library, shelfmark Or. 8210.
Paper made writing much more convenient and marked the beginning of
the production of larger amounts of texts; some conventions that
arose around this time carried over to the period of woodblock
printing, when even larger numbers of texts could be produced
conveniently. Sheets of paper would still be glued together, but
only after the printing, so now the sheets themselves also needed
some metadata, which included in addition to a short title and a scroll
number, also the sheet number and in many cases the number of
characters on the sheet and the name of the carver – the latter was
necessary to calculate the pay.
So a scroll, juan in Chinese, continued to be a
basic unit for the production of texts. Since the length could be
adjusted to a certain degree, the juan came also to resemble not
just a physical, but also a logical unit of a text and it became
customary to refer to specific locations in a text by title and
scroll number. Within a scroll though, there was very little
structure, apart from very few paragraph indications – starting a
new line before the space was used up – the text would flow without
interruption, hundreds and hundreds of characters.
There are, of course, texts that have more internal structure, for
example, with a commentary interlaced with the main text. In this
case, the commentary might be in smaller characters occupying a
quarter of the square a normal character would take up, thus slicing
the text up in (at least) two separate logical streams within a
text. And for texts that had been commented on several times over
the centuries (the way to make a new statement in Chinese thinking
was to make it a comment to a classic, thus making it look like it
was not new at all), sometimes these commentaries would be collected,
and such a text could have six or more additional voices layered on
the source text. As an example for a woodblock print, Fig 2 shows a text with commentary.
Figure 2: History of the later Han, first part of first juan
Beginning of the main text, with the frontmatter marked in yellow – this includes
the title and name of the author, as well of the main commentator. The first heading
is marked in orange, while the root text is in blue, and the commentary is in black.
I preserved some of the text unmarked to show the original shape.
Now this handling is not yet implemented for the new data format, but Fig. 3 shows
how it looks like in the upstream source, displayed in the web interface.
Figure 3: The same location as Fig 2, but a different source
This is a screenshot of a display of this same text location in the Kanseki Repository, with the smaller print text rendered as pink to make the
distinction more obvious. The right hand side shows the optionally activated digital
facsimile of the edition used here.
Digital representation and system design
What about TEI?
TEI/XML is of course perfectly capable of representing Chinese
text and has been used for this for more than 30 years. Probably
the largest, at least the largest publicly available, collection is
the CBETA 電子佛典集成 (CBETA Collection of Buddhist Scriptures[5]), but there might be others. In another project I have
spend many years developing a platform for collaborative research
on such texts, proving that it is indeed possible.
However, over the years I also encountered problems, not so much
with the representation itself, but with the overall system design
with the affordances provided by this structure.
One of the aims of the collaborative platform was to provide full
support for the research workflow for a text, which starts from
establishing the exact characters of the text, including
comparison of variant editions or parallel occurrences while
referencing a digital facsimile of the text. The next step then is
identifying parts of a texts, such as front matter, body or back
matter, as well as internal structure, as far as it is
visible[6]. This is followed by adding sections, paragraphs and
punctuation to the text. At this point the text is ready to be
annotated and translated, which are the main tasks for the project.
It might be blamed on the way TEI was applied to this project, but
this workflow essentially required to prepare the texts outside
the collaborative platform and upload them once they reached a
satisfying state, thus resulting in a waterfall workflow rather
than a circular one[7].
So in a way of speaking, the text format introduced here might not so much be seen
as replacing TEI, but rather providing a scaffolding for the production of a text
that can then be interchanged with others using TEI.
So then, what exactly is a text?
One of the main tasks scheduled for our project this year was the integration
of a large additional trove of texts into the existing platform,
which would result in a tenfold expansion of the number of covered
texts. The main catch was that the new corpus is unstructured and
raw, and could thus not easily be added to the existing system. In
a number of research meetings, we ended up questioning some of the
fundamental assumptions about what a text is, and how it should be
treated. Coming from the raw representation of a text in the
scrolls of the first millenium, everything that was added later
could be seen as an interpretative addition to a text, not an
essential part. So we started to see the text not as a fixed
publication, but rather as a composite artefact that could be made up from
various ingredients at the convenience of the producer (or even of
the reader).
Right, but how do we tell the computer?
This encouraged me to look for a solution that would not rely on
TEI. It still needed to be fit for markup statements, but rather
standoff than inline. One experiment tried to use JSON for text
representation, but that is both awful to edit and to manage in a
git based environment. YAML then seemed a better fit, and so the
current implementation and data format took shape. It is still in
a somewhat experimental state, but with help from today's coding agents, it
could be quickly turned into a viable implementation and tested on
the whole corpus. However, there are still some components
completely missing.
Bunkankun format
The building housing my office in Kyoto is the branch office of our
Institute, Bunkan in Japanese, so I nicknamed my
coding agent Bunkankun =~ the Bunkan
guy. Somehow the name stuck; a domain could be registered,
and no clashes with other names were discovered by a few casual
searches on the Internet and on GitHub (bkk was
already taken, unfortunately), so that became the name for this endeavor.
The texts we are dealing with vary considerably in length, from a few hundred characters
to many millions, with the largest text running to 1000 juan in the order of 20000
characters. For convenience, this is used as a handy unit of division for the texts,
so each juan will
reside in its own YAML file. These are then collected in text
bundles, with a manifest file declaring the assets in a
bundle and adding some administrative metadata. There will be at least a
surface edition – the curated text we establish – and possibly an unlimited number
of additional
editions, residing in a similar way under an edition
subdirectory.
Archival format
All text fields, no matter their location or
type, are accompanied by a hash field whose
value audits the content. This will allow the standoff references to the content by
offset to be pinned to discoverable versions and allow detection of drift.
A juan file has a
front, a body, and a
back. Only the body must be non-empty; the
others are optional and need not be present if empty. Additional
metadata fields are available. A typical front contains
an opening line that locates the juan in a larger collection, the
title of the text, the sequential number of the juan, and an
attribution naming persons and roles with respect to the body. The
back contains a closing line. The placement of prefaces,
postfaces, colophons, and similar paratextual material is open:
such material may go into the body or be separated out into front
or back, at the discretion of the project applying the format.
The body has one text element that holds the canonical character
content of the whole juan. Space characters, punctuation, line
breaks, and similar content are
not present in this stream —
they are extracted into the juan's logical
marker collection. A marker has
at minimum a type and an
offset; further fields are
optional and typically include
id,
content, and additional
structured information appropriate to the marker's type. The set
of marker types is open; a small core vocabulary is defined
separately.
Markers may be stored in several physical locations. A bucket may
carry an inline markers list for structural
markers that are useful when inspecting the juan by itself. Most
markers may instead be stored in a per-juan marker asset under the
bundle's assets/ directory and pinned from the
manifest. Consumers treat inline markers and marker-asset markers
as one logical collection, sorted by offset. This keeps juan files
compact while preserving the same text-addressing model.
One text can be represented in several editions. Additional editions in a format that
parallels the main structure are storied in a subdirectory editions. In addition, they can be made
accessible through the master edition of the text through markers that indicate at which offsets the text differs
from the surface content.
Canonicalization
The markers link to their associated text files by raw offset.
Since this is a potential fragile mechanism, extra care needs to
be taken to ensure the integrity of the text fields. As has been mentioned, a hash
is used to make changes to the text discoverable. For Chinese
text, there are additional steps required to make this process robust. For this purpose,
we define a set of
canonical characters. These
characters are drawn from Unicode, but due to the history of Unicode, there are many
codepoints that essentially encode the same character. For this reason, we need to
exclude some, while providing a mapping of the excluded characters to corresponding
characters in the canonical set. On the other hand, there are rare characters which
do not (yet?) have an assigned codepoint in Unicode. For these cases, we designate
an area within the large block of PUA (private use area) characters for the purpose
of refering to these characters within our texts, while maintaining external information
as part of the text format, which provides ways to render the characters, similar
to the g element in the TEI. This constitutes a reference character set,
which is part of the file format together with other reference
assets.
Source material is brought into this canonical form through a
deterministic procedure; every step that alters the source is
recorded as a marker, so that the source can be reconstructed
exactly from the canonical text and its markers.
The procedure is applied in order:
Source. Input is treated as
Unicode encoded in UTF-8.
Entity expansion. Entity
references in the source — for example,
&KRxxxx; style references in Kanripo
material, or TEI <g/> elements — that
point to characters not available in current Unicode are
expanded to codepoints in the Supplementary Private Use Area
(SPUA-A, U+F0000–U+FFFFD) using the bundle's declared
entity encoding. The expansion is
deterministic and produces no markers: the PUA codepoint,
taken together with the declared encoding, is sufficient to
recover the entity reference. The PUA codepoints produced this
way are first-class members of the canonical text stream and
participate in offsets, the text hash, and downstream marker
logic like any other character.
Unicode normalization. NFC
is applied so that base characters are in precomposed form.
Extraction of layout
features. Characters carrying layout, structural,
or paratextual information — whitespace, punctuation, indent
characters, page and line breaks, register dividers, and
similar — are removed from the text element and emitted as
markers, each with an offset into the remaining text stream.
Substitution to canonical
characters. Any character in the post-extraction
stream that is not a member of the canonical character set is
replaced by its canonical equivalent. Each such substitution
is emitted as a marker recording the offset, the character or
sequence replaced, and the reason for the substitution.
Hash. The resulting text
stream, encoded as UTF-8, is the input to the
hash field that accompanies
the text element.
Offsets count Unicode
codepoints into the post-substitution text stream. Variation
selectors and similar combining characters are not independent
offset targets; they remain attached to the preceding base
character.
Characters that fall outside the declared set are not forbidden in
a source — they are replaced during canonicalization and the
replacement is recorded as a substitution marker. Common reasons
for exclusion include compatibility characters with a documented
preferred form, deprecated codepoints, ad-hoc Private Use Area
assignments from third-party encoding schemes, and blocks
deliberately not yet supported.
Markers
Markers are the mechanism by which information that has been
removed from the text stream during canonicalization, or that
annotates the text stream from outside it, is reattached to
specific positions in the canonical text.
The logical marker collection for a bucket is assembled from the
bucket's inline markers list, if present,
plus the matching list in the juan's marker asset, if the
manifest declares one. Inline markers are therefore a storage
convenience, not a separate semantic class. When both locations
contain markers, consumers merge them by offset and preserve
source order for markers with the same offset.
Markers come in two shapes. Point
markers apply at a single position; they carry an
offset alone. Range
markers apply to a slice of the text stream; they
carry an additional length field, and apply
to the slice [offset, offset + length). The
shape is fixed by the marker type. The length
field mirrors the codepoint-slice form also used in the
recipe-selection vocabulary.
Every marker carries the following required fields:
type: the kind of marker.
offset: the codepoint
position in the canonical text stream where the marker
begins.
length: the codepoint
span of the marker. Present on range-typed markers, absent
on point-typed.
Optional fields are defined per marker type and may include
id,
content,
note,
responds-to (an id referring
to another marker, used by markers that comment on or extend
another marker), and structured fields specific to the type. A
marker carrying an id may be referenced from
elsewhere; ids are local to the juan unless qualified. Id
uniqueness is checked over the assembled logical marker
collection, not merely over one physical file.
The set of marker types is open. A small
core vocabulary is defined
for layout, structural, voicing, and substitution markers: page
break, line break, indent, punctuation, paragraph break,
register divider, head, comment, and substitution are
point-typed; voice (§"Voices") is range-typed.
Projects may extend the set for their own purposes; a marker
type that is not in the core vocabulary should be namespaced by
the project introducing it.
XML-based imports may emit a generic point marker for source
elements whose presence should be preserved but whose semantics
are not otherwise modeled by the core importer. This marker has
typexml-element and carries the required fields
offset,
name, and
role. The
name field records the source
element name, using the same prefix form used elsewhere in
source metadata, and role is
normally open or close.
Additional fields may be present, for example,
id or an
attrs mapping of source
attributes. Page and line breaks, tls:head,
and tls:seg remain represented by their
specialized markers and are not emitted as
xml-element markers[8].
By default, structural and navigation-critical markers remain
inline: tls:head,
tls:div-start,
tls:div-end,
cbeta:juan-start,
cbeta:juan-end,
cbeta:mulu, and any marker directly
referenced by the table of contents. Layout markers,
punctuation, page and line breaks, voice markers, variant
markers, substitution markers, comments, and other bulky project
markers normally live in the marker asset. This default is a
packaging policy rather than a semantic restriction.
Voice markers
A voice marker records
that a slice of the canonical text stream belongs to a named
textual layer. It is the mechanism by which interleaved
threads — a root text and its commentaries, for example —
are disentangled so that a consumer can extract any one
layer, present several in parallel, or reproduce the
interleaved source as published.
A voice marker is range-typed. It carries the required
marker fields together with:
type: the literal
value voice.
length: the slice
length, in codepoints.
name: the textual
layer this slice belongs to.
The name vocabulary is
open. A small recognized set is defined so that
cross-project work stays legible:
root — the primary, commented-upon
text.
commentary — a layer of comment on a
root text.
subcommentary — a layer of comment on
a commentary.
gloss — a short interlinear
annotation (typical layout: between the lines, in
smaller characters).
note — a bracketed span whose
specific role (commentary, gloss, alternate reading,
citation, …) is left unresolved. Used when the only
available signal is a punctuation fence such as
(…=)= and the deriver can't claim
anything stronger.
Projects extend by prefixing —
kr:apparatus, tls:swl,
and so on — consistent with the rest of the marker
vocabulary.
A voice marker may carry optional fields including
id,
note, and
responds-to — the id of
another voice marker that this voice answers to. A
subcommentary voice typically
responds-to a
commentary voice; a
commentary voice
responds-to a root
voice. The relationship is many-to-one: a single root span
may attract several commentary spans, each of which names
that root span as its responds-to target.
Voices coexist with the single text stream of the juan;
there is no separate per-voice text element. The juan's
canonical text contains every voice's content in source
order, and voice markers carve it into named slices. A
consumer extracting only the root filters by
name=root and reads the slices in offset
order; one reproducing the interleaved form walks all voice
markers in offset order. Both presentations are derivations
of the same canonical text and guarded by the same hash.
The lighter-weight point markers comment
and head (which carry out-of-stream
content) remain available for sparse
interlinear material — short editor's notes, occasional
headings — where promoting the inserted text into a
first-class slice of the text stream would be overkill.
Example. A short
commentary passage alternates root lines and commentary on
those lines. The canonical text of the juan, rendered as a
single stream, reads:
A consumer extracting name=root walks the
marker list in offset order and concatenates the slices
[0,4) and [13,17),
yielding 色不異空空不異色. A consumer
reproducing the interleaved source walks every voice marker
in offset order and emits the slices in sequence, producing
the original stream. Both presentations are derivations of
the same canonical text and the same hash; neither
presentation requires altering the underlying juan.
Overlay bundles
An overlay bundle is a bundle
that contributes additional markers to another bundle's text
stream without modifying it. Its manifest declares a
target — the canonical
identifier and hash of a target bundle — and its juan files
carry marker collections that address offsets in the
corresponding juans of the target. The target is unaffected: its
hash does not change, and existing pins to it remain valid. The
overlay is independently addressable, hashed, and versioned per
the usual bundle pattern.
The motivation is straightforward. Useful markers can be
authored after a bundle has been published, by parties who do
not own the target, for purposes its original author may not
have considered: segmentation introduced for the sake of a
translation, modern punctuation added to a classical source,
voice markers added to disentangle a layout the source did not
mark machine-readably, scholarly annotation distributed
independently. A consumer composes the target with whichever
overlays they want via a recipe.
These distributed layers are what makes this system adaptable to a variety of needs
and use cases. A research paper could, for example, keep the passages it quotes as
an overlay and could then use a recipe to pull the source and an accompanying translation
from the corpus, in a similar way to the handling of bibliographies. Readers could
then use such an overlay to inspect the quotations in their original context, comment
or add their own translations.
Conclusions
The text format introduced here is just a few weeks old and still in a very early
phase of experimentation and implementation. After initial testing with a small subset
of texts, a more thorough conversion of texts from three different sources is now
live at the GitHub account bkkbooks, with almost 12500 titles. Code for a variety of maintenance tasks, including import,
export, a web server and the frontend UI are all available at bunkankun/bkk.
The next step will involve adding proper segmentation to the digital text, this will
also be added as markers. Text sections in our sources that start with a separate
header line are easily recognized from analyzing the existing markers. Paragraphs
in the modern sense are not existing and thus not indicated, but preliminary experiments
show that large language models, with the right prompting and harness, can be pressed
into service here. The same also holds for punctuation. And here is where this data
format shines: Responses from different models can easily be overlaid, compared and
further processed, without affecting the base text at all.
At the moment, this looks like a real opportunity to take care of the first few steps
of the research workflow, the establishing of a well understood text, with the option
of downstream paths to either the Kanseki Repository or the TEI based TLS format.
Time will show how these three projects will evolve.
[6]
Ideally, these steps would be applied as needed and in a
repetitive, circular manner, so that only parts of the text that were
needed immediately had to be treated, rather than completing
every step completely before moving on to the next step.
[7]
At some point, user interface elements for most of the text
critical work to establish a text were implemented, but they
proved to be hard to use and brittle and saw little actual
use.
[8] In the reference implementation bkk, a list of elements to be preserved in this way can be supplied.