From 42e5676c8039f5160b1fd8f694875cc670ed7afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=AA=E3=82=AD=E8=90=8C?= Date: Sat, 30 Aug 2025 22:23:22 +0200 Subject: [PATCH 1/2] netcanv: add contributions section --- content/netcanv.dj | 18 ++++++++++++++++++ treehouse.toml | 1 + 2 files changed, 19 insertions(+) diff --git a/content/netcanv.dj b/content/netcanv.dj index 8522a1a..5e41f1f 100644 --- a/content/netcanv.dj +++ b/content/netcanv.dj @@ -162,6 +162,24 @@ I guess you could say we both won in the end.\ And I think that's awesome. +## Contributions + +I'd like to take a moment to thank my friends who participated in NetCanv's development by directly contributing patches. + +- [devildefu][def:person/devildefu], who contributed major refactors to help support building the app to WebAssembly and improve the user experience. + The current maintainer after I stepped down from the project. + + I never managed to carry the WebAssembly work into mainline, but it was awesome seeing the app run in the browser, bit by bit. + +- [firstbober][def:person/firstbober], who contributed an AppImage build, a dark theme (visible in this posts' screenshots!), and significantly improved our UI framework's implementation of text boxes. + + Also responsible for contributing a lot towards stress testing the app, hosting our largest NetCanv canvas on a custom headless server. + +- [ezioleq][def:person/ezioleq], who contributed various smaller fixes. + +And of course, a huge thank you to everyone who participated in testing and pushing the app to its limits. + + ## Inside NetCanv Now that you know the backstory, I'd like to dedicate the following section to the inner workings of the app. diff --git a/treehouse.toml b/treehouse.toml index 8867871..08d6937 100644 --- a/treehouse.toml +++ b/treehouse.toml @@ -50,6 +50,7 @@ feed_id_prefix = "https://liquidex.house" "word/iff" = "https://en.wiktionary.org/wiki/iff" # People +"person/devildefu" = "https://github.com/devildefu" "person/ezioleq" = "https://ezioleq.com" "person/firstbober" = "https://firstbober.com" "person/naricane" = "https://naricane.com/" From 26204b6d03af4b3f525925400ac34b99f8f992c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=AA=E3=82=AD=E8=90=8C?= Date: Sat, 30 Aug 2025 22:51:34 +0200 Subject: [PATCH 2/2] doc layout based on a grid: wider images, and code block text aligned with body text --- content/netcanv.dj | 5 +++++ static/css/doc.css | 31 +++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/content/netcanv.dj b/content/netcanv.dj index 5e41f1f..bfe0383 100644 --- a/content/netcanv.dj +++ b/content/netcanv.dj @@ -52,6 +52,7 @@ I've long since stepped down from maintaining it, but not much has been changed You can [download a build from GitHub](https://github.com/netcanv/netcanv) to play around with it yourself. It does almost nothing on the server side, so don't worry too hard about Slashdotting it. +{.wide} ![The NetCanv lobby screen. There's a dialogue asking you for information to join. It's set against a sky blue background with three stripes of red, green, and dark blue paint flowing out of the app's logo at the top of the screen.][pic:01K3TQY7EM0T5K49KW6RRGR2G0] When you first open NetCanv, you're greeted with a start screen telling you to input your nickname, the server you'd like to join, and a Room ID. @@ -59,6 +60,7 @@ If you'd like to start a session with your friends, you have to _host_ a room, w Once you're in a room, you can start drawing. +{.wide} ![A white canvas with "Hello world!" written on it, as well as some scribbles. On top of the canvas, there's a toolbar with a selection tool, a brush tool, and a colour picker tool. At the bottom, there's a toolbar with a colour palette, an eraser button, and a thickness slider. There's also a hamburger menu on the right.][pic:01K3TRAEMD5T2DKDFAJQ9XRWDA] As for the drawing tools: there's a brush tool, a selection tool, a colour picker, an eraser, a fairly advanced colour palette, and that's it. @@ -130,6 +132,7 @@ I'll say that friendly competition between the two of us was the coolest, wildes It was a fight to the death over who can win the most friends online in a room at once. It was a matter of creating the best multiplayer painting app, and swaying our whole community over to it. +{.wide} ![MultiPixel running in the browser. There's a toolbar listing a bunch of tools on the left, including brushes, a flood fill, an airbrush, and smears. Next to that is a brush settings window, with a colour palette, and sliders for Size, Flow, and Smoothing. On the canvas there's a couple scribbles, including an at "@" and a tilde "~".][pic:01K3XBA43PZMKRC6VGJE0DYSB5] Ultimately, I think MultiPixel won the battle. @@ -303,6 +306,7 @@ It _can't_ have that, because it is drawing things as they're being laid out. That's the biggest limitation of immediate mode UI, and proved to be a big pain in the ass in reality. Centering, or even laying things out from right to left, are very useful things to have in a UI framework, yet we couldn't have them due to how limited this model is. +{.wide} ![The NetCanv lobby screen, again.][pic:01K3TQY7EM0T5K49KW6RRGR2G0] You might be wondering then, how is the dialogue centred in the lobby screen? @@ -532,6 +536,7 @@ I had plans to make NetCanv handle this by checksumming the chunks somehow and r Another place where fearful concurrency strikes, is the selection tool. +{.wide} ![Me using the selection tool from another client. There's a NetCanv logo pasted onto the canvas, with a selection reticle over it indicating my nickname, with an arrow pointing at it saying "That's me in another window."][pic:01K3X35NN7HBCA0DC2C6FC9FKP] When the user pastes a selection, NetCanv will resize it to fit 1024x1024 pixels to prevent DoS attacks, encode it as a PNG (asynchronously), send the encoded data over to other clients, and then those clients will decode the selection data (also asynchronously) and render out the selection reticle on their side. diff --git a/static/css/doc.css b/static/css/doc.css index 74babc2..45d176c 100644 --- a/static/css/doc.css +++ b/static/css/doc.css @@ -22,9 +22,23 @@ main.doc { & .doc-text { --doc-padding: 1.6rem; + --code-block-h-padding: 1.2rem; + --code-block-grid-space: var(--code-block-h-padding); + /* max-width: min(100%, var(--doc-text-width)); */ + + width: 100%; padding: var(--doc-padding); - max-width: min(100%, var(--doc-text-width)); + + display: grid; + grid-template-columns: + [left] 1fr + [left-wide] 1fr + [left-code] var(--code-block-grid-space) + [main] minmax(0, var(--doc-text-width)) + [right-code] var(--code-block-grid-space) + [right-wide] 1fr + [right] 1fr; line-height: 1.6; @@ -38,6 +52,10 @@ main.doc { /* text-align: justify; hyphens: auto; */ + & > * { + grid-column: main; + } + & p { padding-top: 0.5lh; padding-bottom: 0.5lh; @@ -71,6 +89,9 @@ main.doc { & pre, & th-literate-program { + padding: 0.8rem var(--code-block-h-padding); + grid-column: left-code / right-wide; + & code { --recursive-wght: 500; --recursive-mono: 0.5; /* You didn't expect a proportional font being used for code, did you. */ @@ -89,6 +110,10 @@ main.doc { & p:has(img.pic) { text-align: center; + + &.wide { + grid-column: left-wide / right; + } } & header { @@ -141,9 +166,11 @@ main.doc { } } -@media (max-width: 700px) { +@media (max-width: 850px) { main.doc { & .doc-text { + --code-block-grid-space: 0; + & > pre, & > th-literate-program { /* Stretch to whole page.