Hello Leaflet!

Playing with the features.

February 11, 2026

This is my first leaflet doc. Nothing special, but I'm poking around. Nice to see the usual styling options.

I can also embed links and images:

How about a helpful horizontal line to denote the next section?


I can embed Bluesky posts! How about an art post?

brendan's avatar
brendan
3w

this is fun! intervolz.com/sollewitt/ > A generative tribute to Sol LeWitt's instruction-based wall drawings. Each piece is rendered algorithmically from LeWitt's original instructions, producing unique variations with every reload. here are a few examples I generated :)

Wall Drawing #95 (1971)

instructions: On a wall divided vertically into fifteen equal parts, vertical lines, not straight, using four colors in all one-, two-, three-, and four-part combinations.Wall Drawing #88 (1971)

instructions: A 6-inch (15 cm) grid covering the wall. Within each square, not straight lines in either of four directions. Only one direction in each square but as many as desired, and at least one line in each square.Wall Drawing #86 (1971)

instructions: Ten thousand lines about 10 inches (25 cm) long, covering the wall evenly.Wall Drawing #38 (1970)

instructions: Tissue paper cut into 1½-inch (4 cm) squares and inserted into holes in the gray pegboard walls. All holes in the walls are filled randomly.

Ooh, I can put code in here! Here's a piece of my UI engine, a generic Renderer that configures the provided render pass to execute the render.

pub struct Renderer {
    pipeline: wgpu::RenderPipeline,
    vertices: wgpu::Buffer,
    instances: wgpu::Buffer,
    number: u32,
    bindgroups: HashMap<u32, BindGroup>,
}

impl Renderer {
    pub fn render(&self, pass: &mut RenderPass) {
        pass.set_pipeline(&self.pipeline);
        pass.set_vertex_buffer(0, self.vertices.slice(..));
        pass.set_vertex_buffer(1, self.instances.slice(..));
        self.bindgroups.iter().for_each(|(&index, group)| {
            pass.set_bind_group(index, group, &[]);
        });
        pass.draw(0..4, 0..self.number);
    }
}

In conjunction with this IntoRenderer trait, I can fairly easily produce renderers for just about anything.

pub trait IntoRenderer<I: Vertex, U: Uniforms> {
    const SHADER: ShaderModuleDescriptor<'static>;

    fn vertices(&self) -> Vec<Pos> {
        BBox {
            center: (0., 0.),
            size: (1., 1.),
        }.into()
    }

    fn instances(&self) -> &[I];
    fn uniforms(&self) -> U;

    fn renderer(&self, device: &Device, format: &TextureFormat) -> Renderer {
        let module = &device.create_shader_module(Self::SHADER);
        let vertices = self.vertices();
        let instances = self.instances();
        let uniforms = self.uniforms();

        let layout = uniforms.pipeline_layout().map(|desc| device.create_pipeline_layout(&desc));
        
        Renderer {
            pipeline: device.create_render_pipeline(&RenderPipelineDescriptor {
                label: Some("Shape Render Pipeline"),
                layout: layout.as_ref(), // Uniforms would be set here
                vertex: wgpu::VertexState {
                    module,
                    entry_point: Some("vs_main"),
                    compilation_options: wgpu::PipelineCompilationOptions::default(),
                    buffers: &[Pos::LAYOUT, I::LAYOUT],
                },
                fragment: Some(wgpu::FragmentState {
                    module,
                    entry_point: Some("fs_border"),
                    compilation_options: wgpu::PipelineCompilationOptions::default(),
                    targets: &[Some(wgpu::ColorTargetState { // 4.
                        format: *format,
                        blend: Some(wgpu::BlendState::ALPHA_BLENDING),
                        write_mask: wgpu::ColorWrites::ALL,
                    })],
                }),
                primitive: wgpu::PrimitiveState {
                    topology: wgpu::PrimitiveTopology::TriangleStrip, // 1.
                    strip_index_format: None,
                    front_face: wgpu::FrontFace::Cw, // 2.
                    cull_mode: Some(wgpu::Face::Back),
                    // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
                    polygon_mode: wgpu::PolygonMode::Fill,
                    // Requires Features::DEPTH_CLIP_CONTROL
                    unclipped_depth: false,
                    // Requires Features::CONSERVATIVE_RASTERIZATION
                    conservative: false,
                },
                depth_stencil: None,
                multisample: wgpu::MultisampleState {
                    count: 1,
                    mask: !0,
                    alpha_to_coverage_enabled: false,
                },
                cache: None,
                multiview_mask: None,
            }),
            vertices: device.create_buffer_init(&BufferInitDescriptor {
                label: Some("circle vertices"),
                contents: vertices.as_bytes(),
                usage: BufferUsages::VERTEX,
            }),
            instances: device.create_buffer_init(&BufferInitDescriptor {
                label: Some("circle instances"),
                contents: instances.as_bytes(),
                usage: BufferUsages::VERTEX
            }),
            number: instances.len() as u32,
            bindgroups: uniforms.bindgroups(device),
        }
    }
}

With that trait and its dependencies defined, that allows me to write a circle with a very manageable amount of code:

#[derive(Clone, IntoBytes, Immutable, VertexLayout)]
#[layout(Instance)]
#[location = 1]
pub struct Circle {
    pub center: [f32; 2],
    pub radius: f32,
    pub thickness: f32,
    pub color: [f32; 3],
}

impl Vertex for Circle {}

impl IntoRenderer<Circle, ()> for &[Circle] {
    const SHADER: wgpu::ShaderModuleDescriptor<'static> = include_wgsl!("../shaders/circle.wgsl");

    fn instances(&self) -> &[Circle] {
        self
    }

    /// Empty function with no return type implicitly returns `()`
    fn uniforms(&self) { }
}

Anyhow, let's explore more features! We've got math, so here's Euler's formula:

−1=eiπ

We've also got website embeds, so here's 3Blue1Brown with an explainer of Euler's formula.

We've got polls! Let's do a poll on polls.

All votes are public

We can do buttons too. Click this one to go somewhere interesting.

There's date times! At time of writing:

Block quotes are nice.

An especially rousing and inspiring quote.

Last but not least, the most interesting of the features: The canvas.

So I can just organize the other things here however I want, huh

How about some more Rust?

A Title Here

A Title There

I have no idea what I'm doing

That's most of the feature. Good enough for an introductory post, I reckon.