npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@signosoft/tablet-driver

v0.1.1

Published

WebAssembly-based Wacom tablet driver for WebHID signature capture

Readme

WebAssembly Tablet Driver Project

Project Overview

This project implements WebAssembly-based tablet drivers for various Wacom tablets, focusing on secure HID report processing and IP protection through obfuscation techniques.


High-Level Architecture

System Components

1. WASM Module (C++ compiled to WebAssembly)

The core processing engine that handles:

  • HID Report Parsing: Extracts pen coordinates, pressure, and status from raw tablet data
  • Licence Validation: RSA signature verification for anti-tampering protection
  • Device-Specific Drivers: Proprietary parsing constants for different tablet models
  • Command Execution: Sends commands to tablets (display images, clear screen, set pen color, etc.)
  • Event Emission: Publishes normalized pen data and button events to JavaScript

Key WASM Classes:

  • WASMTabletDriver: Main interface between JavaScript and C++ (singleton pattern)
  • TabletDriver: Abstract base class for all tablet implementations
  • DataParser: Extracts pen data from HID reports using device-specific bit offsets
  • Command: Handles complex tablet operations (images, multi-step commands, conditionals)
  • EventEmitter: Publishes events from C++ to JavaScript

2. TypeScript Library — Two-Layer Structure

The library is written in TypeScript under src/ and exposes three entry points: src/index.ts (full API), src/index.driver.ts (Layer 1 only), and src/index.signature.ts (Layer 2 only).

Layer 1 — TabletDriver (src/tablet-driver.ts) Direct WASM bridge that manages:

  • WebHID Communication: Requests device access, reads HID reports, sends output reports
  • WASM Lifecycle: Initializes WASM module, manages driver connection/disconnection
  • Licence Validation: Passes a caller-supplied signed lease to WASM for RSA verification — the library does not fetch leases itself
  • Event Distribution: Subscribes to WASM events and routes them to user callbacks (on(event, callback))
  • Command Interface: Translates TypeScript method calls to WASM command execution

TabletDriver is a thin public façade. Its concerns are split across focused collaborators in src/internal/ that share a single DriverState (the canonical reference for module, device, isWasmInitialized, penAspectCorrector):

Layer 2 — SignatureLayer (src/signature-layer.ts) Higher-level façade that orchestrates the TabletDriver for signature capture workflows:

  • Device-aware signing setup and teardown (startSigning(), stopSigning())
  • Automatic hotspot configuration for OK / Clear / Cancel buttons
  • Canvas drawing and pen data collection via SignatureCapture
  • Fallback to mouse/pointer input when no tablet is connected

Support modules (src/):

Lease fetching is no longer part of the library. Consumers must call their own backend and pass the resulting SignedLease to initialize(). The demo includes demo/license-utility.ts as a reference helper.


Data Flow: Initialization Workflow

Typical Workflow Using SignatureLayer (Layer 2)

import { SignatureLayer, type SignedLease } from "@signosoft/tablet-driver";

// 1. Create SignatureLayer instance
const layer = new SignatureLayer();

// 2. Obtain a signed lease from your own backend (the library does NOT do this)
const lease: SignedLease = await fetch("/api/v1/driver/leases", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ licenceKey, validityHours: 24 }),
}).then(r => r.json());

// 3. Initialize: loads WASM, verifies RSA licence signature, registers enums.
//    The wasm binary (driversWasm.wasm) is a SEPARATE file you host — tell the
//    library where it is via wasmUrl (see "Hosting the WASM binary" below).
await layer.initialize(lease, { wasmUrl: "/assets/driversWasm.wasm" });

// 4. Connect: shows browser WebHID device picker (or auto-connects if already granted)
await layer.connect();

// 5. Retrieve tablet metadata (name, aspect ratio, canvas vs monitor style)
const info = layer.getDeviceInfo();

// 6. Start signing: displays signing screen, sets up hotspots, enables drawing
const canvas = document.querySelector("canvas")!;
await layer.startSigning(canvas);

// 7. Subscribe to button events
layer.onOK(async () => {
    const { penData, image, canvasMetadata } = await layer.stopSigning();
    // submit signature...
});
layer.onClear(() => layer.clearSignature());
layer.onCancel(() => layer.stopSigning());

