Science
Science Calculators
@indoku/science is a pure TypeScript engine with no dependencies and no framework: physics, chemistry, math and Cartesian helpers you can call from a calculator, a server route or a React component.
These demos are plain inputs wired to engine functions. Wrap the results in FormulaBlock, Graph2D or Plot3D for a richer UI.
Import
tsx
import { waveSpeed, molarMass, balanceEquation, projectile } from "@indoku/science"// Subpaths keep bundles small:import { molarMass } from "@indoku/science/chemistry"Examples
Waves
Wave speed and the Doppler effect.
v = fλ = 343.20 m/s
Doppler: 467.2 Hz
tsx
function CalcWave() { const [f, setF] = useState("440") const [l, setL] = useState("0.78") const [vs, setVs] = useState("20") return ( <div style={box}> <div style={row}> <label>f (Hz) <input value={f} onChange={(e) => setF(e.target.value)} size={6} /></label> <label>λ (m) <input value={l} onChange={(e) => setL(e.target.value)} size={6} /></label> </div> <div>v = fλ = <b>{waveSpeed(num(f), num(l)).toFixed(2)}</b> m/s</div> <label>Source speed toward you (m/s) <input value={vs} onChange={(e) => setVs(e.target.value)} size={4} /></label> <div>Doppler: <b>{dopplerFrequency(num(f), 0, num(vs)).toFixed(1)}</b> Hz</div> </div> )}Fluids
Reynolds number and flow regime.
Water, Re = 75000 → turbulent
tsx
function CalcFluid() { const [v, setV] = useState("1.5") const [d, setD] = useState("0.05") const re = reynoldsNumber(1000, num(v), num(d), 0.001) return ( <div style={box}> <div style={row}> <label>v (m/s) <input value={v} onChange={(e) => setV(e.target.value)} size={6} /></label> <label>D (m) <input value={d} onChange={(e) => setD(e.target.value)} size={6} /></label> </div> <div>Water, Re = <b>{Math.round(re)}</b> → {flowRegime(re)}</div> </div> )}Projectile
Range 40.79 m · max height 10.20 m · time 2.88 s
tsx
function CalcProjectile() { const [speed, setSpeed] = useState("20") const [angle, setAngle] = useState("45") const p = projectile({ speed: num(speed), angleDeg: num(angle) }) return ( <div style={box}> <div style={row}> <label>v₀ (m/s) <input value={speed} onChange={(e) => setSpeed(e.target.value)} size={5} /></label> <label>θ (°) <input value={angle} onChange={(e) => setAngle(e.target.value)} size={5} /></label> </div> <div>Range <b>{p.range.toFixed(2)}</b> m · max height <b>{p.maxHeight.toFixed(2)}</b> m · time <b>{p.flightTime.toFixed(2)}</b> s</div> </div> )}Molar mass
Parses brackets and hydrates such as CuSO4·5H2O.
74.092 g/mol · Ca 54.1% · O 43.2% · H 2.7%
tsx
Equation balancer
C3H8 + 5 O2 → 3 CO2 + 4 H2O
tsx
function CalcBalance() { const [eq, setEq] = useState("C3H8 + O2 -> CO2 + H2O") let result = "" try { result = balanceEquation(eq).equation } catch (e) { result = (e as Error).message } return ( <div style={box}> <input value={eq} onChange={(e) => setEq(e.target.value)} style={{ fontFamily: "monospace" }} /> <div><b>{result}</b></div> </div> )}pH
Strong acid and weak acid (exact quadratic).
Strong acid: pH 2.00 · weak acid: pH 3.38
tsx
function CalcPH() { const [c, setC] = useState("0.01") const [ka, setKa] = useState("1.8e-5") return ( <div style={box}> <div style={row}> <label>Concentration (M) <input value={c} onChange={(e) => setC(e.target.value)} size={7} /></label> <label>Ka <input value={ka} onChange={(e) => setKa(e.target.value)} size={7} /></label> </div> <div>Strong acid: pH <b>{pHStrongAcid(num(c)).toFixed(2)}</b> · weak acid: pH <b>{pHWeakAcid(num(ka), num(c)).toFixed(2)}</b></div> </div> )}Quadratic equation
Complex roots included.
x = 2.000, 1.000
tsx
Notes
- All functions use SI units unless the name says otherwise.
- Invalid input throws a plain
Error; catch it and show the message.
Created by @indokudev