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

@womp/kakapo-sdk

v0.8.0

Published

Typed Node.js and browser SDK for controlling Kakapo over WebSocket

Readme

@womp/kakapo-sdk

Migrating to 0.7

Use accessScene(callback, { save: true }) for a single fetch, isolated draft, validation, patch and optional save. Its result includes value, changed, save and the acknowledged scene. editScene and editSceneAndSave remain compatibility shortcuts. getSceneRevision() and getSceneSnapshotRevision() were removed, along with fingerprint-based conflict checks. Hosts must serialize scene access and suspend competing manual writes; independent clients have no atomic cross-client protection. Cached state is invalidated after access. Camera RPC changes made during access are preserved without copying the full scene. The existing renderer-readiness wait remains until supported native engines provide readiness guarantees.

Typed Node.js and browser SDK for manipulating a Kakapo scene through its JSON-RPC WebSocket.

Releases

Pushes to main publish an unpublished stable package.json version newer than npm's latest; already-published versions skip. No Git tag is required. Deliberately bump MAJOR.MINOR.PATCH; prereleases/build metadata are not published automatically. CI uses the frozen Yarn lockfile, typechecks, unit tests and a fresh tarball import check, then publishes that same archive and verifies its registry integrity. Live renderer tests are not run. Registry failures block publication. Releases are serialized; newer pending pushes may supersede older pending runs.

Configure npm's trusted publisher once for @womp/kakapo-sdk: organization wompxyz, repository kakapo-sdk, workflow filename publish.yml, no environment, and allow direct npm publish. GitHub-hosted runners use OIDC without a publishing token. After an uncertain publish, inspect npm before rerunning the failed workflow. Publish the SDK before updating dependent applications.

yarn install
yarn build
import { KakapoAPI } from "@womp/kakapo-sdk";

const kakapo = new KakapoAPI();
await kakapo.connect({ refreshScene: false });

const { value: union } = await kakapo.accessScene((scene) => {
  const root = scene.createNode({
    kind: "union",
    parentId: 0,
    name: "Agent Model",
  });

  const box = scene.createNode({
    kind: "primitive",
    parentId: root.id,
    name: "Body",
    properties: {
      primitive: "box",
      transform: { scale: { x: 10, y: 4, z: 6 } },
    },
  });

  const red = scene.createMaterial({
    color: { x: 1, y: 0.05, z: 0.05 },
    roughness: 0.4,
  });

  const body = scene.node(box.id, "primitive");
  body.materialId = red.id;
  body.position = { x: 0, y: 4, z: 0 };
  body.round = 0.2;
  body.save();
  return root;
});

console.log(await kakapo.getNodeBoundingBox(union.id));

kakapo.disconnect();

The transport uses the browser's native WebSocket when bundled for the web and loads ws dynamically in Node.js.

Applications that already own a renderer connection can pass a KakapoAPITransport as new KakapoAPI({ transport }). The adapter defines connection lifecycle, RPC, and token responses. captureScreenshot({}) requests the active camera's JPEG without automatic framing or a cached scene. Pass camera to frame explicitly, or call setCamera(camera) without taking a screenshot:

await kakapo.captureScreenshot({ camera: {
  position: { x: 30, y: 20, z: 40 },
  target: { x: 0, y: 0, z: 0 },
  projection: "perspective",
  horizontalFovDegrees: 60,
} });

Camera coordinates are native Kakapo world coordinates: Y is up, and one unit is 25 mm. These are not Womp editor coordinates: editor millimetres (x, y, z) map to native (-z / 25, y / 25, -x / 25). SDK renderer bounds use native coordinates; only use bounds known to be in world space when choosing a world-space target. Perspective framing uses horizontal FOV in degrees. Orthographic framing uses orthographicWidth, the visible horizontal span in native units. Omitted projection and lens settings retain their active values, including focus/aperture; no depth-of-field controls are exposed. Position and target determine direction and world-Y up. Exact vertical orientations, coincident positions, and values outside the native controller's supported range are rejected.

Camera changes are immediate, without animation, and remain active after capture. The SDK never fits bounds or restores an earlier camera. SDK camera operations are serialized within a JavaScript realm for the same endpoint URL or shared transport object. Capture requires Kakapo's capture_screenshot RPC: [[token], nativeCamera], or [[token]] to use the active camera when the request reaches the front of the queue. Explicit camera inputs are converted by the SDK; omitted lens fields are preserved from its pre-request camera read. Kakapo queues captures across connections, applies each camera without animation, renders with that request's camera, and freezes the pixels before processing the next capture. The response is a standard token-correlated JPEG, not camera metadata for the SDK to poll. There is no settling delay or frame retry loop. Concurrent editor input can change the active camera afterwards but cannot replace the camera used by an explicit capture. Scene edits are not isolated by this queue. The queue holds at most 64 pending captures. AI-diffusion-composited output returns a token error rather than an unrelated image. Existing buffer RPCs remain available to other renderer clients.

