Rust → WebAssembly  ·  v7.1.0  ·  MIT License

Multimodal Perceptual
Physics Engine

Color · Audio · Haptics — compiled to WebAssembly. Every algorithm grounded in a published standard. Deterministic, energy-conserving, zero unsafe Rust.

output + absorbed + scattered = input  ·  ±1e-4 across all domains

⚡ Quickstart Explore Domains ★ GitHub
3
Domains
2,132
Tests
10
Crates
280+
WASM Exports
0
Unsafe Rust
0
Heap in Hot Loops

Sensory Physics

Three Perceptual Domains

Momoto unifies color science, acoustic loudness, and haptic force under a single energy-conserving model. No magic numbers. No platform hacks.

🎨

Color

Photon wavelength 380–780 nm. OKLCH perceptual polar space, HCT Material Design 3, WCAG 2.1 and APCA-W3 accessibility contrast, CVD simulation, harmony engine with 7 types, and glass physics with GGX PBR.

OKLCH · HCT · CAM16 WCAG 2.1 · APCA-W3 CVD Viénot 1999 GGX PBR · SSS · Thin-film Harmony · Constraint Solver
CIE · ITU-R · WCAG · APCA · 280+ WASM exports
🔊

Audio

Sound pressure 20 Hz–20 kHz. K-weighting IIR biquad filters, integrated/momentary/short-term LUFS gating per ITU-R BS.1770-4, Cooley-Tukey FFT radix-2, Mel filterbank with HTK+Slaney scales, and EBU R128 broadcast compliance.

LUFS · K-weighting FFT radix-2 DIT Mel filterbank EBU R128 compliance Spectral features
ITU-R BS.1770-4 · EBU R128 · 13 WASM exports
📳

Haptics

Vibrotactile force in Hz, N, and Joules. Weber–Fechner perception model, energy budget with capacity and recharge tracking, LRA/ERM/Piezo actuator mapping, and waveform synthesis (Sine, Pulse, Ramp, Buzz).

Weber–Fechner law LRA · ERM · Piezo Energy budget Waveform synthesis Actuator models
IEEE 1451.4 · Weber–Fechner · planned WASM
⚙️

Engine

Cross-domain orchestrator with zero vtable overhead. DomainVariant enum dispatch — LLVM inlines all match arms. Perceptual alignment between any two domain values, system energy validation, and 4096-f32 preallocated scratch buffer.

DomainVariant enum No dyn dispatch Cross-domain normalization Energy invariant validation SystemEnergyReport
Energy invariant · ±1e-4 tolerance · 24 tests
WCAG 2.1 APCA-W3 v0.1.9 CIE Lab/LCh Fresnel equations HCT / CAM16 ITU-R BS.1770-4 EBU R128 Parseval energy Weber–Fechner law IEEE 1451.4

Code

Quickstart

Three sensory domains. One Cargo dependency. One WASM init. All algorithms deterministic across native, browser, and Node.js.

1
OKLCH + APCA contrast Rust
use momoto_core::color::Color;
use momoto_metrics::{APCAMetric, WCAGMetric};

let fg = Color::from_hex("#FFFFFF").unwrap();
let bg = Color::from_hex("#3B82F6").unwrap();

let wcag = WCAGMetric::new().evaluate(fg, bg).contrast;
let apca = APCAMetric::new().evaluate(fg, bg).contrast;
println!("WCAG: {:.2}:1  APCA Lc: {:.1}", wcag, apca);
// WCAG: 3.06:1  APCA Lc: 55.2
2
Color Harmony + HCT palette Rust
use momoto_core::space::oklch::OKLCH;
use momoto_intelligence::{
    generate_palette, harmony_score, HarmonyType
};

let seed = OKLCH::new(0.65, 0.18, 210.0);
let palette = generate_palette(
    seed,
    HarmonyType::Analogous { spread: 45.0 }
);
let score = harmony_score(&palette.colors);
println!("Harmony: {:.3}", score); // 0.0–1.0
1
Integrated LUFS + EBU R128 Rust
use momoto_audio::AudioDomain;

let domain = AudioDomain::at_48khz();
let mut analyzer = domain.lufs_analyzer(1).unwrap();

