% OpenGlyph documentation. Copyright 2026 OpenGlyph contributors. MIT.
% Install the package first, then compile here with XeLaTeX or LuaLaTeX.
\documentclass[11pt,a4paper]{article}
\usepackage[margin=25mm]{geometry}
\usepackage{openglyph}
\usepackage{booktabs,array,longtable,fancyvrb}
\usepackage[unicode,colorlinks=true,urlcolor=blue,linkcolor=blue]{hyperref}
\OpenGlyphLoad{ebag}
\OpenGlyphLoad{examples/myglyphs}
\setlength{\parindent}{0pt}
\setlength{\parskip}{5pt}
\setlength{\emergencystretch}{2em}
\fvset{fontsize=\small,frame=single,framesep=4pt}
\title{OpenGlyph\\\large Named, font-backed historical Chinese glyphs}
\author{OpenGlyph contributors\\Maintainer: Zejia FAN}
\date{Version 0.2.1 --- 28 October 2026\\CTAN submission candidate}
\begin{document}
\maketitle

\begin{abstract}
OpenGlyph lets an author insert a rare glyph by its ASCII identifier and
typeset it as a real font character. An optional offline compiler constructs
new forms from component templates. The built-in collection contains 22,583
GlyphWiki \texttt{ebag\_s} forms with 38,462 source and dependency programs.
This package is a typesetting tool, not an OCR system or a scholarly authority.
It neither determines a character's reading nor proves that a generated form
matches a manuscript. Compare glyphs with the source before publication.
\end{abstract}

\tableofcontents
\newpage
\section{Start with an existing form}

After installation, this is a complete document:
\begin{Verbatim}
\documentclass{article}
\usepackage{openglyph}
\OpenGlyphLoad{ebag}
\begin{document}
An existing form: \ebag{s030-067}.
\end{document}
\end{Verbatim}

The output includes \ebag{s030-067}. Further source IDs produce
\ebag{s131-009} and \ebag{s162-428}. These are font glyphs, not images.
The command \verb|\ebag{s030-067}| abbreviates
\verb|\OpenGlyph{ebag:s030-067}|. You need not enter a rare Chinese character
or memorize its private-use codepoint.

The offline HTML index, \texttt{openglyph-index.html}, searches source IDs and
component references. A component hit is only a visual search lead, not a
claim about character identity. The index uses the supplied OTF; it does not
request glyph images from a server.

\section{Engines, installation and dependencies}

Use XeLaTeX or LuaLaTeX with LaTeX2e dated 2020-10-01 or newer. The runtime
depends on \texttt{fontspec}, \texttt{iftex} and \texttt{xparse}. pdfLaTeX is
not supported. No shell escape or network service is used during ordinary
typesetting. Tectonic can use the project-local layout described below.
The Chinese example additionally uses \texttt{ctex} and Fandol, and LuaTeX-ja
when compiled with LuaLaTeX. This English
manual uses \texttt{geometry}, \texttt{booktabs}, \texttt{array},
\texttt{longtable}, \texttt{fancyvrb} and \texttt{hyperref}.

\subsection{Personal TEXMF installation}
Find your personal tree with \texttt{kpsewhich -var-value=TEXMFHOME}.
Within that tree install:
\begin{Verbatim}
tex/latex/openglyph/openglyph.sty
tex/latex/openglyph/openglyph-ebag.def
fonts/opentype/public/openglyph/OpenGlyphEbag.otf
doc/latex/openglyph/          (contents of doc/)
source/latex/openglyph/       (contents of source/)
\end{Verbatim}
Put the root README, license, notices and disclosure with the documentation.
Preserve the internal directory layout of the documentation and builder.
Refresh the distribution's filename database if necessary. The two files
under \texttt{tex/} are the only runtime TeX files. Example files named
\texttt{catalog.tex} must not be installed globally as runtime files.

The optional builder stays in the source tree and is invoked explicitly by
Python. No executable wrapper or shell-escape permission is needed. A TeX
installation does not supply its Python or Node.js dependencies.

\subsection{Project-local and Overleaf use}
Alternatively place \texttt{openglyph.sty}, \texttt{openglyph-ebag.def} and
\texttt{OpenGlyphEbag.otf} beside the paper's main source. The original local
layout \texttt{ebag/catalog.tex} with its font beside it remains supported.
A local \texttt{ebag/} bundle takes precedence over the installed catalogue.
Use only one version of each glyph namespace in a document.
For custom bundles, specify an explicit relative or absolute directory path
and keep the font there. Discovery solely through an unrelated
\texttt{TEXINPUTS} search path is not supported.

Copy the example \texttt{examples/myglyphs/} directory alongside the two
example sources to compile them locally. An Overleaf project only needs
prebuilt fonts and catalogues; font construction is a separate offline step.

