Run three.js with SvelteKit

Date: 2023-05-07 | create | ctech | threejs | sveltekit |

SvelteKit has been my frontend framework of choice in recent years. Now that I'm getting back into Creative Technology, I wanted to figure out how to use creative coding libraries I love (here three.js) with my go-to tech stack.

In this post, we'll walk through how to get three.js working with a SvelteKit site.

Prerequisites

There are a few things you'll need to follow this tutorial successfully.

With your SvelteKit project ready to run locally with three.js installed, we can continue on with the walkthrough.

Demo

Before we get into code, I want to give you an idea of what we expect this code to do when we run it.

We'll be creating a simple three.js scene with a rotating cube and serving it with our SvelteKit site. This allows us to touch on several different three.js components (camera, objects, renderers, etc) without getting too complicated to prove everything works. It's also a common first scene in tutorials so this should be relatively easy to follow.

Here's an example running vanilla JS from the official three.js docs:

Code

HAMINIONs members have access to the full three.js + sveltekit site project files demoed here.

Implementing this code in SvelteKit is surprisingly easy.

In a framework like React we'd often need to work around the built-in renderer, using things like dangerouslySetInnerHTML which feels bad. We still need a little bit of extra code to make it clear to SvelteKit how we want it to render but the boilerplate is minimal.

Here's the code:

routes/+page.svelte

<script lang="ts">
	import { browser } from '$app/environment'; 
	import * as THREE from "three"

	if(browser) {
		let camera : THREE.PerspectiveCamera;
		let scene : THREE.Scene;
		let renderer : THREE.WebGLRenderer;
		let cube : THREE.Mesh<THREE.BoxGeometry, THREE.MeshBasicMaterial>;

		const init = () => {
			scene = new THREE.Scene();
			camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

			renderer = new THREE.WebGLRenderer();
			renderer.setSize( window.innerWidth, window.innerHeight );
			document.body.appendChild( renderer.domElement );

			const geometry = new THREE.BoxGeometry( 1, 1, 1 );
			const material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
			cube = new THREE.Mesh( geometry, material );
			scene.add( cube );

			camera.position.z = 5;
		}

		const render = () => {
			renderer.clear()
			renderer.render(scene, camera);
		}

		const animate = () => {
			requestAnimationFrame(animate)

			cube.rotation.x += 0.005
			cube.rotation.y += 0.005

			render()
		}

		init()
		animate()
	}
</script>

<svelte:head>
	<title>SvelteKit + ThreeJS</title>
</svelte:head>

<section>
	Hello World.
</section>

Note: I'm using TypeScript here hence the type declarations. If you're using plain JavaScript instead, simply remove the type declarations and everything should work fine.

Most of this code is similar to the vanilla JS embed example found above. But there are a few key differences to get this working nicely with SvelteKit which we'll dive into here:

  • URLs and +page.svelte - The first thing to note is that this code lives in a +page.svelte file. This is part of SvelteKit's routing system in which url routes are mapped to subdirectories of /routes and then to a corresponding +page.svelte in that directory. This allows us to access our scene by simply navigating our web browser to the corresponding URL.
    • Example: This code lives at /routes/+page.svelte so it's accessible at WEBSITEURL/
  • <script> tags - If you're new to SvelteKit you may be confused by all these sections. Basically it works similarly to a vanilla HTML / JS setup where we put our JS in a script tag and have it run on page load.
  • import { browser } from '$app/environment' - We are using SvelteKit's built in browser variable to determine if SvelteKit is trying to render on the server vs in the browser. Usually we like server-side rendering but for things that rely on external libraries and have dynamic content / can't be re-rendered - we actually want these to render client side. Threejs projects typically will need access to the browser window and canvas which only lives client side so we leverage browser to make sure we only try to render this on the client.

Next Steps

You should now have a working three.js + sveltekit sketch! Happy coding!

Want more like this?

The best / easiest way to support my work is by subscribing for future updates and sharing with your network.