OCRtermaUI (CSS)TermaTypePechaForgeDictionaryFonts

Render beautiful Tibetan typography
without ever leaving your HTML.

A utility-first CSS framework packed with classes like tr-jomolhari, tr-guard, tr-text-rainbow and tr-glow-aurora that can be composed to render any Tibetan script, directly in your markup.

36
Typefaces
6
CSS Modules
1
Stylesheet
0
Build tools

termaUI is currently a working prototype. We are actively seeking funding to bring it to full production.

Installation

This entire website is built with termaUI

Every font stack, guardian fix, text effect, and pecha layout you see on termafoundry.com is rendered using termaUI's prototype stylesheet. The framework works — this site is the proof of concept.

Framework Guides

termaUI is framework-agnostic. It's a CSS file plus an optional JS utility — it works in any environment that renders HTML.

✓ Works alongside Tailwind CSS, Bootstrap, and any other CSS framework

Every termaUI class uses a tr- prefix. There are no naming conflicts with Tailwind, Bootstrap, or any other utility framework. Just load both stylesheets and combine classes freely on the same element.

HTML — termaUI + Tailwind together
<!-- Tailwind classes and termaUI tr-* classes coexist on the same element -->
<div class="p-4 rounded-xl bg-slate-900 tr-glass">
  <p class="text-sm text-slate-400 tr-jomolhari tr-guard tr-text-rainbow" lang="bo">
    བཀྲ་ཤིས་བདེ་ལེགས།
  </p>
</div>

Vanilla HTML

Drop the CDN link and optional script into your <head>. No build step needed.

HTML
<head>
  <!-- 1. CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/termaui/dist/termaui.min.css">
  <!-- 2. terma.js (required for correct line breaking) -->
  <script src="https://cdn.jsdelivr.net/npm/termaui/dist/terma.js"></script>
</head>
<body>
  <p class="tr-jomolhari tr-guard" lang="bo">བཀྲ་ཤིས་བདེ་ལེགས།</p>
  <script>
    document.addEventListener('DOMContentLoaded', () => terma.prepareAll());
  </script>
</body>

Next.js (App Router)

Import the CSS in your root layout. terma.prepareAll() needs DOM access, so run it in a 'use client' component inside useEffect.

Terminal
npm install termaui
app/layout.tsx — import CSS here
import 'termaui/dist/termaui.css';
// rest of your layout...
app/TibetanInit.tsx — Client Component for terma.js
'use client';
import { useEffect } from 'react';
import terma from 'termaui';

export function TibetanInit() {
  useEffect(() => {
    terma.prepareAll();
  }, []);
  return null;
}
Add <TibetanInit /> inside the <body> of your root layout. It renders nothing — it just runs terma.prepareAll() on mount and after each navigation.

Next.js (Pages Router)

pages/_app.tsx
import 'termaui/dist/termaui.css';
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import terma from 'termaui';

export default function App({ Component, pageProps }) {
  const router = useRouter();
  useEffect(() => {
    terma.prepareAll();
    router.events.on('routeChangeComplete', () => terma.prepareAll());
    return () => router.events.off('routeChangeComplete', () => terma.prepareAll());
  }, [router]);
  return <Component {...pageProps} />;
}

Astro

Import the CSS in your base layout's frontmatter. Call terma.prepareAll() in a client <script> — Astro bundles it automatically.

src/layouts/BaseLayout.astro (npm)
---
import 'termaui/dist/termaui.css';
---
<html><body>
  <slot />
  <script>
    import terma from 'termaui';
    terma.prepareAll();
  </script>
</body></html>
src/layouts/BaseLayout.astro (CDN — no npm needed)
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/termaui/dist/termaui.min.css">
<script src="https://cdn.jsdelivr.net/npm/termaui/dist/terma.js" is:inline></script>
<script is:inline>
  document.addEventListener('astro:page-load', () => terma.prepareAll());
</script>
Use astro:page-load (not DOMContentLoaded) when View Transitions are enabled — it fires after every client-side navigation.

Vite + React

src/main.jsx — import CSS once at the entry point
import 'termaui/dist/termaui.css';
// rest of your entry point...
Call terma.prepareAll() in a root useEffect
import { useEffect } from 'react';
import terma from 'termaui';

export default function App() {
  useEffect(() => {
    terma.prepareAll();
  }, []);
  // ...your JSX
}

Vite + Vue

src/main.ts — import CSS once
import 'termaui/dist/termaui.css';
import { createApp } from 'vue';
// rest of your entry point...
Root component — call terma.prepareAll() in onMounted
<script setup>
import { onMounted } from 'vue';
import terma from 'termaui';
onMounted(() => {
  terma.prepareAll();
});
</script>
<template><slot /></template>

SvelteKit

src/routes/+layout.svelte
<script>
  import 'termaui/dist/termaui.css';
  import { onMount } from 'svelte';
  import terma from 'termaui';
  onMount(() => {
    terma.prepareAll();
  });
</script>
<slot />

Quick Start

Three things to render Tibetan properly: the stylesheet, lang="bo" on your element, and the classes you need.

HTML
<!-- 1. Add the stylesheet -->
<link rel="stylesheet" href="termaui.css">