All public inputs are checked at runtime as well as by TypeScript. Invalid calls throw structured KakapoValidationError objects with a stable code, offending path, expected rule, and a correction hint intended for automated agents.

accessScene(callback, { save?: boolean }) fetches the scene once and creates one editable draft from an immutable baseline. The callback can inspect summaries, detailed properties and materials, and apply mutations. Incoming JSON is parsed without full-scene validation. Draft operations retain local checks. After the callback the draft is diffed once against the baseline; an empty diff is not validated and does not patch or save. Otherwise the whole tree is checked structurally (root, parent and child membership, cycles, Union ancestry), node values are checked only for nodes the draft changed (their node or ext entry, their parent, or a material or script they reference), and one patch is sent. Untouched nodes are not revalidated, so a pre-existing invalid value blocks only edits that touch that node. A node value failure names the node: path is nodes.<id>.<field> and details holds { nodeId, name, kind }. Callback handles expire on exit. The result contains the callback value, changed, save, and the acknowledged native scene for host reconciliation without another fetch. Preparation failure discards the draft. Cached scene state is invalidated on every exit; use a new access for subsequent inspection.

The host owns permissions, connection lifetime and suspension of local editor changes throughout access, including read-only callbacks. Connect with { refreshScene: false } to avoid a redundant initial fetch. Access does not hash, reread for conflicts, add patch test guards, refetch after errors, or replay uncertain commits. It adds no cross-client atomicity guarantee. editScene and editSceneAndSave are compatibility shortcuts to the same access implementation. node(id, kind).save() stages properties in the draft; it does not submit a separate commit.

For incremental curve edits, use SceneEdit.updateCurvePoint(id, index, changes), cloneCurvePoint(id, sourceIndex, insertionIndex), and deleteCurvePoint(id, index). These retain native per-point fields unknown to this SDK. Replacing a node's entire typed points array replaces that data; use the granular operations when editing existing points.

Engine-backed reads such as bounding boxes and screenshots remain asynchronous. Run them before the first draft mutation or after accessScene() commits.

Accesses are serialized per SDK client. Raw scene-mutating RPCs invalidate cached state; they are not coordinated by an access callback's host suspension.

Node IDs allocated by createNode() and cloneSubtree() increase for the lifetime of a KakapoAPI instance. IDs observed in scene snapshots, draft patches, or numeric node-extension keys remain reserved after deletion, rollback, and reconnect. This prevents delete-and-create edits from changing an existing renderer object's type by reusing its ID. A new API instance starts above IDs in its current snapshot; this is not a persistent project-wide allocator. Raw patches supply their own IDs and must preserve object identity. IDs are not reserved across independent clients.

editSceneAndSave(callback) submits the standard scene_state_patch command and, after acknowledgement, calls save_scene once on the same connection. No new Kakapo command is required. The result preserves the callback value separately from save status: acknowledged includes the returned filename, unknown includes an error, and not_needed means the draft did not change. A save acknowledgement does not prove a new durable snapshot: some endpoints return an existing filename. Verify persistence through the owning service. Never repeat the edit to recover saving. The backend wrapper may apply geometry before extension processing fails; patch errors and lost replies therefore have an unknown outcome unless rejection before execution is proven. SDK state is invalidated after submission, and no mutation is automatically replayed.

Mesh, field, and decal names are syntax-checked, but their existence cannot be enumerated by the current engine RPC surface. Font family/weight/style combinations are checked against listFonts().

Verification

yarn test       # fake WebSocket protocol and API behavior
yarn test:live  # launches the sibling Kakapo build and runs named live tests per API method
yarn test:all   # runs both suites

The live suite starts Kakapo once, runs methods sequentially, and reports failures as names such as live:setNodeParent or live:createNode:mesh. Mutations refresh the authoritative engine scene before asserting their result. See TEST_MATRIX.md for the exact unit/live mapping.

Build the sibling engine before running live tests. On Windows the default executable is ../kakapo/build/code/RelWithDebInfo/kakapo_app.exe; on other platforms it is ../kakapo/build/code/kakapo_app. Set KAKAPO_BINARY to test another build explicitly.

Importing catalog materials

Inside editScene, scene.importMaterial({ data, shaders }) imports native renderer material data and shader slots. data retains opaque fields and constants. Each non-null shader gets a new scene-local ID; null slots remain zero. The returned material can be assigned with setNodeMaterial. Material and shader resources share the draft's commit and rollback boundary. The host supplies the catalog data; the SDK does not fetch account or asset services.