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

@accurona/elements

v0.4.0

Published

Accurona: the shared element library for Axonometra and Reticulyne. One model per element, rendered as plan, isometric, 2D schematic and 3D views.

Readme

Accurona

The shared core behind Axonometra (floor plans and 3D) and Reticulyne (network diagrams): one source of truth for what the two tools draw, so the same thing looks and measures the same in both, and so other tools can build on it too.

Today Accurona is the element library: furniture, fixtures, comms and security equipment, with one set of groups, ids and look. It also holds the shared keymap both tools follow, and the scene format: one file for floor plans, isometric and 2D diagrams, with one stable id per object: the file format both tools open and save, implemented in @accurona/core. And it holds the shared UI: the MUI theme, menus and panels both tools are built from, so that switching between them needs no retraining.

Elements

Each element is modelled once, as a few simple solids at real size in centimetres. Every view is generated from that model:

  • Plan (Axonometra): top-down, true to scale. Built.
  • Isometric (Reticulyne): shaded 30° view. Experimental: generated but not yet reviewed item by item. Needed only for the elements a Reticulyne catalogue item draws with (below).
  • 3D (Axonometra's 3D view): the same solids as meshes, from dist/models.json (solids with colours resolved; decals left out). Built.
  • 2D schematic (Reticulyne's flat, Visio-style view): not to scale, one line weight for every symbol. A ceiling or wall device draws its plan pictogram (see Symbols); anything else is seen from the front, with the ports, LEDs and bezels on its front face. An element whose telling face is its top (a desk phone's keypad) sets schematic: 'plan' to draw its top-down view instead. Built; reviewed for the elements a Reticulyne catalogue item cross-references.

What belongs in the library

The library holds physical things: anything with a real size that can be placed on a floor plan. An element has no ports and knows nothing about connections.

Reticulyne keeps its own catalogue of the things a network diagram connects: devices with their ports, and virtual things that never appear on a floor plan, such as a cloud service or a VPN link. Ports, media and protocols are defined there, not here.

Many things belong in both: a switch, an access point, a smoke detector. Each catalogue keeps its own entry, and the two are related by a free-form cross-reference: an entry names the other catalogue's id, in the same { source, ref } shape a scene uses for links to external tools. Neither schema depends on it, and a missing or stale reference breaks only itself. A Reticulyne item that cross-references an element can be drawn with that element's isometric view (and, in the flat view, its schematic), so a rack is still the same rack, the same size and colours, on a floor plan and in a network diagram.

Packages

Three packages on npm, all MIT:

| Package | What | | ------------------------------------------------------------------------ | ------------------------------------------------------------------------ | | @accurona/elements | This library, built: manifest.json, models.json, plan/<id>.svg, iso/<id>.svg and schematic/<id>.svg. | | @accurona/core | The scene format (a Zod schema and its JSON Schema), length units and the shared keymap. | | @accurona/ui | The shared MUI theme, menus, panels and notifications. |

npm install @accurona/elements
import manifest from '@accurona/elements/manifest.json' with { type: 'json' };
// Each element's plan drawing, e.g. with Vite:
import sofaUrl from '@accurona/elements/plan/sofa-3.svg?url';

Develop

npm install
npm test                 # rules every element must meet
npm run build            # dist/manifest.json, dist/models.json, dist/plan/<id>.svg, dist/iso/<id>.svg (iso experimental), dist/schematic/<id>.svg
npm run sheet            # review/<group>.png contact sheets
npm run sheet -- comms --iso --schematic

A release (a v* tag) runs the tests and the build and publishes all three packages to npm (.github/workflows/publish.yml).

Layout

| Path | What | | -------------------------------- | ----------------------------------------------------- | | src/groups.mjs | The groups, in display order. | | src/elements/<group>.mjs | The elements of one group (default export: an array). | | src/palette.mjs | Colours and line weights. | | src/render/plan.mjs, iso.mjs, schematic.mjs | The three renderers. | | ITEMS.md | The item list: the ids, names and sizes built from. | | packages/core/ | @accurona/core: scene format, units, keymap. | | packages/ui/ | @accurona/ui, the shared UI (below). |

An element

{
  id: 'sofa-3',              // kebab-case, unique, never renamed once shipped
  name: 'Sofa, 3-Seat',      // Title Case; a test enforces it
  group: 'living',
  tags: ['network'],         // optional: network, power, cooling, security, fire, av, safe
  size: { w: 210, d: 90, h: 85 },  // cm: width (x), depth (y), height (z)
  mount: 210,                // optional: cm from mountFrom (wall and ceiling gear)
  mountFrom: 'floor',        // optional: 'floor' (default; mount = underside above the floor),
                             //   'ceiling' (mount = gap from the ceiling to the top; 0 = flush,
                             //   negative = recessed, the top that far above the ceiling)
                             //   or 'surface' (mount = gap above the item it stands on,
                             //   on the floor when it stands on nothing)
  facing: 'up',              // optional: 'up' (default) or 'down', e.g. a dome camera or downlight
  surface: 73,               // optional: cm from the underside to a top that carries other
                             //   items (desks, tables, benches, base cabinets); <= size.h
  parts: [ /* solids, below */ ],
  plan: [ /* optional decals drawn on top of the plan, in footprint cm */ ],
  symbol: { /* optional: draw on plans as a 40 cm symbol, below */ }
}

Axes. x runs left to right, y runs back to front, z runs up. The back of the element (the side against a wall) is at y = 0, the top edge of the plan; the side you use it from faces y = d, the bottom edge. Doors and fronts face the bottom. In the isometric view the front (y = d) and right (x = w) faces show.

Mounting and facing. Parts are always authored facing up, z counting up from the underside; facing: 'down' mirrors them inside the item's height. mountFrom and facing are decided in the scene format and are in scene format version 2. Every element with a mount names its mountFrom: ceiling gear (detectors, dome cameras, access points, ceiling speakers, the AC cassette, cable tray, downlights, pendant lights) is 'ceiling', most of it flush (mount: 0) and facing down, recessed items at a negative mount; wall gear stays 'floor'. Items put on top of something else stand on it: an element whose top carries things (tables, desks, benches, base cabinets, sideboards, TV units, bedside tables, filing cabinets) gives that top's height as surface, and bench-top gear (monitors, the laptop, the desk phone, the router and desktop switch, the NAS, the microwave, the table lamp) is mountFrom: 'surface', standing on whatever carrying item an editor places it over and on the floor when there is none. The renderers draw an element as installed:

  • Isometric: the solids mirrored (a dome hangs below its rim), front and side decals mirrored with them, and top decals left out, because they are on the underside the view cannot see. A down arrow on the top marks the item as facing down.
  • 3D (models.json): the solids mirrored; a dome that narrows downwards carries down: true.
  • Plan: drawn as authored, because a ceiling item on a plan is read as a reflected ceiling plan, looking up at its face. An element with mountFrom: 'ceiling' has its outline dashed, the reflected-ceiling-plan convention (planSvg(el, { reflected: false }) turns it off).

Parts

Solids, in cm, all inside size, never overlapping each other (the isometric renderer orders parts by assuming they are separate; overlapping solids draw in the wrong order).

| Part | Shape | | ---------------------------------- | ----------------------------------------------------------------------------------------- | | { x, y, z, w, d, h, r? } | Box. r rounds its corners on the plan. | | { cyl: [cx, cy, rx, ry?], z, h } | Vertical cylinder, elliptical if ry is given. | | { dome: [cx, cy, r], z, h } | Dome (camera domes, lights). | | { poly: [[x, y], ...], z, h } | Extruded polygon for L-shapes and curves. List points clockwise on the plan (y down). |

Common part options: role (fill, default body), outline (true draws the part with the heavy plan outline; the first part has it unless it sets outline: false), dash (a dashed plan outline, e.g. '6 4', for overhead items such as skylights), and decals per face: top, front, side.

Roles: body, soft (cushions, tops, trays), dark (equipment), metal, wood, glass (glass and water), plant, ground (rugs, paving).

Decals

Marks on a face, in cm relative to the face's top-left corner. On top that is the top-left corner of the part's bounding box on the plan (for a cyl, dome or poly, the box around it, not the plan origin); on front and side, v runs down from the face's top edge.

| Decal | Draws | | ------------------------------------------------------ | ------------------------------------------------ | | { line: [[u, v], ...], closed? } | Polyline or polygon. | | { rect: [u, v, w, h], r? } | Rectangle. | | { circle: [u, v, r] }, { ellipse: [u, v, rx, ry] } | Circle, ellipse. | | { arc: [cx, cy, r, fromDeg, toDeg] } | Arc (0° = +x, 90° = +y, i.e. towards the front). |

Options: fill (a role or accent), stroke (a role, outline or detail; default detail), accent (a tag colour, filled, for LEDs and status marks), dash, weight: 'outline' (heavy line), and view: 'plan' or 'iso' to draw in one view only. A decal on top that only makes sense seen from above (louvres, seat lines on an item mounted high) takes view: 'plan'.

Symbols

Ceiling and wall devices (cameras, detectors, access points, sensors, call points) are far too small to see at plan scale. They set symbol, and the plan draws a 40 × 40 cm frame with a pictogram instead of the model, while size and parts still describe the real device for the isometric and 3D views.

symbol: {
  frame: 'circle',   // or 'square'
  glyph: [ /* decals in the 40 × 40 box; default stroke is the outline colour */ ]
}

Point directional devices (cameras, sirens, exit signs) towards the bottom of the symbol.

Shared UI

@accurona/ui (packages/ui/) is what Axonometra and Reticulyne share on screen. Both use MUI; these are the parts that must look and behave the same in both:

| Export | What | | -------------------------------------- | ---------------------------------------------------------------------- | | createAccuronaTheme(mode) | The theme: palette, type, shadows, component defaults. | | ToolButton, ToolMenu, Surface | Toolbar buttons, a menu that opens on hover or click, their card. | | SidePanel, FloatingPanel | A panel from the right; a non-modal panel pinned top right (help). | | AppDialog, CloseButton | A modal with a titled header; every close is named "Close". | | notify(), NotificationHost | Transient messages, raised from anywhere, including plain classes. | | ContextMenu | The right-click menu on the drawing. | | KeyboardShortcutsDialog | The ? list, from the shared keymap, with its Excalidraw differences. | | Panel, PanelSection, PanelHeader | A properties panel: sticky header, titled sections. |

createAccuronaTheme(mode, { cssVariables }) leaves MUI's CSS variables off unless asked: MUI writes them to :root, which an embedded editor must not do to its host page. accuronaThemeOptions(mode) and accuronaVars(mode) give the same theme as options, for a host that builds its own.

It is built with tsc to packages/ui/dist/ (JavaScript plus types) by npm run build, and takes React, MUI and Emotion as peer dependencies.

House style

  • Recognisable at 1:50, no more. A plan is read from across a room, not inspected. Aim for 5 to 25 marks per element; the plan SVG must stay under 4 KB (a test enforces it).
  • Colour carries meaning, sparingly. Bodies are off-white or grey; accent colours mark a device's kind (blue network, orange power, teal cooling, red security and fire, purple AV, green safe: first aid and evacuation) in one small place: a status strip, a lens, a panel. Never a whole body.
  • Model real sizes. Take dimensions from common Australian products; the sizes in ITEMS.md are the brief.
  • Families from functions. When items differ only in size (beds, racks, wardrobes, desks), write one function and call it per size, as bed() in bedroom.mjs and rack() in comms.mjs do.

Contributing

Issues and pull requests are welcome.

  • Found a bug, or have an idea or a question? Open an issue. For anything substantial, open the issue before writing code so we can agree on the scope.
  • Sending a pull request? Read CONTRIBUTING.md for setup, checks and conventions.
  • Found a security problem? Report it privately, as described in SECURITY.md.

Everyone taking part is expected to follow the Code of Conduct.

Author

Created and maintained by Adam Burgess (adamburgess.me). Adam is available for customer implementation work through QANT Pty Ltd.

License

MIT. Every element is drawn here, from scratch; nothing is copied from a third-party icon set.