<!-- 2. Use lang="bo" + termaUI classes -->
<p class="tr-jomolhari tr-guard" lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</p>

Why lang="bo"?

termaUI uses the :lang(bo) selector to apply sensible defaults — font family, line-height, word-breaking — to all Tibetan content. Always set lang="bo" on elements containing Tibetan text, or on a parent <div> wrapping them.

The base reset provides: font-family: Jomolhari, line-height: 1.8, word-break: keep-all, overflow-wrap: anywhere, and font-size: 1.1em. These kick in automatically with lang="bo".

Fonts

36 Tibetan typefaces — each available via a single tr-* class. Each class sets font-family with correct WOFF2 fallback chains. All fonts are loaded on demand using unicode-range: U+0F00-0FFF, so Latin text is never affected.

HTML — basic usage
<p class="tr-jomolhari tr-guard" lang="bo">བཀྲ་ཤིས་བདེ་ལེགས།</p>
<p class="tr-monlam tr-guard" lang="bo">བཀྲ་ཤིས་བདེ་ལེགས།</p>
<p class="tr-drutsa tr-guard" lang="bo">བཀྲ་ཤིས་བདེ་ལེགས།</p>
Uchen — 24 fonts
.tr-jomolhariJomolhariབཀྲ་ཤིས་བདེ་ལེགས།
.tr-ddc-uchenDDC Uchenབཀྲ་ཤིས་བདེ་ལེགས།
.tr-notoNoto Serif Tibetanབཀྲ་ཤིས་བདེ་ལེགས།
.tr-machine-uniTibetan Machine Uniབཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlamMonlam Bodyigབཀྲ་ཤིས་བདེ་ལེགས།
.tr-babelstoneBabelStone Tibetanབཀྲ་ཤིས་བདེ་ལེགས།
.tr-babelstone-slimBabelStone Slimབཀྲ་ཤིས་བདེ་ལེགས།
.tr-gangjieGangJie Uchenབཀྲ་ཤིས་བདེ་ལེགས།
.tr-jamyangJamyang Monlam Uchenབཀྲ་ཤིས་བདེ་ལེགས།
.tr-panchenPanchen Tsukringབཀྲ་ཤིས་བདེ་ལེགས།
.tr-riwocheRiwoche Dhodriབཀྲ་ཤིས་བདེ་ལེགས།
.tr-sadriSadri Yigchenབཀྲ་ཤིས་བདེ་ལེགས།
.tr-ddc-rinzinDDC Rinzinབཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-ouchan1Monlam OuChan 1བཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-ouchan2Monlam OuChan 2བཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-ouchan3Monlam OuChan 3བཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-ouchan4Monlam OuChan 4བཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-ouchan5Monlam OuChan 5བཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-paytsikMonlam PayTsikབཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-tikrangMonlam Tikrangབཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-tiktongMonlam TikTongབཀྲ་ཤིས་བདེ་ལེགས།
.tr-qomolangma-sarchenQomolangma Sarchenབཀྲ་ཤིས་བདེ་ལེགས།
.tr-qomolangma-betsuQomolangma Betsuབཀྲ་ཤིས་བདེ་ལེགས།
.tr-qomolangma-tsutongQomolangma Tsutongབཀྲ་ཤིས་བདེ་ལེགས།
Drutsa (Cursive) — 6 fonts
.tr-drutsaQomolangma-Drutsaབཀྲ་ཤིས་བདེ་ལེགས།
.tr-gangjie-drutsaGangJie Drutsaབཀྲ་ཤིས་བདེ་ལེགས།
.tr-khampa-drutsaKhampa Dedri Drutsaབཀྲ་ཤིས་བདེ་ལེགས།
.tr-sadri-drutsaSadri Drutsaབཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-dutsa1Monlam Dutsa 1བཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-dutsa2Monlam Dutsa 2བཀྲ་ཤིས་བདེ་ལེགས།
Modern / Sans — 3 fonts
.tr-noto-sansNoto Sans Tibetanབཀྲ་ཤིས་བདེ་ལེགས།
.tr-misansMiSans Tibetanབཀྲ་ཤིས་བདེ་ལེགས།
.tr-monlam-sansMonlam Uni Sansབཀྲ་ཤིས་བདེ་ལེགས།
Semi-cursive — 3 fonts
.tr-joyigJoyigབཀྲ་ཤིས་བདེ་ལེགས།
.tr-chuyigKhampa Dedri Chuyigབཀྲ་ཤིས་བདེ་ལེགས།
.tr-bechuKhampa Dedri Bechuབཀྲ་ཤིས་བདེ་ལེགས།

Noto Serif Tibetan also ships a full weight axis: .tr-noto-thin, .tr-noto-light, .tr-noto-medium, .tr-noto-semibold, .tr-noto-bold, .tr-noto-extrabold, .tr-noto-black.  ·  Preview all 36 fonts with live text →

Effects

Visual effects that work with Tibetan script — gradient text, glows, outlines, and glass panels. These use standard CSS techniques (background-clip: text, text-shadow, backdrop-filter) so they compose with any font class.

.tr-text-rainbow

Multi-color horizontal gradient across the text. Uses background-clip: text.

.tr-text-rainbow Gradient text

