Skip to content

Getting Started

s edited this page Sep 30, 2026 · 14 revisions

Getting Started

Use sn-module-gen 0.1.3 to author a module in an existing Supernote plugin. The CLI calls a module a feature. Plugin creation, package installation, app builds and device deployment remain separate author tasks.

Before changing the plugin

Save your work so you can review the changes. Add creates a new authored package under local_modules/ and generates the complete current project. It does not edit the parent package.json, lockfiles or app scripts, and does not run npm, Yarn or Git. Update preserves authored files but overwrites generated output.

Unsupported old generated layouts are not migrated automatically. Move reviewed implementation source deliberately rather than copying obsolete bindings.

Install the generator

Python 3.9 or newer is required. To follow this version of the Wiki:

python3 -m pip install sn-module-gen==0.1.3

On Windows:

py -m pip install sn-module-gen==0.1.3
sn-module-gen --version

This should report sn-module-gen 0.1.3. See Troubleshooting if the console command is unavailable.

Run from the plugin root

The working directory must contain:

PluginConfig.json
package.json
android/

The generator does not search parent directories. Do not run project commands from android/, a module source folder or the generator repository.

Run Doctor

sn-module-gen doctor

Doctor checks generator-relevant tools and provenance, including Node resolution when needed, CMake/C23/C++23 and Java/Kotlin/KSP when JVM source is present. It does not install tools, build the app or inspect a tablet. Java 17 is the recommended JVM for the documented Gradle analysis workflow.

The Android SDK CMake default remains 3.24.4. Host-native qualification uses 3.24.3 and current CMake separately; those pins are not interchangeable SDK requirements. See tool troubleshooting.

Choose an implementation environment

Open the guided CLI with sn-module-gen, or choose one of these alternatives for a new destination:

sn-module-gen add document --starter cpp --yes
sn-module-gen add document --starter kotlin --yes
sn-module-gen add document --starter cpp --starter kotlin --yes

Do not run all three for the same destination. cpp scaffolds C++23 with author CMake; C23 helpers can be added behind a marked C++ boundary. kotlin scaffolds Kotlin; Java can be added alongside it. Either family may be added later without conversion. Guided Add asks for a package name, description, JavaScript name, Android namespace and package version. --yes supplies safe documented defaults.

Inspect what Add created

local_modules/document/
├── .supernote-module.json
├── package.json
├── CMakeLists.txt                 native starter only; author-owned
├── android/src/main/cpp/          authored native source
├── android/src/main/java/         authored JVM source
└── .supernote-generated/
    ├── index.js
    ├── index.d.ts
    ├── README.md
    ├── package-manifest.json
    └── android/                  generated native/JVM package payload

Only the selected source roots need to exist initially. The author project's shared generated runtime/analysis tree is still under android/.supernote-module/runtime/; the distributable module payload is package-local. See ownership and package consumption.

Add prints an npm install suggestion; run your chosen npm/Yarn command yourself. For distribution or a separate consumer, use the copied-tarball workflow below. The generator never manages your dependencies or lockfiles.

Write one exported function

For C++, edit the authored android/src/main/cpp/feature.cpp in the module:

#include <cstdint>

// @SupernotePluginExport
std::int32_t pageCount() {
  return 42;
}

Or edit its authored FeatureApi.kt:

package com.example.document

import supernote.generated.annotations.SupernotePluginExport

@SupernotePluginExport
fun pageCount(): Int = 42

These are alternatives. Duplicate exported names across the two families are rejected. Ordinary unmarked code remains private to the implementation even if it is public in C++, Kotlin or Java.

Generate and validate

sn-module-gen update --yes
sn-module-gen validate --verbose

Update regenerates every local module and shared output, running bounded publisher-side KSP analysis when necessary. Validate checks source, dependencies, completion state and generated output without publishing it. Neither command runs the app build. Inspect .supernote-generated/index.d.ts, then use your app's normal build/package workflow separately.

Example command sequence

This is a current CLI grammar example for a new mixed module, not a claim that these Wiki commands were executed on a device or by every release CI row. Dependency installation is a separate author step between Add and Validate.

sn-module-gen add wiki-feature \
  --starter cpp --starter kotlin \
  --javascript-name WikiFeature \
  --android-namespace com.example.wiki_feature --yes
sn-module-gen update --yes
sn-module-gen validate

Install and call the package

At the publisher, npm pack ./local_modules/document packages completed output after Update. In a consumer, install that copied module tarball and a matching @supernote/runtime tarball as direct dependencies. Both tarballs must already be available; their example filenames are:

npm install ./document-0.1.0.tgz ./supernote-runtime-0.1.0.tgz

Yarn classic or modern Yarn with nodeLinker: node-modules can consume the same packages. Yarn Plug'n'Play and external linked author-source directories are unsupported. The maintained runtime package source is npm/supernote-runtime/ in the generator repository; obtain a matching package rather than assuming a public-registry release. See the package workflow.

The consumer builds packaged native/JVM bindings through the shared runtime. It does not run the generator or KSP and does not mutate installed packages.

import document from 'document';

function onReadPageCount() {
  const pages: number = document.pageCount();
  // Use pages here.
}

Normal top-level imports are supported. Make actual native calls during the plugin's component, effect or event flow, after the runtime is installed. Explicit async exports return a Promise. The implementation language does not change the JavaScript call shape.

What has been proved?

Host tests, generated compilation, package inspection and device execution are different evidence tiers. The 0.1.3 release notes retain a bounded Nomad test proving one copied C++ module invocation; they do not prove a second invocation, teardown or broad reload/firmware coverage. See release scope. Test your actual plugin on its intended device and PluginHost version.

Next steps

Clone this wiki locally