Skip to content

Jixoai UI v0.3.0: figures, tables, and equations number and cite themselves

jixoai v0.3.0 ui

jixoai-ui v0.3.0 numbers figures, tables, equations, and listings in a document automatically, and the running text can cite them anywhere. Reorder sections and the numbers renumber, anchors keep working, and CSS counters with PagedRef both retire. The registry carries 113 items and @jixoai/vite-plugin 0.2.0 ships alongside. One breaking change.

이 글은 영어로 작성되었습니다. 중국어 버전 읽기 →

$ git log v0.2.0..v0.3.0 --oneline | wc -l
786

jixoai-ui v0.3.0 is out (2026-09-05). From this release on, figures, tables, equations, and listings in a document number themselves, and the running text can cite them anywhere. Move a section and the numbers renumber, with link anchors still working. 786 commits went into this release, and the registry carries 113 items.

Background: documents needed a structural ontology

jixoai-ui used to be a design language shipped as a shadcn registry: terminal aesthetics, the OKLCH one-hue law, components you own once you copy them. The question this release answers comes from a single research question (2026-09-02 design track): "If you were a creator, what structured expression would you need?" A lexicographer works in headword, part of speech, sense number, and citation; a composer works in movement, bar, and rehearsal mark. Web documents today hand them headings and code blocks and nothing else.

The design track's answer is a three-layer ontology. The smallest layer is CodeBlock, one atom of expression. The middle layer is SectionCard, which carries the seven structural primitives drawn from across industries (section / item / column / float / note / quote / break). The top layer is PrintDoc, the genre preset for a document as a whole.

The first consumer is the harvest contract, the agreement that collects structural data out of the rendered DOM and into the static corpus. Once structure lands, search, llms.txt, and print tables of contents get more accurate without rework.

Numbering and cross-references: numbering domains + Figure + Reference

Numbered citation was the unfinished business the legacy numbering mechanisms left behind. Without an ontological home for it, reference-book and textbook pages stay out of reach (the original motivation of the change proposal). That phase lands whole in this release, in three parts.

  • Section numbering domains: a numbering declaration makes a section the root of a numbering subtree and a float-counting domain, and decimal numbers generate level by level on their own (3 → 3.2 → 3.2.1); sections outside any domain stay byte-identical.

  • The Figure family (kind: figure | table | equation | listing): SectionCard carries structure, meaning number, anchor, and caption, and CodeBlock nests in the content slot; plus a citedIn slot for manual back-references.

  • The Reference family: target-self-describing syntax, with resolution following the target entirely. A numbered Figure renders as Eq (4.5), a numbered section as § 3.2.1, and an unnumbered target as its title; a missing id falls back explicitly (console.warn plus a visible marker, never blocking).

Real usage from the v0.3.0 docs page:

<NumberingProvider>
  <Section numbering="decimal" title="Results">
    <Figure kind="equation" id="eq-1" caption="the momentum balance">
      <CodeCard lang="ts">p = m·v</CodeCard>
    </Figure>
    <p>see <Reference to="eq-1" /></p>
  </Section>
</NumberingProvider>

The harvest side pairs it with a two-pass pre-scan: the first pass indexes every referenceable target in the document, the second maps data-ref-to onto the corpus. Forward references still record what they point to in the SSR fallback state, keeping the static corpus complete. The figure's number, the citing block's refids[], and the section's number all entered the harvest contract, reusing the data markers already in place.

Numbers follow DOM order: CSS counters and PagedRef retire

Numbers follow DOM order directly: reorder and it renumbers, and the id never moves, so sections that trade places renumber on their own, link anchors keep working, and printing needs nothing special for numbering. The numbers are already in the DOM and the print pipeline captures them as-is; page numbers stay layout facts and are never pre-harvested. CSS counters and PagedRef, the two legacy numbering mechanisms, formally retire. The replacement is the numbering declaration and Reference from the previous section.

Beyond numbering: the rest of the 786

  • Press physics: raised/flat zones, the paired engrave effects, icon-button joining in, press physics going from a per-component rule to a library-wide rule

  • scroll-run: every scrollable region unified under one shared law set (new registry item @jixoai/scroll-run), with tabs and button-group as its consumers; the five effects slide/blur/blurSlide/progressBlur/shadow all supplied by the same law set, RTL normalized across three engines (aeb747f2)

  • The 2xs density rung: the fifth density, the tightest one for pro-tool operation surfaces. Text lands at 10px (9px stays unshipped as the absolute floor), the 24px row sits at the WCAG 2.5.8 AA floor, and the hit floor is redeclared inside the rung per the non-touch-pointer stance (c8749f86)

  • Print determinism: viewport-independent print output

  • The three defaults-economy changes + the single paint key; control-chrome (the dissolved/self-sustaining duality of in-row control shells)

  • The ghostty version pin and lock-chain CI repairs

  • Repo-wide test suite at 2185/2185 (604f9e01)

Of the 786 commits, 270 are feat and 261 are fix.

Ships with this release: @jixoai/vite-plugin 0.2.0

Vite projects can now wire jixoai-ui's terminal components and icon system straight into their build. vite-plugin 0.2.0 ships with 0.3.0: the pinned ghostty-vt wasm (resolve → serve → emit → hand over the URL via virtual:jixoai-ghostty), the icon system (svg/lucide/font providers), and the jixoai-ghostty-probe ABI sentinel bin. The ghostty pin resolver and the lucide lock sync fix its installs (the release commit's words).

Migration (breaking: data-jx hooks)

This release's window contains one breaking change (2026-08-25): the css-less .jx-* hook classes are fully retired, semantic anchors become data-jx-* attributes, and no compatibility classes are kept. Query migration:

  document.querySelector('[data-jx-kbd]')
  '[data-jx-badge="tonal"]'
  el.setAttribute('data-jx-foo', '')
  el.hasAttribute('data-jx-foo')

Variant families collapse into one valued attribute (data-jx-badge={variant}, with the ladder fill | tonal | outline carrying structural values only and no semantic hue names; error status = variant="tonal" + jx-hue-error injection). The lowest-friction path: re-add items with npx shadcn add @jixoai/<item>, then migrate queries per the table above.

Acknowledgements

The README's own words: everything here graduated from production work on unipty and openspecui.

Links