བཀྲ་ཤིས་བདེ་ལེགས། བོད་ཀྱི་སྐད་ཡིག

HTML
<p class="tr-jomolhari tr-guard tr-text-rainbow" lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</p>

.tr-text-saffron

Warm saffron-to-gold gradient inspired by monastic robes. Ideal for spiritual and ceremonial text.

.tr-text-saffron Gradient text

བཀྲ་ཤིས་བདེ་ལེགས། བོད་ཀྱི་སྐད་ཡིག

HTML
<p class="tr-jomolhari tr-guard tr-text-saffron" lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</p>

.tr-text-ink

Subtle dark vertical gradient evoking traditional ink on paper. Best on light backgrounds.

.tr-text-ink Gradient text

བཀྲ་ཤིས་བདེ་ལེགས། བོད་ཀྱི་སྐད་ཡིག

HTML
<!-- Use on a light background -->
<p class="tr-jomolhari tr-guard tr-text-ink" lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</p>

.tr-glow-aurora

Pulsing teal aurora glow with text-shadow animation. Can be combined with gradient text using the data-text attribute.

.tr-glow-aurora Animated glow

བཀྲ་ཤིས་བདེ་ལེགས། བོད་ཀྱི་སྐད་ཡིག

HTML
<p class="tr-jomolhari tr-guard tr-glow-aurora" lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</p>

<!-- Combine with gradient text: add data-text -->
<h1 class="tr-text-rainbow tr-glow-aurora"
    data-text="བཀྲ་ཤིས་བདེ་ལེགས།"
    lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</h1>

.tr-outline-gold

Gold stroke outline with transparent fill. Uses -webkit-text-stroke. For a filled version, use .tr-outline-gold-fill.

.tr-outline-gold Text stroke

བཀྲ་ཤིས་བདེ་ལེགས། བོད་ཀྱི་སྐད་ཡིག

HTML
<p class="tr-jomolhari tr-guard tr-outline-gold" lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</p>

<!-- Filled version (gold stroke + dark fill) -->
<p class="tr-jomolhari tr-guard tr-outline-gold-fill" lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</p>

.tr-glass

Frosted glass panel with backdrop-filter: blur. Apply to a container, not text. Also available as .tr-glass-dark for darker backgrounds.

.tr-glass Container effect

བཀྲ་ཤིས་བདེ་ལེགས། བོད་ཀྱི་སྐད་ཡིག་དཔེ་མཚོན།

HTML
<div class="tr-glass">
  <p class="tr-jomolhari tr-guard" lang="bo">
    བཀྲ་ཤིས་བདེ་ལེགས།
  </p>
</div>

<!-- Dark variant -->
<div class="tr-glass-dark">...</div>

.tr-shimmer

Animated metallic gold sweep across text. A wide gold gradient animates left-to-right continuously, giving the glyphs a living shine. Uses background-clip: text and @keyframes.

.tr-shimmer Animated gradient

ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།

HTML
<p class="tr-jomolhari tr-guard tr-shimmer" lang="bo">
  ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།
</p>

.tr-text-fire

Bottom-to-top flame gradient — deep crimson at the base rising through orange to bright gold at the tips. A subtle brightness flicker animation adds living fire. Uses background-clip: text.

.tr-text-fire Animated gradient

ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།

HTML
<p class="tr-jomolhari tr-guard tr-text-fire" lang="bo">
  ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།
</p>

.tr-text-lapis

Deep ultramarine gradient echoing lapis lazuli — the sacred blue pigment ground from Himalayan stone and used in Tibetan thangka paintings for centuries. Uses background-clip: text.

.tr-text-lapis Gradient text

ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།

HTML
<p class="tr-jomolhari tr-guard tr-text-lapis" lang="bo">
  ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།
</p>

.tr-emboss

Carved-stone effect using multi-layer text-shadow. A light source from above creates a highlight on the upper edges and a deep shadow below, simulating script cut into warm sandstone. Unlike gradient effects, this uses color so text-shadow works natively.

.tr-emboss text-shadow

ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།

HTML
<p class="tr-jomolhari tr-guard tr-emboss" lang="bo">
  ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།
</p>

Guardian Utilities

Tibetan script has tall vowel marks (གི, གུ, གེ) and stacked consonants that get clipped by tight layouts. Guardian utilities fix these rendering issues.

.tr-guard

Adds vertical padding (padding-block: 0.25em) to prevent clipping of vowel marks and stacked consonants. Since v0.2.0, this is included in [lang="bo"] defaults — you no longer need to add .tr-guard to every element. It remains useful when you need the guard on a non-Tibetan container, or use .tr-guard-lg (0.5em) for extra-large headings.

Without .tr-guard

རྒྱལ་བའི་བསྟན་པ་རིན་པོ་ཆེ།

With .tr-guard

རྒྱལ་བའི་བསྟན་པ་རིན་པོ་ཆེ།

HTML
<p class="tr-jomolhari tr-guard" lang="bo">རྒྱལ་བའི་བསྟན་པ་རིན་པོ་ཆེ།</p>

<!-- For headings / large text -->
<h1 class="tr-jomolhari tr-guard-lg" lang="bo">...</h1>

.tr-overflow-safe

