@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-sdkPeer 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 threeEntries
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 intoui/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:
machineworkspacereduxgcode
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
