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

echo-circuit

v0.0.4

Published

Patoka's Circuit Visualization for Pure JavaScript

Readme

patoka-circuit-js

Patoka's Circuit Visualization for Pure JavaScript

Demo

Tested on: Chrome 137, FireFox 140, Safari 18.5.

How to Use

Pipeline: prepare --> compile --> draw

Write a spec


let spec = {
  selector: '#circuit-0', // DOM selector

  // qubits: 3 // by the number of qubits (normalized to below)
  // qubits: [0, 1, 2] // by the qubit indices (normalized to below)
  qubits: [
    {index: 0, register: {name: 'qubits', n_bits: 3}},
    {index: 1, register: {name: 'qubits', n_bits: 3}},
    {index: 2, register: {name: 'qubits', n_bits: 3}}
  ], // by the full indication (recommended); for Physical qubits, this is highly recommended
  
  
  // clbits: 3 // by the number of classical bits (normalized to below)
  // clbits: [0, 1, 2] // by the classical bit indices (normalized to below)
  clbits: [
    {index: 0, register: {name: 'clbits', n_bits: 3}},
    {index: 1, register: {name: 'clbits', n_bits: 3}},
    {index: 2, register: {name: 'clbits', n_bits: 3}}
  ], // by the full indication (recommended); for Physical qubits, this is highly recommended
  
  operations: [{
    name: 'h',
    is_custom: false,
    qubits: 0 // [0, 0]
  }, {
    name: 'cx',
    is_custom: false,
    controls: [{index: 0, register: {name: 'qubits', n_bits: 3}}]
    qubits: [{index: 1, register: {name: 'qubits', n_bits: 3}}] 
  }, {
    name: 'rz',
    is_custom: false,
    qubits: [{index: 1, register: {name: 'qubits', n_bits: 3}}],
    params: [Math.PI / 2]
  }, {
    name: 'measure',
    is_custom: false,
    qubits: [1], 
    clbits: [1] 
  }, ...], // different ways to specify operations
  // operations: [
    // {
    //   index: 0,
    //   num_operations: 2,
    //   operations: [...] // in the same operation format
    // }, ...
  // ] // by already laid out layers

  globalPhase: Math.PI/8, // optional
  // globalPhase: 'π/8', //  in string
  
  options: {
    showMoments: true, // showing layer numbers
    filterUnusedQubits: boolean, // filter out unused qubits
    pagination: ..., // pagination (see below)
    isOriginal: boolean, // if it is the original circuit as opposed to transpiled ones
    unitId: string, // parent wrapper's id in case there are multiple sets of circuits
    circuitSelectorName?: {
      '#circuit-0': 'Original',
      '#circuit-1': 'Transpiled-1',
      '#circuit-2': 'Transpiled-2'
    } // for tooltips
  }, // (optional)
  matchData: [ ... ] // (optional) see below
  interaction: { ... } // (optional) see below
};

Match

Default structure is:

 [{
    selector: "#circuit-9",
    data: {
      bit: [
        { type: 'qubit', from: 13, to: 0, is_ancilla: false }, // typing is important!
        { type: 'qubit', from: 14, to: 1, is_ancilla: false },
        { type: 'qubit', from: 15, to: 2, is_ancilla: false },
        { type: 'clbit', from: 0, to: 0, is_ancilla: false },
        { type: 'clbit', from: 1, to: 1, is_ancilla: false },
        { type: 'clbit', from: 2, to: 2, is_ancilla: false },
      ],

      // If `operations` is provided as a list of operations
      ayer: [
        { from: 0, to: { matches: [0], complete: true } },
        { from: 1, to: { matches: [0], complete: true } },
        { from: 2, to: { matches: [1], complete: true } },
        { from: 3, to: { matches: [1], complete: true } },
        { from: 4, to: { matches: [2], complete: true } },
        { from: 5, to: { matches: [3], complete: true } },
        { from: 6, to: { matches: [4], complete: true } },
        { from: 7, to: { matches: [5], complete: true } },
        { from: 8, to: { matches: [6], complete: true } }
      ]

      // If `operations` is provided as layered operations
      // [a, b]
      // - a: layer index
      // - b: operation index in Layer a
      layer: [
        { from: [0, 0], to: { matches: [[0, 0], [1, 0]], complete: true } },
        { from: [0, 1], to: { matches: [[0, 1], [1, 1]], complete: true } },
        { from: [1, 0], to: { matches: [[2, 0]], complete: true } },
        { from: [0, 2], to: { matches: [[0, 2]], complete: true } },
        { from: [1, 1], to: { matches: [[1, 2]], complete: true } },
        { from: [2, 0], to: { matches: [[3, 0]], complete: true } },
        { from: [3, 0], to: { matches: [[4, 0]], complete: true } }
      ]
    }
  }],

Interaction

It's possible to specify custom interactions in addition to default ones. makeTooltip, moveTooltip, clearTooltip are provided as presets.

{
  onMouseOver: (event, role, content, clicked) => {
    // event: Event
    // role: string
    // content: tooltip content (auto generated)
    // clicked: if it is a click event
    if (role === 'gate-group-click-wrap') {
      // event, content, unitId
      makeTooltip(event, content, 'vis-wrap-00001');
    }
  },
  onClick: (event, role, content, clicked) => {},
  onFocus: (event, role, content, clicked) => {}
  onMouseMove: (event, role) => {
    // event: Event
    // role: string
    if (role === 'gate-group-click-wrap') {
      // event, unitId
      moveTooltip(event, 'vis-wrap-00001');
    }
  },
  onMouseOut: (event, role) => {
    // event: Event
    // role: string
    if (role == 'gate-group-click-wrap') {
      // unitId
      clearTooltip('vis-wrap-00001');
    }
  },
  onBlur: (event, role) => {}
}
Triggerable role names
  • gate-group-click-wrap: Operations
  • qubit-group-click-wrap: Qubits (on the left)

For Vanilla JS

Import

  <link href="./dist/echo.css" rel="stylesheet" type="text/css" />
  <script src="./dist/echo.umd.js"></script>

Code

...
<div id="vis-wrap-00001">
  <h2>Original</h2>
  <div id="circuit-0"></div>
  <h2>Transpiled 1</h2>
  <div id="circuit-1"></div>
  <h2>Transpiled 2</h2>
  <div id="circuit-2"></div>
</div>
...

// HTML selector
let selector0 = '#circuit-0';
let selector1 = '#circuit-1';
let selector2 = '#circuit-2';
let unitId = 'vis-wrap-00001`;

let prep0 = echo.prepareData(spec0);
let prep1 = echo.prepareData(spec1);
let prep2 = echo.prepareData(spec2);

let circuit_set = {
  [selector0]: prep0,
  [selector1]: prep1,
  [selector2]: prep2,
}

echo.compileSpec(prep0, circuit_set);

For details: take a look at index.html and public/draw_test.js.

For Module (Node based web apps)

For details: take a look at index_module.html and public/draw_test_module.ts.