SkillAgentSearch skills...

Nvk

Vulkan API for JavaScript/TypeScript

Install / Use

/learn @maierfelix/Nvk
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<p align="center"> <a href="#"> <img src="https://i.imgur.com/7rnMbVp.png" height="204"> </a> <br/> <br/> <a href="https://www.npmjs.com/package/nvk"> <img src="https://img.shields.io/npm/v/nvk.svg?style=flat-square" alt="NPM Version" /> </a> <a href="#"> <img src="https://img.shields.io/badge/vulkan-1.2.162-f07178.svg?style=flat-square" alt="Vulkan Header Version" /> </a> <a href="//www.npmjs.com/package/nvk"> <img src="https://img.shields.io/npm/dt/nvk.svg?style=flat-square" alt="NPM Downloads" /> </a> </p>

This is a low-abstraction, high-performance Vulkan API with interfaces for JavaScript and TypeScript.

Platforms:

nvk comes with pre-built N-API binaries for the following platforms:

| OS | Status | | ------------- | ------------- | | <img src="https://i.imgur.com/FF3Ssp6.png" alt="" height="16px"> Windows | ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ✔ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌| | <img src="https://i.imgur.com/bkBCY7V.png" alt="" height="16px"> Linux | ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ✔ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌| | <img src="https://i.imgur.com/iPt4GHz.png" alt="" height="16px"> MacOS | ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ✔ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌|

Examples:

| Real-Time RTX Ray Tracer | :-------------------------:| <a><img src="https://i.imgur.com/ga6CJca.png" height="228"></a>

Why Vulkan in JavaScript?

  • Vulkan is a binding friendly API
  • Less overhead than WebGL/OpenGL
  • Essential features like Compute, Geometry and Tesselation shaders
  • Support for Real-Time Ray Tracing, Mesh shaders, ...
  • Supports Multithreading
  • Low-level memory control using ArrayBuffers

This project is a thin layer on top of native Vulkan, built with simplicity and performance in mind. Native memory for Vulkan gets constructed entirely within JavaScript to reduce trampolining overhead. Bounding checks and type validations are enabled by default, but can be disabled using the --disable-validation-checks flag.

Installation:

npm install nvk

Example:

In most cases the bindings match the C99 style of Vulkan. This allows you to follow existing C/C++ tutorials, but write the implementation itself with nvk. Note that both interfaces end up with a similar amount of code. Optionally you can use some syntactic sugar to write things quicker.

JavaScript/TypeScript:

let instance = new VkInstance();
let appInfo = new VkApplicationInfo();
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "App";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_2;

let validationLayers = [
  "VK_LAYER_KHRONOS_validation"
];
let instanceInfo = new VkInstanceCreateInfo();
instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceInfo.pApplicationInfo = appInfo;
instanceInfo.ppEnabledLayerNames = validationLayers;
instanceInfo.enabledLayerCount = validationLayers.length;
vkCreateInstance(instanceInfo, null, instance);

C++:

VkInstance instance;
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "App";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_2;

const std::vector<const char*> validationLayers = {
  "VK_LAYER_KHRONOS_validation"
};
VkInstanceCreateInfo instanceInfo = {};
instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceInfo.pApplicationInfo = &appInfo;
instanceInfo.ppEnabledLayerNames = validationLayers.data();
instanceInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
vkCreateInstance(&instanceInfo, nullptr, &instance);

TypeScript:

To use the TypeScript definition file, simply follow the installation steps above or use this example as a reference. Afterwards in your .ts file, import and use nvk as follows:

import * as nvk from "nvk";

Object.assign(global, nvk);

let win = new VulkanWindow({
  width: 480,
  height: 320,
  title: "typescript-example"
});

let appInfo = new VkApplicationInfo({
  pApplicationName: "Hello!",
  applicationVersion: VK_MAKE_VERSION(1, 0, 0),
  pEngineName: "No Engine",
  engineVersion: VK_MAKE_VERSION(1, 0, 0),
  apiVersion: VK_API_VERSION_1_2
});

