these arent links

idk what to put here


Rust Libraries

If you're here from crates.io and wondering where shithub is, it's gay and I refuse to use it.
Codeberg's cool though.

This website doubles as a Cargo registry for libraries I wrote over time and a couple of my game projects (WIP). Most of these I'm also putting on crates.io, but I lost my 2fa to shithub & microslop made it literally impossible to recover it, so I'm not relying on them until I can log in with a god damn normal username & password.

Anyway. I'm not mirroring the dependencies, so if crates.io ever goes down stuff will break... might be a good idea even if they'd massively bloat everything.
Another caveat is I'm not gonna host each individual version of my projects, only the latest, so you might need to update your project's lock file occasionally.

To use my registry, append this to your .cargo/config.toml, and when adding dependencies with Cargo, run cargo add --registry tesseract ...

# Docs

arg-kit

arg-kit is a featherweight library that helps parse arguments using one of Rust's most versatile and powerful syntaxes: match {}

Do you really need bloated proc macros when collecting arguments can be simplified to a .next()? You have zero indication of what's going on under the hood, so you can't implement your own behaviour.

That is why I don't call it an "argument parser" on its own. Your program parses the arguments, this just helps iterate over it, like so:

let mut argv = std::env::args();
for_args!(argv; {
    arg!(-h | --help) => eprintln!("{HELP_TEXT}"),
    arg!(-v | --value) => do_something(argv.next()?),
    unknown => panic!("Unknown argument {unknown}"),
});

...which expands to:

let mut argv = std::env::args();
while let Some(args) = argv.next() {
    for arg in args.as_arg() {
        match arg {
            Argument::Short("h") | Argument::Long("help") =>
                eprintln!("{HELP_TEXT}"),
            Argument::Short("v") | Argument::Long("value") =>
                do_something(argv.next()?),
            unknown =>
                panic!("Unknown argument {unknown}"),
        }
    }
}
# Docs : Codeberg

mewgpu

(I wanted to call it just mew but some wanker is hogging it on crates.io)

As you might have guessed, I've got a terminal (not tty) case of made-at-home syndrome - I'd rather make a complete system from scratch than learn a probably-bloated pre-existing framework, that somehow simultaneously overcomplicates and oversimplifies everything with no room for optimization. So, I figured I'd just learn how graphics worked under the hood.

wgpu is a 0.98:1 API for the WebGPU standard. While that makes it very portable, versatile, and pretty well-documented, since I'm not a hardcore graphics chud, I don't find it very intuitive to use. My main problem with it is how many bloody times you need to define the same thing, and quadruple-check that all the layouts line up with each other.

After my first attempt at real graphics, I concluded wgpu wasn't fit for use directly by an end-user application. The obvious next step was to read docs, find patterns in the graphics stack, read docs, come up with a data model, read docs, and extract everything I've learnt along the way into a library. And then read some more docs.

This library aims to, at least a little bit, make it easier to define all the related information in one place (in wrapper structs). It primarily uses like 20 macro_rules! to write boilerplate that generates buffer, bind group, and pipeline layouts. It also stores them in a convenient "render context" struct - see the example for details, but compare the below to having to reference 50 pages in wgpu's docs to get a pyramid to spin (I've done that job for you).

I would still definitely recommend following the wgpu tutorial at least once to get familiar with the concepts, if you've never dealt with low-level graphics shenanigans before.

Example
mew! {
    sampler ExampleSampler as Filtering;

    texture ExampleTexture {
        usage: COPY_DST | TEXTURE_BINDING,
        dimension: D2,
        sample_type: FloatFiltering,
    };

    vertex_struct Vertex [
        0 pos => Float32x3,
        1 uv => Float32x2,
    ];

    buffer VertexBuffer <Vertex> as VERTEX | COPY_DST;

    shader_struct TransformMatrix [
        0 mat => Mat4x4f,
    ];

    buffer TransformBuffer <TransformMatrix> as UNIFORM | COPY_DST;

    bind_group ExampleGroup [
        0 texture @ FRAGMENT => Texture,
        1 sampler @ FRAGMENT => Sampler,
        2 transform @ VERTEX => TransformBuffer,
    ];

    pipeline ExamplePipeline {
        bind_groups: [
            0 => Group,
        ],
        vertex_types: [
            0 => Vertex,
        ],
        fragment_targets: [
            0 => ALPHA_BLENDING ALL as ANY,
        ],
        cull: Front,
    };
}

// Then...
let context_builder = RenderContextBuilder::with_instance(wgpu::Instance::default());
let context = context_builder.build_poll()?;

let sampler: ExampleSampler = context.new_sampler();
let texture: ExampleTexture = context.new_texture((64, 64, 1), TextureFormat::Rgba8Unorm);
let matrix: TransformBuffer = context.new_buffer(1);
let bind_group: ExampleGroup = context.new_bind_group((sampler, texture, matrix));

let vertices: VertexBuffer = context.new_buffer(128);
let pipeline: ExamplePipeline = context.new_pipeline(
    TextureFormat::Rgba8Unorm,
    shader_module,
    None, None,
);

// Make a renderpass & just use as regular wgpu
// (All above structs are deref-able into wgpu types)
render_pass.set_bind_group(0, Some(&*bind_group), &[]);

Again, the point isn't to create an entirely new graphics framework - or any sort of framework at all, really - rather, just to make it maybe easier for us mortals to keep on top of the rendering pipeline, while still giving complete control over what runs when.

also jesus fuck, how many breaking updates can wgpu get between each time I look at it