\section{LaTeX interface}
\begin{longtable}{@{}p{0.49\linewidth}p{0.47\linewidth}@{}}
\toprule
Command & Purpose\\\midrule\endhead
\verb|\OpenGlyphLoad{ebag}| & Load the built-in collection; repeated loads of
the same argument do nothing.\\
\verb|\OpenGlyphLoad{myglyphs}| & Load a local font bundle. Its catalogue is
\texttt{myglyphs/catalog.tex}; the font stays alongside the catalogue.\\
\verb|\OpenGlyph{ebag:s030-067}| & Print an explicitly named glyph.\\
\verb|\ebag{s030-067}| & Short form for a built-in glyph.\\
\verb|\gwglyph{my:n2}| & Synonym for \verb|\OpenGlyph|; often used for custom forms.\\
\verb|\OpenGlyphAlias{short}{my:n2}| & Add a document-specific alias to a
previously loaded glyph; aliases must be unique.\\
\verb|\OpenGlyphSequence{my:n1,my:n2}| & Print a comma-separated list of IDs
in the specified order.\\
\verb|\OpenGlyphIfExistsTF{id}{yes}{no}| & Branch on whether the ID is registered.\\
\bottomrule
\end{longtable}

Glyphs follow the current font size. They can occur in running text,
footnotes\footnote{A font-backed footnote: \gwglyph{my:n2}.} and headings.
They are boxed individually to isolate CJK inter-character font switches.
The supplied font has one drawing style; bold or italic variants are not
automatically designed. Whole-document vertical writing and critical-edition
layouts require other packages and are not provided here.

Unknown IDs, duplicate definitions, missing font files and missing character
mappings produce errors. Compile with \texttt{-halt-on-error}; do not accept
a PDF produced by continuing past errors. Some nonfatal interactive errors
display a bracketed identifier to make failure visible. The package does not
silently substitute a visually similar common character. With
\texttt{hyperref}, bookmarks use bracketed ASCII IDs instead of assuming that
a PDF bookmark can carry a custom font.

\subsection{Low-level declarations}
These declarations define a font and map an ID to a hexadecimal codepoint:
\begin{Verbatim}
\OpenGlyphDeclareFont{namespace}{filename.otf}
\OpenGlyphDeclare{id}{namespace}{E000}
\end{Verbatim}
Generated catalogues use the faster
\verb|\OpenGlyphDeclareEntry| interface after Python validation. This is an
implementation detail for generated, trusted catalogues, not a general
sanitizer for untrusted TeX. IDs begin with an ASCII letter and then use
letters, digits, colon, period, underscore or hyphen.

\section{Construct a new form offline}

Install Python 3.10+, Node.js, FontTools and skia-pathops. In the
\texttt{source/} directory:
\begin{Verbatim}
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements-build.txt
python scripts/openglyph.py inspect ebag:s030-067 \
    --node r4 -o preview
python scripts/openglyph.py build examples/newforms.json \
    -o myglyphs
\end{Verbatim}
On Windows, use \verb|.venv\Scripts\Activate.ps1| for activation. Existing
output folders are never overwritten. Open \texttt{preview/index.html} to
see actual component occurrences and their path IDs. Rendering an isolated
component may change stroke-avoidance details; also inspect the complete form.

Copy the generated \texttt{myglyphs/} into the paper project and add
\verb|\OpenGlyphLoad{myglyphs}|. Then use \verb|\gwglyph{my:n2}|.

\subsection{A small, complete project}
\begin{Verbatim}
{
  "schema": "openglyph.project.v1",
  "namespace": "my",
  "glyphs": [{
    "id": "n2",
    "base": "ebag:s030-067",
    "edits": [{
      "op": "insert", "parent": "root", "id": "inner_dot",
      "glyph": "primitive:dot", "box": [77,129,119,167]
    }]
  }]
}
\end{Verbatim}
The compiler derives filled vector outlines through KAGE, creates an
OpenType/CFF font, and writes a matching catalogue, allocation table,
manifest and exact source programs. Normal paper compilation only reads
these outputs. JSON input does not execute Python or raw JavaScript.

\begin{center}
\renewcommand{\arraystretch}{2.7}
\begin{tabular}{@{}lcc@{}}
\toprule Operation & Base & New form\\\midrule
Replace one occurrence & {\LARGE\ebag{s030-067}} & {\LARGE\gwglyph{my:n1}}\\
Insert a dot template & {\LARGE\ebag{s030-067}} & {\LARGE\gwglyph{my:n2}}\\
Drop a record & {\LARGE\ebag{s030-067}} & {\LARGE\gwglyph{my:n3}}\\
Place a component & {\LARGE\ebag{s030-067}} & {\LARGE\gwglyph{my:n4}}\\
\bottomrule
\end{tabular}
\end{center}
Each example independently edits the same base, rather than accumulating all
four changes. These are synthetic forms without asserted readings or origins.

