Profile
Back to NewsBack
GitHub Trending 7 min
Reader Mode
Makio64/makio-meshline: Meshline

Makio64/makio-meshline: Meshline

12 hours ago

Makio MeshLine

license</a> three.js</a>

A modern MeshLine library for Three.js wide screen strokes and world-space road/ribbon surfaces, with gradients, dashes, textures, shadows, GPU positions, and instancing.

demo</a>

Makio MeshLine is built for creative coding, interactive trails, data visualization, and stylized rendering on top of Three.js WebGPURenderer. It gives you a small fluent API for wide and thick lines, while keeping TSL hooks available when you need custom GPU behavior.

[!IMPORTANT]
Version 2 is the current API and package line. Existing V1 applications should review Migrating from v1 to V2 before upgrading because progress, sharp-bend smoothing, validation, surfaces, and optional WebGPU entry points changed.

Features

  • TSL-powered — Built with Three.js Shading Language for maximum GPU performance
  • WebGPU & WebGL2 — Works with both backends via WebGPURenderer
  • Instancing — Render thousands of lines with a single draw call
  • 14 GPU hooks — Customize position, color, width, opacity, dash, UV and more in the shader
  • Gradients, dashes, textures — Built-in support for common line styles
  • Variable width — Per-vertex width control via callback or GPU hook
  • Bounded line joins & edge AA — miter, bevel, and round billboard joins with camera-invariant 3D fold splitting/clipping (join.fold: 'geometry' | 'exact'), analytic edge antialiasing (.antialias( true )), and optional CPU subdivision
  • Road and ribbon surfaces — Camera-independent geometry with transport frames, banking, normals, tangents, and distance UVs
  • Optional GPU culling — Native-WebGPU chunk compaction and one indirect draw for very large opaque paths
  • Shadow support — Cast and receive shadows across billboards (with 3D cylindrical tube normals) and world-space surfaces
  • GPU positions — Procedural line generation entirely on the GPU
  • Compute-driven trails & morphing — storagePositions() draws lines straight from WebGPU storage buffers, with ring-buffer trails and two-buffer contour morphing
  • Tree-shakeable — ESM-only, sideEffects: false, import only what you need
  • TypeScript — Full type definitions included
  • Zero dependencies — Only Three.js as peer dependency

Why Use Makio MeshLine?

  • Replace older THREE.MeshLine style workflows with a WebGPU-ready Three.js line renderer.
  • Use the same API for one-off wide lines, repeated batches, or thousands of instanced lines.
  • Keep CPU uploads low with setPositions(), local setPositionRange() edits, bulk instance writes, batching, and GPU position nodes.
  • Add styling and motion with gradients, dashes, textures, vertex colors, opacity, and TSL hooks instead of maintaining multiple line systems.

Use Cases

  • Interactive cursor trails, drawing tools, and paint-like strokes
  • Motion design, sci-fi wireframes, stylized ropes, and decorative outlines
  • Data visualization, flow fields, and parametric curves
  • Large repeated scenes such as vegetation, hair-like structures, or wire sculptures
  • Roads, tracks, and textured world-space ribbons

Support Matrix

| Requirement | Version | |---|---| | Three.js | r186+ (every entry point) | | Optional gpu-culling / gpu-path entries | Native WebGPU | | Renderer | WebGPURenderer only | | Backends | WebGPU & WebGL2 (via WebGPURenderer) |

The release gate installs the packed library into clean consumers and runs runtime plus declaration smoke tests against the minimum supported version (r186.0) and the pinned workspace version. A separate Three.js dev branch canary is advisory so upstream movement stays visible without making releases depend on a moving target.

Live Demo

See it in action with examples on https://meshline-demo.makio.io and check out the code here : demo/src/demos

Screenshot

Installation

pnpm add makio-meshline # or npm/yarn

Upgrading an existing v1 application? Review the V2 migration guide before changing the dependency. Progress is now distance-based, sharp-bend smoothing is opt-in, invalid configuration fails earlier, and the optional native-WebGPU imports have a narrower Three.js version requirement.

Quick Start

import * as THREE from 'three/webgpu'
import { MeshLine, circlePositions } from 'makio-meshline'

// 1. Basic Three.js scaffolding ------------------------------------------------ const renderer = new THREE.WebGPURenderer() renderer.setSize(innerWidth, innerHeight) document.body.appendChild(renderer.domElement) await renderer.init()

const scene = new THREE.Scene() const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 100) camera.position.z = 4

// 2. Create a line (fluent API) ------------------------------------------------ const line = new MeshLine() .lines(circlePositions(64), true) // 64-segment circle, closed loop .color(0xff6600) // hex or THREE.Color .lineWidth(0.4) // scene-space width (sizeAttenuation on by default)

scene.add(line)

