Repository navigation
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.
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.
Python 3.9 or newer is required. To follow this version of the Wiki:
python3 -m pip install sn-module-gen==0.1.3On Windows:
py -m pip install sn-module-gen==0.1.3sn-module-gen --versionThis should report sn-module-gen 0.1.3. See
Troubleshooting if the console
command is unavailable.
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.
sn-module-gen doctorDoctor 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.
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 --yesDo 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.
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.
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 = 42These 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.
sn-module-gen update --yes
sn-module-gen validate --verboseUpdate 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.
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 validateAt 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.tgzYarn 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.
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.