// Process audio blocks (K-weighted ITU-R BS.1770-4)
let samples: Vec<f32> = /* your audio blocks */;
analyzer.add_mono_block(&samples);

println!("Integrated: {:.1} LUFS", analyzer.integrated());
let check = domain.validate_broadcast(analyzer.integrated());
println!("EBU R128 passes: {}", check.passes);
// target: -23.0 LUFS ±1 LU
2
FFT power spectrum + Mel filterbank Rust
use momoto_audio::{AudioDomain, MelScale};

let domain = AudioDomain::at_48khz();

// Radix-2 Cooley-Tukey FFT (power-of-2 sizes only)
let frame: [f32; 1024] = /* one FFT frame */;
let power = domain.fft_power_spectrum(&frame);
// power: Box<[f32]> len=513, units: dB FS

// Mel filterbank (40 bands, HTK scale)
let mel = MelScale::htk(40, 48000);
let energies = mel.apply(&power);
// energies: Box<[f32]> len=40
1
LRA energy budget + Weber mapping Rust
use momoto_haptics::{
    ActuatorModel, EnergyBudget,
    mapping::FrequencyForceMapper,
};

// 50 mJ capacity, 10 mJ/s recharge
let mut budget = EnergyBudget::with_recharge(
    0.050, 0.010
);
budget.try_consume(0.005).expect("tap ok");
budget.tick(0.1); // 100 ms elapsed

let mapper = FrequencyForceMapper::new(
    ActuatorModel::Lra
);
let spec = mapper.map(0.7, 100.0);
println!("{:.0} Hz  {:.4} N  {:.4} J",
    spec.freq_hz, spec.force_n, spec.energy_j());
// 175 Hz  0.1400 N  0.0140 J
2
Waveform synthesis (4 kinds) Rust
use momoto_haptics::{HapticWaveform, WaveformKind};

// Generate waveforms at 8 kHz
let tap = HapticWaveform::generate(
    WaveformKind::Pulse,
    200.0, 0.8, 8000, 50
);
let buzz = HapticWaveform::generate(
    WaveformKind::Buzz,
    180.0, 0.6, 8000, 100
);
// WaveformKind: Sine | Pulse | Ramp | Buzz
// All Box<[f32]> — zero-copy, WASM-safe
1
Cross-domain normalization + alignment Rust
use momoto_engine::MomotoEngine;
use momoto_core::traits::domain::DomainId;

let engine = MomotoEngine::new();

// Normalize raw perceptual energy to [0, 1]
// Audio: (lufs + 70) / 70
let color_norm = engine.normalize_perceptual_energy(
    DomainId::Color, 0.72
);
let audio_norm = engine.normalize_perceptual_energy(
    DomainId::Audio, -23.0
);

// Alignment between two domain values (0.0–1.0)
let alignment = engine.perceptual_alignment(
    DomainId::Color, DomainId::Color,
    0.72, 0.68
);
println!("Alignment: {:.3}", alignment);
2
System energy validation Rust
use momoto_engine::MomotoEngine;

let engine = MomotoEngine::new();

// Validate energy invariant across all domains
// output + absorbed + scattered = input (±1e-4)
let report = engine.validate_system_energy();
println!(
    "Conserved: {}  Max error: {:.2e}",
    report.system_conserved,
    report.max_error
);
// Conserved: true  Max error: 1.00e-15

// DomainVariant enum dispatch — no vtable
// LLVM inlines all match arms in hot paths
1
Color + Audio in the browser JavaScript
import init, {
    wcagContrastRatio, wcagPasses,
    audioLufs, audioValidateEbuR128,
    audioFftPowerSpectrum,
} from 'momoto-wasm';

await init(); // load .wasm binary

// Color — WCAG contrast
const ratio = wcagContrastRatio('#FFFFFF', '#3B82F6');
console.log(`WCAG: ${ratio.toFixed(2)}:1`);

// Audio — 1 kHz sine, 1 second at 48 kHz
const samples = new Float32Array(48000);
for (let i = 0; i < 48000; i++)
    samples[i] = Math.sin(2 * Math.PI * 1000 * i / 48000);

const lufs = audioLufs(samples, 48000, 1);
const ok   = audioValidateEbuR128(lufs);
console.log(`Integrated: ${lufs.toFixed(2)} LUFS — EBU R128: ${ok}`);
2
Build with feature flags bash
# Color only (<350 KB gzipped)
wasm-pack build --target web -- \
    --no-default-features --features color

