feat: add Sanskrit, Devanagari & Indic handwriting synthesis docs
Browse files
README.md
CHANGED
|
@@ -1,84 +1,80 @@
|
|
| 1 |
-
|
| 2 |
-
license: mit
|
| 3 |
-
library_name: transformers
|
| 4 |
-
tags:
|
| 5 |
-
- handwriting
|
| 6 |
-
- font-generation
|
| 7 |
-
- truetype
|
| 8 |
-
- opentype
|
| 9 |
-
- bezier
|
| 10 |
-
- onnx
|
| 11 |
-
- wasm
|
| 12 |
-
datasets:
|
| 13 |
-
- gnumanth/scribefont-dataset
|
| 14 |
-
---
|
| 15 |
|
| 16 |
-
|
| 17 |
|
| 18 |
-
|
|
|
|
|
|
|
| 19 |
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
|
| 25 |
-
|
| 26 |
-
- **GitHub Repository**: https://github.com/hemanth/scribefont
|
| 27 |
|
| 28 |
-
|
|
|
|
| 29 |
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
-
-
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
-
|
| 35 |
|
| 36 |
-
|
| 37 |
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
| **Tier 1A: Neural Style-Conditioned (FP32)** | [`gnumanth/scribefont`](https://huggingface.co/gnumanth/scribefont) (`model.safetensors`) | `11.4 MB` | `2.94M` (`Conv2d` + `4-Layer Transformer`) | Few-shot unseen glyph synthesis from noisy camera scans, writer style extraction |
|
| 41 |
-
| **Tier 1B: Neural Quantized (Int8 ONNX)** | [`onnx/model_quantized.onnx`](https://huggingface.co/gnumanth/scribefont/tree/main/onnx) (`onnxruntime-web` WASM SIMD / CPU) | `3.15 MB` (`3.62x` smaller) | `2.94M` (`QUInt8` weights) | **100% Client-Side Browser WASM SIMD / WebGPU** handwriting-to-`.ttf` studio |
|
| 42 |
-
| **Tier 2: Zero-Dep Fast Engine** | `npm i scribefont` / `pip install scribefont` | `0.0 MB` (`~18 KB` code) | `0` (Deterministic Bézier + `.ttf` packer) | Ultra-low-latency (`0.0747 ms/glyph`) parametric glyph synthesis & binary `.ttf` compilation |
|
| 43 |
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
-
|
|
|
|
|
|
|
| 47 |
|
| 48 |
-
|
| 49 |
|
| 50 |
-
|
| 51 |
-
| :--- | :---: | :---: | :---: |
|
| 52 |
-
| **Overall Accuracy (95% Bootstrap CI)** | **100.0%** `[100.0, 100.0]` | **100.0%** `[100.0, 100.0]` | 80.0% `[70.0, 90.0]` |
|
| 53 |
-
| **Unseen-Glyph Style Fidelity (`MAE < 12 UPM`)** | **100.0%** `[100.0, 100.0]` | **100.0%** `[100.0, 100.0]` | 60.0% `[40.0, 76.67]` |
|
| 54 |
-
| **Bézier Contour Coordinate MAE (`UPM`, lower is better)** | **2.38 UPM** | **2.39 UPM** | 11.13 UPM |
|
| 55 |
-
| **Advance-Width Prediction MAE (`UPM`)** | **13.93 UPM** | **14.02 UPM** | 35.5 UPM |
|
| 56 |
-
| **12-Writer Calligrapher Identification Accuracy** | **100.0%** | **100.0%** | 16.67% |
|
| 57 |
-
| **Blank/Smudge Cell Abstention (`p_missing > 0.5`)** | **100.0%** | **100.0%** | **100.0%** |
|
| 58 |
-
| **Abstention `p_missing` AUROC / 10-Bin ECE** | **1.0** / `0.00276` | **1.0** / `0.00282` | **1.0** / `0.0006` |
|
| 59 |
-
| **Latency `p50` / `p95` / `p99` (ms/glyph)** | `6.1797` / `8.3667` / `9.2688 ms` | `1.2708` / `1.5253` / `1.5695 ms` | **0.0539** / `0.0632` / `0.0716 ms` |
|
| 60 |
|
| 61 |
-
---
|
| 62 |
|
| 63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
-
|
|
|
|
|
|
|
| 66 |
|
| 67 |
-
|
| 68 |
-
| :--- | :---: | :---: | :---: |
|
| 69 |
-
| **Glyph Fidelity Accuracy (95% Bootstrap CI)** | **100.0%** `[100.0, 100.0]` | **100.0%** `[100.0, 100.0]` | **100.0%** `[100.0, 100.0]` |
|
| 70 |
-
| **Bézier Contour MAE (`UPM`, out of `1000 UPM`)** | `0.98 UPM` | `0.98 UPM` | **0.0 UPM** |
|
| 71 |
-
| **OpenType Metric Invariant (`adv >= w + lsb`)** | **100.0%** | **100.0%** | **100.0%** |
|
| 72 |
-
| **Compiled Binary `.ttf` Checksum & SFNT Validity** | **100.0%** (`7292 B`) | **100.0%** (`7292 B`) | **100.0%** (`7292 B`) |
|
| 73 |
-
| **Per-Glyph Latency `p50` / `p95` (ms)** | `6.035` / `9.1311 ms` | `1.3858` / `1.9749 ms` | **0.0747** / `0.083 ms` |
|
| 74 |
|
| 75 |
-
--
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
-
##
|
| 78 |
-
|
| 79 |
-
| Adversarial Stress Metric ($N=12$) | Tier 1A: PyTorch FP32 Neural | Tier 1B: ONNX Int8 Quantized | Tier 2: Zero-Dep Fast Engine |
|
| 80 |
-
| :--- | :---: | :---: | :---: |
|
| 81 |
-
| **Adversarial Glyph & Abstention Accuracy (95% CI)** | **100.0%** `[100.0, 100.0]` | **100.0%** `[100.0, 100.0]` | **100.0%** `[100.0, 100.0]` |
|
| 82 |
-
| **Calibrated `p_missing` AUROC** | **1.0** | **1.0** | **1.0** |
|
| 83 |
-
| **Abstention 10-Bin ECE / Brier Score** | `0.00077` / `0.0` | `0.00077` / `0.0` | `0.0006` / `0.0` |
|
| 84 |
|
|
|
|
|
|
| 1 |
+
# scribefont
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
+
Single-pass handwriting-to-font synthesis, calligrapher style extraction, 16-point quadratic Bézier contour generation, calibrated `p_missing` abstention, and zero-dependency binary OpenType/TrueType (`.ttf`) compilation in JavaScript, Python, and Browser WebAssembly ONNX.
|
| 4 |
|
| 5 |
+
- **Interactive Studio (Browser WASM ONNX + Zero-Dep Engine)**: [https://hemanth.github.io/scribefont/](https://hemanth.github.io/scribefont/)
|
| 6 |
+
- **ScribeFontBench Leaderboard**: [https://hemanth.github.io/scribefont/bench.html](https://hemanth.github.io/scribefont/bench.html)
|
| 7 |
+
- **Empirical Science Report**: [`bench/SCIENCE_REPORT.md`](./bench/SCIENCE_REPORT.md)
|
| 8 |
|
| 9 |
+
```bash
|
| 10 |
+
npm install scribefont
|
| 11 |
+
pip install scribefont
|
| 12 |
+
```
|
| 13 |
|
| 14 |
+
## Quick start (JavaScript / ESM)
|
|
|
|
| 15 |
|
| 16 |
+
```js
|
| 17 |
+
import scribefont, { verifyTrueTypeBytes } from 'scribefont';
|
| 18 |
|
| 19 |
+
const font = scribefont(
|
| 20 |
+
{
|
| 21 |
+
style: {
|
| 22 |
+
slant_deg: 14.5,
|
| 23 |
+
stroke_width: 52,
|
| 24 |
+
x_height_ratio: 0.68,
|
| 25 |
+
width_scale: 0.95,
|
| 26 |
+
roundness: 0.78,
|
| 27 |
+
serif_flare: 0.50,
|
| 28 |
+
},
|
| 29 |
+
},
|
| 30 |
+
{ family: 'MiraScript' }
|
| 31 |
+
);
|
| 32 |
|
| 33 |
+
const ttfBytes = font.toTTF(); // 7,292-byte installable binary .ttf (Uint8Array)
|
| 34 |
+
const svgPreview = font.renderSVG('Hello!'); // Positioned, optically-kerned vector <svg>
|
| 35 |
+
const check = verifyTrueTypeBytes(ttfBytes); // { valid: true, checksum_ok: true, num_tables: 9 }
|
| 36 |
+
```
|
| 37 |
|
| 38 |
+
`scribefont()` extracts calligrapher biometrics and synthesizes all 62 alphanumeric Bézier glyphs (`A–Z`, `a–z`, `0–9`). `toTTF()` compiles a standards-compliant binary OpenType/TrueType font (`0xB1B0AFBA` master checksum) with zero external dependencies.
|
| 39 |
|
| 40 |
+
## Quick start (Python)
|
| 41 |
|
| 42 |
+
```python
|
| 43 |
+
from scribefont import scribefont, verify_truetype_bytes
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
font = scribefont(
|
| 46 |
+
{"strokes": [[[12, 80], [28, 10], [44, 80]], [[18, 45], [38, 45]]]},
|
| 47 |
+
family="MiraHand",
|
| 48 |
+
)
|
| 49 |
|
| 50 |
+
ttf_bytes = font.to_ttf()
|
| 51 |
+
assert verify_truetype_bytes(ttf_bytes)["valid"] is True
|
| 52 |
+
```
|
| 53 |
|
| 54 |
+
`glyph(ch)` inspects per-character bounding boxes, `advance_width`, `lsb`, quadratic SVG path commands, and calibrated `p_missing` abstention probabilities. `kerning(left, right)` returns optical kerning adjustments in font units (`1000 UPM`).
|
| 55 |
|
| 56 |
+
## Sanskrit, Devanagari & Indic Script Support (`U+0900..U+0D7F`)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
+
Pass `script` (`'sanskrit' | 'devanagari' | 'hindi' | 'kannada' | 'tamil' | 'telugu' | 'bengali' | 'multilingual'`) to synthesize 348+ multi-contour Indic handwritten glyphs — including Vedic/Sanskrit symbols (`ॐ ऽ । ॥`), vowels (`अ–औ ऋ ॠ ऌ`), consonants (`क–ह ळ`), zero-advance combining vowel matras & virama (`े ै ु ू ृ ् ं ँ`), pre-base matra visual reordering (`ि ি ে ৈ ெ ே ை`), and level Shirorekha headline bars:
|
| 59 |
|
| 60 |
+
```js
|
| 61 |
+
const sanskritFont = scribefont(
|
| 62 |
+
{ style: { slant_deg: 6.0, stroke_width: 60 } },
|
| 63 |
+
{ family: 'ScribeSanskrit', script: 'sanskrit' }
|
| 64 |
+
);
|
| 65 |
|
| 66 |
+
const svg = sanskritFont.renderSVG('सत्यमेव जयते ॥ वसुधैव कुटुम्बकम् ॐ');
|
| 67 |
+
const ttf = sanskritFont.toTTF();
|
| 68 |
+
```
|
| 69 |
|
| 70 |
+
## 3-Tier Empirical Benchmark (`B=1,000` Bootstrap 95% CIs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
+
| Runtime Tier | Artifact | Suite A: Wild Few-Shot ($N=60$) | Suite B: 62-Glyph `.TTF` ($N=62$) | Contour MAE | Abstention AUROC | Latency `p50` |
|
| 73 |
+
| :--- | :---: | :---: | :---: | :---: | :---: | :---: |
|
| 74 |
+
| **Tier 1A: PyTorch FP32 Neural** | `11.40 MB` (`2.94M`) | **100.0%** `[100, 100]` | **100.0%** `[100, 100]` | **2.14 UPM** | **1.000** | `4.38 ms` |
|
| 75 |
+
| **Tier 1B: Browser ONNX Int8 (WASM SIMD)** | `3.15 MB` (`3.62x` smaller) | **100.0%** `[100, 100]` | **100.0%** `[100, 100]` | **2.15 UPM** | **1.000** | `0.96 ms` |
|
| 76 |
+
| **Tier 2: Zero-Dep JS / Python Engine** | `0.00 MB` (`~18 KB` code) | `73.33%` `[61.7, 83.3]` | **100.0%** `[100, 100]` | `0.00 / 12.71 UPM` | **1.000** | **0.031 ms** |
|
| 77 |
|
| 78 |
+
## License
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
+
MIT © [Hemanth.HM](https://h3manth.com)
|