Also note, that it is recommended to enable the --strict mode in the TS compiler options and use the latest version of the TS compiler.

Syntactic Sugar:

The API gives you some sugar to write things quicker, but still gives you the option to write everything explicitly

sType auto-filling

sType members get auto-filled, but you can still set them yourself

let appInfo = new VkApplicationInfo();
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;

Becomes:

let appInfo = new VkApplicationInfo(); // sType auto-filled

Structure creation shortcut

Instead of:

let offset = new VkOffset2D();
offset.x = 0;
offset.y = 0;
let extent = new VkExtent2D();
extent.width = 640;
extent.height = 480;
let renderArea = new VkRect2D();
renderArea.offset = offset;
renderArea.extent = extent;

You can write:

let renderArea = new VkRect2D({
  offset: new VkOffset2D({ x: 0, y: 0 }),
  extent: new VkExtent2D({ width: 640, height: 480 })
});

Nested Structures

nvk allows to use nested structures to improve memory usage and performance. A nested structure is pre-allocated automatically and shares the native memory of it's top-level structure. You can use the --enable-shared-memory-hints flag, to get hints where you could've used a nested structure in your code.

Instead of:

let scissor = new VkRect2D();
scissor.offset = new VkOffset2D();
scissor.extent = new VkExtent2D();
scissor.offset.x = 0;
scissor.offset.y = 0;
scissor.extent.width = 480;
scissor.extent.height = 320;

You can write:

let scissor = new VkRect2D();
scissor.offset.x = 0;
scissor.offset.y = 0;
scissor.extent.width = 480;
scissor.extent.height = 320;

Cached Structures

To reduce GC pressure, nvk allows to use cached structures. Instead of having to allocate a structure every time on the heap, nvk allows to use a caching mechanism to mimic stack allocation.

Imagine the following situation:

let commandBuffers = [...Array(8)].map(() => new VkCommandBuffer());
for (let ii = 0; ii < commandBuffers.length; ++ii) {
  let commandBufferBeginInfo = new VkCommandBufferBeginInfo();
  vkBeginCommandBuffer(commandBuffers[ii], cmdBufferBeginInfo);
  ...
};

This results in 8 allocations of VkCommandBufferBeginInfo structures. When this code gets executed in frequently used code sections, the heap pressure will be high.

Now nvk has a mechanism to simulate stack allocation:

let commandBuffers = [...Array(8)].map(() => new VkCommandBuffer());
for (let ii = 0; ii < commandBuffers.length; ++ii) {
  let commandBufferBeginInfo = VkCommandBufferBeginInfo("0x0");
  vkBeginCommandBuffer(commandBuffers[ii], cmdBufferBeginInfo);
  ...
};

On the first iteration of the loop, a VkCommandBufferBeginInfo structure is allocated on the heap but also gets cached internally. Based on the String id 0x0 you have added, nvk uses this id to identify this structure and return a cached one whenever this code gets executed again.

Obviously, you don't want to add your own ids to each structure by hand. There is a rollup plugin, which detects nvk structure calls (when invoked without new) and inserts a unique id automatically. You can find the rollup plugin here and a project example here.

Project Structure:

  • docs: generated vulkan documentation files
  • generator: code for binding generation
  • generated: the generated binding code
  • examples: ready-to-run examples
  • lib: required third party libs
  • src: classes for e.g. window creation

This tool uses a new JavaScript type called BigInt to represent memory addresses returned by Vulkan. The BigInt type was recently added, so make sure you use a recent node.js version.

Binding Code Generator:

The Generator generates code based on a vk.xml specification file. It first converts the XML file into an AST, which is then used by the code generator. Currently more than ~300.000 lines of code get generated, where ~60.000 lines are JavaScript, `~50

View on GitHub
GitHub Stars947
CategoryDevelopment
Updated7d ago
Forks35

Languages

C++

Security Score

100/100

Audited on Mar 25, 2026

No findings