Last-resort overflow protection for constrained containers. Prevents Tibetan text from spilling out of its box when no break opportunities exist.

Important: this is not tsheg-aware line breaking. It uses overflow-wrap: anywhere which breaks at byte boundaries — potentially mid-syllable — as a fallback. For correct line-breaking at tsheg, use terma.prepare() from terma.js.

HTML
<div class="tr-overflow-safe" style="max-width: 300px">
  <p class="tr-jomolhari tr-guard" lang="bo">
    བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ།
  </p>
</div>

.tr-scale-up

Scales Tibetan text to 120% to match the visual weight of surrounding English text. Use .tr-scale-match (150%) for headings or when Tibetan needs more presence.

Without scaling

The mantra ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ། is sacred.

With .tr-scale-up

The mantra ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ། is sacred.

HTML
<p>The mantra
  <span class="tr-jomolhari tr-guard tr-scale-up tr-baseline" lang="bo">
    ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ།
  </span> is sacred.
</p>

<!-- 150% for headings -->
<h1><span class="tr-jomolhari tr-scale-match" lang="bo">...</span></h1>

.tr-baseline

Fixes vertical alignment when Tibetan appears inline with English. Sets vertical-align: middle and line-height: 1.8. Always pair with .tr-scale-up for inline use.

.tr-baseline Vertical alignment fix

In Tibetan, "hello" is བཀྲ་ཤིས་བདེ་ལེགས། — a common greeting.

HTML
<p>In Tibetan, "hello" is
  <span class="tr-jomolhari tr-guard tr-scale-up tr-baseline" lang="bo">
    བཀྲ་ཤིས་བདེ་ལེགས།
  </span> — a common greeting.
</p>

.tr-shad-pair

Prevents double-shad (། །) from splitting across lines. Wrap the sequence in a <span>. Double-shad marks verse endings and must never be separated.

.tr-shad-pair white-space: nowrap

བྱང་ཆུབ་སེམས་དཔའི་སྡེ་སྣོད་། །ཡང་དག་པའི་མཐའ་ཞེས་བྱ་བ།

HTML
...སྡེ་སྣོད་<span class="tr-shad-pair">། །</span>ཡང་དག...

.tr-nobr-tsheg

Protects non-breaking tsheg + shad sequences (e.g. ང་།) from splitting. The tsheg before shad must never cause a line break. Also fixable via terma.prepare() which auto-replaces with non-breaking tsheg (U+0F0C).

HTML
...རིང་<span class="tr-nobr-tsheg">ང་།</span> ...

Typography

Font sizes, line heights, letter spacing, and alignment utilities tuned for Tibetan script metrics. Each font size class pairs font-size with a line-height optimized for Tibetan's tall vowel marks and stacked consonants.

Font Sizes

T-shirt scale from .tr-text-sm to .tr-text-5xl. Each size sets both font-size and a paired line-height — larger text uses tighter leading, smaller text gets more breathing room.

.tr-text-sm → .tr-text-5xl 8 sizes
sm — བཀྲ་ཤིས་བདེ་ལེགས།
base — བཀྲ་ཤིས་བདེ་ལེགས།
xl — བཀྲ་ཤིས་བདེ་ལེགས།
2xl — བཀྲ་ཤིས་བདེ་ལེགས།
3xl — བཀྲ་ཤིས།
HTML
<p class="tr-jomolhari tr-guard tr-text-sm" lang="bo">...</p>  /* 0.85rem / 1.6 */
<p class="tr-jomolhari tr-guard tr-text-base" lang="bo">...</p> /* 1.1rem / 1.8  */
<p class="tr-jomolhari tr-guard tr-text-lg" lang="bo">...</p>  /* 1.4rem / 1.8  */
<p class="tr-jomolhari tr-guard tr-text-xl" lang="bo">...</p>  /* 1.75rem / 1.7 */
<p class="tr-jomolhari tr-guard tr-text-2xl" lang="bo">...</p> /* 2.25rem / 1.6 */
<p class="tr-jomolhari tr-guard tr-text-3xl" lang="bo">...</p> /* 3rem / 1.5    */
<p class="tr-jomolhari tr-guard tr-text-4xl" lang="bo">...</p> /* 4rem / 1.4    */
<p class="tr-jomolhari tr-guard tr-text-5xl" lang="bo">...</p> /* 5rem / 1.3    */

.tr-leading-*

Standalone line-height overrides. Use .tr-leading-relaxed for verse and liturgical text, .tr-leading-loose for spaced meditation text.

.tr-leading-tight → .tr-leading-loose Line height
leading-tight (1.4)
བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན། བཅོམ་ལྡན་འདས་རྒྱལ་པོའི་ཁབ་བྱ་རྒོད་ཕུང་པོའི་རི་ལ།
leading-relaxed (2.2)
བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན། བཅོམ་ལྡན་འདས་རྒྱལ་པོའི་ཁབ་བྱ་རྒོད་ཕུང་པོའི་རི་ལ།
HTML
<!-- Verse text with relaxed spacing -->
<div class="tr-jomolhari tr-guard tr-text-lg tr-leading-relaxed" lang="bo">
  <p>བྱང་ཕྱོགས་མུན་པའི་སྨག་རུམ་ན། །</p>
  <p>གངས་ལ་ཉི་མ་ཤར་འདྲ་བའི། །</p>
