Skip to content

The template language

Built-in elements

Weft's elements, canvas shapes, scene objects, and the HTML attributes written.

A lowercase name is an element: an HTML element, or one of Weft's own. Inside a canvas2d or scene3d, names mean that surface's shapes and objects instead.

  • HTML elements render as themselves. Any HTML tag works; the ones listed below are those the language server knows and describes.
  • Weft's own elements are listed with the attributes they take. They include heading, markdown, layout primitives such as column and row, and the drawing surfaces canvas2d, scene3d, shader and particles2d.
  • Shapes and objects belong inside a drawing surface. The README's graphics section shows them at work.

Every element on the HTML side also takes class, id, label, role, style, hidden, events and motion-*.

These tables are generated from the element documentation the language server uses for hovers and completions, so they always match what the editor says.

Weft's elements

Elements on the HTML side that Weft adds.

heading

A heading: h1–h6 by level.

AttributeTakesDefaultDoes
level1–61Which heading level.
heading(level: 2) "Our services"

markdown

Renders Markdown (headings, emphasis, links, images, lists, quotes, code). Text is never parsed as HTML.

AttributeTakesDefaultDoes
sourcestring—The Markdown.
markdown(source: post.body)

column

A flex column (a div).

Also written stack.

column(class: "gap-4") { … }

row

A flex row with centred items (a div).

row(class: "gap-2") { … }

group

A labelled group (a div with role="group").

group(label: "Filters") { … }

text

Inline text (a span).

text(class: "font-bold") "Hi"

paragraph

A paragraph (p).

paragraph "…"

A link (a).

AttributeTakesDefaultDoes
hrefurl—Where it goes.
link(href: "/about") "About"

image

An image (img).

AttributeTakesDefaultDoes
srcurl—The image.
altstring—Its text alternative (required unless decorative).
image(src: "/a.jpg", alt: "A cat")

slot

Where a component's content goes.

div(class: "card") { slot }

canvas2d

A 2D drawing: shapes (rect, circle, arc, line, path, text) drawn to a canvas, with accessible proxies for labelled shapes and click/hover events.

AttributeTakesDefaultDoes
widthpx300Logical width (shape coordinates).
heightpx150Logical height.
canvas2d(width: 200, height: 100) { circle(cx: 50, cy: 50, r: 40, fill: "#8b5cf6", label: "Dot") }

scene3d

A WebGL 3D scene, written like React Three Fiber: camera, lights, objects (mesh, primitives, text3d, model), groups, particles and html content.

AttributeTakesDefaultDoes
widthpx300Logical width (without a size class).
heightpx150Logical height.
backgroundcolourdark greyThe colour it clears to; transparent lets the page show through. Without it, a bg-* class shows through.
fognumber0Fog density (towards the background colour).
backdroppreset—An animated shader behind the scene (aurora, plasma, …).
backdrop-colors"c1 c2 …"—The backdrop's palette.
backdrop-intensitynumber1The backdrop's brightness.
backdrop-speednumber1The backdrop's speed.
controlsorbit—Drag, wheel and arrow keys orbit the camera.
scene3d(class: "h-96 w-full", controls: "orbit") {
    camera(position: "0 1 5")
    mesh { sphereGeometry(args: "1") meshStandardMaterial(color: "hotpink") }
}

shader

A full-surface animated fragment shader: a preset or your own GLSL. Reacts to the pointer.

AttributeTakesDefaultDoes
presetnamemesh-gradientmesh-gradient, aurora, plasma, galaxy, waves, synthwave, liquid, topography, rays, grid-glow, silk.
fragmentGLSL—Your own: a main writing out_color, with u_time, u_resolution, u_mouse, u_color[4], u_intensity, fbm, vnoise, u_map…
colors"c1 c2 c3 c4"—The palette (u_color[0..3]).
speednumber1Time multiplier.
intensitynumber1Brightness (u_intensity).
texturetext""Path to an image file
detail"normal" | "high""normal"high renders at up to 2× density, for fine lines such as rain; normal keeps a small pixel budget, which suits smooth gradients.
shader(preset: "aurora", colors: "#000 #8b5cf6 #22d3ee", class: "absolute inset-0")

