We’re organizing an online expert workshop (late April / early May 2026) to dig into the key cost cruxes — media costs, bioreactor scale-up, and the gap between TEA projections and commercial reality. This model is one of the tools we’ll use.
Comment directly on this page using Hypothesis — click the < tab on the right edge. Highlight any text, parameter, or result to annotate it. We actively monitor comments and will respond to questions, incorporate suggestions, and improve the model based on your feedback.
Quick summary: Cultured chicken is produced by growing avian muscle cells in bioreactors. The main cost drivers are media (amino acids, nutrients), growth factors (signaling proteins), bioreactors (capital equipment), and operating costs.
CELL BANK → SEED TRAIN → PRODUCTION → HARVEST → PRODUCT
[O] [OOO] [OOOOOOO] [===] [≡≡≡]
Learn: Understanding Uncertainty & Distributions
This model uses Monte Carlo simulation: we sample thousands of possible futures and see what distribution of costs emerges.
Distribution Types Used:
Parameter Type
Distribution
Why
Examples in model
Costs, intensities
Lognormal
Always positive, right-skewed (some very high values possible)
Media cost per liter, GF price per gram, cell density
Probabilities, fractions
Beta
Bounded between 0 and 1, flexible shape
Maturity factor, adoption probabilities, uptime. For switching parameters (e.g., hydrolysate adoption), the model first samples an adoption probability from a Beta distribution, then uses a Bernoulli draw to determine whether each simulation run uses the “adopted” or “non-adopted” cost regime.
Bounded ranges
Uniform
Equal probability within bounds, used when we have only a plausible range and no reason to favor values within it
Asset life (years), CAPEX scale exponent, fixed OPEX scaling factor
We are open to considering alternative distributional forms (e.g., triangular, PERT, or mixture distributions) and to making the modeling flexible enough for users to select or compare different distributional assumptions. Suggestions are welcome via Hypothesis annotations.
Reading the Results:
p5 (5th percentile): “Optimistic” - only 5% of simulations are cheaper
p95 (95th percentile): “Pessimistic” - 95% of simulations cheaper
The “Maturity” Correlation:
A key feature is the latent maturity factor that links:
Technology adoption rates
Reactor costs
Financing costs (WACC)
In “good worlds” for cultured chicken (high maturity), multiple things improve together. This prevents unrealistic scenarios where technology succeeds but financing remains difficult.
This approach draws on the concept of copula-based correlation in Monte Carlo simulation, where a shared latent variable induces dependence among otherwise independent marginal distributions. See Vose (2008), Risk Analysis for a textbook treatment of correlated sampling in cost models, and Morgan & Henrion (1990), Uncertainty for foundational discussion of dependent uncertainties.
More detail on the maturity factor implementation
The maturity factor is sampled once per simulation from a Beta distribution (mean set by the “Industry Maturity” slider, standard deviation 0.20). It then shifts the adoption probabilities (hydrolysates, food-grade, recombinant GFs) and adjusts WACC downward in high-maturity draws. This creates positive correlation among “good news” variables without imposing a rigid structure. The strength of the correlation is moderate by design – maturity explains some but not all of the variation in each parameter.
Interactive Model
Code
functionmulberry32(seed) {returnfunction() {let t = seed +=0x6D2B79F5; t =Math.imul(t ^ t >>>15, t |1); t ^= t +Math.imul(t ^ t >>>7, t |61);return ((t ^ t >>>14) >>>0) /4294967296; }}// ============================================================// STATISTICAL SAMPLING FUNCTIONS// ============================================================// Box-Muller transform for standard normalfunctionboxMuller(rng) {const u1 =rng();const u2 =rng();returnMath.sqrt(-2*Math.log(u1)) *Math.cos(2*Math.PI* u2);}// Sample from lognormal given p5 and p95functionsampleLognormalP5P95(rng, p5, p95, n) {const Z_95 =1.6448536269514722;const mu = (Math.log(p5) +Math.log(p95)) /2;const sigma = (Math.log(p95) -Math.log(p5)) / (2* Z_95);const samples =newArray(n);for (let i =0; i < n; i++) { samples[i] =Math.exp(mu + sigma *boxMuller(rng)); }return samples;}// Sample uniformfunctionsampleUniform(rng, lo, hi, n) {const samples =newArray(n);for (let i =0; i < n; i++) { samples[i] = lo + (hi - lo) *rng(); }return samples;}// Beta distribution parameters from mean/stdevfunctionbetaFromMeanStdev(mean, stdev) {let variance = stdev * stdev;const maxVar = mean * (1- mean);if (variance <=0|| variance >= maxVar) { stdev =Math.sqrt(maxVar *0.99); variance = stdev * stdev; }const t = maxVar / variance -1;const a =Math.max(mean * t,0.01);const b =Math.max((1- mean) * t,0.01);return [a, b];}// Sample from beta using Joehnk's algorithm (simple, works for all a,b > 0)functionsampleBeta(rng, a, b) {// Use gamma ratio methodconst gammaA =sampleGamma(rng, a);const gammaB =sampleGamma(rng, b);return gammaA / (gammaA + gammaB);}// Sample from gamma distribution (Marsaglia and Tsang's method)functionsampleGamma(rng, shape) {if (shape <1) {returnsampleGamma(rng, shape +1) *Math.pow(rng(),1/ shape); }const d = shape -1/3;const c =1/Math.sqrt(9* d);while (true) {let x, v;do { x =boxMuller(rng); v =1+ c * x; } while (v <=0); v = v * v * v;const u =rng();if (u <1-0.0331* (x * x) * (x * x)) return d * v;if (Math.log(u) <0.5* x * x + d * (1- v +Math.log(v))) return d * v; }}// Sample from beta given mean/stdevfunctionsampleBetaMeanStdev(rng, mean, stdev, n) {const [a, b] =betaFromMeanStdev(mean, stdev);const samples =newArray(n);for (let i =0; i < n; i++) { samples[i] =sampleBeta(rng, a, b); }return samples;}// Capital Recovery Factorfunctioncrf(wacc, nYears) {return wacc *Math.pow(1+ wacc, nYears) / (Math.pow(1+ wacc, nYears) -1);}// Clip values between min and maxfunctionclip(arr, min, max) {return arr.map(v =>Math.min(Math.max(v, min), max));}// Element-wise operationsfunctionadd(a, b) { return a.map((v, i) => v + b[i]); }functionmul(a, b) { return a.map((v, i) => v * b[i]); }functiondiv(a, b) { return a.map((v, i) => v / b[i]); }functionscale(arr, s) { return arr.map(v => v * s); }// ============================================================// MAIN SIMULATION FUNCTION// ============================================================functionsimulate(n, seed, params) {const rng =mulberry32(seed);// Latent maturity factorconst maturity =sampleBetaMeanStdev(rng, params.maturity_mean,0.20, n);// Scale and uptimeconst plant_kta =sampleLognormalP5P95(rng, params.plant_kta_p5, params.plant_kta_p95, n);const uptime =sampleBetaMeanStdev(rng, params.uptime_mean,0.05, n);const output_kgpy =mul(scale(plant_kta,1e6), uptime);// Adoption probabilities (maturity-adjusted)let p_hydro =sampleBetaMeanStdev(rng, params.p_hydro_mean,0.10, n); p_hydro =clip(add(p_hydro,scale(maturity.map(m => m -0.5),0.25)),0,1);let p_foodgrade =sampleBetaMeanStdev(rng, params.p_foodgrade_mean,0.10, n); p_foodgrade =clip(add(p_foodgrade,scale(maturity.map(m => m -0.5),0.20)),0,1);let p_recf =sampleBetaMeanStdev(rng, params.p_recfactors_mean,0.15, n); p_recf =clip(add(p_recf,scale(maturity.map(m => m -0.5),0.25)),0,1);// Bernoulli draws for adoptionconst is_hydro = p_hydro.map(p =>rng() < p);const is_foodgrade = p_foodgrade.map(p =>rng() < p);const is_recf_cheap = p_recf.map(p =>rng() < p);// Process intensitiesconst density_gL =sampleLognormalP5P95(rng, params.density_gL_p5, params.density_gL_p95, n);const cycle_days =sampleLognormalP5P95(rng,0.5,5.0, n);const media_turnover =sampleLognormalP5P95(rng, params.media_turnover_p5, params.media_turnover_p95, n);const L_per_kg =mul(div(density_gL.map(_ =>1000), density_gL), media_turnover);// Media costconst media_cost_hydro =sampleLognormalP5P95(rng,0.2,1.2, n);const media_cost_pharma =sampleLognormalP5P95(rng,1.0,4.0, n);const media_cost_L = is_hydro.map((h, i) => h ? media_cost_hydro[i] : media_cost_pharma[i]);const cost_media =mul(L_per_kg, media_cost_L);// Commodity micronutrientsconst g_comm_food =sampleLognormalP5P95(rng,0.1,2.0, n);const g_comm_pharma =sampleLognormalP5P95(rng,1.0,10.0, n);const g_comm = is_foodgrade.map((f, i) => f ? g_comm_food[i] : g_comm_pharma[i]);const price_comm_food =sampleLognormalP5P95(rng,0.02,2.0, n);const price_comm_pharma =sampleLognormalP5P95(rng,0.5,20.0, n);const price_comm = is_foodgrade.map((f, i) => f ? price_comm_food[i] : price_comm_pharma[i]);const cost_comm_micros =mul(g_comm, price_comm);// Recombinant growth factors (FGF-2, IGF-1, TGF-β, etc.)// CRITICAL: Literature shows GFs can be 55-95% of media cost at current prices// Current prices: FGF-2 ~$50,000/g, TGF-β up to $1M/g// Target prices: $1-10/g with scaled recombinant production// Quantity (g/kg meat) - based on typical concentrations in media// ~10-100 ng/mL in media × 20-60 L/kg = 0.0002-0.006 g/kgconst g_recf_cheap =sampleLognormalP5P95(rng,1e-4,5e-3, n);// Reduced usage with optimizationconst g_recf_exp =sampleLognormalP5P95(rng,5e-4,2e-2, n);// Standard usageconst g_recf = is_recf_cheap.map((c, i) => c ? g_recf_cheap[i] : g_recf_exp[i]);// Price ($/g) - Scaled by gf_progress parameter (0-100%)// At 0% progress: current prices ($5k-500k expensive, $100-10k cheap)// At 100% progress: target prices ($50-5k expensive, $1-100 cheap)const progress = params.gf_progress/100;// 0 to 1// Interpolate price ranges based on progress// Cheap scenario: $100-10,000 at 0% → $1-100 at 100%const cheap_p5 =100*Math.pow(0.01, progress);// 100 → 1const cheap_p95 =10000*Math.pow(0.01, progress);// 10000 → 100const price_recf_cheap =sampleLognormalP5P95(rng, cheap_p5, cheap_p95, n);// Expensive scenario: $5,000-500,000 at 0% → $50-5,000 at 100%const exp_p5 =5000*Math.pow(0.01, progress);// 5000 → 50const exp_p95 =500000*Math.pow(0.01, progress);// 500000 → 5000const price_recf_exp =sampleLognormalP5P95(rng, exp_p5, exp_p95, n);const price_recf = is_recf_cheap.map((c, i) => c ? price_recf_cheap[i] : price_recf_exp[i]);const cost_recf =mul(g_recf, price_recf);// Other variable costsconst other_var =sampleLognormalP5P95(rng,0.5,5.0, n);// VOC totalconst voc =add(add(add(cost_media, cost_comm_micros), cost_recf), other_var);// CAPEX calculationlet capex_perkg =newArray(n).fill(0);if (params.include_capex) {const prod_kg_L_day =div(scale(density_gL,1/1000), cycle_days);const total_working_volume_L =div(output_kgpy,scale(prod_kg_L_day,365));const reactor_cost_L_pharma =sampleLognormalP5P95(rng,50,500, n);const custom_ratio =sampleUniform(rng,0.35,0.85, n);let custom_share =sampleBetaMeanStdev(rng,0.55,0.15, n); custom_share =clip(add(custom_share,scale(maturity.map(m => m -0.5),0.30)),0,1);const reactor_cost_L_avg = reactor_cost_L_pharma.map((p, i) => p * (custom_share[i] * custom_ratio[i] + (1- custom_share[i])) );const capex_s =sampleUniform(rng,0.6,0.9, n);const plant_factor =sampleLognormalP5P95(rng,1.5,3.5, n);const V_ref =1e6;const capex_total = reactor_cost_L_avg.map((r, i) => r * total_working_volume_L[i] *Math.pow(total_working_volume_L[i] / V_ref, capex_s[i] -1) * plant_factor[i] );let wacc =sampleLognormalP5P95(rng, params.wacc_p5, params.wacc_p95, n); wacc =clip(wacc.map((w, i) => w -0.03* (maturity[i] -0.5)),0.03,1);const asset_life =sampleUniform(rng, params.asset_life_lo, params.asset_life_hi, n);const crf_val = wacc.map((w, i) =>crf(w, asset_life[i])); capex_perkg = capex_total.map((c, i) => (c * crf_val[i]) / output_kgpy[i]); }// Fixed OPEX calculationlet fixed_perkg =newArray(n).fill(0);if (params.include_fixed_opex) {const ref_output =20e6*0.9;const fixed_perkg_ref =sampleUniform(rng,1.0,6.0, n);const fixed_annual_ref =scale(fixed_perkg_ref, ref_output);const fixed_scale =sampleUniform(rng,0.6,1.0, n);const fixed_annual = fixed_annual_ref.map((f, i) => f *Math.pow(output_kgpy[i] / ref_output, fixed_scale[i]) ); fixed_perkg =div(fixed_annual, output_kgpy); }// Downstream processing (scaffolding, texturization) for structured productslet downstream_perkg =newArray(n).fill(0);if (params.include_downstream) {// Downstream adds $2-15/kg for structured products downstream_perkg =sampleLognormalP5P95(rng,2.0,15.0, n); }// Total unit costconst unit_cost =add(add(add(voc, capex_perkg), fixed_perkg), downstream_perkg);return { unit_cost, cost_media, cost_comm_micros, cost_recf,cost_other_var: other_var,cost_capex: capex_perkg,cost_fixed: fixed_perkg,cost_downstream: downstream_perkg,pct_hydro: is_hydro.filter(x => x).length/ n,pct_foodgrade: is_foodgrade.filter(x => x).length/ n,pct_recf_cheap: is_recf_cheap.filter(x => x).length/ n,// Input parameters for sensitivity analysismaturity_samples: maturity,density_samples: density_gL,media_turnover_samples: media_turnover,L_per_kg_samples: L_per_kg,media_cost_L_samples: media_cost_L,is_hydro_samples: is_hydro.map(x => x ?1:0),is_foodgrade_samples: is_foodgrade.map(x => x ?1:0),is_recf_cheap_samples: is_recf_cheap.map(x => x ?1:0),g_recf_samples: g_recf,price_recf_samples: price_recf,plant_kta_samples: plant_kta,uptime_samples: uptime };}// Statistical helpersfunctionquantile(arr, q) {const sorted = [...arr].sort((a, b) => a - b);const idx = (sorted.length-1) * q;const lo =Math.floor(idx);const hi =Math.ceil(idx);const frac = idx - lo;return sorted[lo] * (1- frac) + sorted[hi] * frac;}functionmean(arr) {return arr.reduce((a, b) => a + b,0) / arr.length;}// Spearman rank correlation coefficientfunctionspearmanCorr(x, y) {const n = x.length;// Rank function (handles ties with average rank)functionrank(arr) {const sorted = arr.map((v, i) => ({v, i})).sort((a, b) => a.v- b.v);const ranks =newArray(n);let i =0;while (i < n) {let j = i;while (j < n -1&& sorted[j +1].v=== sorted[j].v) j++;const avgRank = (i + j) /2+1;for (let k = i; k <= j; k++) ranks[sorted[k].i] = avgRank; i = j +1; }return ranks; }const rx =rank(x);const ry =rank(y);// Pearson correlation of ranksconst meanRx =mean(rx);const meanRy =mean(ry);let num =0, denX =0, denY =0;for (let i =0; i < n; i++) {const dx = rx[i] - meanRx;const dy = ry[i] - meanRy; num += dx * dy; denX += dx * dx; denY += dy * dy; }return num /Math.sqrt(denX * denY);}
html`<div id="simplified-note" style="display: ${simpleMode ?'block':'none'}; background: #f0f4e8; border-left: 4px solid #5a7a5a; padding: 0.7rem 0.9rem; margin-bottom: 1rem; font-size: 0.82em; line-height: 1.5; border-radius: 0 4px 4px 0;"><strong>Simplified view:</strong> Less pivotal parameters (plant capacity, uptime, financing costs, food-grade micronutrients, media turnover) are set to reasonable defaults.In our sensitivity analysis, these contribute less than 10% of the variance in cost estimates.<em>Switch off to adjust all parameters.</em></div>`
What are these options? Why would you toggle them?
CAPEX: Bioreactor and facility capital costs, annualized. On by default because capital costs are a substantial portion of total production cost. You might toggle this off to isolate variable operating costs or to compare with analyses that report only VOC.
Fixed OPEX: Labor, maintenance, overhead (scales sub-linearly with plant size). On by default for the same reason. Toggle off to focus on marginal costs only.
Downstream: Scaffolding, texturization, and forming for structured products. Off by default because the base model estimates cost of unstructured cell mass. Toggle on if you are interested in structured products (steaks, chicken breast), which add $2-15/kg.
Blended product cost: Most cultivated meat products in development are hybrids — e.g., 10-30% cultured cells blended with plant-based filler. Toggle on to see estimated blended ingredient cost alongside pure cell cost. Default: 25% CM inclusion, $3/kg filler (plant protein / mycoprotein).
Note: Most published TEAs report costs with CAPEX and Fixed OPEX included. Toggling them off produces numbers that are not comparable to standard literature estimates.
Key Parameters
These sliders set the center of each parameter’s distribution used in the Monte Carlo simulation. They are not simple point estimates – the simulation samples around these values. For example, setting Plant Capacity to 20 kTA means the simulation draws plant sizes from a lognormal distribution centered near 20 kTA (specifically, p5=10 and p95=40). All charts and results below update dynamically as you adjust these sliders.
What is this? Where do these ranges come from? (click to expand)
Annual production capacity in thousand metric tons (kTA). Current pilots: <1 kTA. Commercial target: 10-50 kTA.
Slider range (5-100 kTA): The lower bound (5 kTA) represents a modest first-generation commercial facility. The upper bound (100 kTA) represents an optimistic large-scale facility. The default (20 kTA) matches the reference scale in Risner et al. (2021) and is a commonly used benchmark in TEA literature.
What plant size affects:
Cost Component
Effect of Larger Plant
CAPEX per kg
↓ Scales sub-linearly (power law ~0.6-0.9)
Fixed OPEX per kg
↓ Overhead spread over more output
Variable costs per kg
— No direct effect (same $/L, $/g)
Larger plants have lower per-kg costs due to economies of scale in capital and fixed costs. Variable costs (media, growth factors) don’t change with scale — they depend on technology adoption.
What is this?
Fraction of capacity actually used. Accounts for downtime, cleaning, maintenance. 90% is optimistic for new industry.
Code
viewof maturity = Inputs.range([0.1,0.9], {value:0.5,step:0.05,label:"Industry Maturity by 2036"})
What is this?
A latent factor (0=nascent, 1=mature) that affects all technology adoption, reactor costs, and financing. High maturity = correlated improvements.
What does the year affect?
Earlier years → lower maturity, less technology adoption. Later years → more time for cost reductions and scale-up. The model adjusts maturity expectations based on years from 2024.
Technology Adoption by
Probability that each cost-reducing technology is widely adopted by the projection year.
Why 75% baseline?Recent research (2024-2025) shows hydrolysates are already validated across plant, yeast, insect, and fish sources. Companies like IntegriCulture have reduced media components by replacing amino acids with yeast extract. The main uncertainty is regulatory approval for food products, not technical feasibility.
viewof gf_progress = Inputs.range([0,100], {value:50,step:5,label:html`GF cost reduction by ${target_year} (%)`})
What do these sliders control? (click to expand)
Two controls for growth factors: (1) P(Scalable GF technology) sets the probability of a breakthrough reaching commercial scale (switches between “expensive” and “cheap” price regimes). (2) GF cost reduction progress sets how far prices have fallen within each regime by the projection year — 0% = current prices, 100% = industry targets achieved.
Growth factors are signaling proteins (FGF-2, IGF-1, TGF-β, etc.) that tell cells to proliferate. Currently the most expensive media component — often 55-95% of media cost at research scale.
Why this is modeled as a binary switch + continuous progress:
The switch represents whether any scalable technology reaches commercial viability
The progress slider represents how far costs have dropped within that regime
Even in the “expensive” scenario (no breakthrough), incremental improvements occur
This structure captures the bimodal nature of the uncertainty: either scalable production is achieved, or it isn’t
Model cost impact:
Scenario
Usage (g/kg)
Price ($/g)
Cost/kg chicken
No breakthrough
0.0005 - 0.02
$500 - $50,000
$0.25 - $1,000
Breakthrough achieved
0.0001 - 0.005
$1 - $100
$0.0001 - $0.50
This is a pivotal uncertainty. The GFI 2024 State of the Industry report identifies growth factor cost reduction as one of the top technical challenges. If solved, GFs become negligible; if not, they dominate the cost structure.
viewof wacc_lo = Inputs.range([5,20], {value:8,step:1,label:"WACC Low (%)"})viewof wacc_hi = Inputs.range([10,35], {value:20,step:1,label:"WACC High (%)"})viewof asset_life_lo = Inputs.range([5,15], {value:8,step:1,label:"Asset Life Low (years)"})viewof asset_life_hi = Inputs.range([10,30], {value:20,step:1,label:"Asset Life High (years)"})
What are WACC and Asset Life? (click to expand)
WACC (Weighted Average Cost of Capital): The blended rate of return required by debt and equity investors, used to annualize capital costs via the Capital Recovery Factor (CRF). A WACC of 8% is typical for established food manufacturing; 20%+ reflects the high risk premium investors demand for an unproven technology. The simulation samples WACC from a lognormal distribution between these bounds, further adjusted by the maturity factor.
Asset Life: How many years bioreactor and facility equipment is depreciated over. Shorter life (8 years) means higher annual capital charges; longer life (20 years) spreads costs but assumes equipment remains productive. The range reflects uncertainty about equipment durability in a novel industry.
These two parameters together determine the Capital Recovery Factor: CRF = r(1+r)^n / ((1+r)^n - 1), where r = WACC and n = asset life in years.
Cell Density Range
Code
viewof density_lo = Inputs.range([10,100], {value:30,step:10,label:"Cell Density Low (g/L)"})viewof density_hi = Inputs.range([50,300], {value:200,step:10,label:"Cell Density High (g/L)"})
What is cell density? (click to expand)
Cell density (g/L) determines how much meat you get per liter of media. Higher density = less media per kg of product = lower cost. Current lab scale: 10-50 g/L. TEA projections: 50-200 g/L. This is a key driver of media efficiency.
results = {// Adjust maturity based on target year (2024 baseline)// Later years allow more time for industry developmentconst yearFactor =Math.max(0,Math.min(1, (target_year -2024) /20));const adjustedMaturity = maturity * (0.5+0.5* yearFactor);const params = {plant_kta_p5: simpleMode ?10: plant_capacity *0.5,plant_kta_p95: simpleMode ?40: plant_capacity *2.0,uptime_mean: simpleMode ?0.90: uptime,maturity_mean: adjustedMaturity,p_hydro_mean: p_hydro,p_foodgrade_mean: simpleMode ?0.65: p_foodgrade,p_recfactors_mean: p_recfactors,wacc_p5: simpleMode ?0.08: wacc_lo /100,wacc_p95: simpleMode ?0.20: wacc_hi /100,asset_life_lo: simpleMode ?8: asset_life_lo,asset_life_hi: simpleMode ?20: asset_life_hi,density_gL_p5: density_lo,density_gL_p95: density_hi,media_turnover_p5: simpleMode ?1: media_turnover_lo,media_turnover_p95: simpleMode ?10: media_turnover_hi,include_capex: simpleMode ?true: include_capex,include_fixed_opex: simpleMode ?true: include_fixed_opex,include_downstream: simpleMode ?false: include_downstream,gf_progress: gf_progress };returnsimulate(30000,42, params);}// Calculate statisticsstats = {const uc = results.unit_cost;const bs =typeof blending_share ==="number"? blending_share :0.25;const fc =typeof filler_cost ==="number"? filler_cost :3;const blended = uc.map(c => c * bs + fc * (1- bs));return {n: uc.length,p5:quantile(uc,0.05),p50:quantile(uc,0.50),p95:quantile(uc,0.95),prob_10: uc.filter(x => x <10).length/ uc.length*100,prob_25: uc.filter(x => x <25).length/ uc.length*100,prob_50: uc.filter(x => x <50).length/ uc.length*100,prob_100: uc.filter(x => x <100).length/ uc.length*100,blended_p50:quantile(blended,0.50),blended_p5:quantile(blended,0.05),blended_p95:quantile(blended,0.95) };}
Results Summary
Code
html`<div style="background: #f8f9fa; padding: 1rem 1.25rem; border-left: 4px solid #3498db; margin-bottom: 1.5rem; font-size: 0.95em; line-height: 1.6;"><strong>What these numbers represent:</strong> Simulated <strong>production cost per kilogram of pure cultured chicken cells</strong> (wet weight, unprocessed) in <strong>${target_year}</strong>, based on ${stats.n.toLocaleString()} Monte Carlo simulations. This is the cost to produce cell mass in a bioreactor — not the cost of a consumer product, and not retail price.<br><br><strong><span title="UPSIDE Foods' chicken cutlet is a blend of cultured chicken cells and plant-based ingredients. SuperMeat's chicken burger used ~30% cultured cells. The GFI State of the Industry 2024 report notes that 'hybrid products combining cultivated and plant-based ingredients are the most likely near-term path to market.' Eat Just/GOOD Meat's Singapore-approved product uses cultured chicken in a plant-protein matrix.">Pure cells vs. consumer products:</span></strong> Most cultivated meat products on the market or in development are <em>hybrid products</em> — blending a fraction of cultured cells with plant-based or mycoprotein ingredients. A product with (say) 20% cultured cells and 80% plant-based filler at $3/kg would have a blended ingredient cost far below the pure-cell cost shown here. The "price parity with conventional meat" threshold may therefore be achievable at higher per-kg cell costs than these numbers suggest.<br><br><strong>Why it matters:</strong> If production costs for pure cells reach <strong>~$10/kg</strong>, even 100% cultured products could compete with conventional chicken. At <strong>$25-50/kg</strong>, hybrid products with moderate cell inclusion rates may still reach price parity. If costs remain <strong>>$100/kg</strong>, even hybrid products face significant price premiums. These thresholds inform whether animal welfare interventions should prioritize supporting this industry.</div>`
Code
html`<div class="grid" style="grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 2rem;"><div class="card" style="background: linear-gradient(135deg, #3498db, #2980b9); color: white; padding: 1.5rem; border-radius: 8px;"><h4 style="margin: 0; opacity: 0.9;">Median Cost (p50)</h4><h2 style="margin: 0.5rem 0;">$${stats.p50.toFixed(1)}/kg</h2><small>Pure cell mass — half of simulations above, half below</small></div><div class="card" style="background: linear-gradient(135deg, #27ae60, #1e8449); color: white; padding: 1.5rem; border-radius: 8px;"><h4 style="margin: 0; opacity: 0.9;">Optimistic (p5)</h4><h2 style="margin: 0.5rem 0;">$${stats.p5.toFixed(1)}/kg</h2><small>Only 5% of simulations cheaper</small></div><div class="card" style="background: linear-gradient(135deg, #e74c3c, #c0392b); color: white; padding: 1.5rem; border-radius: 8px;"><h4 style="margin: 0; opacity: 0.9;">Pessimistic (p95)</h4><h2 style="margin: 0.5rem 0;">$${stats.p95.toFixed(1)}/kg</h2><small>95% of simulations cheaper</small></div></div>${include_blending ?html`<div style="background: #eaf7ea; border-left: 4px solid #27ae60; padding: 0.8rem 1rem; margin-top: 0.5rem; font-size: 0.9em;"><strong>Blended product estimate (${Math.round(blending_share *100)}% CM, ${Math.round((1-blending_share)*100)}% filler at $${filler_cost}/kg):</strong>Median <strong>$${stats.blended_p50.toFixed(1)}/kg</strong> · 90% CI: $${stats.blended_p5.toFixed(1)} – $${stats.blended_p95.toFixed(1)}/kg</div>`:html`<div style="background: #fef9e7; border-left: 4px solid #f39c12; padding: 0.8rem 1rem; margin-top: 0.5rem; font-size: 0.9em;"><strong>Hybrid product estimate:</strong> At a CM inclusion rate of ~25% with plant-based filler at ~$3/kg, the blended ingredient cost would be approximately <strong>$${(stats.p50*0.25+3*0.75).toFixed(1)}/kg</strong> (median). Enable "Show blended product cost" in the sidebar to adjust these assumptions.</div>`}</div>`
The width of the distribution shows uncertainty. Narrow = confident. Wide = uncertain.
Probability Thresholds
These percentages answer: “What’s the chance that production costs fall below key price points?” — based on the parameter distributions you’ve set above. These are the decision-relevant outputs for evaluating whether cultured meat can compete with conventional chicken.
Where does the cost come from? This chart shows the average contribution of each cost component across all simulations. The largest bars are the cost drivers to focus on — these are where technological progress or parameter uncertainty has the most impact.
Code
{const allComponents = [ {name:"Media",value:mean(results.cost_media),color:"#27ae60"}, {name:"Micronutrients",value:mean(results.cost_comm_micros),color:"#3498db"}, {name:"Growth Factors",value:mean(results.cost_recf),color:"#9b59b6"}, {name:"Other VOC",value:mean(results.cost_other_var),color:"#7f8c8d"}, {name:"CAPEX (annualized)",value:mean(results.cost_capex),color:"#e74c3c"}, {name:"Fixed OPEX",value:mean(results.cost_fixed),color:"#f39c12"}, {name:"Downstream",value:mean(results.cost_downstream),color:"#1abc9c"} ];// Filter out zero-value components (e.g., downstream when not included)const components = allComponents.filter(c => c.value>0.001).sort((a, b) => b.value- a.value);const total = components.reduce((s, c) => s + c.value,0);return Plot.plot({width:1000,height:520,marginLeft:180,marginRight:120,x: {label:"Average Cost ($/kg)",grid:true },y: {label:null },marks: [ Plot.barX(components, {y:"name",x:"value",fill:"color",sort: {y:"-x"} }), Plot.text(components, {y:"name",x: d => d.value+0.5,text: d =>`$${d.value.toFixed(2)} (${(d.value/total*100).toFixed(0)}%)`,textAnchor:"start",fontSize:12 }) ],title:`Cost Breakdown by Component (Total: $${Math.round(total)}/kg)` })}
Understanding the cost components
Variable Operating Costs (VOC):
Media: Nutrient broth for cell growth (amino acids, glucose, vitamins)
CAPEX: Capital costs (reactors, facilities) annualized via Capital Recovery Factor
Fixed OPEX: Labor, maintenance, overhead (scales with plant size)
The relative sizes shift dramatically based on technology adoption assumptions.
Component Distributions
Individual distributions for each cost driver. These charts update dynamically when you change the sidebar parameters. If you adjust plant capacity, the CAPEX and Fixed OPEX distributions will shift; if you change technology adoption probabilities, the media and growth factor distributions will change. (Note: some parameters, like plant capacity, primarily affect CAPEX and fixed costs rather than variable costs like media.)
Each mini-histogram shows the distribution for one cost component across 30,000 simulations:
Solid black line: Median (p50) - the middle value
Dashed black lines: 5th and 95th percentiles (90% confidence interval)
Width of distribution: Uncertainty - wider means more uncertain
These distributions are generated from the simulation using the parameters you set in the sidebar above. When you adjust the sliders, these distributions update accordingly. They are analogous to Squiggle/Guesstimate visualizations – showing the full range of possible values, not just a point estimate.
Using hydrolysates → lower cost (cheaper amino acids)
Bar length: How much that parameter affects the output
|correlation| > 0.5 = strong effect
|correlation| 0.3-0.5 = moderate effect
|correlation| < 0.3 = weak effect
This is Spearman rank correlation, which captures monotonic relationships (not just linear). A correlation of -0.7 means “when this parameter is high, costs tend to be low” across the 30,000 simulations.
Key insight: The parameters with the longest bars are the ones to focus on when: - Forecasting (these drive your uncertainty) - Prioritizing R&D (these are the levers to pull) - Gathering expert input (these are worth eliciting carefully)
Industry Maturity Deep Dive
The maturity factor is a continuous variable ranging from 0 (nascent industry) to 1 (fully mature) that correlates multiple model inputs. It is not binary — intermediate values represent partial industry development. Higher maturity means:
Color gradient: Higher density (yellow) tends to cluster at lower costs
Spread: Even at high maturity, costs vary due to other random factors
This correlation structure prevents unrealistic scenarios where technology succeeds but financing remains difficult, or vice versa.
Quick Start
Explore the “Learn” sections at the top to understand how cultured chicken production works and how this model handles uncertainty.
Adjust parameters in the left sidebar. Each parameter has an expandable explanation.
Results update automatically as you change the Basic Parameters sliders — the summary cards, cost distribution, and probability thresholds all recalculate. (The Component Distributions section shows the underlying distributions and updates when you change the relevant sliders.)
Navigate the results to see:
Cost Distribution: Full probability distribution with key percentiles
Probability Thresholds: Chances of hitting key price points
The model runs 30,000 Monte Carlo simulations, sampling from parameter distributions and technology adoption switches to produce cost distributions and probability thresholds.
Key Insights
The table below summarizes typical outcomes from this interactive model at different maturity settings. These are illustrative ranges – the actual results shown in the charts above update dynamically as you adjust the sidebar parameters.
Scenario
Typical Median Cost
Key Drivers
High maturity (0.7+)
$15-30/kg
All technologies adopted, low WACC
Baseline (0.5)
$25-50/kg
Mixed adoption, moderate uncertainty
Low maturity (0.3-)
$50-100+/kg
Pharma-grade inputs, high financing costs
Most sensitive parameters:
Technology adoption (especially hydrolysates)
Cell density at harvest
Industry maturity (affects multiple factors)
Limitations & Caveats
Model status (March 2026): This model is largely AI-generated and we cannot yet vouch for all parameter values. It is provided to fix ideas, give a sense of the sort of modeling we’re interested in, and present a framework for discussion and comparison — not a definitive cost estimate. We welcome scrutiny and suggestions via Hypothesis annotations or email.
Static snapshot model — Projects costs for a single projection year (adjustable 2026-2050). Does not model year-over-year learning curves; instead, the “maturity” parameter serves as a proxy for cumulative industry development.
Downstream is optional — Scaffolding, texturization, and forming costs can be included via toggle (+$2-15/kg for structured products).
No geography — Assumes generic global costs, not region-specific labor, energy, or regulatory factors.
Limited contamination modeling — No batch failure or contamination event distributions.
Sources
The model draws on parameter ranges and structural assumptions from the following published techno-economic analyses and industry reports, among others: