createCanvas(windowWidth, windowHeight, WEBGL)
branchShader = baseMaterialShader().modify({
vertexDeclarations: 'out vec3 pos;',
fragmentDeclarations: 'in vec3 pos; vec3 normal;',
'float t': () => millis(),
'vec3 getLocalPosition': `(vec3 inPos) {
20. * (vTexCoord.y*0.1) * sin(t*0.00025*(-1000. - 0.25*vTexCoord.y)),
'Inputs getPixelInputs': `(Inputs inputs) {
// Do some bump mapping based on texture coords to get the ridges in the bark
inputs.normal = normalize(inputs.normal + (0.3*uViewMatrix*vec4(
0.5*sin(inputs.texCoord.x * 8. * ${TWO_PI}),
cos(sin(inputs.texCoord.x * 12. * ${TWO_PI})),
'vec4 getFinalColor': `(vec4 color) {
vec4(235., 213., 136., 255.)/255.,
pow(abs(dot(normal, vec3(0.0, 0.0, 1.0))), 0.5)
leafShader = baseMaterialShader().modify({
'float t': () => millis(),
declarations: 'float alpha; vec3 normal;',
'vec3 getLocalPosition': `(vec3 inPos) {
20. * (inPos.y*0.001) * sin(t*0.0000025*(-1000. - 0.25*inPos.y)),
'Inputs getPixelInputs': `(Inputs inputs) {
// Use the texture coordinates to make leaf veins
vec3 lightGreen = vec3(166., 191., 65.)/255.;
float vein = fract(inputs.texCoord.y * 4. + abs(inputs.texCoord.x - 0.5));
smoothstep(0.45, 0.5, inputs.texCoord.x) * (1. - smoothstep(0.5, 0.55, inputs.texCoord.x)),
smoothstep(0.8, 0.9, vein) * (1. - smoothstep(0.9, 1., vein))
float threshold = pow(1. - inputs.texCoord.y, 0.5) * 0.5;
abs(inputs.texCoord.x - 0.5)
inputs.ambientMaterial = inputs.color.xyz;
inputs.emissiveMaterial =
pow(abs(dot(inputs.normal, vec3(0., 0., 1.))), 2.) *
'vec4 getFinalColor': `(vec4 color) {
vec4(235., 213., 136., 255.)/255.,
mix(1., abs(dot(normal, vec3(0.0, 0.0, 1.0))), 0.5)
'void afterFragment': `() {
function windowResized() {
resizeCanvas(windowWidth, windowHeight)
const treeGen = Tree.init()
branches = treeGen.branchesToGeometry()
leafCenters = treeGen.leafCenters()
box = branches.calculateBoundingBox()
setTimeout(genTree, 16000)
const s = max(box.size.x, box.size.y, box.size.z) + 40
scale(min(width, height) * 0.65 / s)
translate(-box.offset.x, -box.offset.y, -box.offset.z)
for (const [i, { center: { x, y, z }, r }] of leafCenters.entries()) {
scale(map(y, 0, -300, 10, 40, true) / 40)
rotateX((noise(i*10, 0) + 0.025*sin(t*0.1/y)) * PI)
rotateY(noise(i*10, 20) + 0.05*sin(t*0.1/y) * PI)