It’s here: the new home of Nilkins Engine.

This site was rebuilt from the ground up. Not just to look better, but to be a working part of the project. Now, you don’t only download or get documentation. You also can read about the engine, and code against it in your browser.

This first post walks through what’s new compared to the old site, and ends with a few live demonstrations of the WebAssembly build, executed right in this article.

A refreshed look

The old site did the job, but after a few years it was lagging behind in terms of demonstrative effect.

This new website offers a modernized experience and new features allowing to better leverage the capabilities of the recents builds of the engine:

  • Enjoy a better documentation: documentation has been made easier to navigate.
  • Understand better the engine’s capabilities: latest images and projects used for demonstrations.
  • See it in action: the wasm build is usable right here in your browser.

All in all, everything that was there is still here. However, the navigation should be easier, clearer, prettier, and offer more.

Clearer UI, less friction

Beyond the look, the structure itself is cleaner:

  • The homepage is a showcase with clearer descriptions and pictures.
  • The download flow is more intuitive with the main download page linking to the latest release directly; a past releases page keeps the rest of the history for clearer versioning.
  • Easier to navigate tutorials with filtering capabilities, syntax colored code and an overall more appealing look and feel.
  • Introducing the playground, a full in-browser editor with a console, canvas surface, and syntax-highlighted snippets giving some inspiration.

On top of that, the website has been fully remade with a new underlying technology, improving performances and loading speed.

Up to date with the latest engine improvements

One of the biggest pain points of the old site was that it lagged behind the engine. Releases and documentation were up to date but not the demonstrations. But now:

  • Latest projects are directly part of the website.
  • You can enjoy the latest wasm build live to witness and test it before downloading it.

You’re reading that last point being put to use right now. The demos below are not screenshots or video captures, but the real WebAssembly build of the engine, loaded into your browser when you press ▶ Run (if it is not auto-running).

The Wasm build, running inside this post

The engine now compiles to WebAssembly, and the site takes full advantage of it. The playground page gives you the full editor experience, but the same machinery is available inline. This very post embeds three live demos. Each one shows its code syntax-highlighted in the page, and executes it in the real engine.

There is no trickery. What you see is the code executed live.

1. nkMaths, a simple demonstration

Here is a small nkMaths snippet. It’s highlighted in place, and, because it’s been marked as such, it runs automatically the moment the engine loads in your browser.

01-nkMaths-computation.js
const a = new nkMaths.Vector(5, 2, 6);const b = new nkMaths.Vector(14, 30, 1);log('a . b (dot product) =', a.dotProductVec3(b));log('|a| (length)       =', a.getLengthVec3().toFixed(4));log('a x b (cross)      =', a.getCrossVec3(b));// 90 degrees around Z, applied to the "up" vectorconst q = new nkMaths.Quaternion(0.7071068, 0, 0, 0.7071068);log('(0,1,0) rotated 90deg around Z ->', new nkMaths.Vector(0, 1, 0).mulQuaternion(q));

Same vector and quaternion types as the native build, here used in their managed version. If you wish to discover the performance difference with the unmanaged version, see the playground’s 01-nkMaths demo.

2. nkGraphics — a basic spinning cube

This demo pushes further and starts a basic demo for nkGraphics. This demonstrates the lower level graphics access and the use of the provided canvas surface. Press ▶ Run to spin it:

02-nkGraphics-cube.js
//// nkGraphics - Spinning cube// Setting up a basic rendering pipeline to animate a cube//// Prepare a basic logger (logs in dev console)const logger = new nk.nkLog.ConsoleLogger () ;nkGraphics.LogManager.getInstance().setReceiver(logger) ;// Initialize the systemconst system = nkGraphics.System.getInstance() ;if (!system.initialize())	throw new Error("nkGraphics.System.initialize() failed — WebGL2 unavailable in this browser?") ;log("nkGraphics system initialised (WebGL2)") ;// Prepare a basic cube's data (position + normals)// Both attributes will be vec4const faces = [	{ n: [-1, 0, 0],  v: [[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [-1, 1, -1]] },	{ n: [0, -1, 0], v: [[1, -1, -1], [1, -1, 1], [-1, -1, 1], [-1, -1, -1]] },	{ n: [0, 0, -1], v: [[1, -1, -1], [-1, -1, -1], [-1, 1, -1], [1, 1, -1]] },	{ n: [1, 0, 0], v: [[1, -1, 1], [1, -1, -1], [1, 1, -1], [1, 1, 1]] },	{ n: [0, 1, 0],  v: [[-1, 1, -1], [-1, 1, 1], [1, 1, 1], [1, 1, -1]] },	{ n: [0, 0, 1],  v: [[-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1]] }] ;const positions = [] ;const indices = [] ;faces.forEach((f, fi) => {	const base = 4 * fi ;	for (const p of f.v)		positions.push(p[0], p[1], p[2], 1, f.n[0], f.n[1], f.n[2], 0) ;	indices.push(base, base + 2, base + 1, base, base + 3, base + 2) ;}) ;const vbuffer = new nkMemory.Buffer (positions.length * 4) ;new Float32Array(vbuffer.getData().buffer).set(positions) ;const ibuffer = new nkMemory.Buffer (indices.length * 4) ;new Int32Array(ibuffer.getData().buffer).set(indices) ;// Bake input layout describing the data providedconst layout = new nkGraphics.MeshInputLayout() ;layout.addAttribute(new nkGraphics.MeshInputLayoutAttribute("POSITION", nkGraphics.FORMAT.R32G32B32A32_FLOAT)) ;layout.addAttribute(new nkGraphics.MeshInputLayoutAttribute("NORMAL", nkGraphics.FORMAT.R32G32B32A32_FLOAT)) ;// Assemble all of that into the meshconst mesh = nkGraphics.MeshManager.getInstance().createOrRetrieve('CubeMesh') ;mesh.setInputLayout(layout) ;mesh.addVertexBufferForward(vbuffer) ;mesh.setIndexBufferForward(ibuffer) ;mesh.setVertexCount(faces.length * 4) ;mesh.setIndexCount(indices.length) ;if (!mesh.load())	throw new Error('CubeMesh failed to load') ;log(`Mesh built — ${positions.length / 8} vertices, ${indices.length} indices`) ;// Use the default render queue to leverage the default pipelineconst queue = nkGraphics.RenderQueueManager.getInstance().createOrRetrieve(nkGraphics.RenderQueueManager.DEFAULT_RENDER_QUEUE) ;// A null shader will use the best built-in shaderconst renderInfo = new nkGraphics.EntityRenderInfo() ;renderInfo.addSlot(new nkGraphics.EntityRenderInfoSlot(mesh, null)) ;const entity = queue.addEntity() ;entity.setRenderInfo(renderInfo) ;// Attach the entity to a node to allow moving/rotating/scaling it in the environmentconst node = nkGraphics.Node.create() ;node.setPositionAbsolute(new nkMaths.Vector (0, 0, 4)) ;entity.setParentNode(node) ;// Prepare the rendering contextconst context = nkGraphics.RenderContextManager.getInstance().createRenderContext(new nkGraphics.RenderContextDescriptor()) ;context.setGammaCorrected(true) ;// Attach its canvas within the playgroundplayground.attachCanvas("nkGraphics — Spinning cube", context.getAttachedWin().getDomElement()) ;log('Surface attached to the canvas pane') ;// Proceed to launch animationlet last = performance.now() ;let angle = 0 ;const frame =	(now) =>	{		// Animate based on time		const dt = Math.min((now - last) / 1000, 0.05) ;		last = now ;		angle = (angle ?? 0) + dt * 0.9 ;		const half = angle / 2; // Euler angle → quaternion half-angle about Y		node.setOrientationAbsolute(new nkMaths.Quaternion(0, Math.sin(half), 0, Math.cos(half))) ;		// Loop around		system.frame(context) ;		playground.requestFrame(frame) ;	} ;// Request animation to the playgroundplayground.requestFrame(frame) ;log('spinning — pick another demo or hit Reset to stop it') ;

A WebGL2 pipeline assembled from the public nkGraphics API with compositors, passes, entities, render context, driven entirely from JavaScript running on the Wasm build.

3. nkAstraeus — a physically based atmosphere

Lastly, the high-level component. This is 03-nkAstraeus-atmosphere: a physically based atmosphere rendered through the nkAstraeus effect system. One line of effect code building on nkGraphics, plus the shared pipeline that displays it:

03-nkAstraeus-atmosphere.js
//// nkAstraeus - Atmosphere// Using nkAstraeus built-in effects to display a physically based atmosphere//// Prepare a basic logger (logs in dev console)const logger = new nk.nkLog.ConsoleLogger () ;nkGraphics.LogManager.getInstance().setReceiver(logger) ;nkAstraeus.LogManager.getInstance().setReceiver(logger) ;// Initialize the systemconst system = nkAstraeus.System.getInstance() ;if (!system.initialize())  throw new Error('nkAstraeus.System.initialize() failed — WebGL2 unavailable in this browser?');log('nkAstraeus system initialised (WebGL2)') ;// Prepare effectconst effect = nkAstraeus.EffectManager.getInstance().createOrRetrieve("Atmosphere", nkAstraeus.EFFECT_TYPE.ATMOSPHERE) ;effect.setSunPosition(new nkMaths.Vector (0, 0.04, 1)) ;if (!effect.load())  log("Failure in initializing the nkAstraeus effect") ;// Prepare rendering pipelineconst compositor = nkGraphics.CompositorManager.getInstance().createOrRetrieve('AtmosphereDisplay') ;const ops = compositor.addNode().addOperations() ;ops.setToBackBuffer(true) ;const clearPass = ops.addClearTargetsPass() ;clearPass.setClearColor(new nkMaths.Vector(0.02, 0.03, 0.06)) ;const processPass = ops.addPostProcessPass() ;processPass.setShader(effect.getShader()) ;// Prepare the rendering contextconst context = nkGraphics.RenderContextManager.getInstance().createRenderContext(new nkGraphics.RenderContextDescriptor()) ;context.setCompositor(compositor) ;context.setGammaCorrected(true) ;// Attach its canvas within the playgroundplayground.attachCanvas("nkAstraeus — Atmosphere", context.getAttachedWin().getDomElement()) ;log('Surface attached to the canvas pane') ;// Request renderingconst frame =  () => {    nkGraphics.System.getInstance().frame(context) ;    playground.requestFrame(frame) ;  } ;playground.requestFrame(frame) ;

That’s the promise of the new site in miniature: the engine, just here, running where you’re reading about it.

Where to go from here

The website core is now updated and more is to come to feed it with new resources. New posts are coming alongside more showcasing pictures and live demos as the engine moves forward.