{
"path": "/posts/renderdude",
"site": "at://did:plc:pans3xjam4khj7y54dx7gtfg/site.standard.publication/3mdqevmg6w32c",
"$type": "site.standard.document",
"title": "Render, dude",
"description": "Writing a minimal renderer for a photo editor using TypeScript and WebGPU.",
"publishedAt": "2024-11-08T05:34:42.000Z",
"textContent": "<a href=\"/posts/skittles\" target=\"_blank\" rel=\"noopener noreferrer\">Previous post</a> | <a href=\"/dots\" target=\"_blank\" rel=\"noopener noreferrer\">Photo-editor</a>\n\nIn the last post I built the UX component, but so far it doesn't do anything other than being highly entertaining for cats.\n\nIn this one I'm gonna write a render pipeline and by the end it still won't makes sense how to connect the \\cough\\ Dots.\n\nHow old is this browser?\n\nIn a past life I worked on an extremely cool photo editor that had a ton of features and 100k MAUs.\nIt was built using WebGL, and it works on most browsers and most phones. So naturally I wanted to build this one on WebGPU which is available on less than 50% of the browsers that matter.\n\nI use Firefox, so to build this thing I downloaded Firefox Nightly. Safari works too, but I had to enable the WebGPU feature flag.\n\nRender..er\n\nAs I'm quite an overachiever I decideed that the API had to be right from the beginning, and I couldn't just throw everything inside a useEffect.\n\nSo I wrote a class that takes care of initialization, tear down, and rendering. WebGPU initialization is async, and Javascript doesn't have async constructors so I did the right thing and routed the initialization through a static function. Do the right thing.\n\nLoading an image\n\nVertex Shader\n\nIt's easier to render a triangle, but that's unrelated to photo editors so I just skipped that part.\nThe simplest vertex shader I could write for the editor is one that loads an image.\n\nFragment Shader\n\nThis is even simpler as all I did here was to return the color sampled from the texture, using the texture coordinates.",
"canonicalUrl": "https://afloat.boats/posts/renderdude"
}