What Happens Internally During Initialization

  1. WASM load — the library imports the Emscripten loader (driversWasm.js, an ES module) and calls its factory to create the WebAssembly module. The factory fetches the separate driversWasm.wasm binary (see Hosting the WASM binary).
  2. Licence verification — WASM fetches public key from /api/v1/driver/public-key, verifies RSA-SHA256 signature and expiration
  3. Device connectionnavigator.hid.requestDevice() or getDevices() opens the HID interface
  4. Driver creationTabletDriverFactory matches VID/PID and creates a device-specific C++ driver instance
  5. Hotspot setupSignatureDeviceConfig provides per-device button layout; HotspotManager registers OK / Clear / Cancel regions
  6. Screen displayDisplayImage command sends the idle or signing screen to the tablet

Hosting the WASM binary

This package ships two runtime artifacts: the JavaScript library (dist-driver/) and the WebAssembly binary driversWasm.wasm. The library imports the Emscripten loader for you — there is no <script> tag and no window global — but the .wasm is a separate file your app must serve, and you tell the library where it lives:

await layer.initialize(lease, { wasmUrl: "/assets/driversWasm.wasm" });
// TabletDriver (Layer 1) takes the same option:
await tablet.initialize(lease, { wasmUrl: "/assets/driversWasm.wasm" });

