Useful snippet for computing pixel dimensions from paper sizes (both metric (DIN) and (US) imperial presets included) using https://thi.ng/units, an elaborate & powerful unit converter/calculator/DSL for all SI dimensions:
Been doing heavy work on improving/updating the return types of various polymorphic shape operators in https://thi.ng/geom — this work will soon trigger another major version update. Also been using the opportunity to add many more 3D versions of various shapes types (incl. groups & paths) and main bottleneck now is to properly document and test the various implicit shape type conversions which might happen going from A→B. For example, applying an arbitrary transformation matrix to a circle implictly converts the circle into a path of cubic segments. Likewise, rotating a (axis-aligned) rectangle, results in a freeform quad/polygon, etc. There're dozens of such cases and dozens of operators to consider & update, but I'm guessing I'm ~50-66% done already (minus tests)...
This next thi.ng/geom update will also update the polygon → cubic bezier conversions to (optionally) support John Hobby's control point placements, aka "Hobby curves" (aka The Most Friendliest Looking Splines™), both for closed & open geometries. A new example will be included...
If you ever had some questions about the inner workings of https://thi.ng/rdom's$klist (aka keyed list) component wrapper, you might find my answer to @arnaudcys's issue helpful:
Finally, I'm extremely grateful to those of you supporting my #OpenSource work financially! 🙏😍 I'm still a far cry from making this effort sustainable, but everything helps! Also — I don't do this often — if you'd like to contribute and become a sponsor yourself, please head over to:
Just updated the convex hull example (and the underlying clipConvex() function in https://thi.ng/geom) to support paths (shown in the examples) and complex polygons...
New demo (and last new test case) for the upcoming https://thi.ng/geom release (and related packages): Here parsing a SVG path, converting to an SDF, deforming the SDF and sampling/converting the SDF back into SVG at multiple contour levels... all in just a few lines of code!
Still only on a feature branch, but over the past few days I've been working on updating https://thi.ng/geom to add support for polygons with holes and paths with holes (or more generally support for sub-paths, e.g. multiple curves). Since both of these shape types are containers of multiple geometries and therefore require in some situations (e.g. shape conversions) different handling than the other shapes with a single boundary/geometry, adding support for these also includes updating a dozen or so polymorphic shape operators/functions and unfortunately will involve a few of breaking changes. For instance, some of these functions are returning an array of shapes now, instead of just a single one. Also related, some of the other geom support packages (e.g. https://thi.ng/geom-axidraw, https://thi.ng/geom-sdf) will have to be refactored more and partially have been already (likely only internally, though)...
As part of this work, I've also just added example #160(!!!) to demonstrate & test out some of this new functionality:
For those interested in using reactive attributes in SVG elements using https://thi.ng/rdom, I hope you'll find this small new example and comments/explanations helpful:
Press 1 - 6 to select/launch/reset any of the examples
Press Space to download screenshot
Apart from the raster bars and lissajous curve all other demos can be interacted with via mouse
Open the browser console to see the (already transpiled) source code of all examples
Example #1: Scribble & color cycling
Hold down left mouse button to cycle the colors (the current palette is also always shown in bottom-left corner). Nice, powerful oldskool effect, which is actually easier to do with these indexed, non-RGB pixel buffers[1]
Example #2: Lissajous bobs
The spheres are actually 2x2 tiles of 8x8 pixel sprites with one color slot chosen as transparency. Drawing 100 spheres here, but could be a lot more...
Example #3: Raster bars
This oldskool effect is achieved via HSYNC interrupts only, i.e. no lines are being drawn — for every single pixel row we simply change the color value of the first palette entry. The text is also only being drawn once, at startup...
Example #4: Particle system
Simple particle system (2k particles) with the emitter position linked to the mouse. 6% probability for larger particles.
Example #5: Random pattern
Classic oldskool generative art, here by defining 4 custom bitmap font characters and then drawing a single randomly chosen char per frame
Example #6: Bitmap font editor
Select a character on the RHS to edit in the left box. Left click to set a pixel, right click to clear it. Press Delete to clear the char entirely. The system supports proportional width fonts and the little red triangle can be moved horizontally to adjust the width of each char... Clicking on the Save button will download a JSON file of the font's binary data (9 bytes per char: width + 8 data bytes)
In preparation for teaching a 3-day "Computing within limits" workshop @ University of Applied Sciences in Augsburg, almost exactly a year ago (next week) I created a little fantasy console (heavily inspirered by TIC80) to introduce students to:
the idea of virtual machines / computing environments
the freedom to design & control any aspect of that environment (and how this relates to the overall idea of personal computing these days)
designing & building a small (virtual) env from the bottom up (incl. defining opcodes, memory limits, maps/regions, device control registers, interrupts (hsync/vsync), device I/O, comms & multi-tasking possibilities, various retro-computing inspired graphics techniques)
defining a small low-level API/language for creative coding
learning about binary/hex and how that knowledge translates visually
The short video gives an overview of five small examples & tools (incl. a bitmap font editor) I had prepared for the workshop — the entire system was built within a couple of days with http://thi.ng/umbrella and incl. examples is only 12KB (gzipped). In the workshop we later ended up mostly using the TIC80 instead, since we covered quite a few other wider perma- & retro-computing related topics too... The 3 days were barely enough to provide an overview and have some exploration time...
If anyone is interested in a similar workshop, please do let me know, I'm keen to repeat it/extend it...
(Ps. I will post a link to the interactive version later too)
Just updated all https://thi.ng/wasm-api packages, bindgen, build scripts, readmes and examples to be compatible with the brand new Zig v0.12.0 released a couple of days ago... This includes adapting to breaking changes (esp. Zig's build system) and updating the hybrid Zig/WASM/TypeScript project template:
Phew... One key step closer to replicating & simplifying core https://thi.ng/rstream functionality via just standard async iterables: Just added a mult() base-operator to https://thi.ng/transducers-async [1] which allows splitting a single async iterable into multiple child async iterables (aka subscriptions, aka 1:N splitting), each of which can be added/removed dynamically and individually processed e.g. via transducers, vanilla for await() consumers, and/or used as input for downstream mult()s to construct entire graph topologies (cycles allowed) of async processors etc. Back pressure is handled by waiting for all child subscriptions to deliver the value before consuming a new one from the source...
For @made and others who might have questions about the new https://thi.ng/transducers-async library, I've tried to illuminate the behind-the-scenes approach over here:
Upcoming, a new & simplified implementation of https://thi.ng/csp (currently still only on a feature branch[2]) for building blocks for Communicating Sequential Processes.
Also still WIP only, async iterable support for https://thi.ng/rdom, i.e. in the same way as rstream subscriptions, such async iterables can soon be directly embedded as component/element bodies or attribute values and then perform pinpointed DOM updates each time their value changes...
As I said, async all the thi.ngs...
[1] h/t @sjb3d for an ancient tweet with a similar sentiment & outcome :)
[2] The CSP package too was somewhat deprecated (for similar reasons) and a while ago I added another alternative CSP implementation via https://thi.ng/fibers, but that package too might see some more refactoring/simplifying by switching to async generators...
TIL #GitHub is limiting statistics/graphs for repos with more than 10,000 commits... Considering ~99% of those in https://thi.ng/umbrella are my own, it seems I've been rather busy... 😇
https://thi.ng/meta-css — Added a doc command to generate Markdown documentation for generated CSS frameworks (also used to document the included base framework as a section of the readme). Added documentation for the hot-reloading develop mode/command and updated/extended the included framework rules (now 1000+ classes & parametric CSS templates)
https://thi.ng/memoize — Added new, faster & more minimal memoization functions specifically for functions with numeric/string args only (most common in my own usage)
#ReleaseThursday 🚀 — This week's second round of releases is featuring:
https://thi.ng/geom — added support for more shape pairings in the polymorphic intersection function to altogether 18, now also including: line↔︎group (incl. nested groups), line↔︎polygon, line↔︎polyline, ray↔︎group, ray↔︎line
https://thi.ng/geom-isec — simplified intersection result type (intersection point(s) now always in an array), added computation of point-inside-shape flags to more shape types, bug fixes
https://thi.ng/meta-css — more updates to CSS template handling, spec doc system and tons more additions to the generative baseframework specs/templates, now already consisting of 932 CSS utility classes (incl. 61 callable templates/functions/macros), which can be used as-is or as starting point to define your own custom CSS framework(s). All explained in the readme... This toolchain will likely keep on seeing a flurry of other updates since I'm heavily using it for the design of the new thi.ng website too! Together with mprocs[1] and Vite it also offers a very nice hot-reloading workflow...
https://thi.ng/hiccup-css — added support for SASS-style &-parent reference when defining nested selectors, updated readme w/ examples
https://thi.ng/random — added a weightedProbability() function to simplify dealing with arbitrarily shaped distributions (attached code example to compute the histogram & visualize results as ASCII-art is from the API docs)
As usual, please check the readmes and changelogs for more details!
Earlier today[1], helped my son with a raycasting issue and then ended up updating/extending the 2D shape intersection function in https://thi.ng/geom, which now also supports ray intersections with nested shape groups/hierarchies (via same single function call) and a new option to return all intersection points found (rather than just the first/closest). Both of these features are shown in a new example project (forthcoming) and in the anim below...
So much to do, but can't stop watching & hacking on this pseudo fluid sim every now & then... 🤩 Probably will develop this further into a tutorial for https://thi.ng/shader-ast
Today's #ReleaseSunday features a major update for the https://thi.ng/meta-css toolchain, a data-driven codegen for creating custom modular CSS frameworks, incl. transpiler, bundler, dev/watch mode...
The new version supports callable parametric templates, which not only help to reduce the overall API surface (i.e. the total number of rules) of a generated CSS framework, but also enable advanced operations like those shown in the attached images (e.g. declarations of CSS color variables (in rgb, hsl, lch, or oklch modes) and pure CSS color per-color-channel adjustments...).
Also new, is added support for documentation metadata for all generative CSS class & template specs (incl. template params). Parts of the readme are generated from these embedded docs and the next version will include a new CLI command to generate Markdown files from/for these CSS docs...
The readme for this package is already pretty detailed by now and should cover most important patterns and usage (incl. the new template features). Take a look (also the examples linked from the readme)!
#ReleaseFriday 🚀 - This week's #ThingUmbrella releases are mainly related to ShaderAST & ongoing repo-wide documentation updates of all 190 packages...
https://thi.ng/shader-ast — Added polymorphic syntax sugar versions of various math ops to simplify "self-assignments" aka ops in the form of x = x+ 2, which would in shader AST syntax looked like assign(x, add(x, 2)), now addSelf(x, 2)... See changelog & docs for details of supported ops.
https://thi.ng/shader-ast-stdlib — The "standard library" for https://thi.ng/shader-ast has had several new additions of useful helpers & metaprogramming tools, e.g. a new branches() function (see screenshot) to simplify n-ary A/B testing of params (or debugging of shader outputs) as is commonly done by e.g. visualizing different versions as columns based on fragment position. Other additions include surface normal calculation from a 2D terrain/grayscale texture (e.g. for GIS or fluid sims), float packing/unpacking (to/from 8bit/channel RGBA textures as a lot of mobile devices still don't support float render textures in WebGL)...
https://thi.ng/shader-ast-optimize — This package is used to apply various optimizations on a given shader AST program (or expression). Recursive constant folding has been extended to more ops & built-in functions. There's also a new wrapper function defOptimized() which can be used in place of defMain() to create auto-optimized shader main functions. The new version also has several bug fixes and more tests... See updated readme for examples.
As mentioned in earlier toots, I've also been doing several large rounds/commits of general documentation related updates/revamps, incl. updating all code examples in readmes & API docs to provide all required import statements, writing a new tooling (see below) to extract said code blocks from their original files and export them to their own source files for easier testing/trying them out from the command line. That work is only partially completed (with still hundreds of files to edit/update), but if you've got a clone of the https://thi.ng/umbrella repo, you can already try it out by running yarn tool:tangle (to extract examples from API docs in source files) or yarn doc:readme (to extract from readmes). In both cases, make sure your first build everything via yarn build. The tools will log where each of the examples is written to. Once I'm done, there will be ~800 example files extracted via this process... 💪
Been thinking again about recent #ThingUmbrella survey results and also what @inthehands emphasized recently, i.e. that "Software development is an intensely social discipline.". I fully agree.
Too much power in a programming language/tooling means no or very few struggles. On the other hand, very few struggles also mean very little incentives for community to form/grow, to exchange, to debate, to contribute... (basically also one of the more indirect morals of The Lisp Curse)
60-80% of the survey feedback (finaly comments) are along the lines of "thi.ng is amazing", "thi.ng has been a huge inspiration", "a real treasure trove", "love the project", "thi.ng is awesome and a joy to work with"... Hearing this makes my heart jump for joy!
Yet, I'm also keenly aware there are aspects of these projects which cause people to "struggle", and I'm also constantly working on improving the DX & docs for everyone, including creating new custom tooling and automation...
Today, I spent most of my time on new tooling to extract the almost 800 code examples embedded in API docs to individual source files, in order to run/try them directly from the command line... With the vast scope of the larger project, this means each time there's a new update/tool like this, there're 100s (sometimes 1000+) of source files to check, to edit and verify, mostly manually (today I managed write the tool, but only updated a few dozen source files...)
I'm often feeling the effort & time spent on these tasks is becoming harder to justify, if there's so little feedback for all the documentation materials which are actually there. The mostly vague complaints about docs missing, being confusing or difficult topics are not really helpful to improving these aspects. I also can't help but wonder why there's been so very, very little offers to help with that (if people have issues, the least is to be constructive about it...)
How do other OSS project maintainers deal with this? Has this ever been an issue for you? Apart from investing even more time in these things, what else can I do? The 150+ example projects don't seem to help either... Part of this discussion feels like catch-22...
I ❤️ where this is going (incl. quite a few incoming additions to https://thi.ng/shader-ast-stdlib) - but still lacking the language to describe what's going on here...
Announcing #HowToThing, small code snippets illustrating useful patterns and use cases for various libraries/projects in the https://thi.ng ecosystem/anti-framework...
(Ps. Have been trying to start similar stuff in the past on the birdsite, but let's see if I can control my attention and be more consistent this time... If you have any topic requests, please reply below [or via DM])