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

@sienci/gsender-plugin-sdk

v0.2.1

Published

SDK for gSender UI plugins — bridge client, React hooks, and G-code viewer

Readme

@sienci/gsender-plugin-sdk

SDK for building gSender UI plugins. Talk to the host app over the plugin bridge, subscribe to live state, and optionally embed the same G-code viewer gSender uses.

Install

npm install @sienci/gsender-plugin-sdk

Peer dependencies are optional and only needed for the entry points that use them:

| Entry | Peers | |-------|--------| | @sienci/gsender-plugin-sdk | none | | @sienci/gsender-plugin-sdk/react | react ≥ 18 | | @sienci/gsender-plugin-sdk/viewer | @sienci/gviewer, three |

# React hooks
npm install react

# G-code preview
npm install @sienci/gviewer three

Entries

Build plugin (/vite)

Add the SDK's Vite plugin to your build — it is the only build config a plugin needs:

// vite.config.ts
import gsenderPlugin from "@sienci/gsender-plugin-sdk/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
	plugins: [react(), gsenderPlugin()],
	base: "./",
	build: { outDir: "ui", emptyOutDir: true },
});

It handles everything the gSender host needs, automatically:

  • Keeps the SDK's specifiers external in your bundle, so gSender can statically scan which SDK functions you import and show the user an accurate permission prompt. At runtime they resolve (via an injected import map) to the SDK copy gSender itself serves at /plugin-sdk/*.js — the executing SDK always matches the host's bridge.
  • Keeps react/react-dom/JSX runtimes external too, and vendors one shared React build into ui/vendor/ (single React instance — hooks in your components and in the SDK share the same dispatcher).
  • Injects the import map into your built index.html.

No manual external, no manual import map, no vendoring by hand. Note the built ui/ only runs inside gSender's plugin iframe (vite preview will not resolve the SDK imports).

Bridge client (default)

Framework-agnostic RPC + subscriptions. Safe for vanilla JS, Vue, Svelte, etc. — does not import React.

Individual clients:

  • machine
  • workspace
  • redux
  • gcode

gsender includes all these clients in one object.

import {
  gsender,
  getWorkspaceState,
  subscribeWorkspaceState,
  subscribeSelector,
} from "@sienci/gsender-plugin-sdk";

const ctx = await gsender.machine.getContext();
await gsender.gcode.loadToVisualizer(gcode, "job.nc");

const unsub = subscribeWorkspaceState((state) => {
  console.log(state);
});

React hooks

import { gsender } from "@sienci/gsender-plugin-sdk";
import {
  useWorkspaceState,
  useTypedSelector,
} from "@sienci/gsender-plugin-sdk/react";

const workspace = useWorkspaceState();
const isConnected = useTypedSelector((s) => s.connection?.isConnected);

G-code viewer

Uses @sienci/gviewer (same engine as gSender’s visualizer). Requires a bundler.

React:

import {
  GCodeVisualizer,
  type GCodeViewerHandle,
} from "@sienci/gsender-plugin-sdk/viewer";
import { useEffect, useRef } from "react";

const ref = useRef<GCodeViewerHandle>(null);
useEffect(() => {
  ref.current?.loadFromText(gcode).then(() => ref.current?.focusToModel());
}, [gcode]);

<GCodeVisualizer ref={ref} id="preview" style={{ height: 320 }} />;

Imperative:

import { GCodeViewer } from "@sienci/gsender-plugin-sdk/viewer";

const viewer = new GCodeViewer({
  id: "preview",
  container: document.getElementById("preview"),
});
await viewer.loadFromText(gcode);
viewer.focusToModel();

Bridge API surface

| API | Description | |-----|-------------| | machine.getContext() | Current machine / controller context | | machine.command(cmd, ...args) | Run a host machine command | | workspace.getState() | One-shot workspace snapshot | | redux.getState() | One-shot full Redux state | | gcode.loadToVisualizer(gcode, name?) | Load G-code into the main visualizer/job | | subscribeWorkspaceState(cb) | Live workspace updates | | subscribeSelector(selector, cb, equalityFn?) | Live Redux slice | | useWorkspaceState() | React hook for workspace | | useTypedSelector(selector, equalityFn?) | React hook for Redux slice |

Plugins run in an iframe; the SDK posts messages on the gsender:plugin-bridge channel to the parent window.

License

MIT