How to get driversWasm.wasm to a served URL, depending on your tooling:

  • Bundler that handles import.meta.url assets (Vite, webpack 5, Parcel): it may emit and serve the .wasm automatically — try initialize(lease) with no wasmUrl first. If the wasm 404s, fall back to hosting it explicitly (below).
  • Explicit hosting (always works): copy node_modules/@signosoft/tablet-driver/driversWasm.wasm into your served static assets (e.g. an assets//public/ folder, or an Angular assets glob) and pass that URL as wasmUrl.
  • Advanced: pass locateFile: (path, dir) => … instead of wasmUrl for full control over how the loader resolves the binary.

The package also exposes the raw files via subpath exports — @signosoft/tablet-driver/driversWasm.wasm and @signosoft/tablet-driver/driversWasm.js — so bundlers that support asset URL imports can resolve the binary directly (e.g. new URL("@signosoft/tablet-driver/driversWasm.wasm", import.meta.url)).


Data Flow: Main Event Loop

HID Input Processing Pipeline

1. Browser HID Event → TypeScript (src/tablet-driver.ts)

device.addEventListener("inputreport", (event) => {
    // Pass directly to WASM; the bridge converts the DataView internally
    this.module.processHIDReport(event, event.reportId);
});

2. TypeScript → WASM Bridge (Driver/Driver/WASMwrapper.cpp)

  • WASMTabletDriver::processHIDReport(val event, int reportId)
  • Converts JavaScript typed array to C++ std::vector<uint8_t>
  • Calls driver->processHIDReport(data, reportId)

3. HID Report Processing (Driver/Driver/TabletDriver.cpp)

  • Log Raw Data: If enabled, logs hex dump of HID report
  • Parse Data: parser->getPenData(parsedData, timeData) extracts and normalizes pen coordinates/pressure
    • Example: xParam = {bitOffset: 24, numBits: 16, littleEndian: true}
    • Reads 16 bits starting at bit 24 to get X coordinate, returns values in 0.0-1.0 range
  • Log Parsed Data: Shows raw tablet units (e.g., x=5000, y=3000, pressure=512)
  • Button Detection: Checks inputRegistrations for special input patterns (e.g., pen at 0,0 = OK button)
  • Normalize Data: Normalization to 0.0-1.0 is handled within getPenData()
  • Log Normalized Data: Shows final coordinates (e.g., x=0.26, y=0.28, pressure=0.5)

4. Event Emission (Driver/Driver/TabletDriver.cpp)

  • Creates InputEvent(type, penData) where type is "Pen", "OK", "Clear", etc.
  • Calls inputEmitter.emit(event) to publish to JavaScript

5. WASM → JavaScript Event Bridge (Driver/Driver/WASMwrapper.cpp)

  • WASMEvent<InputEvent>::emit() converts C++ event to JavaScript object
  • Calls JavaScript callback with {type: "Pen", penData: {x, y, pressure, inContact, ...}}

6. TypeScript Event Distribution (src/tablet-driver.ts)

  • Master callback receives event from WASM
  • Looks up subscribed callbacks in the internal event-callback map
  • Executes all registered callbacks for that input type

7. User Callback Execution (consumer code, e.g. demo/driver_simple_impl.ts)

tablet.on("Pen", (penData) => {
    drawPenInput(penData); // Draws on canvas
});

tablet.on("OK", () => {
    handleOK(); // Returns to home screen
});

8. Hotspot System (src/hotspot-manager.ts)

  • Subscribes to 'Pen' events automatically
  • Checks if pen coordinates fall within hotspot boundaries
  • Tracks state per hotspot (isPenInside, isPenDown, isValidForClick)
  • Fires hotspot-specific events (enter, leave, down, up, click, move)

Command Execution Flow

Example: tablet.screenClear(imageArgs)

  1. TypeScript Call (src/tablet-driver.ts)

    • sendCommand("Clear", imageArgs.build())
  2. WASM Command Lookup (Driver/Driver/WASMwrapper.cpp)

    • WASMTabletDriver::sendCommand("Clear", jsonArgs)
    • Converts string to CommandType::Clear enum
    • Calls driver->sendCommand(CommandType::Clear, jsonArgs)
  3. Driver Command Execution (Driver/Driver/TabletDriver.cpp)

    • Looks up command in supportedCommands map
    • Executes command->execute(jsonArgs)
  4. Command Implementation (Driver/Driver/Command.cpp)

    • SimpleCommand: Sends single HID output report
    • ImageCommand: Sends init report → data chunks → completion report
    • MultiCommand: Executes sequence of commands
    • ConditionalCommand: If/else logic based on JSON arguments
    • WrapperCommand: Delegates to another command with static arguments
  5. HID Output Report (Driver/Driver/Utils.cpp)

    • Converts CommandData{reportId, data} to JavaScript
    • Calls device.sendReport(reportId, data) via Emscripten

Project Structure

Core Components

  • Driver/Driver/: C++ source code for the WASM module
    • Tablet-specific drivers: DTK1660E.hpp, DTC121.hpp, DTU1031.hpp, DTU1141B.hpp, STU300.hpp, STU430.hpp, STU520.hpp, STU530.hpp, STU540.hpp, STU541.hpp, UG05.hpp, UG0501DL.hpp, UG1070H.hpp (Contains proprietary parsing constants — CRUCIAL IP)
    • Core classes: TabletDriver, DataParser, DefaultDriver, InputData, EventEmitter
    • WASM interface: WASMwrapper.cpp/hpp
    • Utilities: Logger, Utils, JavaScriptUtils, Command
    • Driver.cpp: Console application for testing without WASM compilation
  • src/: TypeScript source for the driver library (Layers 1 & 2 + utilities)
  • demo/: Vite-served TypeScript demo pages plus a few legacy standalone HTML utilities

Build Outputs

  • driversWasm.js — produced by build.bat; the Emscripten loader as an ES module (MODULARIZE + EXPORT_ES6). The TS library imports it (it is externalized from the bundle and shipped alongside it). driversWasm.wasm — the separate binary; consumers host it and point the library at it via wasmUrl (see Hosting the WASM binary).
  • dist/tsc output, ESM + .d.ts (local/dev convenience)
  • dist-driver/ — Vite bundle of src/index.ts, minified. This is what package.json exports (and the published package) resolves to; it imports driversWasm.js from the package root.

Build Scripts

  • build.bat: Compiles C++ to WASM with three profiles:
    • debug: Fast compilation with full debugging
    • release: Optimized build without debugging
    • protected: Maximum optimization and obfuscation
  • decompile.bat: Decompiles WASM for reverse engineering analysis
  • npm scripts (see package.json): dev, build, build:driver, build:signature — TypeScript-side only, never invoke emcc

Tools Directory (Not in Repository)

  • tools/emsdk/: Emscripten SDK for WebAssembly compilation
  • tools/wabt-1.0.37/: WebAssembly Binary Toolkit for decompilation
  • tools/ghidra_11.2_PUBLIC/: Reverse engineering analysis tool (optional)

Note: Tools are excluded from repository (.gitignore) due to size - see Prerequisites section for setup instructions.

Build Instructions

Prerequisites

  • Windows CMD (not PowerShell - the build scripts use Windows batch syntax)
  • Git for cloning dependencies
  • curl for downloading header files (included in Windows 10+)

Quick Start Setup

Complete setup from scratch --- run init.bat from project root in Windows CMD

⚠️ Important Note for Build Script Development: When modifying build.bat, do NOT use variable names containing "EMSDK" - they get cleared by emsdk_env.bat. Use alternative names like EMSCRIPTEN_DIR instead.

Required External Dependencies

The C++ WASM module requires several external libraries for image processing and encoding. These must be manually installed before building.

1. STB Image Libraries (Driver/Driver/external/stb/)

STB is a collection of single-file public domain libraries for C/C++. We use:

  • stb_image.h - Image loading (PNG, JPG, etc.)

  • stb_image_resize2.h - High-quality image resizing

  • https://github.com/nothings/stb/blob/master/stb_image.h

  • https://github.com/nothings/stb/blob/master/stb_image_resize2.h

Place both files in Driver/Driver/external/stb/

2. cppcodec Base64 Library (Driver/Driver/external/cppcodec/)

Header-only C++ library for base64/base32 encoding/decoding.

  • https://github.com/tplgy/cppcodec
  • Extract to Driver/Driver/external/cppcodec/

Required Build Tools Setup

The following build tools need to be installed in the tools/ directory. These are excluded from version control due to size.

Emscripten SDK (tools/emsdk/)

  • Download from: https://github.com/emscripten-core/emsdk
  • Install: git clone https://github.com/emscripten-core/emsdk.git tools/emsdk
  • Setup: cd tools/emsdk && emsdk install latest && emsdk activate latest

WebAssembly Binary Toolkit (tools/wabt-1.0.37/)

  • Download from: https://github.com/WebAssembly/wabt/releases
  • Extract to: tools/wabt-1.0.37/ (or update version in decompile.bat)

Ghidra (tools/ghidra/) - Optional for reverse engineering analysis

  • Download from: https://github.com/NationalSecurityAgency/ghidra/releases
  • Extract to: tools/ghidra_11.2_PUBLIC/
  • WASM Plugin Required: Download https://github.com/nneonneo/ghidra-wasm-plugin/releases
  • Install plugin in Ghidra for WebAssembly analysis support

Quick Build (WASM)

build.bat protected

Build Profiles (WASM)

  • debug: -g -O0 with assertions and safety checks
  • release: -O2 -DNDEBUG optimized build
  • protected: -O3 -DNDEBUG with maximum obfuscation

TypeScript / npm Scripts

The TS library and the WASM binary are built independently — build.bat produces driversWasm.js (ESM loader) + driversWasm.wasm, and the npm scripts produce the TS bundle that imports the loader. Run build.bat first, then the npm build, when shipping a release.

npm install                  # one-time install of TS toolchain (Vite, tsc, terser)

npm run dev                  # Vite dev server on http://localhost:4200, opens demo with HMR
npm run build                # tsc → dist/ (ESM + .d.ts; this is the package's published entry)
npm run build:driver         # Vite → dist-driver/index.js (Layer 1 only, minified ESM)
npm run build:signature      # Vite → dist-signature/index.js (Layer 2 only, minified ESM)
npm run clean                # remove dist/

The dist/ build is what consumers resolve via import { TabletDriver } from "@signosoft/tablet-driver". The two split bundles (dist-driver/, dist-signature/) exist for consumers who want the smallest possible payload for their use case.

Development & Testing

Console Testing

The project includes a console application (Driver/Driver/Driver.cpp) for testing tablet drivers without WebAssembly compilation.

Web Testing

Run npm run dev to start the Vite dev server on http://localhost:4200 with HMR. WebHID requires a secure context, so the demo must be served over localhost or HTTPS — not opened from file://.

Primary test pages (TypeScript, served via Vite):

  • demo/driver_playground.html — Full testing environment for the TabletDriver layer (Layer 1). All commands, events, logging controls, and hotspot debugging are accessible directly. Use this when working on the WASM bridge or raw tablet communication.
  • demo/driver_simple_impl.html — Reference implementation using SignatureLayer (Layer 2). Shows the complete signing workflow in a realistic setting. Use this when working on or testing the higher-level signing API.
  • demo/index.html — Landing page with license-validation test buttons.

Legacy standalone utility pages (.js.html suffix, plain-JS — served as static assets by Vite):

These two .js.html files predate the TS rewrite and may reference modules that no longer exist; treat them as scratch tools and migrate or delete as needed.

Reverse Engineering Analysis

Use decompile.bat to analyze WASM obfuscation effectiveness:

decompile.bat

This generates driversWasm.wat and driversWasm.c for inspection.

Security & IP Protection

Critical IP Components

The tablet-specific driver classes contain proprietary constants for interpreting HID reports from various Wacom tablets. This parsing logic is the core intellectual property requiring protection.

Obfuscation Techniques

  • String encryption and conditional compilation
  • Runtime decryption of sensitive parameters
  • Build-time obfuscation flags
  • Debug string removal in production builds

Production Deployment

Before deployment, ensure Logger.cpp has LogLevel set to Error:

Logger::currentLevel = LogLevel::Error;

Architecture

The system processes tablet input through a multi-layer pipeline:

  1. RAW HID reports from tablet hardware
  2. PARSED data extraction using tablet-specific constants (C++ WASM)
  3. NORMALIZED coordinate and pressure values (0.0–1.0 range)
  4. Layer 1 eventsTabletDriver routes pen data and button events to JavaScript callbacks
  5. Layer 2 orchestrationSignatureLayer manages the signing workflow: hotspots, canvas drawing, and pen data collection

System Features & Capabilities

Two-Layer TypeScript API

The library is split into two layers so applications can consume exactly the level of abstraction they need:

  • TabletDriver (Layer 1) provides the raw WASM bridge: event subscriptions, command execution, and WebHID lifecycle management.
  • SignatureLayer (Layer 2) is a higher-level façade built on top of Layer 1 that handles the full signature capture workflow with a minimal API surface.

Reliable Connection Management

  • Automatic USB hardware disconnect detection with proper C++ resource cleanup via disconnectDriver()
  • Auto-connect functionality for devices already granted browser permission
  • Consistent connection state available via isConnected()

Multi-Device Support

Supports STU, DTU, DTK, UG, and DTC series tablets with device-specific:

  • HID parsing constants (bit offsets for X, Y, pressure, buttons)
  • Signing screen layouts and button hotspot positions
  • Aspect ratio correction (canvas-style vs monitor-style tablets)

Advanced Hotspot System

Interactive area system supporting multiple region types:

  • Static hotspots: Normalized 0–1 coordinates for consistent cross-device positioning
  • Element hotspots: DOM element tracking for web page integration
  • Page hotspots: Full-screen mapping for monitor-style tablets (DTU/DTK/UG-1070H)

Full web-button event cycle (enter / leave / down / up / click / move) with per-hotspot state tracking.

Image and Command System

  • Multi-format image processing pipeline: Canvas, File, HTMLImageElement, base64, URL
  • Text-to-image generation for dynamic tablet screen content
  • Full command set: DisplayImage, ClearScreen, EnableDrawing, SetPenStyle, GetSerialNumber, and more

Contributing

When adding new tablet support, create a new driver class in the pattern of existing tablet drivers (DTK1660E.hpp, etc.) with the specific parsing constants for that tablet model.

Development Workflow

  1. Modular Development: Add new modules under src/ as .ts files (kebab-case naming). Re-export public symbols from the relevant entry point (src/index.ts, src/index.driver.ts, or src/index.signature.ts).
  2. Device Testing: Test with both demo/driver_simple_impl.html and demo/driver_playground.html via npm run dev.
  3. Disconnect Testing: Always verify proper cleanup when devices are unplugged.
  4. Hotspot Configuration: Ensure new devices have appropriate hotspot layouts in src/data/device-configs.ts.
  5. Documentation: Update this README and CLAUDE.md for significant changes.

License

Proprietary Commercial License — Copyright © 2026, Signosoft. All rights reserved.

This software is proprietary to Signosoft and is protected by copyright laws. It is not open source.

🔐 Commercial Usage

A valid, paid, and active commercial license agreement with Signosoft is strictly required for the use, operation, reproduction, distribution, or deployment of this software in any environment (including development, testing, staging, and production).

Operation additionally requires a current, valid, signed licence lease obtained from Signosoft at runtime — the software will not function without it.

📜 Key Terms

  • Unauthorized Use: Any use without a current, fully paid license is expressly prohibited and constitutes a violation of our intellectual property rights.
  • Legal Action: Signosoft reserves the right to pursue legal action to enforce its rights and seek damages for unauthorized use.
  • Restrictions: You may not reverse-engineer, decompile, or disassemble this software except as permitted by applicable law.

For information on how to obtain a valid commercial license, pricing, and support, please contact us at [email protected].

See the LICENSE file for the full legal text.