Build your own MESS in /lab
A complete walkthrough of the lab workbench — pick a reactor topology, customise every component (anode material, cathode catalyst, chamber geometry, microbial culture, load circuit, separator), watch predictions update live as you change parameters, run a 30-day simulation with timed protocol keyframes, and export a reproducibility manifest + protocol Markdown when you're done.
What /lab is and what you can do with it
The /lab workbench is a parameter-driven, live-firing reactor design system. State lives in a single ModelParameters object with undo/redo (250ms coalescing window, 50-entry history, per-side A/B compare). Every parameter change re-runs the predictor and re-derives 3D mesh geometry in the same React commit — no polling, no fetches.
- Pick a model (left rail) → geometry swaps in the 3D canvas, parameter panel re-maps applicable fields.
- Open a designer drawer (Electrode, Chamber, Circuit, Stack, Collector, Port, Membrane, Organism) and edit components.
- Watch predictions update live (50ms debounce, coalesced undo). Power / current / CE / voltage with calibrated CI.
- Compatibility + advisory surface inline as you change things (7 hard rules + up to 3 contextual suggestions).
- Optional: add a timeline schedule — multi-step protocol applied as timed parameter patches over 30 days.
- Export reproducibility manifest (JSON) + protocol Markdown so the methods can be replicated.
Five minutes to your first design
Pick a topology
Left rail lists 21 reactor models grouped by class (B-MFC, S-MFC, P-MFC, MSC, BPV, BFC, X-MFC, RFB-MFC). Default: membraneless-mfc-air-cathode. Click to swap geometry.
Edit electrode design
Open the Anode tab. Pick a material from the grid (Carbon cloth is most-published; Graphite brush has highest surface area). Toggle surface treatments (heat-450 / acid / ammonia / PANI). Watch the polarization curve update.
Set operating conditions
Open the Conditions panel (right rail). Set temperature (35 °C is canonical), pH (7), HRT (12 h), COD (1000 mg/L), external resistance (1 kΩ). The predictor recomputes on each change.
Pick a microbe
Open the Organism drawer. Geobacter sulfurreducens for acetate substrates; Shewanella oneidensis for lactate / mixed; mixed-culture for wastewater. Each card shows growth-rate τ and fit-to-reactor advisory.
Check the live prediction
Right rail ModelingPanel → Live tab. Shows rolling Power / Current / CE / Voltage as you tweak parameters. TrustBadge per metric flags calibrated vs modeled vs curated confidence.
Compare alternatives
Toggle ComparePane to spin up A/B/C/D candidate designs. Each gets independent parameters + prediction history. Sticky delta footer shows power / current / CE / cost shifts.
Export protocol + manifest
ModelingPanel → Export tab. Downloads JSON manifest (schema 1.1) with inputs + predictions + material physics. Designer panel → Export Protocol button downloads Markdown with per-treatment assembly steps, references, decision-history trail.
ModelParameters — one object, all the truth
Every input in /lab lives in a single ModelParameters record. The page-level useUndoableParameters() hook tracks history (max 50 entries) with a 250ms coalescing window so slider drags don't fill the stack. URL syncs via writeUrlState() so deep links survive a refresh.
Shape
ModelParameters = {
// Geometry
chamberLengthMm, chamberWidthMm, chamberHeightMm,
electrodeSpacingMm, membraneThicknessMm, chamberCount,
// Materials
anodeMaterial, cathodeMaterial, membraneType,
anodeTreatments: string[], cathodeTreatments: string[],
anodeThicknessMmOverride?, cathodeAreaM2PerGOverride?,
// Chamber design
chamberMaterialId, chamberGeometryId, sealingId, portConfigId,
wallThicknessMm,
// Electronics
loadId, daqId, collectorMaterial, collectorDiameterMm,
collectorInsertionLengthMm, externalResistanceOhmOverride?,
// Biology
microbialSpecies, biofilmThicknessMm, inoculumConcentrationMgPerL,
cultureMix: string[],
// Operating
temperatureC, ph, flowRateMlPerMin, hrtHours,
currentDensityAPerM2, substrateConcentrationCodMgPerL,
operationMode: 'static' | 'continuous',
// Optional timeline
schedule?: ParameterSchedule // see Timeline section
}Undo / redo
250ms coalescing window — slider drags / live-fire changes coalesce into a single undo step. Intentional clicks > 300ms apart each register separately. Max 50-entry stack.
A/B compare
2–4 parallel workspaces, each with independent ModelParameters + prediction history. Shared undo disabled; each side has its own. Toolbar toggle switches single vs multi-workspace rendering.
URL state
Every change writes ?model=... query params via writeUrlState(). Deep links preserve full workspace state. Share a URL = share a reactor design.
Eight panels, every component customisable
The right-rail designer drawers are stacked disclosure-style. Each loads its own catalog (materials, geometries, treatments) and writes back to ModelParameters. Cross-panel dependencies trigger recompute (e.g. changing anode material updates the polarization curve in ModelingPanel).
ElectrodeDesignPanelMaterial grid (16 anode + 11 cathode) · 10 surface treatments · live polarization / biofilm / stability charts · ComparePane (2–4 candidates) · CompatibilityPane (8 rules) · ScaleUpPanel (lab → pilot → full) · DesignerAdvisoryColumn (3 suggestions). Deep dive in next section.
ChamberDesignPanel8 geometry options (flat single-chamber, tubular, stacked, etc.) · material (acrylic / polycarbonate / glass / PDMS) · sealing (o-ring / gasket / gland-fitting) · port config (inlet / outlet / sampling / vent / instrument) · wall thickness 0.5–5 mm. Rules: incompatible sealing for operating pressure, material chemical resistance vs substrate.
CircuitDesignPanelLoad topology: fixed resistor (1 Ω – 100 kΩ), variable load, potentiostat (constant voltage). DAQ: potentiostat + multi-channel ADC / standalone resistive / passive. Compatibility: constant-voltage mode requires potentiostat DAQ.
StackDesignPanelCell count (2–64) · series / parallel / hybrid topology · balancing (individual shunt resistors vs shared) · monitoring (per-cell voltage, current, temperature).
CollectorDesignPanelMaterial (Ti / Cu / Ni / stainless — corrosion + conductivity tradeoff) · diameter 0.5–2 mm wire gauge · insertion depth (affects electrode contact area).
PortDesignPanelPer-port connector type (luer-lock / compression-fitting / male-female nut) · shared tubing material (silicone / PTFE / polyurethane) · diameter 1–6 mm. Compatibility: connector ↔ tubing fit, pressure rating.
MembraneDesignPanelMaterial (Nafion 117, CMI-7000, sulfonated PEEK, etc.) · thickness override. Surfaces ion-transport selectivity + crossover risk per choice.
OrganismDesignPanelStrain tab: ranked species cards by MES roles (exoelectrogen-friendly first). Each card shows optimal pH/T range, growth-rate τ (hours), fit-to-reactor advisory, literature success count with similar electrodes. Community + Substrate tabs are stubs (not yet shipped).
ElectrodeDesignPanel — anode + cathode
The most-used designer. 1,000+ lines, modularised in feat/electrode-design-panel-first-pass (−540 LOC refactor 2026-05-15). Wraps two draft-tracked tabs (anode + cathode), each with material grid → treatments → biofilm predictor → polarization chart → compatibility pane → compare pane → scale-up panel → advisory column.
31 total (19 anode + 12 cathode) at apps/lab/src/app/lab/components/electrode-catalog.ts. Each card shows popularity ranking, conductivity (S/cm), specific surface area (m²/g), cost tier, cost per m², embodied carbon, recyclability, notes, reference DOI, and the full Phase A/B/C property triplet.
Anode (16)
Cathode (14)
10 treatments multiply conductivity, effective area, and biocompatibility factors. Each adds a cost increment. Stack treatments by toggling multiple — the order matters for Markdown protocol generation (heat first, then acid wash, then coating).
heat-450Burns off PTFE binder; +30% effective areaacid-HNO₃+10% area, +40% biocompatibilityammonia+20% conductivity, +60% biocompatibilityPANI coatingPolyaniline electron-shuttle layerCNT surface coating+2× effective areaO₂ plasma+30% biocompatibilityPTFE binder (10 wt%)Cathode standardNafion binder+proton conductivity (cathode)GDL (gas-diffusion layer)Cathode air-sidePTFE waterproofing (4×)Prevents cathode floodingPolarizationChartButler-Volmer per material (i₀, α, Tafel from catalog). Overlays anode oxidation + cathode ORR + ohmic drop. Shows operating point + max power + internal resistance. From `predict-polarization.ts`.
BiofilmCoverageChartExponential lag (~hours) then logistic rise to plateau. Inputs: material, treatments, species, HRT, substrate. Outputs: lag time, 90% coverage time, predicted electron-transfer mode (direct / mediated / mixed). From `predict-biofilm-coverage.ts`.
StabilityChart6-month decay envelope accounting for corrosion + fouling. Anode conductivity decline, cathode catalyst deactivation. From `predict-stability.ts`.
7 hard rules + 1 advisory rule. Evaluated by evaluateCompatibility() at every draft change; sorted by severity (error → warn → info). Each returns {ruleId, severity, message, reference?}.
gdl-on-anodeGDL appears on the anode (wrong side for gas diffusion)nafion-non-ptNafion used on non-Pt cathode (overkill; expensive)pt-sulfide-poisoningPt cathode + sulfide > 0.1 M (irreversible poisoning)mno2-acidic-phpH < 5 with MnO₂ (catalyst dissolves)stainless-anode-sulfideStainless anode + high sulfide (corrosion)biocathode-coldBiocathode start-up < 18 °C (slow colonization)pt-with-biocathode-redundancyBoth Pt-loaded (benchmark rig, not scale-up)high-cost-no-treatmentExpensive material with zero surface treatmentsComparePane2–4 candidate columns (A/B/C/D). Each shows full resolved metrics. Sticky delta footer: power Δ%, current Δ, CE Δ, cost shift $/cell, embodied carbon shift. "Promote to Design" applies the winner.
ScaleUpPanelInputs: lab electrode dimensions + measured lab power. Outputs: pilot (×20 area), full (×500). Per-phase learning curve from Logan 2008 literature. Cost / cell, start-up time, expected power.
DesignerAdvisoryColumn3 contextual suggestions max. Examples: "At pH 7 with Geobacter, Graphite brush is +12% power, +$23/cell" · "3 papers use Heat + Ammonia stacking — read papers" · "Pt is 65% of cost; Activated carbon gives 80% power at 12% cost". Re-evaluates every render.
ModelingPanel — 9 leaf tabs
Right-rail analysis surface. Two-level nested tabs (Live · Snapshot · Analyze · More with leaf children). URL deep-link via ?tab=<leafId>. /lab/wastewater?archetype=<slug> redirects (307) into Process TEA.
LivetopwhatPerformanceOverlay — rolling buffer of `predict()` snapshots (one per parameter change). Stacked time-series for Power (mW/m²), Current (A/m²), CE (%), Voltage (V), T, pH.
controlsHover inspector · play/pause simulation timeline (0–30 days) · speed presets 0.5× / 1× / 2× / 4× · TrustBadge per metric (calibrated / modeled / curated).
SnapshottopwhatSingle steady-state prediction from `predict()` + derived metrics. Power / current / CE / voltage cards, operating point on polarization curve. WastewaterEvidence overlay when config is wastewater-shaped.
controlsPer-system MEC/MES/MDC/MNRC/MMRC/MBES metric variants · species kinetics card · literature comparator (active vs reported range).
SensitivityAnalyzewhatTornado chart — one parameter varied ±10% (or literature bounds), impact on power/CE/voltage. R3-4 empirical effect bars from corpus.
controlsClick to perturb which parameter (temp, pH, HRT, electrode spacing, biofilm thickness, COD).
TrendsAnalyzewhatThree sub-views. Parameter sweep: fix others, vary one across range. Startup (0–30 days): exponential rise to asymptote, τ from species kinetics. Long-term (0–180 days): ±drift envelope, phase shading (lag → rise → steady → decline).
controlsAxis selector dropdown · operating-point marker.
Process TEAAnalyzewhatQSDsan-backed 7-archetype simulator. Archetypes: AnaerobicDigesterCSTR, MFCWithAnaerobicDigester, ActivatedSludgeProcess, MECWithAnaerobicDigester, ElectrocoagulationCell, StruviteFluidizedBed, AmmoniaStrippingTower. Streams table: IN/OUT flows (CH₄, CO₂, effluent, biosolids).
controlsArchetype picker · substrate composition edit (COD fractions) · inoculum dosing · HRT · 3D archetype viewer. Disclaimer: prototype, use for sensitivity not absolute TEA.
DiagnosticsAnalyzewhatSolver identifier (Butler-Volmer + Monod default, heuristic if env var set). Parameter validation against `/data/parameters/<slug>.json` fixtures — Status: OK / warn (out of typical range) / unknown / loading.
controlsFeature gates: roughness · ohmic · mass-transport corrections (toggleable). Validation caveat: "approximate — replace with bench-validated values once measured".
LiteratureMorewhatPreset literature ranges + W5 hierarchical corpus priors stratified by (system × domain) > domain > system > pooled. Distribution chart.
controlsFilter by journal year, organism, substrate type.
CouplingMorewhatReact-KaTeX equations for dominant coupled pathways (e.g. "Power ∝ i₀ · exp(αηF/RT) — electron transfer kinetics"). SVG reaction graph: nodes (H₂ / e⁻ / oxidized substrate), edges (enzymatic / abiotic transfer rates).
controlsRead-only pedagogical view.
ExportMorewhatReproducibility manifest (schema 1.1): inputs + predictions + material physics block (catalog i₀ / α / Tafel / ASR / Cdl when resolved). Optional notes + citations.
controlsDownload as `.json`, embeddable in GitHub / lab notebooks.
MESSViewer3D + electron-flow visualisation
React Three Fiber Canvas with 21 model geometries. Camera control (orbit / zoom / home / front / side / top). Click-to-select electrodes — highlights in teal, opens info sidebar. Live-fire mesh updates: every parameter change instantly re-renders 3D geometry (no polling, single React commit).
Particle-based visualisation in apps/web/src/app/lab/components/models/shared/MESSFlows.tsx. Each model declares its flow config; MESSFlows derives anchor points, particle counts (8–22 per flow), animation speed. ElectrodeAnchorContext lets models register electrode positions via useRegisterElectrodeAnchor() so paths derive synchronously.
Each model declares a parasitic: string[] array. MESSFlows renders these as secondary particle streams with PARASITIC_TINT (dimmed colour, slower animation). resolveParasiticFractions() computes the coulombic efficiency shortfall per pathway.
o2-crossoverOxygen diffuses through the separator into the anolyte → competes with the anode for electrons. Common in air-cathode and single-chamber designs.
methanogenesisArchaeal methanogens reduce CO₂ + H₂ → CH₄, consuming electrons that should hit the anode. Common in wastewater / mixed-culture inocula.
internal-shortDendrite growth or particulate bridge between anode and cathode → current bypasses the load. Higher risk with thin separators + biofilm overgrowth.
staticNo particles. Geometry only. Lowest GPU cost.biofilmMicrobial particles only. Useful for studying colonization patterns.flowAll 7 flow types render. Default mode.coupledAdds algae / redox flows for photosynthetic + hybrid models.30-day simulation with timed parameter patches
SimulationTimeline.tsx renders an 8px-tall phase-coloured track across 30 days. Default lifecycle events: day 0 (inoculation) · day 3 (nucleation) · day 7 (maturation) · day 14 (steady state) · day 21 (optimization window).
ScheduleEvent shape
ParameterSchedule = ScheduleEvent[]
ScheduleEvent = {
day: number // 0..30
patch: Record<string, number | string> // partial ModelParameters
rationale?: string
substrateSlug?: string // e.g. "brewery_wastewater"
}
// Applied in ascending day order
// Last event with day ≤ current time is active
// Array keys (e.g. anodeTreatments) stripped before patchingPlayheadDiamond slider on the timeline track. Drag to scrub through any day.SpeedPresets 0.5× · 1× · 2× · 4×.Play / pauseToggle animation.Qualitylow / medium / high — affects 3D particle count + render fidelity.Keyframe pinsSurface when schedule prop is non-empty (from user or AI agent).Hover tooltipEvent name + description on each phase marker.The AI chat's createSchedule tool proposes a multi-step protocol (e.g. "Day 0: inoculate. Day 7: switch to continuous flow + raise temperature to 37 °C. Day 14: switch substrate to brewery wastewater"). Surfaces as a new ParameterSchedule object; you apply or dismiss. Integrates with SimulationTimeline keyframe rendering.
Reproducibility manifest + procedural Markdown
Two exports, both grounded in the current design state. The JSON manifest captures every input + prediction + material physics block. The Markdown procedure is a Methods-section-ready document with per-treatment assembly steps, inoculation + start-up details, and a decision-history trail.
JSON manifest
schema 1.1- Inputs (full ModelParameters)
- Predictions (PredictionResult + validationStatus)
- materialPhysics block: anode/cathode catalog id + resolved physics (i₀, α, Tafel, ASR, Cdl)
- Optional researcher notes + citations
- Embeddable in GitHub / Zenodo / reproducibility archives
- Triggered from ModelingPanel → Export tab
Protocol Markdown
generate-protocol.ts- Title (design name) + ISO timestamp
- Materials (effective area m²/g, treatments, thickness, references)
- Reactor context (chamber dims, electrode spacing, T, pH, species)
- Per-treatment assembly steps (heat-450 → acid-HNO₃ → ammonia → PANI → CNT → ...)
- Assembly + inoculation + start-up (expected lag, 90% coverage, EIS sweep schedule)
- References (deduped from material + treatment papers)
- Decision-history trail (if enabled): "Considered PANI@CNT sponge on day 2; predicted +340 mW/m²; dismissed for budget"
- Footer caveat about prediction honesty
LocalStorage-backed event log (max 200 entries, workspace-scoped). Tracks candidate-considered, candidate-promoted, finding-dismissed (with microform reason), optimiser-run. The learningOptIn flag sends dismissal reasons to a separate shared bucket for future server sync. generateProtocolMarkdown() appends this trail to the exported Markdown so methods are auditable.
ISMET 2026 5-parameter minimum + 13 advisory criteria
The 5-parameter checklist is empirically validated: 63 papers, >40% IQR reduction on power density (487 → 278 mW/m²; p < 0.05). The additional 13 criteria are best-practice but untested for variance impact. Interactive scorer at /tools/reproducibility.
Electrode spacing
electrode_spacing · electrode_distance · inter_electrode_distance · anode_cathode_distance
Electrode surface area
anode_surface_area · cathode_surface_area · electrode_area · projected_electrode_area
External resistance
external_resistance · load_resistance · circuit_resistance · r_ext
Measurement method
measurement_method · measurement_protocol · data_acquisition_system · polarization_curve_protocol · sampling_interval
Unit normalization basis
unit_normalization_basis · power_density_basis · current_density_basis · normalization_reference
Implemented in open-source/mess-methods/src/validation/scientific_validator.py (Python). Consumed by the v2 extractor (inline quality checks) and the /hunter pipeline. Currently advisory in the chat + extraction layer, NOT hard-enforced in the lab form (so you can still type CE > 100% if you really want).
power_identityP_observed ≈ V_cell · I (OCV fallback if V missing).
ce_bounds0 ≤ CE ≤ 100% — anything outside the unit interval is a flag.
voltage_orderingV_cell ≤ V_oc (5% slack for measurement noise).
max_power_ohmP_peak ≤ V_oc² / (4·R_int) — ohm-law ceiling.
ocv_thermodynamic_ceilingOCV ≤ system-class ceiling (MFC/MEC/MDC bounds from thermodynamics).
faraday_h2_ceilingr_H₂ ≤ I·A / (2F·V) · 22.414 (MEC only; Faraday ceiling on H₂ rate).
temperature_out_of_plausible_rangeOutside −20 to 100 °C → flag as likely extraction error.
removal_out_of_unit_intervalCOD / N / P removal must be 0–100%.
non_positivecurrentDensity, powerDensity must be > 0 in steady operation.
within_paper_duplicateSame slug, same conditionSet, < 5× spread — otherwise flag.
/tools/reproducibilityInteractive 5-param scorer with toggle controls + comprehensive 18-param view. IQR-reduction evidence chart. Corpus distribution (289 papers).
/research/paper/[slug]Per-paper reproducibility score visible on paper detail pages. Five-param status + which criteria are missing.
/research/uploadOn submitting a DOI, scores it automatically against both 5-param + 18-param checklists. Returns one of 4 status shapes.
Templates, suggestions, methodology
Recommendations surface at three levels: in the Designer (advisory column), in the lab catalog (literature + demo templates), and through the AI chat (recommendLiteratureTemplate + getDemoTemplate + getObservationTemplate).
Demo templates
23 hand-curatedIn apps/web/src/app/[lang]/demo/*-extracted-data.ts. Each has source DOI, innovation framing, 1–4 baselines (each: parameters, measured_outcomes, materials, microbe, substrate). Pre-selected best_baseline_index. Outrank corpus templates (ranking_score 2.5 + 0.5/outcome).
Literature templates
148 corpus-derivedBuilt from 18,114 parameter rows across 3,944 papers (build-literature-templates.ts). Each: source, system_type, model_class, parameters, measured_outcomes, substrate, materials (anode/cathode/other), microbes, n_param_rows, ranking_score.
Observation templates
12 (v1.3 schema)Auto-derived from v1.x extractions. Rich v1.3 fields: significance (domain_first, quantitative_claim), prior_work_comparisons (DOI + metric + relative_improvement), author_recommended_variations (parameter + direction + rationale).
Six tabs in MethodologyTabContent.tsx. Markdown bundled at build via scripts/generate-methodology-fixture.ts so first paint pays no fetch cost. Tier-1 verdict summary above tabs shows 5 sub-checks (grounding 85.95% FLAG · literature cross-check 12/15 PASS · unit coverage 97.18% PASS · duplicate agreement 97.37% PASS · noise floor FAIL).
How we build the catalogMarkdown from METHODOLOGY.md — extraction pipeline, schema decisions, manual curation steps.
Known limitationsMarkdown from SCIENTIFIC_INTEGRITY.md (515 lines) — correlation caveats, reproducibility scoring tier heuristics, sample-size limits, confounding.
Extraction SchemaRich component (ExtractionMethodologyTab) showing the v2 flat schema (paper_header + values[]).
GlossaryRich component (GlossaryTab) with parameter aliases + canonical slug mapping.
Collection EngineRich component (CollectionEngineTab) — how papers enter the corpus (paperscraper, DOI lookup, OCR).
Open Source DataRich component (OpenSourceTab) — link out to the 9 mess-* packages + their data files.
What predictions are — and aren't
The /lab predictor is a single-overpotential snapshot, not a full multi-physics solve. Reading the validation status badges and feature gates matters for interpreting results.
Single-overpotential snapshot · ±25% uncertainty · no full multi-physics solve. Default for predict.ts. Use for design sensitivity, NOT for absolute performance claims.
Heuristic v1 fallback. Active when NEXT_PUBLIC_LAB_PHYSICS=heuristic. Less rigorous; for early exploration only.
These system types currently fall back to MFC kinetics with confidence="low" — no dedicated PEM / SOFC / PAFC predictors exist yet. Note in `predictors/index.ts` lines 268-283.
QSDsan-backed simulator. Use for sensitivity, NOT for absolute TEA. Disclaimer surfaced in-panel.
effects.json currently data_status="below_threshold" (28 obs, 2 papers; need 30 obs + 5 papers). Within-paper effects card greys out until corpus catches up.
pgmpy BN posterior cells = 0 (corpus has 18 cod_removal extractions total; R3-NEW pipeline backfill in progress). Falls back to stratum priors.
The 10 ScientificValidator rules (power_identity, ce_bounds, etc.) flag in extraction + chat — they do NOT hard-block lab form input. You can enter CE > 100% if you want; the prediction will reflect that.
Generate-protocol.ts produces a generic per-treatment Markdown. It does NOT yet annotate steps with the exact methods from a specific paper. "Reproduce this paper" requires reading the source DOI directly. Known gap.
Only the 5-param checklist has empirical validation (63 papers, p < 0.05 on IQR reduction). The 13 additional criteria are best-practice but untested. Category-level averaging masks within-category variance.