npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@alphaelements/aelm-renderer

v0.6.0

Published

AELM circuit-diagram renderer (WASM). Renders .aelm DSL to SVG or HTML Canvas.

Downloads

157

Readme

@alphaelements/aelm-renderer

WebAssembly-powered renderer for AELM circuit-diagram DSL. Drives the same Rust pipeline that ships in the AELM VS Code extension and the aelm CLI, so a .aelm source is rendered identically across all three.

  • One-shot SVG: renderToSvg(source) → string
  • One-shot Canvas: renderToCanvas(ctx, source, viewport) paints into an HTMLCanvasElement
  • Interactive recalculation: evaluate(source, overrides) re-runs formulas and plots when a variable changes — no re-parse of layout / routing (see Interactive recalculation)
  • No server required: pure client-side WASM (works in Node 18+, Bun, Deno, browsers, edge runtimes)
  • MIT licensed

Install

npm install @alphaelements/aelm-renderer

Browser / bundler usage (Vite, Webpack, Next.js, Rollup, …)

import init, { render_to_svg, render_to_canvas } from '@alphaelements/aelm-renderer';

await init();

const source = `
  module Divider {
    instances {
      R1: Resistor(value: 10k)
      R2: Resistor(value: 10k)
    }
    connections {
      R1.b -> R2.a
    }
  }
`;

const svg = render_to_svg(source, { background: { r: 255, g: 255, b: 255, a: 255 }, margin_mm: 5 });
document.getElementById('diagram')!.innerHTML = svg;

Next.js dynamic import

@alphaelements/aelm-renderer ships a WASM binary so it must run on the client only:

'use client';
import { useEffect, useState } from 'react';

export function CircuitPreview({ source }: { source: string }) {
  const [svg, setSvg] = useState('');
  useEffect(() => {
    import('@alphaelements/aelm-renderer').then(async ({ default: init, render_to_svg }) => {
      await init();
      setSvg(render_to_svg(source, {}));
    });
  }, [source]);
  return <div dangerouslySetInnerHTML={{ __html: svg }} />;
}

Node.js usage

import init, { render_to_svg } from '@alphaelements/aelm-renderer';
import { readFileSync, writeFileSync } from 'node:fs';

await init();
const source = readFileSync('circuit.aelm', 'utf8');
writeFileSync('out.svg', render_to_svg(source, { background: { r: 255, g: 255, b: 255, a: 255 }, margin_mm: 5 }));

Canvas usage

import init, { render_to_canvas } from '@alphaelements/aelm-renderer';

await init();

const canvas = document.querySelector('canvas')!;
const ctx = canvas.getContext('2d')!;

// Auto-fit (viewport=null) or explicit:
render_to_canvas(ctx, source, null, { background: null, device_pixel_ratio: window.devicePixelRatio });

Configuration

SvgConfig

| Field | Type | Default | Description | | ------------- | ------------------- | ---------------- | ---------------------------------------- | | background | Color \| null | {r:255,g:255,b:255,a:255} (white) | Background fill. null for transparent. | | margin_mm | number | 5.0 | Margin around the diagram in mm. |

CanvasConfig

| Field | Type | Default | Description | | -------------------- | ---------------- | ------- | --------------------------------------------- | | background | Color \| null | null | Optional fill before drawing content. | | device_pixel_ratio | number | 1.0 | DPR multiplier for crisp text on HiDPI. |

ViewportConfig (used by render_to_canvas)

| Field | Type | Description | | --------------- | -------- | ---------------------------------------- | | offset_x | number | World-mm at canvas centre (X). | | offset_y | number | World-mm at canvas centre (Y). | | zoom | number | Pixels per mm. | | canvas_width | number | canvas.width in pixels. | | canvas_height | number | canvas.height in pixels. |

Pass null for viewport to auto-fit to the diagram bounds.

Interactive recalculation

