nape-js API
    Preparing search index...

    nape-js API

    nape-js logo

    @newkrok/nape-js

    npm version npm downloads CI bundle size license docs

    Fully typed, tree-shakeable 2D physics engine — a modern TypeScript rewrite of the Nape Haxe physics engine.

    Homepage & Interactive Demos | API Reference | Examples | Multiplayer Demo

    Cookbook | Troubleshooting | Anti-Patterns

    • Originally created in Haxe by Luca Deltodesco
    • Ported to TypeScript by Istvan Krisztian Somoracz
    npm install @newkrok/nape-js
    
    import { Space, Body, BodyType, Vec2, Circle, Polygon } from "@newkrok/nape-js";

    // Create a physics world with downward gravity
    const space = new Space(new Vec2(0, 600));

    // Static floor
    const floor = new Body(BodyType.STATIC, new Vec2(400, 550));
    floor.shapes.add(new Polygon(Polygon.box(800, 20)));
    floor.space = space;

    // Dynamic box
    const box = new Body(BodyType.DYNAMIC, new Vec2(400, 100));
    box.shapes.add(new Polygon(Polygon.box(40, 40)));
    box.space = space;

    // Dynamic circle
    const ball = new Body(BodyType.DYNAMIC, new Vec2(420, 50));
    ball.shapes.add(new Circle(20));
    ball.space = space;

    // Game loop
    function update() {
    space.step(1 / 60);

    for (const body of space.bodies) {
    console.log(`x=${body.position.x.toFixed(1)} y=${body.position.y.toFixed(1)}`);
    }
    }

    Full API documentation: TypeDoc Reference

    Class Description
    Space Physics world — add bodies, step simulation, deterministic mode for rollback/prediction
    Body Rigid body with position, velocity, mass
    Vec2 2D vector — pooling, clone(), equals(), lerp(), fromAngle()
    Vec3 3D vector for constraint impulses — clone(), equals()
    AABB Axis-aligned bounding box — clone(), equals(), fromPoints()
    Mat23 2×3 affine matrix — clone(), equals(), transform, inverse
    Ray Raycasting — clone(), fromSegment(), spatial queries
    Class Description
    Circle Circular shape
    Polygon Convex polygon (with Polygon.box(), Polygon.rect(), Polygon.regular())
    Capsule Capsule shape (Capsule.create(), Capsule.createVertical())
    Shape Base class with material, filter, sensor support
    Class Description
    Material Elasticity, friction, density
    BodyType STATIC, DYNAMIC, KINEMATIC
    InteractionFilter Bit-mask collision/sensor/fluid filtering
    FluidProperties Density, viscosity for fluid shapes
    Class Description
    PivotJoint Pin two bodies at a shared point
    DistanceJoint Constrain distance between anchors
    WeldJoint Fix relative position and angle
    AngleJoint Constrain relative angle
    MotorJoint Apply angular velocity
    LineJoint Slide along a line
    PulleyJoint Constrain combined distances
    Class Description
    InteractionListener Collision/sensor/fluid events
    BodyListener Body wake/sleep events
    ConstraintListener Constraint events
    PreListener Pre-collision filtering
    CbType Tag interactors for filtering
    CbEvent BEGIN, ONGOING, END, WAKE, SLEEP, BREAK
    Class Description
    NapeList<T> Iterable list with for...of support
    MatMN Variable-sized M×N matrix — clone(), equals(), multiply, transpose

    Full physics state snapshot/restore — suitable for save/load, replay, and multiplayer server↔client synchronization.

    import "@newkrok/nape-js";
    import { spaceToJSON, spaceFromJSON } from "@newkrok/nape-js/serialization";

    // Serialize
    const snapshot = spaceToJSON(space);
    const json = JSON.stringify(snapshot);

    // Restore (e.g. on another machine / after network transfer)
    const restored = spaceFromJSON(JSON.parse(json));
    restored.step(1 / 60);

    The /serialization entry point is tree-shakeable — it does not pull in the engine bootstrap when unused. The snapshot captures bodies, shapes, materials, interaction filters, fluid properties, all constraint types (except UserConstraint), and compounds. Arbiters and broadphase tree state are reconstructed automatically on the first step.

    Run physics off the main thread for smooth rendering even with hundreds of bodies.

    import "@newkrok/nape-js";
    import { PhysicsWorkerManager } from "@newkrok/nape-js/worker";

    const mgr = new PhysicsWorkerManager({ gravityY: 600, maxBodies: 256 });
    await mgr.init();

    const id = mgr.addBody("dynamic", 100, 50, [{ type: "circle", radius: 20 }]);
    mgr.start();

    // Read transforms on the main thread (zero-copy with SharedArrayBuffer)
    function render() {
    const t = mgr.getTransform(id);
    if (t) drawCircle(t.x, t.y, t.rotation);
    requestAnimationFrame(render);
    }
    render();

    Uses SharedArrayBuffer for zero-copy transform sharing when COOP/COEP headers are present, with automatic postMessage fallback otherwise.

    • Zero-friction tunneling — Bodies with zero-friction material and horizontal velocity may tunnel through floors. This affects all shape types (circles, polygons, capsules). Workaround: use small friction values (e.g. 0.01).
    npm install
    npm run build # tsup → dist/ (ESM + CJS + DTS)
    npm test # vitest — 4773 tests across 208 files
    npm run benchmark # Performance benchmarks

    MIT