Sanskrit Developer Guide (Rust & WASM)
Project Vyasa provides two primary integration pathways for developers building Sanskrit computational applications:
- Direct Rust Crates: For native applications, backend services, high-throughput pipelines, and command-line tools.
- WebAssembly (WASM) Bridge (
@project-vyasa/sanskrit-wasm): For web applications, browser extensions, Svelte/React user interfaces, and Node.js runtimes.
1. Architectural Comparison
Section titled “1. Architectural Comparison”| Dimension | Direct Rust Crates | WebAssembly Bridge (@project-vyasa/sanskrit-wasm) |
|---|---|---|
| Target Runtime | Native OS (macOS, Linux, Windows, bare-metal no_std) |
Web Browsers, SvelteKit, React, Electron, Node.js |
| Distribution | Cargo workspace / crates.io |
NPM package (@project-vyasa/sanskrit-wasm) / pkg/ |
| Dependencies | Zero external dependencies (no_std ready) |
wasm-bindgen, serde-wasm-bindgen |
| Binary Overhead | Direct native compilation | 133 KB .wasm binary (opt-level s) |
| Execution Latency | Sub-microsecond native execution | <1ms JIT-compiled in-browser execution |
| Vedic Accents | Lossless preservation across all 11 scripts | Lossless preservation across all 11 scripts |
2. Option A: Direct Rust Crates
Section titled “2. Option A: Direct Rust Crates”If you are developing in Rust, add the crates directly to your Cargo.toml:
[dependencies]vyasa-phonetics = { path = "../crates/vyasa-phonetics" }vyasa-lipi = { path = "../crates/vyasa-lipi" }vyasa-patha = { path = "../crates/vyasa-patha" }Direct Rust Examples
Section titled “Direct Rust Examples”1. Transliteration (vyasa-lipi)
Section titled “1. Transliteration (vyasa-lipi)”use vyasa_lipi::{detect_script, transliterate, Script};
fn main() { let deva = "अ॒ग्निमी॑ळे पु॒रोहि॑तम्";
// Auto-detect script let detected = detect_script(deva); // Some(Script::Devanagari)
// Transliterate with full Vedic pitch accent preservation let telu = transliterate(deva, Script::Devanagari, Script::Telugu); assert_eq!(telu, "అ॒గ్నిమీ॑ళే పు॒रोహి॑తమ్");}2. Recitation: Krama & Jaṭā (vyasa-patha)
Section titled “2. Recitation: Krama & Jaṭā (vyasa-patha)”use vyasa_patha::{parse_pada_patha, generate_krama_patha, format_krama_patha, generate_jata, Script};
fn main() { let pada_text = "अ॒ग्निम् । ई॒ळे॒ । पु॒रो-हि॑तम् ।"; let padas = parse_pada_patha(pada_text);
// Generate Krama steps let steps = generate_krama_patha(&padas); let krama_output = format_krama_patha(&steps); println!("Krama:\n{}", krama_output); // => "अ॒ग्निमी॑ळे । ई॒ळे॒ पु॒रोहि॑तम् । पु॒रो-हि॑तम् । पु॒रोहि॑तमिति॑ पु॒रो-हि॑तम् ॥"
// Generate Jaṭā (1-2, 2-1, 1-2 with Abhinihita reverse Sandhi) let jata_output = generate_jata(pada_text); println!("Jaṭā:\n{}", jata_output); // => "अ॒ग्निमी॑ळ ई॒ळे॒ऽग्निर॒ग्निमी॑ळे । ई॒ळे॒ पु॒रोहि॑तं पु॒रोहि॑तमी॑ळ ई॒ळे॒ पु॒रोहि॑तं पु॒रोहि॑तमिति॑ पु॒रो-हि॑तम् ।"}3. Phonetics & Śiva Sūtras (vyasa-phonetics)
Section titled “3. Phonetics & Śiva Sūtras (vyasa-phonetics)”use vyasa_phonetics::{Pratyahara, SHIVA_SUTRAS, Varna, Consonant, sthana, abhyantara_prayatna, is_ghosha};
fn main() { // Resolve Pāṇinian Pratyāhāras let ac = Pratyahara::from_name("ac").unwrap(); let hal = Pratyahara::from_name("hal").unwrap();
// Articulatory classification let k = Varna::Consonant(Consonant::K); let places = sthana(&k); // [Sthana::Kantha] let effort = abhyantara_prayatna(&k); // AbhyantaraPrayatna::Sprshta let voiced = is_ghosha(&k); // false}4. Krishna Yajurveda Phonology (vyasa-phonetics)
Section titled “4. Krishna Yajurveda Phonology (vyasa-phonetics)”use vyasa_phonetics::{ karana, sthana, classify_taittiriya_svarita, should_double_in_taittiriya, Karana, Sthana, Svara, SvaritaJunctureContext, TaittiriyaSvarita, Varna, Consonant, Ayogavaha,};
fn main() { // 1. Active Articulator (Karaṇa) vs Passive Place (Sthāna) under TPr Ch. 2 let c = Varna::Consonant(Consonant::C); assert_eq!(karana(&c), Karana::Jihvopamadhya); // Tongue blade/edges assert_eq!(sthana(&c), vec![Sthana::Talu]); // Hard palate
// 2. 8-fold Svarita classification under TPr Ch. 20 let kshaipra = classify_taittiriya_svarita( Svara::Svarita, SvaritaJunctureContext::SemivowelSandhi, ); assert_eq!(kshaipra, Some(TaittiriyaSvarita::Kshaipra));
// 3. Consonant gemination (Dvitva) under TPr Ch. 14 // In "arkaḥ", k preceded by r doubles before a vowel let r = Varna::Consonant(Consonant::R); assert!(should_double_in_taittiriya(Some(&r), Consonant::K, None));}3. Option B: WebAssembly (@project-vyasa/sanskrit-wasm)
Section titled “3. Option B: WebAssembly (@project-vyasa/sanskrit-wasm)”The WASM bridge compiles the three Rust engines into an ultra-fast, 133 KB WebAssembly bundle that runs 100% in the client browser with zero backend requests.
Installation
Section titled “Installation”In your web application (e.g. apps/sanskrit-studio in vyasa-apps):
{ "dependencies": { "@project-vyasa/sanskrit-wasm": "file:../../../../vyutils/crates/vyasa-sanskrit-wasm/pkg" }}Module Initialization
Section titled “Module Initialization”Before calling any WASM functions in the browser, initialize the module:
import init from '@project-vyasa/sanskrit-wasm';
// Call once on application startup (e.g. onMount in Svelte)await init();4. WebAssembly Exported Functions Reference
Section titled “4. WebAssembly Exported Functions Reference”Below is a complete reference with a dedicated code example for each of the 19 exported functions.
import init, { transliterate, detect_script, get_supported_scripts, generate_krama, generate_krama_text, generate_jata, generate_jata_text, generate_ghana, generate_ghana_text, parse_padas, get_shiva_sutras, get_pratyahara_sounds, check_pratyahara_contains, inspect_varna, analyze_syllables, get_taittiriya_svaritas, inspect_taittiriya_varna, check_taittiriya_dvitva, classify_taittiriya_svarita_by_context} from '@project-vyasa/sanskrit-wasm';Function 1: transliterate
Section titled “Function 1: transliterate”Transliterates text between any of the 11 supported Indic, Roman, and ASCII scripts while maintaining 100% preservation of Vedic pitch accents (Anudātta, Udātta, Svarita, Dīrgha Svarita).
const result = transliterate( "अ॒ग्निमी॑ळे पु॒रोहि॑तम्", // input text "devanagari", // source script "telugu" // target script);
console.log(result);// Output: "అ॒గ్నిమీ॑ళే పు॒रोహి॑తమ్"Function 2: detect_script
Section titled “Function 2: detect_script”Automatically detects the script of the provided Sanskrit text by analyzing Unicode codepoints.
const script1 = detect_script("धर्मक्षेत्रे कुरुक्षेत्रे");console.log(script1); // "Devanagari"
const script2 = detect_script("ధర్మక్షేత్రే కురుక్షేత్రే");console.log(script2); // "Telugu"
const script3 = detect_script("dharmakṣetre kurukṣetre");console.log(script3); // "IAST"Function 3: get_supported_scripts
Section titled “Function 3: get_supported_scripts”Returns metadata for all 11 supported scripts, including family classification (is_indic) and Vedic pitch accent capabilities (has_vedic_pitch).
const scripts = get_supported_scripts();
console.log(scripts);/* Output:[ { id: "devanagari", name: "Devanagari (देवनागरी)", is_indic: true, has_vedic_pitch: true }, { id: "telugu", name: "Telugu (తెలుగు)", is_indic: true, has_vedic_pitch: true }, { id: "kannada", name: "Kannada (ಕನ್ನಡ)", is_indic: true, has_vedic_pitch: true }, { id: "grantha", name: "Grantha (𑌗𑍍𑌰𑌨𑍍𑌥)", is_indic: true, has_vedic_pitch: true }, { id: "malayalam", name: "Malayalam (മലയാളം)", is_indic: true, has_vedic_pitch: true }, { id: "bengali", name: "Bengali (বাংলা)", is_indic: true, has_vedic_pitch: true }, { id: "iast", name: "IAST (Roman Diacritics)", is_indic: false, has_vedic_pitch: true }, { id: "iso15919", name: "ISO 15919", is_indic: false, has_vedic_pitch: true }, { id: "slp1", name: "SLP1 (ASCII Phonetic)", is_indic: false, has_vedic_pitch: false }, { id: "harvardkyoto", name: "Harvard-Kyoto (HK)", is_indic: false, has_vedic_pitch: false }, { id: "wx", name: "WX Notation", is_indic: false, has_vedic_pitch: false }]*/Function 4: generate_krama
Section titled “Function 4: generate_krama”Generates structured step-by-step Krama recitation data. Designed for UI data tables (DataGrid) and interactive chanting flashcards.
const steps = generate_krama( "अ॒ग्निम् । ई॒ळे॒ । पु॒रो-हि॑तम् ।", "devanagari" // target script);
console.log(steps);/* Output:[ { step_number: 1, formula: "1-2", first_index: 1, second_index: 2, raw_pada: "अ॒ग्निम् ई॒ळे॒", sandhied: "अ॒ग्निमी॒ळे॒", is_parigraha: false, pragrhya_detected: false }, { step_number: 2, formula: "2-3", first_index: 2, second_index: 3, raw_pada: "ई॒ळे॒ पु॒रो-हि॑तम्", sandhied: "ई॒ळे॒ पु॒रो-हि॑तम्", is_parigraha: false, pragrhya_detected: false }, { step_number: 3, formula: "3-iti-3", first_index: 3, second_index: null, raw_pada: "पु॒रो-हि॑तम्", sandhied: "पु॒रोहि॑तमिति॑ पु॒रो-हि॑तम्", is_parigraha: true, pragrhya_detected: false }]*/Function 5: generate_krama_text
Section titled “Function 5: generate_krama_text”Generates continuous, traditional Krama-pāṭha recitation text directly in the requested target script.
const kramaChant = generate_krama_text( "अ॒ग्निम् । ई॒ळे॒ । पु॒रो-हि॑तम् ।", "telugu");
console.log(kramaChant);// Output: "అ॒గ్నిమీ॒ళే॒ । ఈ॒ళే॒ పు॒రో-హి॑తమ్ । పు॒రోహి॑తమితి॑ పు॒రో-హి॑తమ్ ॥"Function 6: generate_jata
Section titled “Function 6: generate_jata”Generates structured step-by-step Jaṭā recitation data ($1\text{-}2, 2\text{-}1, 1\text{-}2$). Combines forward and reverse Sandhi (including Pāṇini 6.1.109 Abhinihita avagraha elision) with compound and terminal Parigraha clauses.
const jataSteps = generate_jata( "अ॒ग्निम् । ई॒ळे॒ । पु॒रो-हि॑तम् ।", "devanagari" // target script);
console.log(jataSteps);/* Output:[ { step_number: 1, formula: "1-2-2-1-1-2", first_index: 1, second_index: 2, forward_12: "अ॒ग्निमी॑ळे", reverse_21: "ई॒ळे॒ऽग्निम्", forward_return_12: "अ॒ग्निमी॑ळे", parigraha: null, full_step_text: "अ॒ग्निमी॑ळ ई॒ळे॒ऽग्निर॒ग्निमी॑ळे" }, { step_number: 2, formula: "2-3-3-2-2-3", first_index: 2, second_index: 3, forward_12: "ई॒ळे॒ पु॒रोहि॑तम्", reverse_21: "पु॒रोहि॑तमी॑ळे", forward_return_12: "ई॒ळे॒ पु॒रोहि॑तम्", parigraha: "पु॒रोहि॑तमिति॑ पु॒रो-हि॑तम्", full_step_text: "ई॒ळे॒ पु॒रोहि॑तं पु॒रोहि॑तमी॑ळ ई॒ळे॒ पु॒रोहि॑तं पु॒रोहि॑तमिति॑ पु॒रो-हि॑तम्" }]*/Function 7: generate_jata_text
Section titled “Function 7: generate_jata_text”Generates continuous, traditional Jaṭā-pāṭha recitation text directly in the requested target script.
const jataChant = generate_jata_text( "अ॒ग्निम् । ई॒ळे॒ । पु॒रो-हि॑तम् ।", "devanagari");
console.log(jataChant);// Output: "अ॒ग्निमी॑ळ ई॒ळे॒ऽग्निर॒ग्निमी॑ळे । ई॒ळे॒ पु॒रोहि॑तं पु॒रोहि॑तमी॑ळ ई॒ळे॒ पु॒रोहि॑तं पु॒रोहि॑तमिति॑ पु॒रो-हि॑तम् ।"Function 8: generate_ghana
Section titled “Function 8: generate_ghana”Generates structured step-by-step Ghana recitation data. Each row reuses Jaṭā fields (forward_text, reverse_text, sandhied) and adds triples when a third pada is present (1-2, 2-1, 1-2-3, 3-2-1, 1-2-3). The last pair of a sequence has no third pada, so it falls back to Jaṭā.
const ghanaSteps = generate_ghana( "अ॒ग्निम् । ई॒ळे॒ । पु॒रो-हि॑तम् ।", "devanagari");
console.log(ghanaSteps[0]);/* Output:{ step_number: 1, formula: "1-2-2-1-1-2-3-3-2-1-1-2-3", first_index: 1, second_index: 2, third_index: 3, forward_text: "अ॒ग्निमी॑ळे", reverse_text: "ई॒ळे॒ऽग्निम्", forward_triple: "अ॒ग्निमी॑ळे पु॒रोहि॑तम्", reverse_triple: "पु॒रोहि॑तमी॑ळेऽग्निम्", sandhied: "अ॒ग्निमी॑ळे ई॒ळे॒ऽग्निम् अ॒ग्निमी॑ळे पु॒रोहि॑तम् पु॒रोहि॑तमी॑ळेऽग्निम् अ॒ग्निमी॑ळे पु॒रोहि॑तम्", is_parigraha: false}*/Function 9: generate_ghana_text
Section titled “Function 9: generate_ghana_text”Generates continuous Ghana-pāṭha recitation text in the requested target script.
const ghanaChant = generate_ghana_text( "अ॒ग्निम् । ई॒ळे॒ । पु॒रो-हि॑तम् ।", "devanagari");Function 10: parse_padas
Section titled “Function 10: parse_padas”Parses raw Pada-pāṭha strings into structured grammatical tokens, identifying compound boundaries (samāsa) and Pāṇinian Pragṛhya vowels (Pāṇini 1.1.11–19).
const padas = parse_padas("अ॒ग्निम् । हरी॒ । पु॒रो-हि॑तम् ।");
console.log(padas);/* Output:[ { raw: "अ॒ग्निम्", clean: "अग्निम्", compound_parts: [], is_compound: false, is_pragrhya: false, pragrhya_type: null }, { raw: "हरी॒", clean: "हरी", compound_parts: [], is_compound: false, is_pragrhya: true, pragrhya_type: "DualI" // Pāṇini 1.1.11: dual ending in long ī }, { raw: "पु॒रो-हि॑तम्", clean: "पुरोहितम्", compound_parts: ["पुरो", "हितम्"], is_compound: true, is_pragrhya: false, pragrhya_type: null }]*/Function 11: get_shiva_sutras
Section titled “Function 11: get_shiva_sutras”Returns all 14 Māheśvara Sūtras (Śiva Sūtras) with individual sound tokens and terminating it-markers in both Devanagari and IAST.
const sutras = get_shiva_sutras();
// Inspect Sūtra 1 (अ इ उ ण्)console.log(sutras[0]);/* Output:{ index: 1, name: "aiuṇ", it_marker_deva: "ण्", it_marker_iast: "ṇ", sounds_deva: ["अ", "इ", "उ"], sounds_iast: ["a", "i", "u"]}*/Function 12: get_pratyahara_sounds
Section titled “Function 12: get_pratyahara_sounds”Resolves any canonical Pāṇinian Pratyāhāra (sound abbreviation) into its constituent phonemes with full articulatory properties.
// Resolve 'yaṇ' (यण्) = semivowels (y, v, r, l)const yanSounds = get_pratyahara_sounds("yaṇ");
console.log(yanSounds.map(s => s.glyph_iast));// Output: ["y", "v", "r", "l"]Function 13: check_pratyahara_contains
Section titled “Function 13: check_pratyahara_contains”A high-speed boolean predicate checking if a given sound belongs to a Pratyāhāra abbreviation.
// Is 'i' in 'ac' (all vowels)?console.log(check_pratyahara_contains("ac", "i")); // true
// Is 'k' in 'ac'?console.log(check_pratyahara_contains("ac", "k")); // false
// Is 'k' in 'hal' (all consonants)?console.log(check_pratyahara_contains("hal", "k")); // true
// Is 'y' in 'yaṇ' (semivowels)?console.log(check_pratyahara_contains("yaṇ", "y")); // trueFunction 14: inspect_varna
Section titled “Function 14: inspect_varna”Computes the classical articulatory phonetics (Śikṣā tradition) for any single Sanskrit sound.
const analysis = inspect_varna("k");
console.log(analysis);/* Output:{ glyph_deva: "क", glyph_iast: "k", varna_type: "consonant", sthana: ["Kantha (Velar)"], abhyantara_prayatna: "Sprshta (Complete contact)", is_ghosha: false, // Aghoṣa (voiceless) is_alpaprana: true, // Alpaprāṇa (unaspirated) matra: 0.5 // Ardhamātrā (consonant weight)}*/Function 15: analyze_syllables
Section titled “Function 15: analyze_syllables”Performs syllable-level analysis of an entire Sanskrit word or verse, decomposing each Akṣara into its consonants, vowels, accents, and total mātrā weights.
const syllables = analyze_syllables("अ॒ग्निः", "devanagari");
console.log(syllables);/* Output:[ { surface: "अ", consonants: [], vowel: { glyph_deva: "अ", glyph_iast: "a", matra: 1.0, ... }, ayogavaha: null, svara: "Anudatta", total_matra: 1.0 }, { surface: "ग्निः", consonants: [ { glyph_deva: "ग", glyph_iast: "g", matra: 0.5, ... }, { glyph_deva: "न", glyph_iast: "n", matra: 0.5, ... } ], vowel: { glyph_deva: "इ", glyph_iast: "i", matra: 1.0, ... }, ayogavaha: "Visarga", svara: null, total_matra: 2.5 }]*/Function 16: get_taittiriya_svaritas
Section titled “Function 16: get_taittiriya_svaritas”Returns the canonical 8-fold Svarita accent varieties defined in Taittirīya-Prātiśākhya Chapter 20, identifying whether each accent is Nitya (independent/inherent) or enclitic (contextual).
const svaritas = get_taittiriya_svaritas();
console.log(svaritas);/* Output:[ { id: "Jatya", name_deva: "जात्य", name_iast: "Jātya", is_nitya: true }, { id: "Kshaipra", name_deva: "क्षैप्र", name_iast: "Kṣaipra", is_nitya: true }, { id: "Abhinihita", name_deva: "अभिनिहित", name_iast: "Abhinihita", is_nitya: true }, { id: "Prashlishta", name_deva: "प्रश्लिष्ट", name_iast: "Praśliṣṭa", is_nitya: true }, { id: "Tairovyanjana", name_deva: "तैरोव्यञ्जन", name_iast: "Tairovyañjana", is_nitya: false }, { id: "Tairovirama", name_deva: "तैरोविराम", name_iast: "Tairovirāma", is_nitya: false }, { id: "Padavrtta", name_deva: "पादवृत्त", name_iast: "Pādavṛtta", is_nitya: false }, { id: "Tathabhavya", name_deva: "तथाभाव्य", name_iast: "Tathābhāvya", is_nitya: false }]*/Function 17: inspect_taittiriya_varna
Section titled “Function 17: inspect_taittiriya_varna”Computes the articulatory classification for a single sound symbol under the Taittirīya-Prātiśākhya Chapter 2 framework, calculating both the passive place (Sthāna) and active articulator (Karaṇa).
const analysis = inspect_taittiriya_varna("t");
console.log(analysis);/* Output:{ glyph_deva: "त", glyph_iast: "t", varna_type: "consonant", sthana: ["Danta (Dental)"], karana: "Jihvāgram (Tongue tip)", abhyantara_prayatna: "Spṛṣṭa (Complete contact)", is_ghosha: false, is_alpaprana: true, matra: 0.5}*/Function 18: check_taittiriya_dvitva
Section titled “Function 18: check_taittiriya_dvitva”Evaluates whether a consonant geminates (doubles) in Taittirīya recitation according to the rules of Taittirīya-Prātiśākhya Chapter 14 (e.g. TPr 14.1 post-vocalic conjuncts, TPr 14.4 consonants following r or h).
// In "arkaḥ" (अ॒र्कः॑): does 'k' preceded by 'r' double?const doublesArka = check_taittiriya_dvitva("r", "k", null);console.log(doublesArka); // true => "arkkaḥ"
// Does initial 'k' double before a vowel without preceding consonant?const doublesSimple = check_taittiriya_dvitva(null, "k", "a");console.log(doublesSimple); // falseFunction 19: classify_taittiriya_svarita_by_context
Section titled “Function 19: classify_taittiriya_svarita_by_context”Classifies an accent into one of the 8 canonical Taittirīya-Prātiśākhya Svaritas given its phonological juncture context.
// Semivowel Sandhi (e.g., ví + abravīt -> vyàbravīt)const svarita1 = classify_taittiriya_svarita_by_context("SemivowelSandhi");console.log(svarita1); // "Kshaipra"
// Avagraha elision (e.g., té + abruvan -> té 'bruvan)const svarita2 = classify_taittiriya_svarita_by_context("AbhinihitaElision");console.log(svarita2); // "Abhinihita"
// Post-Udātta enclitic across consonantconst svarita3 = classify_taittiriya_svarita_by_context("PostUdattaConsonant");console.log(svarita3); // "Tairovyanjana"5. SvelteKit Integration Example
Section titled “5. SvelteKit Integration Example”Here is a complete, production-ready Svelte component using the WASM module:
<script lang="ts"> import { onMount } from 'svelte'; import init, { transliterate, generate_krama } from '@project-vyasa/sanskrit-wasm';
let isReady = false; let input = 'अ॒ग्निमी॑ळे पु॒रोहि॑तम्'; let targetScript = 'telugu'; let transliterated = ''; let kramaSteps: any[] = [];
onMount(async () => { await init(); isReady = true; update(); });
function update() { if (!isReady) return; transliterated = transliterate(input, 'devanagari', targetScript); kramaSteps = generate_krama(input, targetScript); }
$: if (input || targetScript) update();</script>
{#if !isReady} <div class="loading">Loading Sanskrit WASM engine...</div>{:else} <div class="workbench"> <textarea bind:value={input} rows="3" />
<select bind:value={targetScript}> <option value="telugu">Telugu</option> <option value="grantha">Grantha</option> <option value="kannada">Kannada</option> <option value="iast">IAST</option> </select>
<div class="output">{transliterated}</div>
<div class="krama-list"> {#each kramaSteps as step} <div class="krama-step"> <span class="step-num">{step.step_number}.</span> <span class="step-formula">{step.formula}</span> <strong class="step-text">{step.sandhied}</strong> </div> {/each} </div> </div>{/if}6. Data-Driven Test Harness & Regression Suite
Section titled “6. Data-Driven Test Harness & Regression Suite”To ensure absolute fidelity to traditional Vedic recitation without continually modifying Rust test files when new verses are added, vyasa-patha includes a data-driven test harness (crates/vyasa-patha/tests/data_driven_krama.rs).
Architecture: Everyday Regression vs. Pre-Release Verification
Section titled “Architecture: Everyday Regression vs. Pre-Release Verification”Test Harness Architecture├── Everyday Regression Suite (<1 ms)│ └── crates/vyasa-patha/tests/data/rv_01_001.json│ ├── Standalone bundled dataset (all 9 ṛks of Sūkta 1.1)│ ├── Validates Pada parsing, Svarita shift, Ardharca limits, and Parigraha│ └── Runs unconditionally in CI/CD without local filesystem dependencies│└── Pre-Release Verification Suite (~10 ms) └── Driven by local data pipeline: sa.wikisource.org/data/processed/rigveda ├── Iterates through full Sūktas (e.g. Mandala 1 Sūktas 001 - 020) ├── Tests hundreds of ṛks and thousands of Krama steps └── Enabled dynamically via environment variables1. Running Everyday Regression Tests
Section titled “1. Running Everyday Regression Tests”Run the bundled regression tests (<30 ms for both RV 1.1 and the 169-verse curated tricky suite):
# Run both everyday and curated tricky suitescargo test -p vyasa-patha --test data_driven_krama
# Run only the 169-verse curated tricky suitecargo test -p vyasa-patha --test data_driven_krama test_curated_tricky_suite -- --nocaptureThe test runner will output:
✓ Curated Tricky Suite: Validated 169 verses and 2947 Krama steps across 11 canonical hymns in <20ms!test test_curated_tricky_suite ... ok2. Dataset Management with scripts/rigveda_dataset.py
Section titled “2. Dataset Management with scripts/rigveda_dataset.py”To synchronize, inspect, or add verses from the Wikisource pipeline without writing ad-hoc scripts:
# Inspect current curated tricky datasetpython3 scripts/rigveda_dataset.py inspect
# Rebuild the curated tricky dataset from the pipelinepython3 scripts/rigveda_dataset.py build-tricky
# Add or replace a specific verse (e.g. RV 1.164.1)python3 scripts/rigveda_dataset.py add -m 1 -s 164 -r 1 -c "Asya Vamasya Opening"3. Running Pre-Release Pipeline Verification
Section titled “3. Running Pre-Release Pipeline Verification”Prior to a release or significant crate update, run the harness against the comprehensive Wikisource pipeline:
RIGVEDA_PIPELINE_PATH="/Users/anand/Projects/project-vyasa/sa.wikisource.org/data/processed/rigveda" \RIGVEDA_SAMPLE_SUKTAS=20 \cargo test -p vyasa-patha --test data_driven_krama -- --nocaptureThe test runner will output:
=== Pre-Release Krama Pipeline Test ===Checking pipeline directory: .../processed/rigvedaProcessing Sukta file: .../001.vy (9 verses)Processing Sukta file: .../002.vy (9 verses)Processing Sukta file: .../003.vy (13 verses)Processing Sukta file: .../004.vy (10 verses)Processing Sukta file: .../005.vy (10 verses)✓ Validated 51 ṛks and generated 600+ Krama steps successfully!4. Krishna Yajurveda Data-Driven Harness (kyv_corpus.json)
Section titled “4. Krishna Yajurveda Data-Driven Harness (kyv_corpus.json)”Modeled directly after the Rigveda harness, vyasa-phonetics includes a dedicated corpus-driven test suite (crates/vyasa-phonetics/tests/data_driven_taittiriya.rs) driven by a standalone, version-controlled JSON dataset (crates/vyasa-phonetics/tests/data/kyv_corpus.json).
Curated Benchmark Corpus
Section titled “Curated Benchmark Corpus”The dataset bundles 7 canonical passages across the 3 core Taittirīya texts:
- Taittirīya Saṃhitā:
- TS 1.1.1 (Opening: iṣe tvorje tvā…)
- TS 4.5.1 (Śrī Rudram / Namakam)
- TS 4.7.1 (Camakam)
- Taittirīya Upaniṣad:
- Śīkṣāvallī 1.1.1 (śam no mitraḥ śam varuṇaḥ…)
- Ānandavallī 2.1.1 (brahmavid āpnoti param…)
- Taittirīya Āraṇyaka:
- TA 3.12.1 (Puruṣa Sūkta: sahasraśīrṣā puruṣaḥ…)
- TA 3.12.16 (Puruṣa Sūkta Phalaśruti)
Running the KYV Test Harness
Section titled “Running the KYV Test Harness”# Run the complete Taittirīya data-driven regression suite (<5 ms)cargo test -p vyasa-phonetics --test data_driven_taittiriya -- --nocaptureThe harness automatically executes:
- Karaṇa & Sthāna exhaustive check: Validates active articulator coordinates across all Sanskrit varṇas.
- Svarita taxonomy verification: Evaluates 25 distinct Svarita context tokens across the 7 corpus passages.
- Dvitva gemination verification: Validates 12 consonant doubling occurrences under TPr 14.1, 14.4, and 14.8.
Corpus Management with scripts/kyv_dataset.py
Section titled “Corpus Management with scripts/kyv_dataset.py”# Validate JSON structure and phonological schemaspython3 scripts/kyv_dataset.py validate
# Inspect all 7 benchmark passages with detailed phonetic annotationspython3 scripts/kyv_dataset.py inspect7. Recommended Unicode Font Stack
Section titled “7. Recommended Unicode Font Stack”The WASM/CLI emit Unicode. Tofu (empty boxes) means the page never loaded a font that covers that script, not that Lipi failed. Longer field note in this repo: notes/indic-fonts.md (Studio + Starlight incidents, cmap vs Google Fonts slices, whether a coverage CLI is worth it).
Rule: every family you list in font-family must be installed or fetched (<link> / @font-face). A CSS name with no file is a no-op. Google Fonts also slices WOFF2 by unicode-range; Noto Sans Mono’s Latin slice often omits Vedic U+0331, so prefer Menlo/Monaco/Courier for monospace IAST pitch.
Load at least: Noto Sans Devanagari, Telugu, Kannada, Malayalam, Bengali, Noto Serif Grantha, and Noto Sans (Latin). Then:
.font-sanskrit { font-family: "Noto Sans Devanagari", "Noto Sans Telugu", "Noto Sans Kannada", "Noto Serif Grantha", "Noto Sans Malayalam", "Noto Sans Bengali", "Noto Sans", "Gentium Plus", sans-serif; font-feature-settings: "kern" 1, "liga" 1;}
.font-sanskrit-mono { font-family: Menlo, Monaco, "Courier New", monospace;}Apply that class (or the same stack on --font-sans) to tables and selects, not only <textarea>. Inter/system-ui alone will box Malayalam and Bengali in Chromium.
8. Appendix: Traditional Phonological Assessment & The “Tricky” Ṛgveda Suite
Section titled “8. Appendix: Traditional Phonological Assessment & The “Tricky” Ṛgveda Suite”A comprehensive survey of all 10,547 verses across all 1,028 Sūktas (10 Maṇḍalas) in the pipeline reveals why certain Vedic hymns are regarded by traditional Vaidikas, Ghanapāṭhins, and phonologists as the ultimate benchmark for recitation engines.
The 6 Categories of Phonological Complexity
Section titled “The 6 Categories of Phonological Complexity”| Category | Phonological Phenomenon | Traditional Authority | Canonical Hymns & Triggers |
|---|---|---|---|
| 1. Dual Pragṛhyas & Compound Parigraha | Duals in -ī, -ū, -e block sandhi; compound names require Unified + इति + Split parigraha. |
Pāṇini 1.1.11 (īdūded dvivacanam) | RV 1.2 (वायो॒ इति॑, इन्द्र॑वायू॒ इति॑, वाजिनीवसू), RV 6.69 (Indrā-Viṣṇū, 7 dual pragṛhyas in 8 verses). |
| 2. Pronoun Sandhi & Refrains | Pronoun सः (saḥ) obligatorily drops visarga before consonants, but retains it before vowels. |
Pāṇini 6.1.132 (eta-tadoḥ sulopo ’kor anañ-sve hali) | RV 2.12 (Indra Sūkta): 15 verses each ending with refrain स जना॑स॒ इन्द्रः॑ (सः + जनासः $\to$ स जनास). |
| 3. Svarita Accent Shift & Exceptions | Udātta + Anudātta $\to$ Svarita ($U + A \to S$), but suppressed if following syllable is accented. | Pāṇini 8.4.66 & 8.4.67 (nodātta-svaritodātta-pade) | RV 1.1 (अ॒ग्निमी॑ळे shift vs. दे॒वमृ॒त्विज॑म् non-shift). |
| 4. Deep Multi-Member Compounds (Samāsa) | Multi-avagraha compounds, nested Bahuvrīhis, and riddle terms requiring clean sandhi in steps. | Śākalya Padapāṭha & Ṛk-Prātīśākhya | RV 1.164 (Asya Vāmasya, 52 verses, 121 compounds, 800+ lateral flaps ळ/ळ्ह), RV 9.86 / 9.97 (Pavamāna Soma). |
| 5. Liturgical Core (“Crown Jewels”) | Ubiquitous ritual hymns scrutinized by traditionalists for zero-error sandhi, virāma, and neuter forms. | Śrauta & Smārta Liturgical Tradition | RV 10.90 (Puruṣa Sūkta, 16 verses), RV 10.125 (Devī Sūkta, 8 verses), RV 10.129 (Nāsadīya Sūkta, 7 verses). |
| 6. Sacred Metrical Transitions | Metrical pauses, relative pronoun sandhi (धियो यो नः), and boundary Parigrahas. |
Gāyatrī, Triṣṭubh, and Jagatī Chandas | RV 3.62 (incl. Gāyatrī 3.62.10), RV 7.59 (incl. Mahāmṛtyuñjaya 7.59.12), RV 1.32 (Indra-Vṛtra epic). |
The 11 Canonical Hymns in rv_curated_tricky.json
Section titled “The 11 Canonical Hymns in rv_curated_tricky.json”The curated test dataset (crates/vyasa-patha/tests/data/rv_curated_tricky.json) bundles 169 verses (2,947 Krama steps) covering all 6 categories:
- RV 1.1 (Agni Sūkta - 9 verses): Universal opening; tests Pāṇini 8.4.66/67 accent shift, compound unification (
ई॒ळे॒ पु॒रोहि॑तम्), and ardharca boundaries. - RV 1.2 (Vāyu & Indra-Vāyu - 9 verses): Canonical textbook introduction to dual Pragṛhyas (
-ū), vocative-o, and compound Parigraha. - RV 1.32 (Indra Vṛtra-vadha - 15 verses): Classical epic narrative phonology, dense consonant clusters, and aspirated lateral flaps (
वृ॒ळ्हम्). - RV 1.164 (Asya Vāmasya - 52 verses): Supreme phonological test of Maṇḍala 1; 121 compounds, 800+ lateral flaps, and philosophical riddle constructions.
- RV 2.12 (Indra Sūkta / Gṛtsamada - 15 verses): Celebrated refrain hymn testing pronoun visarga drop
स जनास इन्द्रः. - RV 3.62 (Viśvāmitra - 18 verses): Contains the Gāyatrī mantra (3.62.10); tests relative pronoun sandhi (
धियो॒ यो नः॑). - RV 6.69 (Indrā-Viṣṇū - 8 verses): Highest concentration of dual Pragṛhyas in the Ṛgveda (7 pragṛhya
iticlauses in 8 verses). - RV 7.59 (Maruts - 12 verses): Contains the Mahāmṛtyuñjaya mantra (7.59.12); tests metrical transitions.
- RV 10.90 (Puruṣa Sūkta - 16 verses): Chanted across all Vedic rituals; dense with compounds (
स॒हस्र॑-शीर्षा,स॒हस्र॑-अक्षः,स॒हस्र॑-पात्) and neuter virāma sandhi. - RV 10.125 (Devī Sūkta / Vāk - 8 verses): Sovereign first-person affirmations with intense consonant assimilation.
- RV 10.129 (Nāsadīya Sūkta - 7 verses): The Hymn of Creation; negative particle sandhi (
नास॑दासी॒न्नो सदा॑सीत्), interrogatives, and pluta.