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?
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 :)
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:
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.
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.