\subsection{Editing vocabulary}
Node paths such as \texttt{r4/r0} identify component occurrences, not every
instance of a shared GlyphWiki part. Get the paths from \texttt{inspect}.
For the example above, the four edits are:
\begin{Verbatim}
{"op":"replace","node":"r4/r0","glyph":"u9f9c-j"}
{"op":"insert","parent":"root","id":"inner_dot",
 "glyph":"primitive:dot","box":[77,129,119,167]}
{"op":"drop","node":"r4/r0/r2"}
{"op":"place","node":"r4/r0","box":[28,12,92,112]}
\end{Verbatim}
\texttt{move} translates an occurrence with \texttt{delta:[dx,dy]}.
\texttt{group} groups adjacent records in their existing order using
\texttt{parent}, \texttt{id} and \texttt{nodes}. Inserted/grouped record IDs
use an \texttt{a\_} prefix. Existing record IDs are not renumbered after
deletion. Local boxes use integer coordinates in the parent's 200-unit design
space, not page-image pixels. The compiler preserves source program versions
and transformations; it does not optimize a glyph against a scanned image.

\section{Reusable modules and selected records}
Version 0.2 introduces named modules. A module is itself a base plus edits;
another edit refers to it as \texttt{module:marked\_loop}. The supplied
\texttt{examples/modules.json} contains:
\begin{Verbatim}
{
  "schema": "openglyph.project.v1",
  "namespace": "modules",
  "glyphs": [{
    "id": "newform", "base": "ebag:s030-067",
    "modules": {
      "marked_loop": {
        "schema": "guwenzi.template-program.v1",
        "base": "primitive:loop",
        "edits": [{
          "op": "insert", "parent": "root", "id": "mark",
          "glyph": "primitive:dot", "box": [70,70,130,130]
        }]
      }
    },
    "edits": [{"op":"replace", "node":"r4/r0",
               "glyph":"module:marked_loop"}]
  }]
}
\end{Verbatim}
Compile it with:
\begin{Verbatim}
python scripts/openglyph.py build examples/modules.json \
    -o moduleglyphs
\end{Verbatim}
Load the resulting bundle and print \verb|\gwglyph{modules:newform}|.
Definitions are checked, including unused circular references. Nested
\texttt{modules} dictionaries are not accepted; modules refer to definitions
in the same dictionary.

An optional \texttt{select} takes existing records out of one parent:
\begin{Verbatim}
"select": {"parent": "r4", "nodes": ["r0"]}
\end{Verbatim}
The paths and record names must come from inspection of the chosen base.
Selection occurs before edits, so inspect the source and understand the new
root before applying further edits. Records must remain in source order;
unsupported scope-transform selections are rejected. This is structural
reuse, not automatic decomposition of any arbitrary image.

\section{Stable identity and exchange}
Keep these concepts separate:
\begin{enumerate}
\item Source IDs name entries in a collection.
\item Occurrence paths name nodes in a particular template.
\item Project aliases identify an author's named glyphs.
\item A PUA codepoint addresses a glyph only within a font.
\item Hashes distinguish exact programs and outlines.
\item Scholarly identification and reading require research.
\end{enumerate}
For revisions, preserve the old allocation file:
\begin{Verbatim}
python scripts/openglyph.py build revision.json -o revised \
    --allocation myglyphs/allocation.json
\end{Verbatim}
Existing addresses stay fixed; retired addresses are not assigned to another
ID. This does not mean a revised glyph has the same content hash. Always
share the matching font, catalogue and manifest. The built-in collection
uses standard Private Use Area A slots, not the old SEAL plane 10--13 scheme.

PDF readers need no separately installed font because fonts are embedded.
Extracted text still contains font-local PUA characters: copying those into
another font can produce a box or an unrelated form. The package does not
promise semantic searchability or interoperable Unicode identities for new
forms. Keep the source IDs and scholarly annotations with the editable work.

\section{Rebuilding, licensing and review}
The optional source tree includes the full selected GlyphWiki programs,
address table, font-construction scripts and eight unmodified KAGE JavaScript
files. From \texttt{source/}, run:
\begin{Verbatim}
python scripts/build_ebag.py -o rebuilt
\end{Verbatim}
This reconstructs the built-in collection in a fresh folder.

Keep the locked address file, \path{data/ebag-addresses.json}. Do not assign new addresses from sort order
when updating the collection. Rebuilding the full font is a separate,
potentially lengthy operation, not part of document compilation.

OpenGlyph's own code and documentation use MIT. GlyphWiki data and derived
fonts retain the permissive upstream data grant; they are not relicensed as
MIT or OFL. The optional KAGE engine is GPL v3, with corresponding source.
See the root license, third-party notices and the license files under
\texttt{source/}. No local SEAL font, private scan or unverified local IDS
annotation dataset is included.

This work includes substantial AI assistance. See \path{AI-ASSISTANCE.md}.
Automated tests do not replace knowledgeable
human review, licensing review or scholarly glyph verification. This
candidate does not certify completion of human review. It has not been
submitted to or accepted by CTAN, TeX Live or MiKTeX.

Repository and issue tracker:
\url{https://github.com/Open-Glyph/OpenGlyph-LaTeX}.
\end{document}
