Implementation Plan: Prototype Redesign¶
This document outlines the redesign of the prototype's pipeline system to support maximum user freedom across all configuration layers, re-enable ONNX Runtime, add LiteRT.js, and enable framework overhead measurement.
Terminology¶
Precise naming avoids confusion across the four browser ML runtimes:
| Term | Definition | Examples |
|---|---|---|
| Task | The ML problem type | Image Classification, Object Detection, Pose Estimation |
| Model | The neural network architecture (not the file format) | MobileNet v2, SqueezeNet 1.1, EfficientNet-Lite0 |
| Runtime | The low-level inference engine that executes model graphs on hardware | ORT Web, TF.js, LiteRT.js |
| Framework | Optional wrapper around a runtime that adds preprocessing, model discovery, or a friendlier API | Transformers.js (wraps ORT), MediaPipe Tasks (wraps LiteRT), ml5.js (wraps TF.js) |
| Backend | The hardware accelerator used by the runtime | WASM, WebGPU, WebGL, CPU |
| Dataset | The input data for inference | Sample images, user-uploaded images |
Runtime vs Framework¶
A runtime is a self-contained inference engine with its own model format and backend system. A framework is a wrapper that depends on a runtime underneath:
| Runtime | Model format | Under the hood | Framework wrappers |
|---|---|---|---|
| ORT Web | .onnx |
C++ ORT → WASM | Transformers.js |
| TF.js | model.json + .bin |
JS kernels + WASM/XNNPACK | ml5.js |
| LiteRT.js | .tflite |
C++ LiteRT → WASM + XNNPACK | MediaPipe Tasks |
ml5.js is included as a TF.js framework wrapper to enable symmetric overhead measurement across all three runtimes.
Model format is determined by runtime¶
| Model | ORT Web | TF.js | LiteRT.js | MediaPipe Tasks |
|---|---|---|---|---|
| MobileNet v2 | .onnx |
model.json (CDN) |
.tflite |
— |
| SqueezeNet 1.1 | .onnx |
— | .tflite |
— |
| EfficientNet-Lite0 | — | — | .tflite |
.tflite (GCS) |
All models load from CDN — no local files in the repository.
Pipeline order¶
The user configures selections in dependency order. Each step constrains what follows:
Task → Model → Runtime → Framework → Backend → Dataset → Run
| Step | Why this position | What it constrains |
|---|---|---|
| Task | Always first — determines which models exist | Available models |
| Model | Architecture choice determines which runtimes can run it (format compatibility) | Available runtimes |
| Runtime | Low-level engine determines available frameworks and backends | Available frameworks and backends |
| Framework | Wrapper layer — optional, determines overhead measurement | None (optional layer) |
| Backend | Hardware accelerator, filtered by runtime COMPAT matrix | Execution hardware |
| Dataset | Independent of all above — the input to inference | None |
| Run | Execute the configured pipeline | — |
Cascade rules¶
When a user changes a selection, downstream selections are cleared:
| Changed | Clears |
|---|---|
| Task | Model, Runtime, Framework, Backend, Dataset |
| Model | Runtime, Framework, Backend |
| Runtime | Framework, Backend |
| Framework | Backend |
| Backend | (nothing) |
| Dataset | (nothing) |
Block system redesign¶
6 layers (up from 5)¶
| Block | Label | Icon | Options |
|---|---|---|---|
| Task | Task | 🎯 | Image Classification (enabled), Object Detection, Segmentation, Pose (disabled) |
| Model | Model | 🧠 | MobileNet v2, SqueezeNet 1.1, EfficientNet-Lite0 |
| Runtime | Runtime | ⚙️ | ORT Web, TF.js, LiteRT.js |
| Framework | Framework | 📦 | "Direct" (no wrapper) or framework wrapper — varies by runtime |
| Backend | Backend | 🖥️ | WASM, WebGPU, WebGL, CPU — filtered by runtime COMPAT matrix |
| Dataset | Dataset | 🗃️ | 5 sample images + upload |
Framework options by runtime¶
| Runtime | Framework options |
|---|---|
| ORT Web | "Direct (ORT Web)", "Transformers.js" |
| TF.js | "Direct (TensorFlow.js)", "ml5.js" |
| LiteRT.js | "Direct (LiteRT.js)", "MediaPipe Tasks" |
When "Direct" is selected, the adapter calls the runtime API directly. When a framework wrapper is selected, the adapter uses the framework's higher-level API.
Model × Runtime availability¶
The MODEL_REGISTRY maps architecture → runtime → CDN URL. If a model is not available for a runtime, that runtime is greyed out in the UI.
| Model | ORT Web | TF.js | LiteRT.js | MediaPipe Tasks |
|---|---|---|---|---|
| MobileNet v2 | ✅ HuggingFace CDN | ✅ @tensorflow-models/mobilenet CDN |
✅ TF Hub .tflite |
— |
| SqueezeNet 1.1 | ✅ HuggingFace CDN | — | ✅ TF Hub .tflite |
— |
| EfficientNet-Lite0 | — | — | ✅ GCS .tflite |
✅ GCS .tflite |
Framework overhead measurement¶
The prototype enables direct comparison: same model, same runtime, with vs without framework wrapper.
| Comparison | Direct (runtime) | With wrapper | What it measures |
|---|---|---|---|
| ORT overhead | ort.InferenceSession.create() |
Transformers.js pipeline() |
Model discovery + preprocessing overhead |
| TF.js overhead | TF.js mobilenet.load() |
ml5.js ml5.imageClassifier() |
API abstraction overhead |
| LiteRT.js overhead | LiteRT.js direct API | MediaPipe Tasks ImageClassifier |
Task-specific API overhead |
This gives 6 benchmark combinations (3 runtimes × 2 modes) for a clean overhead comparison table in the thesis.
Runtime and adapter changes¶
New runtime: LiteRT.js¶
LiteRT.js (released July 9, 2026) is Google's JavaScript binding of the LiteRT C++ runtime via WASM. It loads .tflite models and supports WebGPU, WASM+XNNPACK, and WebNN backends.
| Property | Value |
|---|---|
| CDN | https://cdn.jsdelivr.net/npm/@anthropic-ai/litert.js (or equivalent) |
| Model format | .tflite |
| Backends | WASM+XNNPACK, WebGPU, WebNN |
| Relationship to TF.js | Successor — Google positions it as the "performance evolution from TensorFlow.js" |
| Relationship to MediaPipe | MediaPipe Tasks wraps LiteRT internally |
Updated adapter list¶
| Adapter | Wraps | Model format | Status |
|---|---|---|---|
TFJSAdapter |
TF.js (self-contained) | model.json via CDN |
✅ Existing — keep as-is |
ONNXAdapter |
ORT Web | .onnx via HuggingFace CDN |
🔧 Fix — set CDN URL, remove null check |
LiteRTAdapter |
LiteRT.js | .tflite via CDN |
🆕 New adapter |
MediaPipeAdapter |
MediaPipe Tasks (wraps LiteRT) | .tflite via GCS |
✅ Existing — keep as-is |
TransformersAdapter |
Transformers.js (wraps ORT) | .onnx via HuggingFace |
✅ Existing — keep as-is |
ML5Adapter |
ml5.js (wraps TF.js) | model.json via CDN |
🆕 New adapter |
COMPAT matrix update¶
export const COMPAT = {
ort: {
webgpu: { supported: true, hw: ["GPU"] },
wasm: { supported: true, hw: ["CPU"] },
webgl: { supported: false, reason: "ORT dropped WebGL support" },
cpu: { supported: false, reason: "Use WASM instead" },
},
tfjs: {
webgl: { supported: true, hw: ["GPU"] },
webgpu: { supported: true, hw: ["GPU"] },
wasm: { supported: true, hw: ["CPU"] },
cpu: { supported: true, hw: ["CPU"] },
},
litert: {
webgpu: { supported: true, hw: ["GPU"] },
wasm: { supported: true, hw: ["CPU"] },
webgl: { supported: false, reason: "LiteRT.js uses WebGPU, not WebGL" },
cpu: { supported: false, reason: "Use WASM instead" },
},
};
Model registry¶
The MODEL_REGISTRY is the source of truth for which models exist and where to load them from.
const MODEL_REGISTRY = {
"mobilenet-v2": {
label: "MobileNet v2",
description: "Fast, general-purpose image classifier (13 MB)",
inputSize: 224,
runtimePaths: {
ort: "https://huggingface.co/onnxmodelzoo/mobilenetv2-12/resolve/main/mobilenetv2-12.onnx",
tfjs: null, // loaded via @tensorflow-models/mobilenet CDN package, not a URL
litert: "https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/5/converted_default/1",
},
},
"squeezenet-1.1": {
label: "SqueezeNet 1.1",
description: "Tiny model, fastest load, lower accuracy (~5 MB)",
inputSize: 224,
runtimePaths: {
ort: "https://huggingface.co/onnxmodelzoo/squeezenet11/resolve/main/squeezenet11.onnx",
litert: "https://tfhub.dev/google/squeezenet/1.0/classification/1/converted_default/1",
},
},
"efficientnet-lite0": {
label: "EfficientNet-Lite0",
description: "Balanced accuracy and speed (~4 MB)",
inputSize: 224,
runtimePaths: {
mediapipe: "https://storage.googleapis.com/mediapipe-models/image_classifier/efficientnet_lite0/float32/1/efficientnet_lite0.tflite",
litert: "https://storage.googleapis.com/mediapipe-models/image_classifier/efficientnet_lite0/float32/1/efficientnet_lite0.tflite",
},
},
};
Note: The TF.js adapter loads MobileNet via the @tensorflow-models/mobilenet CDN package (not a direct URL), so its runtimePaths entry is null — the adapter handles loading internally.
UI behavior¶
Model layer¶
When the user opens the Model layer, all three models are shown. After selecting a model, incompatible runtimes are greyed out with an explanation:
MobileNet v2 ✅ Click to select
SqueezeNet 1.1 ✅ Click to select
EfficientNet-Lite0 ✅ Click to select
After selecting "MobileNet v2", the Runtime layer shows:
ORT Web ✅ .onnx (HuggingFace CDN)
TF.js ✅ model.json (CDN)
LiteRT.js ✅ .tflite (TF Hub)
MediaPipe ❌ No model available — use EfficientNet-Lite0
Framework layer¶
After selecting a runtime, the Framework layer shows wrapper options:
[ORT Web selected]
Direct (ORT Web) — No wrapper overhead
Transformers.js — Wraps ORT, adds model discovery + preprocessing
[TF.js selected]
Direct (TF.js) — No wrapper overhead
ml5.js — Wraps TF.js, friendly API for creative coding
[LiteRT.js selected]
Direct (LiteRT.js) — No wrapper overhead
MediaPipe Tasks — Wraps LiteRT, task-specific API
Backend layer¶
After selecting a runtime, backends are filtered by the COMPAT matrix (existing behavior, extended for 3 runtimes).
Files to modify¶
| File | Changes |
|---|---|
js/pipeline.js |
Add MODEL_REGISTRY, FRAMEWORK_REGISTRY; restore model selection cards; add framework layer; update COMPAT matrix for 3 runtimes; update PipelineState for 6 layers; update PipelineCanvas rendering |
js/ml-adapter.js |
Fix ONNX adapter CDN URL; add LiteRTAdapter class; add ML5Adapter class; update AdapterFactory for 5 adapters; make model loading use registry URLs; add framework-aware adapter selection |
js/tutorial.js |
Update steps to: Task → Model → Runtime → Framework → Backend → Dataset → Run |
js/playground.js |
Update to use 6-layer pipeline; add framework selection |
js/bench.js |
No changes needed — already generic |
index.html |
Update layer bar if needed |
css/main.css |
Add styles for framework layer if needed |
Implementation phases¶
Phase 1: Fix ONNX and restore model selection¶
- Set
ONNX_MODEL_URLto HuggingFace CDN URL - Remove the
nullcheck and early throw inONNXAdapter.load() - Update
COMPAT.onnx→COMPAT.ortwith correct supported backends - Restore interactive model selection cards in
_renderModelCards() - Add
MODEL_REGISTRYwith CDN URLs for all models × runtimes - Filter runtime cards based on selected model
Phase 2: Add LiteRT.js runtime¶
- Implement
LiteRTAdapterclass (load.tflitefrom CDN, WASM+XNNPACK backend) - Add LiteRT.js to
COMPATmatrix - Add LiteRT.js to runtime options in
LayerRegistry - Add CDN URLs for
.tflitemodels toMODEL_REGISTRY
Phase 3: Add framework layer¶
- Add
FRAMEWORK_REGISTRYwith per-runtime framework options - Implement
_renderFrameworkCards()inPipelineCanvas - Add framework selection to
PipelineState(6th field) - Implement
ML5Adapterclass (wrapml5.imageClassifier()) - Update
AdapterFactoryto return framework-aware adapters - Update cascade rules (runtime change clears framework + backend)
Phase 4: Update tutorial and playground¶
- Update
tutorial.jssteps to match new pipeline order - Update
playground.jsto use 6-layer pipeline - Test all 6 benchmark combinations (3 runtimes × 2 modes)
- Update result display to show framework name alongside runtime
Phase 5: Polish and verify¶
- Verify all CDN URLs work (ORT models from HuggingFace,
.tflitefrom TF Hub/GCS) - Test model × runtime filtering (greyed out cards with reasons)
- Test cascade behavior (changing model clears runtime, etc.)
- Test framework overhead measurement (direct vs wrapper comparison)
- Update documentation (
index.md,architecture.md)
CDN sources for models¶
| Model | Format | CDN URL |
|---|---|---|
| MobileNet v2 | .onnx |
https://huggingface.co/onnxmodelzoo/mobilenetv2-12/resolve/main/mobilenetv2-12.onnx |
| MobileNet v2 | model.json |
Loaded via @tensorflow-models/mobilenet CDN package |
| MobileNet v2 | .tflite |
https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/5/converted_default/1 |
| SqueezeNet 1.1 | .onnx |
https://huggingface.co/onnxmodelzoo/squeezenet11/resolve/main/squeezenet11.onnx |
| SqueezeNet 1.1 | .tflite |
https://tfhub.dev/google/squeezenet/1.0/classification/1/converted_default/1 |
| EfficientNet-Lite0 | .tflite |
https://storage.googleapis.com/mediapipe-models/image_classifier/efficientnet_lite0/float32/1/efficientnet_lite0.tflite |
Thesis benchmark combinations¶
With all 3 runtimes × 2 modes (direct + framework wrapper), the prototype produces these benchmark rows:
| # | Runtime | Framework | What it measures |
|---|---|---|---|
| 1 | ORT Web | Direct | Baseline ORT inference |
| 2 | ORT Web | Transformers.js | Transformers.js wrapper overhead |
| 3 | TF.js | Direct | Baseline TF.js inference |
| 4 | TF.js | ml5.js | ml5.js wrapper overhead |
| 5 | LiteRT.js | Direct | Baseline LiteRT.js inference |
| 6 | LiteRT.js | MediaPipe Tasks | MediaPipe task API overhead |
For each combination, the user selects: model (MobileNet v2, SqueezeNet, or EfficientNet-Lite0) and backend (WASM, WebGPU, etc.), then runs inference on an input image.