</div>

Text Alignment

.tr-text-left, .tr-text-center, .tr-text-right, .tr-text-justify — standard alignment utilities.

HTML
<p class="tr-jomolhari tr-guard tr-text-center" lang="bo">
  བཀྲ་ཤིས་བདེ་ལེགས།
</p>

.tr-indent

Adds text-indent: 2em for traditional Tibetan prose paragraphs.

.tr-indent text-indent: 2em

བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན། བཅོམ་ལྡན་འདས་རྒྱལ་པོའི་ཁབ་བྱ་རྒོད་ཕུང་པོའི་རི་ལ།

HTML
<p class="tr-jomolhari tr-guard tr-indent" lang="bo">
  བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ...
</p>

.tr-justify-bo

Tibetan justification. Requires terma.prepare() — without it, this class does nothing useful. Browsers treat all Tibetan text as a single unbreakable word, so text-align: justify has no break points to work with. terma.prepare() injects zero-width spaces after each tsheg, giving the browser the break opportunities it needs. This class then applies the alignment.

.tr-justify-bo Tibetan justification

བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན། བཅོམ་ལྡན་འདས་རྒྱལ་པོའི་ཁབ་བྱ་རྒོད་ཕུང་པོའི་རི་ལ། དགེ་སློང་གི་དགེ་འདུན་ཆེན་པོ་དང་། བྱང་ཆུབ་སེམས་དཔའི་དགེ་འདུན་ཆེན་པོ་དང་ཐབས་གཅིག་ཏུ་བཞུགས་ཏེ།

HTML
<p class="tr-jomolhari tr-guard tr-justify-bo" lang="bo">
  བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ...
</p>

Stacking & Complex Script

Tibetan consonants stack vertically within syllables using Unicode subjoined characters (U+0F90-U+0FBC). Sanskrit mantras and dharani contain especially complex stacks — 3 or 4 consonants deep — that need extra vertical room and explicit OpenType feature support.

.tr-stack-safe

Extra line-height and padding for text containing complex consonant stacks. Prevents clipping of tall Sanskrit mantra syllables that extend well below the baseline.

.tr-stack-safe line-height: 2.4 + padding
Sanskrit mantra with complex stacks

ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ། ཏདྱ་ཐཱ། ཨོཾ་གཏེ་གཏེ་པཱ་ར་གཏེ་པཱ་ར་སཾ་གཏེ་བོ་དྷི་སྭཱ་ཧཱ།

HTML
<!-- Text with complex stacks needs extra room -->
<p class="tr-jomolhari tr-guard tr-stack-safe tr-ligatures" lang="bo">
  ཨོཾ་མ་ཎི་པདྨེ་ཧཱུྃ། ཏདྱ་ཐཱ།...
</p>

.tr-ligatures

Explicitly enables OpenType ligature features (blws — Below Base Substitution, abvs — Above Base Substitution) that fonts use to compose vertical consonant stacks. Without these, some browsers may render stacked consonants as separate glyphs on the baseline. Since v0.2.0, these features are included in [lang="bo"] defaults — .tr-ligatures is now optional for standard Tibetan elements.

.tr-ligatures OpenType features

རྒྱུ། སྒྲུབ། བསྒྲིགས། སྤྱོད།

HTML
<p class="tr-jomolhari tr-guard tr-ligatures" lang="bo">
  རྒྱུ། སྒྲུབ། བསྒྲིགས། སྤྱོད།
</p>

.tr-yig-chung

Commentary text (ཡིག་ཆུང་།) — traditional 25% size reduction with letter-heads aligned to the top of root text. Use as an inline <span> within root text.

.tr-yig-chung Commentary size

བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན། བཅོམ་ལྡན་འདས་རྒྱལ་པོའི་ཁབ་བྱ་རྒོད་ཕུང་པོའི་རི་ལ། དགེ་སློང་གི་དགེ་འདུན་ཆེན་པོ་དང་།

HTML
<p class="tr-jomolhari tr-guard tr-ligatures" lang="bo">
  བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི...
  <span class="tr-yig-chung">འདི་སྐད་བདག་གིས་ཐོས...</span>
  དགེ་སློང་གི...
</p>

Pecha Styling

Traditional Tibetan loose-leaf manuscript format (དཔེ་ཆ།). Authentic three-column layout: abbreviated title (ཆིང་) in the left margin, main text in the center, folio number on the right — all separated by vertical red rules. Wide ~6:1 landscape ratio with double red border.

.tr-pecha

Main container: 6:1 aspect ratio, double red border, three-column grid. Use .tr-pecha-title for the left margin, .tr-pecha-body for the text, and .tr-pecha-folio for the right folio number.

