npm package: @hubblehome/module-scaffolding
Description: CLI tool for scaffolding Hubble modules
Latest version: 1.10.0

# create-hubble-module

CLI tool for scaffolding and developing [Hubble](https://github.com/hubble) modules.

---

## Installation

Build and link the CLI locally:

```bash
cd tools/create-hubble-module
npm run link
```

This runs `npm run build && npm link`, making `create-hubble-module` available globally.

---

## Commands

Run all commands from inside your module directory unless stated otherwise.

| Command | Description |
|---|---|
| `init` | Interactive scaffolding for a new Hubble module (run from any directory) |
| `register` | Build, deploy, and register in Hubble's database (first-time local install) |
| `build` | Build connector (CJS) and visualizations (ESM) for distribution |
| `deploy` | Build, copy to Hubble, and reload (one-shot update) |
| `dev` | Watch mode: sync files to Hubble and reload on change |
| `validate` | Validate module manifest and file structure |
| `add-visual` | Add a new visualization to the module |
| `add-property` | Add a top-level property to the module's manifest |
| `add-property-visual` | Add a property to a specific visualization |
| `add-config-panel` | Add a config panel to a visualization |
| `add-endpoint` | Add an API endpoint to the module's manifest |

**Options:**

| Option | Default | Description |
|---|---|---|
| `--hubble-port <port>` | `3000` | Port of the running Hubble instance |
| `--module-dir <dir>` | `.` | Path to the module directory |

---

## Module directory structure

After running `init`, the scaffolded module looks like this:

```
my-module/
├── manifest.json
├── package.json
├── tsconfig.json
├── hubble-sdk.d.ts
├── connector/
│   └── index.ts
├── visualizations/
│   └── default/
│       ├── index.tsx
│       ├── style.css
│       └── panels/
│           └── configure.tsx   (optional)
├── .github/
│   ├── workflows/
│   │   ├── ci.yml
│   │   └── release.yml
│   └── scripts/
│       └── bump-version.mjs
└── README.md
```

- `connector/` — Server-side TypeScript. Handles data fetching, scheduling, and SDK emit calls.
- `visualizations/` — React TSX components rendered inside Hubble widget containers. Each subdirectory is one visualization.

---

## Local dev workflow

### First time: register the module

Before you can see a module in the Admin UI or place it on the dashboard, it must be registered in Hubble's database. Run this once while Hubble is running:

```bash
create-hubble-module register
```

This builds the module, copies `dist/` to Hubble's modules directory, and registers it in the database. The module will appear in the Admin UI immediately.

If Hubble is not running when you run `register`, the files will be deployed to disk but the database record won't be created. Run `register` again once Hubble is running to complete the process.

### Subsequent sessions: watch mode

Once the module is registered, use `dev` to auto-reload on change:

```bash
create-hubble-module dev
```

With a specific port:

```bash
create-hubble-module dev --hubble-port 3000
```

### One-shot update

```bash
create-hubble-module deploy
```

Builds, copies files, and triggers a hot-reload without re-registering.

### Summary

```
# First time (Hubble must be running)
npm run register

# Day-to-day development
npm run dev

# One-off update
npm run deploy
```

If you run `register` again after the module is already in the database, you'll get a clear message directing you to use `deploy` instead.

---

## Publishing a release

Releases are managed through GitHub Actions.

1. Go to the Actions tab of your module's GitHub repository.
2. Select the **Release** workflow and click **Run workflow**.
3. Choose a version bump type: `patch`, `minor`, or `major`.

The workflow will:
- Bump the version in `manifest.json` and `package.json`
- Build the module
- Create a ZIP from `dist/` with the following structure:
  ```
  manifest.json
  connector/index.js
  visualizations/<name>/index.js
  ...
  ```
- Create a GitHub Release with the ZIP attached

To install in Hubble: Admin → Modules → Install from ZIP, then paste the release ZIP URL.

---

## hubble-ui quick reference

Always use `hubble-ui` components instead of writing custom equivalents.

```tsx
import { Button, IconButton, Input, Select, Slider, Toggle, ColorPicker, StatusDot, Badge, Field, Collapsible } from 'hubble-ui';
```

| Component | Purpose |
|---|---|
| `Button` | Primary/secondary/ghost actions |
| `IconButton` | Icon-only action button |
| `Input` | Text input field |
| `Select` | Dropdown selector |
| `Slider` | Range slider |
| `Toggle` | Boolean on/off switch |
| `ColorPicker` | Color selection |
| `StatusDot` | Colored status indicator dot |
| `Badge` | Small status/count label |
| `Field` | Form field wrapper with label and validation |
| `Collapsible` | Expandable/collapsible section |

---

## CSS variable tokens

Never use inline styles. Always write CSS classes using these `--hubble-*` variables:

| Variable | Purpose |
|---|---|
| `--hubble-text-primary` | Main text color |
| `--hubble-text-secondary` | Muted text |
| `--hubble-panel-bg` | Glassmorphism panel background |
| `--hubble-panel-blur` | Backdrop blur value |
| `--hubble-border` | Standard border style |
| `--hubble-radius-lg` | Large border radius |
| `--hubble-accent` | Accent/brand color |

Example:

```css
.my-widget {
  background: var(--hubble-panel-bg);
  backdrop-filter: blur(var(--hubble-panel-blur));
  border: var(--hubble-border);
  border-radius: var(--hubble-radius-lg);
  color: var(--hubble-text-primary);
}
```