TypeScript / JavaScript API Reference
Installation
npm install sci-form-wasmAll functions accept and return JSON strings (or typed arrays), since WASM cannot pass complex objects directly.
Initialization
All platforms require initializing the WASM module once:
import init, { embed, eht_calculate, /* ... */ } from 'sci-form-wasm';
await init();For Node.js CommonJS:
const sci = require('sci-form-wasm');
// No async init required for Node.js pkgConformer Generation
embed
function embed(smiles: string, seed?: number): stringReturns a JSON string with the full conformer result.
const json = embed('CCO', 42);
const result = JSON.parse(json);
// result.num_atoms, result.coords, result.elements, result.bonds, result.errorembed_coords
function embed_coords(smiles: string, seed?: number): stringReturns compact JSON: {"coords": [x0,y0,z0,...], "num_atoms": N}.
embed_coords_typed
function embed_coords_typed(smiles: string, seed: number): Float64ArrayReturns coordinates as a typed array directly — no JSON parsing overhead. Preferred for high-throughput use.
const coords: Float64Array = embed_coords_typed('CCO', 42);
// coords = Float64Array [x₀, y₀, z₀, x₁, y₁, z₁, ...]embed_batch
function embed_batch(smiles_list: string, seed?: number): stringBatch embed from newline-separated SMILES. Returns JSON array.
const smiles = "CCO\nc1ccccc1\nCC(=O)O";
const results = JSON.parse(embed_batch(smiles, 42));
results.forEach(r => console.log(`${r.smiles}: ${r.num_atoms} atoms`));parse_smiles
function parse_smiles(smiles: string): stringReturns {"num_atoms": N, "num_bonds": M} or {"error": "..."}.
EHT — Extended Hückel Theory
eht_calculate
function eht_calculate(
elements: string, // JSON: [8, 6, 6, 1, 1, 1, 1, 1, 1]
coords_flat: string, // JSON: [x0,y0,z0,x1,y1,z1,...]
k: number // Wolfsberg-Helmholtz constant (0.0 → default 1.75)
): stringReturns JSON:
interface EhtResult {
energies: number[]; // eV, all MO energies
n_electrons: number;
homo_index: number;
lumo_index: number;
homo_energy: number; // eV
lumo_energy: number; // eV
gap: number; // HOMO-LUMO gap eV
}const coords = embed_coords_typed('CCO', 42);
const elements = JSON.stringify([8, 6, 6, 1, 1, 1, 1, 1, 1]);
const coordsJson = JSON.stringify(Array.from(coords));
const eht = JSON.parse(eht_calculate(elements, coordsJson, 0.0));
console.log(`HOMO: ${eht.homo_energy.toFixed(3)} eV`);
console.log(`Gap: ${eht.gap.toFixed(3)} eV`);eht_orbital_mesh
function eht_orbital_mesh(
elements: string,
coords_flat: string,
mo_index: number,
spacing: number, // Å, e.g. 0.2
isovalue: number // e.g. 0.02
): stringReturns JSON for rendering the molecular orbital as a 3D mesh:
interface OrbitalMesh {
vertices: number[]; // flat [x,y,z, ...]
normals: number[]; // flat [nx,ny,nz, ...]
indices: number[]; // flat triangle indices [i0,i1,i2, ...]
num_triangles: number;
isovalue: number;
}const mesh = JSON.parse(eht_orbital_mesh(elements, coordsJson, homoIdx, 0.2, 0.02));
// Three.js example:
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position',
new THREE.Float32BufferAttribute(mesh.vertices, 3));
geometry.setAttribute('normal',
new THREE.Float32BufferAttribute(mesh.normals, 3));
geometry.setIndex(mesh.indices);eht_orbital_grid_typed
function eht_orbital_grid_typed(
elements: string,
coords_flat: string,
mo_index: number,
spacing: number
): Float32ArrayReturns the raw volumetric grid as a Float32Array for GPU-based volume rendering (WebGL, WebGPU). Use compute_esp_grid_info to get grid dimensions.
Electrostatic Potential
compute_esp_grid_typed
function compute_esp_grid_typed(
elements: string, // JSON array of atomic numbers
coords_flat: string, // JSON flat xyz array
spacing: number, // grid interval in Å
padding: number // extra space around molecule in Å
): Float64ArrayReturns ESP grid values as Float64Array (no JSON). Pair with compute_esp_grid_info for grid metadata.
const espData = compute_esp_grid_typed(elements, coordsJson, 0.5, 3.0);
const espInfo = JSON.parse(compute_esp_grid_info(elements, coordsJson, 0.5, 3.0));
// espInfo = {origin:[x,y,z], spacing:0.5, dims:[nx,ny,nz]}compute_esp_grid_info
function compute_esp_grid_info(
elements: string,
coords_flat: string,
spacing: number,
padding: number
): stringReturns JSON:
interface EspInfo {
origin: [number, number, number];
spacing: number;
dims: [number, number, number]; // [nx, ny, nz]
}Gasteiger Charges
compute_charges
function compute_charges(smiles: string): stringReturns JSON:
interface ChargeResult {
charges: number[]; // per-atom partial charges
iterations: number;
total_charge: number;
}const result = JSON.parse(compute_charges('CCO'));
console.log(result.charges); // [-0.387, -0.042, -0.228, ...]SASA
compute_sasa
function compute_sasa(
elements: string,
coords_flat: string,
probe_radius: number // 0.0 → default 1.4 Å
): stringReturns JSON:
interface SasaResult {
total_sasa: number; // Ų
atom_sasa: number[]; // per-atom Ų
probe_radius: number;
num_points: number;
}Population Analysis
compute_population
function compute_population(
elements: string,
coords_flat: string
): stringReturns JSON:
interface PopulationResult {
mulliken_charges: number[];
lowdin_charges: number[];
num_atoms: number;
total_charge_mulliken: number;
total_charge_lowdin: number;
}Dipole Moment
compute_dipole
function compute_dipole(
elements: string,
coords_flat: string
): stringReturns JSON:
interface DipoleResult {
vector: [number, number, number]; // Debye [x, y, z]
magnitude: number; // Debye
unit: 'Debye';
}Density of States
compute_dos
function compute_dos(
elements: string,
coords_flat: string,
sigma: number, // Gaussian smearing width (eV)
e_min: number, // energy range start (eV)
e_max: number, // energy range end (eV)
n_points: number // number of energy grid points
): stringReturns JSON:
interface DosResult {
sigma: number;
energies: number[]; // eV axis
total_dos: number[]; // DOS curve
n_atoms_pdos: number; // number of atoms with PDOS
}import { Chart } from 'chart.js';
const dos = JSON.parse(compute_dos(elements, coordsJson, 0.2, -20, 5, 200));
new Chart(ctx, {
type: 'line',
data: {
labels: dos.energies,
datasets: [{ data: dos.total_dos, label: 'DOS' }],
},
});Molecular Alignment
compute_rmsd
function compute_rmsd(
coords: string, // JSON flat array
reference: string // JSON flat array
): stringReturns {"rmsd": 0.034281}.
Force Field Energy
compute_uff_energy
function compute_uff_energy(smiles: string, coords: string): stringReturns {"energy": 12.345, "unit": "kcal/mol"} or {"error": "..."}.
Spectroscopy (Track D)
compute_stda_uvvis
function compute_stda_uvvis(
elements: string, // JSON number[]
coords_flat: string, // JSON number[] flat [x0,y0,z0,...]
sigma: number,
e_min: number,
e_max: number,
n_points: number,
broadening: string // "gaussian" | "lorentzian"
): stringReturns JSON StdaUvVisSpectrum:
interface StdaUvVisSpectrum {
wavelengths_nm: number[]; // wavelength axis in nm
intensities: number[]; // ε(λ) values
excitations: {
energy_ev: number;
wavelength_nm: number;
oscillator_strength: number;
from_mo: number;
to_mo: number;
}[];
homo_energy: number; // eV
lumo_energy: number; // eV
gap: number; // eV
n_transitions: number;
broadening_type: string;
notes: string[];
}const r = JSON.parse(embed('c1ccccc1', 42));
const el = JSON.stringify(r.elements);
const co = JSON.stringify(r.coords);
const spec = JSON.parse(compute_stda_uvvis(el, co, 0.3, 1.0, 8.0, 500, 'gaussian'));
const maxIdx = spec.intensities.indexOf(Math.max(...spec.intensities));
console.log(`λ_max ≈ ${spec.wavelengths_nm[maxIdx].toFixed(1)} nm, gap ${spec.gap.toFixed(2)} eV`);compute_vibrational_analysis
function compute_vibrational_analysis(
elements: string, // JSON number[]
coords_flat: string, // JSON number[] flat
method: string, // "eht" | "pm3" | "xtb"
step_size: number | null
): stringReturns JSON VibrationalAnalysis:
interface VibrationalAnalysis {
n_atoms: number;
modes: {
frequency_cm1: number; // negative = imaginary (transition state)
ir_intensity: number; // km/mol
displacement: number[]; // 3N normal-coordinate displacements
is_real: boolean;
}[];
n_real_modes: number;
zpve_ev: number; // zero-point vibrational energy in eV
method: string;
notes: string[];
}const vib = JSON.parse(compute_vibrational_analysis(el, co, 'xtb', null));
console.log(`ZPVE: ${vib.zpve_ev.toFixed(4)} eV, ${vib.n_real_modes} real modes`);compute_ir_spectrum
function compute_ir_spectrum(
analysis_json: string, // JSON-serialised VibrationalAnalysis
gamma: number, // Lorentzian HWHM in cm⁻¹
wn_min: number,
wn_max: number,
n_points: number
): stringReturns JSON IrSpectrum { wavenumbers, intensities, peaks, gamma, notes }.
const spec = JSON.parse(compute_ir_spectrum(JSON.stringify(vib), 15.0, 600.0, 4000.0, 1000));
const peak_wn = spec.wavenumbers[spec.intensities.indexOf(Math.max(...spec.intensities))];
console.log(`Dominant IR band: ${peak_wn.toFixed(1)} cm⁻¹`);predict_nmr_shifts
function predict_nmr_shifts(smiles: string): stringReturns JSON NmrShiftResult:
interface NmrShiftResult {
h_shifts: { atom_index: number; element: number; shift_ppm: number; environment: string; confidence: number }[];
c_shifts: { atom_index: number; element: number; shift_ppm: number; environment: string; confidence: number }[];
notes: string[];
}const shifts = JSON.parse(predict_nmr_shifts('CCO'));
shifts.h_shifts.forEach((h: any) =>
console.log(`H#${h.atom_index}: ${h.shift_ppm.toFixed(2)} ppm [${h.environment}]`));predict_nmr_couplings
function predict_nmr_couplings(
smiles: string,
coords_flat: string // JSON number[] or "[]" for free-rotation average
): stringReturns JSON array of JCoupling { h1_index, h2_index, j_hz, n_bonds, coupling_type }.
compute_nmr_spectrum
function compute_nmr_spectrum(
smiles: string,
nucleus: string, // "1H" | "13C"
gamma: number,
ppm_min: number,
ppm_max: number,
n_points: number
): stringFull NMR spectrum pipeline. Returns JSON NmrSpectrum { ppm_axis, intensities, peaks, nucleus, gamma }.
const spec = JSON.parse(compute_nmr_spectrum('CCO', '1H', 0.01, -2.0, 12.0, 2000));
const maxIdx = spec.intensities.indexOf(Math.max(...spec.intensities));
console.log(`Most intense peak: δ ${spec.ppm_axis[maxIdx].toFixed(2)} ppm`);compute_hose_codes
function compute_hose_codes(smiles: string, max_radius: number): stringReturns JSON array of HoseCode { atom_index, element, code_string, radius }.
Materials
create_unit_cell
function create_unit_cell(
a: number, b: number, c: number,
alpha: number, beta: number, gamma: number
): stringReturns JSON: {"a":..., "b":..., "c":..., "alpha":..., "beta":..., "gamma":..., "volume":...}.
assemble_framework
function assemble_framework(
topology: string, // "pcu" | "dia" | "sql"
metal: number, // atomic number
geometry: string, // "linear" | "trigonal" | "tetrahedral" | "square_planar" | "octahedral"
lattice_a: number, // Å
supercell: number // replication factor (1 = no), number
): stringReturns JSON CrystalStructure with elements, cart_coords, frac_coords, labels, lattice.
const mof = JSON.parse(assemble_framework("pcu", 30, "octahedral", 26.3, 1));
console.log(`${mof.num_atoms} atoms in framework`);Web Workers / Batch Transport
pack_batch_arrow
function pack_batch_arrow(results_json: string): stringPack a JSON array of conformer results into Arrow-compatible columnar format for efficient Worker postMessage transfer.
split_worker_tasks
function split_worker_tasks(
smiles_json: string, // JSON array of SMILES
n_workers: number,
seed: number
): stringSplit SMILES into balanced task batches for Web Workers.
estimate_workers
function estimate_workers(n_items: number, max_workers: number): numberHeuristic to pick the optimal worker count.
Usage Patterns
High-Throughput Conformer Generation
import init, { embed_coords_typed, estimate_workers, split_worker_tasks } from 'sci-form-wasm';
await init();
// Single molecule — typed array (fastest)
const coords = embed_coords_typed('c1ccccc1', 42);
// coords[0], coords[1], coords[2] = x₀, y₀, z₀ of atom 0
// Check auto worker estimate
const nWorkers = estimate_workers(1000, navigator.hardwareConcurrency ?? 4);
const tasks = JSON.parse(split_worker_tasks(
JSON.stringify(smilesList), nWorkers, 42
));Three.js Molecule Viewer
import init, { embed, eht_calculate, eht_orbital_mesh } from 'sci-form-wasm';
import * as THREE from 'three';
await init();
const smiles = 'c1ccccc1';
const result = JSON.parse(embed(smiles, 42));
const elements = JSON.stringify(Array.from(result.elements));
const coordsJson = JSON.stringify(result.coords);
// Atom spheres
const scene = new THREE.Scene();
for (let i = 0; i < result.num_atoms; i++) {
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(0.3),
new THREE.MeshPhongMaterial({ color: 0x336699 })
);
sphere.position.set(result.coords[i*3], result.coords[i*3+1], result.coords[i*3+2]);
scene.add(sphere);
}
// HOMO orbital
const eht = JSON.parse(eht_calculate(elements, coordsJson, 0.0));
const mesh = JSON.parse(eht_orbital_mesh(elements, coordsJson, eht.homo_index, 0.2, 0.02));
const orbGeom = new THREE.BufferGeometry();
orbGeom.setAttribute('position', new THREE.Float32BufferAttribute(mesh.vertices, 3));
orbGeom.setAttribute('normal', new THREE.Float32BufferAttribute(mesh.normals, 3));
orbGeom.setIndex(mesh.indices);
scene.add(new THREE.Mesh(orbGeom, new THREE.MeshPhongMaterial({
color: 0x0077ff, transparent: true, opacity: 0.5, side: THREE.DoubleSide
})));React Hook
import { useEffect, useState } from 'react';
import init, { embed } from 'sci-form-wasm';
export function useConformer(smiles: string) {
const [result, setResult] = useState<any>(null);
useEffect(() => {
(async () => {
await init();
setResult(JSON.parse(embed(smiles, 42)));
})();
}, [smiles]);
return result;
}