.tr-pecha Manuscript container
ཤེས་རབ་སྙིང་པོ།
༄༅། །བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན། བཅོམ་ལྡན་འདས་རྒྱལ་པོའི་ཁབ་བྱ་རྒོད་ཕུང་པོའི་རི་ལ། དགེ་སློང་གི་དགེ་འདུན་ཆེན་པོ་དང་། བྱང་ཆུབ་སེམས་དཔའི་དགེ་འདུན་ཆེན་པོ་དང་ཐབས་གཅིག་ཏུ་བཞུགས་ཏེ།
HTML
<div class="tr-pecha tr-jomolhari tr-guard" lang="bo">
  <!-- Left: abbreviated title (ching) -->
  <div class="tr-pecha-title">ཤེས་རབ་སྙིང་པོ།</div>
  <!-- Center: main text -->
  <div class="tr-pecha-body">༄༅། །བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ...</div>
  <!-- Right: folio number -->
  <div class="tr-pecha-folio"></div>
</div>

.tr-pecha-dark

Gold text on dark indigo — sacred text variant (གསེར་ཡིག). The amber column separators adapt automatically.

.tr-pecha-dark Gold on indigo
རྡོ་རྗེ་གཅོད་པ།
༄༅། །བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན། བཅོམ་ལྡན་འདས་རྒྱལ་པོའི་ཁབ་བྱ་རྒོད་ཕུང་པོའི་རི་ལ། དགེ་སློང་གི་དགེ་འདུན་ཆེན་པོ་དང་། བྱང་ཆུབ་སེམས་དཔའི་དགེ་འདུན་ཆེན་པོ་དང་ཐབས་གཅིག་ཏུ་བཞུགས་ཏེ།
HTML
<div class="tr-pecha tr-pecha-dark tr-jomolhari tr-guard" lang="bo">
  <div class="tr-pecha-title">རྡོ་རྗེ་གཅོད་པ།</div>
  <div class="tr-pecha-body">༄༅། །བཅོམ་ལྡན་འདས་མ...</div>
  <div class="tr-pecha-folio"></div>
</div>

.tr-pecha-title / .tr-pecha-folio / .tr-yig-mgo

.tr-pecha-title — left margin column for the abbreviated title (ཆིང་). .tr-pecha-folio — right margin column for the folio number (ཤོག་གྲངས་). .tr-yig-mgo — add this class to a <span> to automatically prepend the traditional opening mark ༄༅།.

Full pecha with yig mgo Complete structure
བར་དོ་ཐོས་གྲོལ།
བར་དོ་ཐོས་གྲོལ་ཆེན་མོ། ཞེས་བྱ་བ་ལས། ཁྲིད་ཡིག་རིག་འཛིན་གྱི་ཕྲིན་ལས། མི་ལོ་འགར་གྱིས་མི་ཤེས་ཤིང་། ཆོས་ཀྱི་གཞི་ལ་བརྟེན་ནས་ཀུན་གྱིས་སྒྲུབ་པར་བྱ་བའི་ཕྱིར།
HTML
<div class="tr-pecha tr-jomolhari tr-guard" lang="bo">
  <div class="tr-pecha-title">བར་དོ་ཐོས་གྲོལ།</div>
  <div class="tr-pecha-body">
    <span class="tr-yig-mgo"></span>བར་དོ་ཐོས་གྲོལ...
  </div>
  <div class="tr-pecha-folio"></div>
</div>

.tr-pecha-title-rotated

Optional modifier for the title column. Rotates the label 90° counter-clockwise using transform: rotate(-90deg) — uses transform rather than writing-mode for reliable Tibetan glyph rendering.

Default (horizontal)
ཤེས་རབ།
ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན།
Rotated (vertical label)
ཤེས་རབ།
ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ། འདི་སྐད་བདག་གིས་ཐོས་པ་དུས་གཅིག་ན།
HTML
<div class="tr-pecha-title">
  <span class="tr-pecha-title-rotated">ཤེས་རབ།</span>
</div>

terma.js

JavaScript companion for termaUI that fixes problems CSS alone cannot solve. The CSS classes work without it — fonts, effects, sizes, guardian utilities, pecha, and all visual styling are CSS-only. But for correct Tibetan line breaking you need terma.js. Without it, browsers break text at every tsheg, splitting multi-syllable words mid-word by default.

CSS only — no terma.js needed
All font classes (.tr-jomolhari etc.)
All effects (.tr-text-rainbow, .tr-shimmer etc.)
Guardian utilities (.tr-guard, .tr-scale-up etc.)
Typography (.tr-text-xl, .tr-leading-* etc.)
Pecha styling (.tr-pecha, .tr-pecha-dark etc.)
Stacking (.tr-stack-safe, .tr-ligatures etc.)
.tr-shad-pair (manual wrapping)
Requires terma.js
Correct line breaking — browsers break at every tsheg without it
.tr-justify-bo — does nothing without terma.prepare()
.tr-nobr-tsheg — CSS partial fix only; terma.js automates correctly
Double-shad auto-protection (terma.js wraps them automatically)
Unicode NFC normalization for search & storage
Live ZWS maintenance in contenteditable editors
Dotted-circle artifact prevention (with terma-clusters.js)
Pixel-perfect head-mark alignment across mixed font sizes

terma.prepare(element)

Processes all Tibetan text inside the given element:

  • Inserts zero-width spaces after tsheg () for proper line-break opportunities
  • Replaces tsheg before shad with non-breaking tsheg (U+0F0C) to prevent ང་། splitting
  • Wraps double-shad (། །) with word-joiners so they stay together
HTML
<!-- Include the script (CDN) -->
<script src="https://cdn.jsdelivr.net/npm/termaui/dist/terma.js"></script>

