Skip to content

gSender Plugins ‐ Getting Started

Sage edited this page Aug 13, 2026 · 5 revisions

How to get started with gSender plugins

gSender plugins are small web apps that run inside gSender (in an iframe). You build the UI yourself — plain JavaScript, React, or anything that compiles to static files — and talk to gSender through the Plugin SDK.

You don’t need to fork gSender. A plugin is:

  1. A gsender-plugin.json manifest
  2. A built ui/ folder with an index.html entry
  3. Optional use of @sienci/gsender-plugin-sdk

What you’ll need

  • Node.js (for installing deps and building with Vite)
  • A recent gSender build that includes the plugin system
  • Basic web skills (HTML/JS is enough to start)

Pick a starter template

The gSender repo ships examples under plugins/:

Template Best if you want…
example-hello/ Plain JS, learn the bridge quickly
react-ts-app/ React + TypeScript hooks
example-viewer/ Embedded G-code preview
basic-cam/ Full CAM-style tool (forms → G-code → preview → load to job)

Recommendation: start with example-hello or react-ts-app, then graduate to basic-cam when you need a real tool.


Create your first plugin (5 steps)

1. Copy a template

cp -R plugins/example-hello plugins/my-tool
cd plugins/my-tool

2. Edit the manifest

Open gsender-plugin.json and make it yours:

{
  "id": "com.example.my-tool",
  "name": "My Tool",
  "description": "A short blurb shown on the Tools page.",
  "version": "0.1.0",
  "engine": ">=1.6.0",
  "ui": {
    "entry": "ui/index.html",
    "contributions": [
      {
        "slot": "tools-page",
        "route": "my-tool",
        "label": "My Tool"
      }
    ]
  },
  "capabilities": {
    "requestTypes": ["gcode:load:to:visualizer"],
    "topics": ["workspace"],
    "allowedFunctions": ["gcode", "useWorkspaceState", "GCodeVisualizer"]
  }
}

Important fields:

  • id — unique reverse-DNS id (com.yourorg.plugin-name). Use com.sienci.* only for official Sienci plugins.
  • route / label — how it appears under Tools
  • capabilities — what bridge access the plugin is allowed to use (see below)

Capabilities

The capabilities block is the plugin’s access list. gSender uses it to decide which bridge calls and live subscriptions the plugin may use — anything not listed is denied.

This block will be populated during the plugin import process. For development testing, you need to fill it in yourself.

"capabilities": {
  "requestTypes": ["gcode:load:to:visualizer"],
  "topics": ["workspace"],
  "allowedFunctions": ["gcode", "useWorkspaceState", "GCodeVisualizer"]
}
Field What it controls
requestTypes One-shot bridge RPCs the plugin can call (e.g. gcode:load:to:visualizer, machine:get:context)
topics Live subscriptions the plugin can open (workspace, redux)
allowedFunctions SDK symbols the plugin is expected to use (e.g. gcode, useWorkspaceState) — used for scanning / review

Request Types

This table lists the request types that will be required depending on what symbols you have used from the SDK.

SDK Import Request Type
gsender All Request Types
machine machine:get:context, machine:command
gcode gcode:load:to:visualizer
workspace workspace:get:state
getWorkspaceState workspace:get:state
redux redux:get:state
getReduxState redux:get:state
getSelector redux:get:state

Topics

This table lists the topics that will be required depending on what symbols you have used from the SDK.

SDK Import Topic
subscribeWorkspaceState workspace
subscribeSelector redux
useWorkspaceState workspace
useTypedSelector redux

3. Edit your vite.config

In order for your plugin to work, you will need to import the vite plugin from the SDK into your vite.config. Add it to the plugins section like so:

import gsenderPlugin from "@sienci/gsender-plugin-sdk/vite";

export default defineConfig({
    plugins: [gsenderPlugin()],
    [...]
});

4. Install and build

npm install
npm run build

That writes the production bundle to ui/ (this folder is build output — rebuild after code changes).

5. Load it in gSender

Developing against the gSender repo

With npm run electron:hot / NODE_ENV=development, gSender loads plugins from the repo’s plugins/ folder automatically. After adding a new plugin folder, restart the server once so its route is mounted.

Installing into a normal gSender app

Copy the whole plugin folder (including built ui/) into the plugins directory:

OS Location
macOS ~/Library/Application Support/gSender/plugins/
Windows %APPDATA%\gSender\plugins\
Linux ~/.config/gSender/plugins/

Exact path is also shown under Tools → Plugins. Then restart gSender and enable the plugin if needed.

6. Open it

Go to Tools → your plugin’s card/label. You should see your UI in the panel.


Talk to gSender with the SDK

Install the SDK in your plugin:

npm install @sienci/gsender-plugin-sdk

(In the monorepo examples this is often file:../../packages/plugin-sdk.)

Plain JavaScript

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

// One-shot: machine context
const ctx = await gsender.machine.getContext();

// Live workspace (units, profile, etc.)
subscribeWorkspaceState((workspace) => {
  console.log(workspace?.units);
});

// Live Redux slice
subscribeSelector(
  (state) => state.connection?.isConnected ?? false,
  (connected) => console.log("connected:", connected),
);

// Load G-code into gSender’s main job/visualizer
await gsender.gcode.loadToVisualizer(gcode, "my-part.nc");

React

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);

Embedded G-code preview (optional)

npm install @sienci/gviewer three
import { GCodeViewer } from "@sienci/gsender-plugin-sdk/viewer";

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

Give the container a fixed height and position: relative; overflow: hidden so the canvas doesn’t overflow the iframe.


Local development loop

  1. Run gSender in development.
  2. In the plugin folder:
npm run build -- --watch
  1. Edit source → Vite rebuilds ui/ → the open plugin iframe reloads.

Tips:

  • New plugin folders need a server restart once.
  • Edits to an already-loaded plugin hot-reload.
  • Style dark mode with html.dark (or Tailwind dark: class strategy). gSender sets html.dark on the iframe — don’t rely on prefers-color-scheme alone.

Suggested project layout

my-tool/
  gsender-plugin.json   # required
  package.json
  vite.config.js        # base: "./", outDir: "ui"
  index.html            # Vite entry
  src/
    main.js             # or App.tsx
    style.css
  ui/                   # build output (do not hand-edit)

Vite config essentials:

export default {
  base: "./",
  build: { outDir: "ui", emptyOutDir: true },
};

Relative base matters because plugins are served from a subpath, not the site root.


Checklist before you share a plugin

  • Unique id (not colliding with another plugin)
  • Clear name, description, version
  • ui.entry points at ui/index.html and that file exists after build
  • capabilities match what you actually use
  • Built ui/ included when distributing (zip the folder after npm run build)
  • Works with gSender light and dark themes

Where to look next

Resource Purpose
plugins/example-hello Minimal bridge demo
plugins/react-ts-app React hooks demo
plugins/example-viewer Preview + load-to-job
plugins/basic-cam End-to-end CAM reference
@sienci/gsender-plugin-sdk README Full API surface
Tools → Plugins in the app Install path, enable/disable

Mental model (one sentence)

A gSender plugin is a small SPA that gSender hosts locally; the SDK is your only door into machine state, live UI data, and loading jobs — keep all CNC logic and UI in the plugin, and call the host through the bridge.