# Color + Audio (<500 KB)
wasm-pack build --target web -- \
    --features audio

# Full multimodal (<550 KB)
wasm-pack build --target web -- \
    --features multimodal

# With browser panic messages
wasm-pack build --target web -- \
    --features multimodal,panic_hook

Design

Multimodal Architecture

Enum dispatch instead of vtable — LLVM inlines every match arm. No heap in hot loops. No unsafe Rust. Zero dynamic dispatch in the critical path.

┌──────────────────────────────────────────────────────────────────┐ momoto-wasm (WASM bindings) feature: color ────── feature: audio ────── feature: haptics └────────┬────────────────────┬────────────────────┬───────────────┘ ┌─────▼──────┐ ┌───────▼─────┐ ┌───────▼─────┐ momoto- momoto-audio momoto- intelligence LUFS/FFT/ haptics materials Mel/EBU R128 energy/wave metrics └───────┬─────┘ └───────┬─────┘ └─────┬──────┘ └──────────┬──────────┘ └───────────────────────────────┤ ┌──────▼──────┐ momoto-engine DomainVariant enum dispatch └──────┬──────┘ ┌──────▼──────┐ momoto-core OKLCH·traits zero deps └─────────────┘

Energy Invariants — output + absorbed + scattered = input

DomainPhysical quantityEnergy modelTolerance
ColorPhoton 380–780 nmLossless optical (R + T = 1)1e-4
AudioSound pressure 20 Hz–20 kHzK-weighting Parseval-conserving1e-4
HapticsVibrotactile force (Hz, N, J)delivered + remaining = capacity1e-12

WASM Feature Flags

color
OKLCH, HCT, APCA, materials, glass physics — always compiled
<350 KB gzipped
audio
LUFS, FFT, Mel filterbank, EBU R128 compliance
<500 KB gzipped
haptics
Energy budget, actuator models, waveform synthesis
planned
multimodal
audio + haptics — full three-domain bundle
<550 KB gzipped
panic_hook
Readable panic messages in the browser console
+~2 KB

Ecosystem

Ten Crates

Each crate is independently usable. Zero unsafe. Zero heap allocation in hot loops. All publish to crates.io at v7.1.

CrateDomainDescriptionStatusTests
momoto-core Foundation OKLCH · HCT · CAM16 · traits · zero deps STABLE 290
momoto-metrics Color WCAG 2.1 + APCA-W3 v0.1.9 contrast STABLE 50
momoto-intelligence Color Harmony (7 tipos) · CVD Viénot · constraint solver STABLE 44
momoto-materials Color Glass physics · GGX PBR · SSS · thin-film · shadows STABLE 1,616
momoto-audio Audio ITU-R BS.1770-4 · EBU R128 · FFT · Mel filterbank STABLE 70
momoto-haptics Haptics Weber's law · LRA/ERM/Piezo · energy budget · waveforms STABLE 36
momoto-engine Orchestration MomotoEngine · DomainVariant · cross-domain normalization STABLE 24
momoto-events Infrastructure PubSub · EventBroadcaster · EventStream (RAII) STABLE
momoto-agent Orchestration Workflow · session · visual generation · audit BETA
momoto-wasm WASM JS/TS bindings: 280+ color · 13 audio · haptics planned STABLE
Total 2,132

Design Principles

⚛️

Physics first

Fresnel equations, K-weighting, Weber's law. No heuristics or magic numbers.

🔒

Deterministic

Same input → same output on every platform: native, browser, Node.js.

No dynamic dispatch

DomainVariant enum instead of Box<dyn Domain> — LLVM inlines all match arms.

🧠

No heap in hot loops

Box<[f32]> allocated once per call. Inner loops are zero-alloc.

Reference

Pipeline Diagrams

Visual reference for the color intelligence pipeline and agent workflow.

SIREN Neural Correction Flow
SIREN Neural Correction Flow
9→16→16→3 network, 483 params, ω₀=30. Corrects OKLCH pairs for perceptual quality.
Agent Visual Generator Pipeline
Agent Visual Generator Pipeline
4-phase agent pipeline: recommend → configure materials → render → validate.