particles2d

An interactive 2D particle background: drifting shapes joined by lines, reacting to hover and clicks. Decorative unless it has a label.

AttributeTakesDefaultDoes
countnumber80How many particles (per density area).
densitynumber | false800Thousand square pixels per count particles; false keeps count fixed.
colorcolours | random"#94a3b8"Colours, space-separated (each particle picks one).
shapecircle square triangle polygon star imagecircleShapes, space-separated.
sidesnumber5Polygon sides, star points.
strokecolour—Outline colour.
stroke-widthpx0Outline width.
imageurl—Image for shape: "image" (an SVG takes the particle's colour).
image-widthnumber1Image width, for its aspect ratio.
image-heightnumber1Image height, for its aspect ratio.
opacity0–10.5Opacity.
opacity-randombooleanfalseRandom opacity up to opacity.
opacity-speednumber0Pulse speed (0: none).
opacity-min0–10.1Lowest pulsing opacity.
opacity-syncbooleanfalsePulse together.
sizepx3Radius.
size-randombooleantrueRandom radius up to size.
size-speednumber0Pulse speed (0: none).
size-minpx0.1Smallest pulsing radius.
size-syncbooleanfalsePulse together.
linksbooleantrueLines between nearby particles.
link-distancepx150How near.
link-colorcolour"#94a3b8"Line colour.
link-opacity0–10.4Opacity of the shortest lines.
link-widthpx1Line width.
movebooleantrueDrift.
speednumber2Drift speed.
directionnone top top-right right bottom-right bottom bottom-left left top-leftnoneDrift direction.
random-speedbooleanfalseVary speed between particles.
straightbooleanfalseMove exactly in direction.
edgeout | bounceoutAt the edges: wrap round, or bounce.
collidebooleanfalseBounce off each other.
attractbooleanfalseLinked particles pull together.
attract-xnumber3000Horizontal pull (smaller is stronger).
attract-ynumber3000Vertical pull (smaller is stronger).
detectwindow | canvaswindowWhere the pointer is followed.
hovergrab bubble repulse | nonegrabHover effects.
clickpush remove bubble repulse | nonepushClick effects.
grab-distancepx140Reach of grab.
grab-opacity0–11Opacity of grab lines.
bubble-distancepx200Reach of bubble.
bubble-sizepx40Radius to bubble to.
bubble-opacity0–10.8Opacity to bubble to.
bubble-durationseconds0.4A click's bubble time.
repulse-distancepx200Reach of repulse.
repulse-durationseconds0.4A click's repulse time.
pushnumber4Particles a click adds.
removenumber2Particles a click removes.
seednumber1Random seed.
particles2d(class: "absolute inset-0 -z-10", color: "#38bdf8", hover: "repulse", click: "push")

canvas2d shapes

Inside canvas2d(width, height, label): shapes drawn on a 2D canvas. A label makes a shape part of the accessibility tree.

rect

A rectangle, optionally rounded.

AttributeTakesDefaultDoes
xpx0Left.
ypx0Top.
wpx0Width.
hpx0Height.
rpx0Corner radius.
rect(x: 10, y: 10, w: 80, h: 40, r: 8, fill: "#22d3ee")

circle

A circle.

AttributeTakesDefaultDoes
cxpx0Centre x.
cypx0Centre y.
rpx0Radius.
circle(cx: 50, cy: 50, r: 20, fill: "red")

arc

An arc or ring segment (degrees, clockwise from the top).

AttributeTakesDefaultDoes
cxpx0Centre x.
cypx0Centre y.
rpx0Outer radius.
innerpx0Inner radius (a ring when above 0).
startdegrees0Start angle.
enddegrees360End angle.
arc(cx: 50, cy: 50, r: 40, inner: 30, end: 270, fill: "#8b5cf6")

line

A straight line.

AttributeTakesDefaultDoes
x1px0Start x.
y1px0Start y.
x2px0End x.
y2px0End y.
line(x1: 0, y1: 0, x2: 100, y2: 50, stroke: "white", line-width: 2)

path

A polyline or polygon through points, optionally smoothed.

AttributeTakesDefaultDoes
points"x,y x,y …"—Its points.
closedflag—Close it into a polygon.
smoothflag—Curve through the points (Catmull-Rom).
path(points: "0,50 50,10 100,50", smooth: true, stroke: "#22d3ee")

text

Text drawn on the canvas.

AttributeTakesDefaultDoes
xpx0Anchor x.
ypx0Baseline y.
sizepx14Font size.
alignleft | center | rightleftAlignment at the anchor.
weightCSS weight—Font weight.
text(x: 50, y: 20, align: "center", fill: "white") "Hello"

scene3d objects

Inside scene3d(width, height, label): the camera, lights, meshes and materials of a WebGL scene.

camera

The scene's camera.

Also written perspectiveCamera.

AttributeTakesDefaultDoes
position"x y z"0 0 5Where it is (also x, y, z).
target"x y z"0 0 0What it looks at (also tx, ty, tz).
fovdegrees60Vertical field of view.
camera(position: "0 1 6", fov: 45)

light

The key (directional) light, and the hemisphere ambient. cast-shadow gives it shadows.

Also written directionalLight.

AttributeTakesDefaultDoes
position"x y z"—Direction it shines from (also x, y, z).
colorcolourwhiteIts colour.
intensitynumber1Its brightness.
ambient0–1—Ambient (hemisphere) light amount.
skycolour—Ambient colour from above.
groundcolour—Ambient colour from below.
directionalLight(position: "2 3 4", intensity: 1.2)

ambientLight

Even light from everywhere.

AttributeTakesDefaultDoes
intensity0–10.5How much.
colorcolour—Its colour (sky and ground).
ambientLight(intensity: 0.4)

hemisphereLight

Ambient light shading from a sky colour to a ground colour.

AttributeTakesDefaultDoes
skycolour—From above (or color).
groundcolour—From below.
intensity0–1—How much.
hemisphereLight(sky: "#bde0fe", ground: "#3a2e1f")

pointLight

A light at a point (up to four per scene). cast-shadow gives it shadows (a cube map, six passes).

AttributeTakesDefaultDoes
position"x y z"—Where it is.
colorcolourwhiteIts colour.
intensitynumber1Its brightness.
distanceunits0Where it fades out (0: falls off with distance).
pointLight(position: "2 2 2", color: "#f472b6", intensity: 2)

spotLight

A cone of light from a point towards a target (up to four per scene). cast-shadow gives it shadows.

AttributeTakesDefaultDoes
position"x y z"0 4 0Where it is (also x, y, z).
target"x y z"0 0 0What it points at (also tx, ty, tz).
colorcolourwhiteIts colour.
intensitynumber1Its brightness.
distanceunits0Where it fades out (0: falls off with distance).
angledegrees30Half-angle of the cone.
penumbra0–10.2How much of the cone's edge fades.
xnumber—Position x.
ynumber—Position y.
znumber—Position z.
txnumber—Target x.
tynumber—Target y.
tznumber—Target z.
spotLight(position: "-2 4 2", angle: 30, penumbra: 0.3, cast-shadow: true)

particles

A GPU particle field.

AttributeTakesDefaultDoes
countnumber—How many.
radiusunits—How far they spread.
shapegalaxy | ring | shell | disc | box—Their arrangement.
colorcolour—Colour (mixed towards color2).
color2colour—Second colour.
sizepx—Point size.
speednumber—How fast they move.
seednumber—Random seed.
position"x y z"—Centre (also x, y, z).
particles(count: 400, radius: 5, shape: "shell", color: "#a78bfa")

group

Groups objects under one transform.

AttributeTakesDefaultDoes
position"x y z"—Offset of everything in it.
rotation"x y z" (degrees)—Rotation of everything in it.
scalenumber | "x y z"1Scale of everything in it.
group(rotation: "0 30 0") { … }

mesh

An object: a geometry child (boxGeometry, sphereGeometry, … or a text3d) and a material child (meshStandardMaterial, shaderMaterial). Without a geometry it's a unit cube. Takes @click and pointer events, and html children.

mesh(position: "0 1 0", @click: buy, label: "Lamp") {
    torusKnotGeometry(args: "1 0.3")
    meshStandardMaterial(color: "hotpink", roughness: 0.3)
}

cube

A cube (shorthand for mesh { boxGeometry }).

AttributeTakesDefaultDoes
sizeunits1Edge length.
cube(size: 2, color: "#22d3ee", spin-y: 30)

sphere

A UV sphere.

AttributeTakesDefaultDoes
radiusunits1Its radius.
sphere(radius: 1, color: "hotpink")

plane

A flat rectangle in the XY plane, facing +z, as three.js. Turn it with rotate-x: -90 to make a floor.

AttributeTakesDefaultDoes
widthunitssizeAlong x.
heightunitssizeAlong y.
sizeunits4Sets both.
plane(size: 10, y: -1, rotate-x: -90)

torus

A ring torus.

AttributeTakesDefaultDoes
radiusunits1Ring radius.
tubeunits0.4Tube radius.
torus(radius: 1, tube: 0.3)

torus-knot

A (p, q) torus knot.

AttributeTakesDefaultDoes
radiusunits1Size.
tubeunits0.4Tube radius.
pnumber2Windings round the axis.
qnumber3Windings through the hole.
torus-knot(radius: 1, tube: 0.3, p: 2, q: 3)

icosphere

A geodesic sphere.

AttributeTakesDefaultDoes
radiusunits1Its radius.
detail0–50Subdivisions.
icosphere(radius: 1.2, detail: 3, wobble: 0.3)

cylinder

A capped cylinder along y.

AttributeTakesDefaultDoes
radiusunits1Its radius.
heightunits1Its height.
cylinder(radius: 0.5, height: 2)

cone

A capped cone along y, apex up.

AttributeTakesDefaultDoes
radiusunits1Base radius.
heightunits1Its height.
cone(radius: 0.5, height: 1)

boxGeometry

A box's geometry, inside a mesh.

AttributeTakesDefaultDoes
args"size"1args: "…" (three.js constructor arguments)
boxGeometry(args: "1.5")

sphereGeometry

A sphere's geometry, inside a mesh.

AttributeTakesDefaultDoes
args"radius"1args: "…" (three.js constructor arguments)
sphereGeometry(args: "1")

planeGeometry

A plane's geometry, inside a mesh: args: "width height", as three.js (one number makes a square). It lies in the XY plane, facing +z.

AttributeTakesDefaultDoes
args"width height"1 1args: "…" (three.js constructor arguments)
planeGeometry(args: "16 9")

torusGeometry

A torus's geometry, inside a mesh.

AttributeTakesDefaultDoes
args"radius tube"1 0.4args: "…" (three.js constructor arguments)
torusGeometry(args: "1 0.3")

torusKnotGeometry

A torus knot's geometry, inside a mesh.

AttributeTakesDefaultDoes
args"radius tube _ _ p q"1 0.4 _ _ 2 3args: "…" (three.js constructor arguments)
torusKnotGeometry(args: "1.1 0.34 128 32 2 3")

icosahedronGeometry

A geodesic sphere's geometry, inside a mesh.

AttributeTakesDefaultDoes
args"radius detail"1 0args: "…" (three.js constructor arguments)
icosahedronGeometry(args: "1 2")

cylinderGeometry

A cylinder's geometry, inside a mesh.

AttributeTakesDefaultDoes
args"top bottom height"1 1 1args: "…" (three.js constructor arguments)
cylinderGeometry(args: "0.5 0.5 2")

coneGeometry

A cone's geometry, inside a mesh.

AttributeTakesDefaultDoes
args"radius height"1 1args: "…" (three.js constructor arguments)
coneGeometry(args: "0.5 1")

meshStandardMaterial

The built-in lit material: hemisphere ambient, Blinn-Phong, rim light, gradients, textures, fog. With preset, a shader preset drawn on the object instead.

AttributeTakesDefaultDoes
colorcolourwhiteBase colour.
color2colour—Gradient to this colour, bottom to top.
roughness0–1—0 glossy, 1 matte.
metalness0–10Adds a metallic rim.
shininessnumber32Specular exponent.
rimnumber0Fresnel rim-light strength.
rim-colorcolourwhiteRim-light colour.
emissive0–10Self-illumination (also emissive-intensity).
wobblenumber0Animated noise displacement.
opacity0–11Opacity.
mapurl—Base-colour texture (also texture; wrap, filter, flip-y).
presetname—Draw a shader preset on the object (colors, intensity).
meshStandardMaterial(color: "#8b5cf6", color2: "#22d3ee", roughness: 0.25, metalness: 0.6)

meshPhysicalMaterial

Physically based shading, metallic-roughness (as glTF, whose models use it): GGX highlights, the hemisphere ambient as a blurred environment, and texture maps. Tangents for normal maps come from the uvs.

Also written physicalMaterial, pbrMaterial, pbr.

AttributeTakesDefaultDoes
colorcolourwhiteBase colour (albedo).
metallic0–100 dielectric, 1 metal (also metalness).
roughness0–10.50 mirror-like, 1 matte.
emissivecolour | number—Emitted colour, or how much the base colour glows.
emissive-intensitynumber1Strength of the emitted colour.
opacity0–11Opacity.
env-intensitynumber1How strongly it reflects the sky and ground ambient.
mapurl—Base-colour (albedo) texture.
metallic-roughness-mapurl—Roughness in green, metalness in blue (glTF's packing).
roughness-mapurl—Roughness from its green channel.
metallic-mapurl—Metalness from its blue channel.
normal-mapurl—Tangent-space normals.
normal-scalenumber1Normal map strength.
occlusion-mapurl—Ambient occlusion from its red channel.
occlusion-strength0–11How much the occlusion map darkens.
emissive-mapurl—Emitted colour texture.
meshPhysicalMaterial(color: "#e9b44c", metallic: 1, roughness: 0.3)

shaderMaterial

Your own GLSL. A source without #version gets a prelude (only what you don't declare): a_position, a_normal, a_uv, a_color; u_size (the mesh's size in world units), u_mvp, u_model, u_view, u_projection, u_normal_matrix, u_time, u_resolution (the canvas's, in device pixels), u_camera, u_color, u_opacity, u_map, the lights; snoise, weft_lambert(n, world), weft_skin(), out_color. Preset-style code (fbm, u_color[i]) gets the preset library. Uniforms come from uniform children or a uniforms record.

Also written rawShaderMaterial.

AttributeTakesDefaultDoes
fragmentGLSL—The fragment shader (pass it from scope; inline braces need { }).
vertexGLSL—The vertex shader (default passes v_uv, v_normal, v_world, v_position, v_color).
presetname—Use a shader preset as the fragment shader.
uniformsrecord—Uniforms from scope (numbers, colours, lists, {src} textures).
attributesrecord—Per-vertex data by name ({size, data}).
textureurl—Shorthand for a u_map texture uniform.
colors"c1 c2 …"—The palette u_color[4] for preset-style code.
intensitynumber—u_intensity.
opacity0–11Opacity (makes it transparent).
transparentflag—Blend it (drawn after opaque objects).
sidefront | back | doublefrontWhich faces draw.
blendingnormal | additivenormalHow it blends.
depth-writeflag—Write depth (off when transparent).
shaderMaterial(fragment: lava, transparent: true) {
    uniform(name: "u_noise", texture: "/noise.png")
    uniform(name: "u_tint", value: "#ff5a18")
}

uniform

A shaderMaterial uniform.

AttributeTakesDefaultDoes
nameidentifier—The uniform's name in the shader.
valuenumber | colour | "x y z" | bool—Its value (a float, vecN, or bool).
textureurl—A sampler2D texture instead.
wraprepeat | clamp | mirrorrepeatTexture wrapping.
filterlinear | nearestlinearTexture filtering.
flip-yflagtrueFlip the image's rows on upload.
uniform(name: "u_amp", value: 0.3)

attribute

Per-vertex data for a shaderMaterial.

AttributeTakesDefaultDoes
nameidentifier—The attribute's name in the vertex shader.
size1–41Components per vertex.
values"…" | list—The data (vertex count × size).
attribute(name: "a_offset", size: 1, values: offsets)

text3d

Text set in a font (TTF, OTF, WOFF, WOFF2, or a .wfont), flat or extruded, with the font's kerning. Needs weft's fonts feature for font files. Its text is its accessible label. With a material child, put the text inside the block.

Also written text3D, Text3D.

AttributeTakesDefaultDoes
fonturl—The font.
textstring—The text (or the element's own text).
sizeunits per em1Size.
depthunits0Extrusion (0 is flat).
bevelunits0Bevel on the front and back edges.
alignleft | center | rightcenterAlignment.
line-heightems1.2Line spacing.
letter-spacingems0Extra space between letters.
curveems0.01How closely curves are followed (smaller is smoother).
text3d(font: "/fonts/Inter.woff2", size: 0.8, depth: 0.2, bevel: 0.02) {
    "Hello"
    meshStandardMaterial(color: "#fff")
}

model

A model file: glTF/GLB (meshes, materials, textures, node and skeletal animation), OBJ+MTL, STL, PLY, an SVG drawing (its shapes as meshes, flat or extruded), or a .wmodel. Needs weft's models feature for model files. A material child replaces its own.

Also written gltf.

AttributeTakesDefaultDoes
srcurl—The file.
animationname | index—The clip to play.
animation-speednumber1Playback speed.
loopbooltrueRepeat the clip (once stops at the end).
nodename—Only this node and what's under it (an SVG shape by its id).
depthnumber0SVG: extrude the shapes this thick (the drawing's longer side is 1); flat at 0.
bevelnumber0SVG: round the extruded edges by this much.
curvenumber0.001SVG: how far flattened curves may stray (smaller is smoother).
model(src: "/models/fox.glb", animation: "Run", scale: 0.02)

html

Real DOM in the scene (Weft UI components and all): pinned to a point facing the screen, or on a plane in perspective with transform. Inside an object it rides on it.

Also written Html.

AttributeTakesDefaultDoes
position"x y z"0 0 0Where it is.
rotation"x y z" (degrees)—Its rotation (planes).
scalenumber1Its scale.
transformflag—Lay it on a plane in the scene (100 CSS px per unit).
distance-factornumber—Pinned: natural size at this distance, scaling with distance. Plane: × the 100 px per unit.
centerbooltrueCentre it on its point.
occludeflag—Hide it while an object is in front.
classTailwind classes—Classes for its layer.
html(position: "0 1.5 0", occlude: true) { Card { Button(@click: buy) "Buy" } }

HTML elements

Any HTML tag can be used. These are the ones the language server describes:

ElementIs
aA link.
articleA self-contained piece of content.
asideTangential content.
buttonA button.
divA generic block.
footerA footer.
formA form (@submit; the page isn't reloaded).
h1A top-level heading.
h2A second-level heading.
h3A third-level heading.
h4A fourth-level heading.
headerA header.
imgAn image (src, alt).
inputA form field (type, value, @input).
labelA form field's label.
liA list item.
mainThe page's main content.
navNavigation.
olA numbered list.
pA paragraph.
sectionA section.
selectA drop-down (with options).
spanGeneric inline content.
svgSVG graphics (attributes pass through).
tableA table.
textareaA multi-line text field.
ulA bulleted list.

HTML attributes

On an HTML element, these attributes are written as text when they aren't null:

id, href, src, alt, value, placeholder, name, title, type, target, for, min, max, step, rows, cols, tabindex, autocomplete, inputmode, pattern, maxlength, minlength, colspan, rowspan, scope, abbr, datetime, lang, dir, rel, download, loading, decoding, poster, width, height, srcset, sizes, action, method, enctype, accept, list, form, headers, start, popover, popovertarget, spellcheck, draggable, enterkeyhint, allow, referrerpolicy, sandbox, srcdoc, preload, media, cite, crossorigin, frameborder, allowfullscreen, usemap, shape, coords, kind, srclang, content, charset, integrity.

These flags are written with no value when truthy, and left out otherwise:

checked, disabled, readonly, required, autofocus, hidden, inert, open, selected, multiple, controls, muted, loop, autoplay, playsinline, novalidate, reversed.

class, style, role, label (as aria-label), aria-* and data-* are written too, and gap, padding, margin, color and background go into style. Anything else is left out, except inside svg, where every attribute passes through.