GUIDE 09 / 28 · NATIVE 2.0.7

Your first plugin

Create, install and verify a complete native-compatible plugin, from two files to a working counter.

Create the plugin folder#

A plugin is a directory directly below %APPDATA%\Hydro Clips\plugins. The loader scans immediate child directories for plugin.json and the JavaScript entry file. Keep one plugin per directory, with a unique manifest ID. A ZIP is a distribution format; the loader does not execute an unopened ZIP.

Folder layout
plugins/
  clip-counter/
    plugin.json
    index.js

Open the native app's Plugins panel and use Open Folder to find the location actually used by your account. The app can record locally without a website login; local plugin execution does not require an account either.

Add the manifest#

plugin.json
{
  "id": "example-clip-counter",
  "name": "Clip Counter",
  "version": "1.0.0",
  "description": "Count saved clips with a persistent counter and a custom panel.",
  "author": "HydroClips Documentation",
  "main": "index.js",
  "enabled": true,
  "config": { "count": 0, "showToast": true, "includeScreenshots": false },
  "configSchema": {
    "showToast": { "label": "Show a notification", "type": "boolean", "default": true },
    "includeScreenshots": { "label": "Count screenshots too", "type": "boolean", "default": false }
  }
}

This example starts enabled and has explicit runtime configuration values. configSchema describes the settings UI; it does not automatically seed values returned by getConfig(). The entry point is resolved relative to the plugin folder.

Add the entry point#

index.js
function count(context) {
  const value = Number(context.getConfig().count);
  return Number.isFinite(value) && value >= 0 ? Math.floor(value) : 0;
}
function render(context) {
  context.ui.setTabContent('counter', '<h3>Saved clips</h3><p>Total: <strong>' + count(context) + '</strong></p>');
}
function increment(clip, context) {
  context.saveConfig({ count: count(context) + 1 });
  render(context);
  context.log('Counted clip ' + clip.id, 'success');
  if (context.getConfig().showToast !== false) context.showNotification('Clip Counter', 'Saved clips: ' + count(context), 'success');
}
module.exports = {
  onInit(context) {
    context.ui.registerTab({ id: 'counter', title: 'Clip Counter', icon: 'radio', actions: [
      { id: 'reset', label: 'Reset counter', location: 'custom_tab', actionId: 'reset', variant: 'danger' }
    ] });
    context.ui.registerButton({ id: 'open-counter', label: 'Clip Counter', icon: 'radio', location: 'sidebar_actions', actionId: 'refresh', openTabId: 'counter' });
    render(context);
  },
  onClipSaved: increment,
  onScreenshot(clip, context) { if (context.getConfig().includeScreenshots === true) increment(clip, context); },
  onAction(actionId, context) {
    if (actionId === 'reset') context.saveConfig({ count: 0 });
    if (actionId !== 'reset' && actionId !== 'refresh') throw new Error('Unknown action: ' + actionId);
    render(context);
    return { count: count(context) };
  }
};

Use module.exports exactly as shown. The supplied sandbox has separate exports and module.exports objects, so assigning exports.onInit alone is not a supported way to export hooks. No npm install or Electron import is needed for this example.

Install and verify#

  1. Save both files as UTF-8, with valid JSON in the manifest.
  2. Choose Reload Plugins, or wait for the file watcher to reload changes.
  3. Confirm Clip Counter appears and is enabled. Its sidebar action opens the Counter tab.
  4. Save a short manual recording. The counter increases by one.
  5. Save a replay. It increases again. Screenshots only count when that setting is enabled.
  6. Restart the app: the count should survive because it is saved in this plugin's manifest.

The tab's Reset counter action intentionally changes only the example's counter. Existing video files and the main clip library are untouched.

Choose the next topic#

Read Lifecycle & reload before adding timers, Settings & validation before accepting configuration, and Runtime & compatibility before adapting older Electron code. Download all three runnable examples from the example collection.

Implementation reference: src/main/plugins/PluginManager.ts · native 2.0.7.