// 3. Render loop --------------------------------------------------------------- renderer.setAnimationLoop(() => renderer.render(scene, camera))

Road / Ribbon Surface

Use the separate surface profile when the width and orientation must live in world space:

const road = new MeshLine()
  .lines(roadPoints)
  .lineWidth(4)
  .surface({
    frame: 'transport',
    up: [0, 1, 0],
    uvMode: 'distance',
    uvScale: 5
  })
  .join({ type: 'round', limit: 3, segments: 8 })
  .cap({ type: 'round', segments: 8 })
  .build()

The ordinary miter/butt case stays on the compact two-row path. Bevels, round fans, caps, over-limit miters, and reversal splits add topology only where required. See World-space surfaces for banking, PBR maps, join policies, and precision guidance.

Optional GPU Culling

Very large opaque paths can opt into native-WebGPU chunk compaction (native WebGPU only, from an optional entry point):

import MeshLineCullingSystem from 'makio-meshline/gpu-culling'

const culling = MeshLineCullingSystem.attach(renderer, scene, { mode: 'auto' }) const handle = culling.add(line)

// The first draw warms the compact index buffer; then prepare a culling result. renderer.render(scene, camera) await culling.update(camera)

// Explicit diagnostic readback of the active result. const snapshot = await handle.readCullingSnapshot() console.log(snapshot?.culledChunks)

Unsupported backends, cameras, materials, or bounds draw the complete geometry. See GPU culling for the bounds contract, chunk-range snapshot format, readback cost, and profiling guidance.

Experimental GPU Path

Very large static open paths can instead use the point-centric native-WebGPU renderer:

import MeshLineGPUPath from 'makio-meshline/gpu-path'

const path = new MeshLineGPUPath( { lines: points, lineWidth: 0.35 }, { chunkSegments: 128, simplify: { localTolerance: 0.05 }, } )

scene.add( path ) await path.prepare( renderer, camera )

It emits stable segment records and one non-indexed indirect draw while retaining a complete CPU MeshLine fallback. See GPU path for its deliberately narrow local-space guarantee and current unsupported profiles.

Vanilla Three.js Example

The vanilla starter follows the familiar Three.js example structure: init(), onWindowResize(), and animate(), with explicit WebGPU renderer and OrbitControls setup.

pnpm --filter makio-meshline-vanilla-example dev

Framework Quickstart

Use Makio MeshLine with React Three Fiber or Vue. Each example ships a declarative wrapper and is ready to open on StackBlitz.

React Three Fiber

Open in StackBlitz</a>

import { Canvas } from '@react-three/fiber'
import { circlePositions } from 'makio-meshline'
import { WebGPURenderer } from 'three/webgpu'
import { MeshLine } from './MeshLine.jsx' // wrapper from the example

const circlePoints = circlePositions( 64, 3 )

async function createRenderer( props ) { const renderer = new WebGPURenderer( { ...props, antialias: true } ) await renderer.init() return renderer }

export default function App() { return ( <Canvas camera={{ position: [0, 0, 10] }} gl={createRenderer} > <MeshLine points={circlePoints} closed lineWidth={0.2} color={0xff8800} gradientColor={0xffffff} /> </Canvas> ) }

Full example & wrapper source: examples/react-three-fiber/ — docs

Vue

Open in StackBlitz</a>

<script setup>
import { circlePositions } from 'makio-meshline'
import MeshLine from './MeshLine.vue'

defineProps( { parent: { type: Object, required: true }, } )

const points = circlePositions( 64, 3 ) </script>

<template> <MeshLine :parent="parent" :points="points" closed :line-width="0.2" :color="0xff8800" :gradient-color="0xffffff" /> </template>

Pass any Three.js Object3D already attached to your scene as parent.

Full example & wrapper source: examples/vue/ — docs

Documentation

Check out the documentation site for detailed instructions, API reference, and examples.

Screenshot 2025-07-14 at 19 45 01

About

The concept was to build a performant but easily customizable MeshLine with TSL for WebGPURenderer, allowing the devs to focus on creativity instead of implementation. (read more about it)

Coming from THREE.MeshLine?

If you've been using spite/THREE.MeshLine, makio-meshline is a modern replacement built for the Three.js WebGPU era. The API is different (fluent/chainable), but the concepts are familiar. Start with Getting Started for the Makio MeshLine API. The V2 migration guide is specifically for existing makio-meshline v1 applications.

Thanks

A big thanks to the community, especially to my friend @Floz for his constant support, Samsyyyy for the early tests & feedbacks, to TheSpite for making the first version i knew of MeshLine, to MrDoob and Sunag for Three.js and TSL!

Learn more about meshlines :


Contributing

Bug reports, feature requests and PRs are welcome. Please open an issue first to discuss major changes.

License

This project is licensed under the MIT License .


Made with ❤️ by Makio64

Chat with me