When a .aelm source has a calcs { } block (editable variables + formulas) and/or plots { }, you can let users change input values and recompute results without re-parsing the layout or re-routing wires. The typical flow:

  1. list_calc_inputs(source) — discover the editable variables to build an input UI.
  2. list_plots_from_source(source) — discover the plot frames to draw.
  3. On every value change, call evaluate(source, overrides) and update the formula readouts and plot traces from the result.
  4. (Optional) render_with_overrides(source, overrides, config) to re-render the whole diagram as SVG with the new values baked in (e.g. for download).
import init, {
  list_calc_inputs, list_plots_from_source, evaluate, render_with_overrides,
} from '@alphaelements/aelm-renderer';

await init();

// 1. Build the input UI.
const inputs = list_calc_inputs(source);
// → [{ id: "R", kind: "var", default_value: "10k", param_type: "Ohm", label: "R" },
//    { id: "fc", kind: "formula", expr: "1 / (2 * pi * R * C)", display: "$f_c = {fc}$ Hz" }, ...]

// 2. Recompute when the user edits a value (target < 100 ms, no re-layout).
const result = evaluate(source, { R: '20k', C: '47n' });
// result.formulas → [{ id: "fc", display: "$f_c = 169.3$ Hz", value: "169.3" }, ...]
// result.plots    → [{ id: "bode", traces: [{ id: "mag", x: [...], y: [...] }] }, ...]

// 3. Or re-render the whole figure with overrides applied.
const svg = render_with_overrides(source, { R: '20k' }, null);

API

| Function | Returns | Purpose | | -------- | ------- | ------- | | list_calc_inputs(source) | CalcInputInfo[] | Calc variables + formulas, for building input UIs. | | list_plots_from_source(source) | PlotSummary[] | Plot axis + trace metadata, for drawing plot frames. | | evaluate(source, overrides) | EvaluateResult | Recompute formulas + plot traces with overridden variable values. | | render_with_overrides(source, overrides, config) | string (SVG) | One-shot SVG render with overrides applied; config is the same SvgConfig as render_to_svg. |

overrides is a Record<string, string> mapping variable id → value string ("20k", "47n", "3.14", "42"). Pass null for defaults. Unknown ids are ignored; a non-numeric value on a numeric variable yields NaN in the affected formula's error.

Types

interface CalcInputInfo {
  id: string;
  kind: 'var' | 'formula';
  default_value?: string; // var only — SI-formatted, e.g. "10k"
  param_type?: string;    // var only — "Ohm" | "Farad" | "Hertz" | "Volt" | "Float" | "Integer" | ...
  label?: string;         // var only
  expr?: string;          // formula only — raw expression
  display?: string;       // formula only — LaTeX display template with {id} slots
}

interface PlotSummary {
  id: string;
  title?: string;
  x_axis: AxisSummary;
  y_axis: AxisSummary;
  y2_axis?: AxisSummary;
  traces: { id: string; label?: string; kind: 'function' | 'csv' | 'samples' }[];
}
interface AxisSummary { label?: string; range?: [number, number]; log: boolean; }

interface EvaluateResult {
  formulas: { id: string; display: string; value: string; error?: string }[];
  plots: { id: string; traces: { id: string; label?: string; x: number[]; y: number[] }[] }[];
}

Error handling

All entry points surface diagnostics on parse / IR / layout / render failure:

try {
  const svg = render_to_svg(badSource, {});
} catch (err: any) {
  // err.diagnostics: Array<{ severity, message, span?, code? }>
  for (const d of err.diagnostics ?? []) {
    console.error(d.code, d.message, d.span);
  }
}

What's NOT in this package

This is the render-only subset of AELM:

  • ✅ Parse .aelm
  • ✅ Layout + routing
  • ✅ Render to SVG / Canvas
  • ✅ Interactive recalculation (evaluate / render_with_overrides)
  • ❌ Reverse sync (component move, wire reconnect, …)
  • ❌ DRC checking
  • ❌ LSP / language-server features

For those, use the AELM VS Code extension or the aelm CLI.

License

MIT — see LICENSE.