<!-- Process a single element -->
<script>
  terma.prepare(document.querySelector('[lang="bo"]'));
</script>

<!-- Or process all Tibetan text on the page -->
<script>
  terma.prepareAll();
</script>

Combine with .tr-justify-bo for the best Tibetan justification: terma.prepare() gives browsers break points, and the CSS class handles the alignment.

terma.prepareEditable(element)

Prepares a contenteditable element for live Tibetan text entry. Calls prepare() immediately, then re-applies it on every input event (debounced 150 ms) so zero-width spaces survive further typing. Use instead of prepare() for any live-edit Tibetan surface — note-taking UIs, typing tutors, rich text editors.

termaUI automatically adds white-space: pre-wrap to [contenteditable][lang="bo"] elements to prevent ZWS from being collapsed by the browser.

JS
<!-- HTML -->
<div contenteditable="true" lang="bo" class="tr-jomolhari" id="editor"></div>

// JS — one call, no listener boilerplate
terma.prepareEditable(document.getElementById('editor'));

// Or target all [contenteditable][lang="bo"] at once
terma.prepareAllEditables();

terma.cluster(element)

Prevents dotted-circle artifacts (◌) — phantom characters that appear when a browser tries to display a combining mark (vowel sign, subjoined consonant) with no base character before it. This happens when Tibetan text is built character-by-character via JavaScript DOM operations (e.g. textContent += char).

Requires terma-clusters.js to be loaded alongside terma.js. When both are present, terma.prepare() calls clustering automatically — you only need cluster() when you want clustering without the full prepare pipeline.

HTML
<!-- Load both scripts -->
<script src="https://cdn.jsdelivr.net/npm/termaui/dist/terma-clusters.js"></script>
<script src="https://cdn.jsdelivr.net/npm/termaui/dist/terma.js"></script>

<!-- terma.prepare() now auto-clusters on every call -->
<script>
  terma.prepareAll(); // clusters + line-break fixes in one call
</script>

terma.normalize(element)

Applies Unicode NFC normalization to all text inside the element. Solves the "invisible search failure" problem: the same Tibetan syllable can be encoded as different Unicode sequences that look identical but compare as unequal strings. Normalizing to NFC before storing or searching ensures consistent matching.

  • Fixes mismatches between pre-composed and decomposed sequences
  • Run on user input before database queries, or on content at render time
  • Note: NFC does not fix wrong character order (dotted circle bugs) — that requires fixing the source data or input method
JS
// Normalize a single element
terma.normalize(document.querySelector('[lang="bo"]'));

// Or normalize all Tibetan text on the page
terma.normalizeAll();

// Normalize a string directly (e.g. before a search query)
const query = userInput.normalize('NFC');

terma.alignHeadMarks(element)

Pixel-perfect head-mark alignment for mixed font sizes. Tibetan script aligns from the head mark (མགོ་ཅན།) at the top of each letter, but CSS uses baseline (bottom) alignment. When differently-sized Tibetan spans appear inline, head marks scatter vertically. This function fixes that.

prepare() calls this automatically as its final step — you only need alignHeadMarks() when you change font sizes dynamically after prepare() has already run.

  • CSS Layer 1 (instant, ~95%): termaui.css applies vertical-align: text-top to sized spans inside [lang="bo"] — works without JavaScript
  • JS Layer 2 (pixel-perfect): Measures each font's ascent ratio via Canvas TextMetrics and computes a per-span vertical-align offset to within 0.04 px
  • Latin-only spans are detected and classified as .tt-latin — reverted to baseline so English text is unaffected
  • Automatically re-runs on document.fonts.ready to correct measurements after webfont swap
JS
// Re-align after dynamically changing a span's font-size
terma.alignHeadMarks(document.querySelector('[lang="bo"]'));

// Or re-align all Tibetan containers on the page
terma.alignHeadMarksAll();

// Measure a font's ascent ratio (advanced use)
const ratio = terma.measureAscentRatio('Jomolhari');
// → 0.740 (Jomolhari's head-mark height as fraction of font-size)

Mixed Language Patterns

Real-world apps mix Tibetan and English. Here are the recommended patterns.

Inline Tibetan in English text — .tr-mixed

Add .tr-mixed to any inline Tibetan <span>. It scales the Tibetan text to 1.15em and shifts the baseline by -0.15em so both scripts sit on the same visual line — no manual font-size or vertical-align needed.

Inline pattern Most common

The Heart Sutra (ཤེས་རབ་སྙིང་པོ།) is one of the most important texts in Mahayana Buddhism. Its full title in Tibetan is བཅོམ་ལྡན་འདས་མ་ཤེས་རབ་ཀྱི་ཕ་རོལ་ཏུ་ཕྱིན་པའི་སྙིང་པོ།

HTML
<p>The Heart Sutra
  (<span class="tr-jomolhari tr-mixed" lang="bo">
    ཤེས་རབ་སྙིང་པོ།
  </span>) is one of the most
  important texts in Mahayana Buddhism.
</p>

Tibetan block in English page

For a full block of Tibetan text (a verse, prayer, or paragraph), use a <div> or <blockquote> with lang="bo".

Block pattern Verse / prayer

Milarepa's Homage:

ན་མོ་གུ་རུ།

མར་པ་ལོ་ཙཱ་བཀའ་དྲིན་ཅན།

མི་ལ་རས་པ་རྣལ་འབྱོར་པ།

HTML
<blockquote class="tr-jomolhari tr-guard tr-overflow-safe" lang="bo">
  <p>ན་མོ་གུ་རུ།</p>
  <p>མར་པ་ལོ་ཙཱ་བཀའ་དྲིན་ཅན།</p>
  <p>མི་ལ་རས་པ་རྣལ་འབྱོར་པ།</p>
</blockquote>

UI labels and navigation

For bilingual interfaces — nav items, buttons, labels — use the inline pattern at smaller sizes.

HTML
<nav>
  <a href="/home">
    Home / <span class="tr-noto tr-guard tr-scale-up tr-baseline" lang="bo">གཙོ་ངོས།</span>
  </a>
  <a href="/about">
    About / <span class="tr-noto tr-guard tr-scale-up tr-baseline" lang="bo">སྐོར།</span>
  </a>
</nav>

Font size normalization

Since v0.2.0, all 44 @font-face declarations include a size-adjust descriptor measured against Jomolhari as the reference. Fonts that naturally render large (e.g. Qomolangma-Drutsa) are scaled down; fonts that render small (e.g. Monlam Uni OuChan variants) are scaled up. The result: you can swap fonts with a single class change and body text stays the same visual size — no per-font font-size overrides needed.

HTML
<!-- All three render at the same visual size — no font-size override -->
<p class="tr-jomolhari tr-text-lg" lang="bo">བཀྲ་ཤིས་བདེ་ལེགས།</p>
<p class="tr-noto tr-text-lg" lang="bo">བཀྲ་ཤིས་བདེ་ལེགས།</p>
<p class="tr-babelstone tr-text-lg" lang="bo">བཀྲ་ཤིས་བདེ་ལེགས།</p>

Cheat sheet — v0.2.0

Quick reference for the most common class combinations. Since v0.2.0, .tr-guard and .tr-ligatures are included in [lang="bo"] defaults and no longer need to be listed explicitly.

Common Combos
/* Body text */
tr-jomolhari

/* Inline Tibetan in English — auto-scales & aligns */
tr-jomolhari tr-mixed

/* Decorative heading */
tr-drutsa tr-guard-lg tr-text-saffron

/* Modern UI text */
tr-noto tr-overflow-safe

/* Verse in a glass card */
tr-glass > tr-jomolhari tr-overflow-safe

/* Live contenteditable editor */
tr-jomolhari + contenteditable lang="bo" + terma.prepareEditable(el)

What's New

v0.3.0 — Lean package, extended font library

  • npm package reduced from 12.9 MB → ~600 KB — only 4 curated fonts now ship with the npm package: Jomolhari, Monlam Bodyig, Qomolangma-UchenSarchen, and Qomolangma-Drutsa. These cover traditional Uchen, modern digital Uchen, scholarly Uchen, and cursive (drutsa) — the essential four.
  • Extended font library (termaui-fonts) — the remaining 40+ fonts are available as a separate CDN-only package. Browsers only download fonts that are actually used on the page, so there is no performance penalty for having a large font list in the stylesheet.
  • Fallbacks updated — all font-family fallbacks in utility classes now reference only bundled fonts. If an extended font fails to load, Jomolhari or Qomolangma-Drutsa takes over gracefully.
  • :lang(bo) default stack updated — base font stack is now Jomolhari, Qomolangma-UchenSarchen, Monlam Bodyig, serif.

v0.2.0

CSS

  • size-adjust on all 44 @font-face declarations — every Tibetan font is normalized against Jomolhari (ascent = 74 px reference) so swapping fonts with a single class change keeps body text at the same visual size
  • [lang="bo"] defaults now include .tr-guard and .tr-ligatures — padding-block and OpenType ligatures are applied automatically; these classes are no longer required on every element
  • .tr-mixed — new utility for inline Tibetan inside English text; auto-scales to 1.15em and shifts baseline by -0.15em
  • Head-mark alignment (Layer 1) — sized spans inside [lang="bo"] get vertical-align: text-top automatically; Latin-only spans classified as .tt-latin revert to baseline

terma.js

  • terma.prepareEditable(element) — prepares a contenteditable element for live Tibetan text entry with debounced re-processing on every input event
  • terma.prepareAllEditables() — convenience wrapper that targets all [contenteditable][lang="bo"] elements
  • Auto-clustering in prepare() — when terma-clusters.js is loaded, prepare() automatically wraps combining marks into .tr-cluster spans to prevent dotted-circle artifacts
  • Head-mark alignment (Layer 2)terma.prepare() now auto-aligns head marks across mixed font sizes using Canvas TextMetrics; pixel-perfect to 0.04 px
  • terma.alignHeadMarks(el) / terma.alignHeadMarksAll() — explicit alignment API for dynamic size changes after prepare() has already run
  • terma.measureAscentRatio(fontFamily) — exposed Canvas ascent measurement for advanced use; cached per font family
  • Automatic re-alignment on document.fonts.ready — ascent cache clears and all aligned containers re-measure after webfont swap