# Stanko Tadić

Making visual and interactive stuff

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## SpaceDeck X July devlog: upgrades, backgrounds, and more

DevFeed: [SpaceDeck X July devlog: upgrades, backgrounds, and more](<https://devfeed.tech/articles/spacedeck-x-july-devlog-upgrades-backgrounds-and-more-37356.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/spacedeck-x-july-devlog/>)

Author: Stanko

Published: 2026-07-23T00:00:00Z

Content type: article

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Development](<https://devfeed.tech/topics/development.md>), [Website](<https://devfeed.tech/topics/website.md>)

Tags: [customization](<https://devfeed.tech/tags/customization.md>), [game-dev](<https://devfeed.tech/tags/game-dev.md>), [pixel-art](<https://devfeed.tech/tags/pixel-art.md>), [redesign](<https://devfeed.tech/tags/redesign.md>), [steam](<https://devfeed.tech/tags/steam.md>), [updates](<https://devfeed.tech/tags/updates.md>), [upgrades](<https://devfeed.tech/tags/upgrades.md>)

### AI overview

A July development log for SpaceDeck X describes progress toward a Steam release, including a new upgrades system and library, redesigned UI panels, ship weapon and characteristic tweaks, decorative backgrounds and shadows, run-history work, and controller-button customization.

### Source excerpt

I've been developing SpaceDeck X since December last year. It started as me playing with a random framework I found fun, and it grew so much that I'm now working towards releasing it on Steam. I kept a devlog on Itch, but I feel like it is time to bring it to my own website. Especially considering that these updates are exclusive to the Steam version. I have a pretty clear vision for the release, and lately I've made amazing progress. Here are the major things I've made, in no particular order. Upgrades system # The new upgrades system was brewing in my head for a long time. Honestly, I thought it would take me longer to implement it, but once I started, I got in the zone and built a completely new system. This is the new upgrades selection screen: Compare it to the old one: Upgrades library # Upgrades got their own library, so players can inspect and learn about all of them. In two days I managed to draw 44 upgrade icons. Some of them I just winged and now I'm retrofitting them to the actual game upgrades. Redesigned UI panels # After making new upgrade cards, I got an urge to redesign some of the game's UI. I'm trying to avoid scope creep, but I had to create a way for the player to see their upgrades, so I decided to give a facelift to the deck panel as well. You can open both panels by holding Tab in the boss fight: And they show automatically in the pause menu: Ships # Ships are not brand new, but in the last few weeks I tweaked their specific weapons and characteristics. It is still a work in progress, but all ships are functional and have their own quirks. Backgrounds and shadows # These are purely decorative, but I think they elevate the experience a lot. These background objects add more visual depth. They also change every few levels, giving the player a better sense of progression. For now I created two sets of backgrounds (the gray tech-industrial one and an Aztec/Protoss-inspired one). The plan is to have four or five for the full game. These are quite

## SpaceDeck X is coming to an arcade cabinet

DevFeed: [SpaceDeck X is coming to an arcade cabinet](<https://devfeed.tech/articles/spacedeck-x-is-coming-to-an-arcade-cabinet-37357.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/spacedeck-x-on-arcade-cabinet/>)

Author: Stanko

Published: 2026-05-21T00:00:00Z

Content type: release

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [arcade](<https://devfeed.tech/topics/arcade.md>), [3D](<https://devfeed.tech/topics/3d.md>), [JavaScript](<https://devfeed.tech/topics/javascript.md>), [pixel](<https://devfeed.tech/topics/pixel.md>)

Tags: [3d](<https://devfeed.tech/tags/3d.md>), [3d-printing](<https://devfeed.tech/tags/3d-printing.md>), [game](<https://devfeed.tech/tags/game.md>), [javascript](<https://devfeed.tech/tags/javascript.md>), [pixel-art](<https://devfeed.tech/tags/pixel-art.md>), [release](<https://devfeed.tech/tags/release.md>), [steam](<https://devfeed.tech/tags/steam.md>)

### AI overview

The article announces that SpaceDeck X will be released on a physical arcade cabinet at Blast Galaxy in Amsterdam on June 14, with a release party and high-score tournament. The author also describes a 3D-printed trophy modeled in JavaScript with Replicad and mentions work toward a Steam release.

### Source excerpt

I want your coins! I'm making a game. It is called SpaceDeck X and you can try it online. But thanks to Amsterdam Indie Arcade, it will be available on a physical arcade cabinet at Blast Galaxy. It will be released on the 14th of June with a small release party and hi-score tournament. If you are in Amsterdam, be sure to come and check it out. It will be available for the next two months, then a new indie game will take its place. Hi-Score Tournament # We are going to organize a hi-score tournament. The Indie Arcade organizer asked me if I could come up with a fun prize for the winner, so I did: I designed and 3D printed the main player ship from the game on a little pedestal. It was super fun figuring out how to bring my pixel art to the real world and break it down for 3D printing. The model is made in JavaScript using Replicad. Come and claim the trophy on the 14th! Steam Release # The arcade release is just a pit stop. I'm actively working towards a Steam release, so stay tuned!

## Birds - Art

DevFeed: [Birds - Art](<https://devfeed.tech/articles/birds-art-37199.md>)

Original publisher: [Read original article](<https://muffinman.io/art/birds/>)

Author: Stanko

Published: 2025-11-15T00:00:00Z

Content type: article

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Algorithm](<https://devfeed.tech/topics/algorithm.md>), [Tool](<https://devfeed.tech/topics/tool.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [art](<https://devfeed.tech/tags/art.md>), [black](<https://devfeed.tech/tags/black.md>), [experimentation](<https://devfeed.tech/tags/experimentation.md>), [liquid](<https://devfeed.tech/tags/liquid.md>), [photos](<https://devfeed.tech/tags/photos.md>), [process](<https://devfeed.tech/tags/process.md>), [studio](<https://devfeed.tech/tags/studio.md>), [tool](<https://devfeed.tech/tags/tool.md>)

### AI overview

An art post describes using vector fields, algorithmic experimentation, and a procedural tool to generate bird-like plot drawings, along with their sizes, materials, and photography details.

### Source excerpt

I love everything about these. The process was so much fun and I'm super happy how the plots turned out. I got the idea while playing with vector fields and noticed that some shapes resembled a bird. I started tweaking the algorithm and after a lot of experimentation, made a tool that procedurally generates birds. The first drawing is 22x22cm, and others are around 15x15cm. As usual, these are hard to photograph (which is why it took me ages to post them here), so thanks to my friend David for letting me use his studio lighting to take proper photos. Created: November 2025Size: Various sizesPaper: Fabriano Black Black 300gsmPens: Molotow Liquid Chrome, UniBall Signo and Sakura Jelly Rolls

## Promise based Web Worker Messaging

DevFeed: [Promise based Web Worker Messaging](<https://devfeed.tech/articles/promise-based-web-worker-messaging-37370.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/web-workers-promises/>)

Author: Stanko

Published: 2025-11-03T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Promise](<https://devfeed.tech/topics/promise.md>), [Messaging](<https://devfeed.tech/topics/messaging.md>), [Web](<https://devfeed.tech/topics/web.md>), [async/await](<https://devfeed.tech/topics/async-await.md>), [Code](<https://devfeed.tech/topics/code.md>), [Error Handling](<https://devfeed.tech/topics/error-handling.md>)

Tags: [async](<https://devfeed.tech/tags/async.md>), [await](<https://devfeed.tech/tags/await.md>), [code](<https://devfeed.tech/tags/code.md>), [error-handling](<https://devfeed.tech/tags/error-handling.md>), [event](<https://devfeed.tech/tags/event.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [messaging](<https://devfeed.tech/tags/messaging.md>), [thread](<https://devfeed.tech/tags/thread.md>), [web](<https://devfeed.tech/tags/web.md>), [worker](<https://devfeed.tech/tags/worker.md>)

### AI overview

This tutorial presents a Promise-based wrapper for Web Worker messaging. It explains how unique message identifiers map worker responses to stored promises, allowing the main thread to resolve or reject the corresponding promise and use async/await with simpler error handling. The same pattern can also be applied to Service Workers.

### Source excerpt

If you've ever used Web Workers (or any other event-based communication), you probably noticed that this kind of code can be hard to read and reason about. You also have to implement some kind of identifier for each message to recognize which worker response corresponds to which request. To simplify that, we can write a small wrapper that lets us use Promises to communicate with Workers. I'll show you an example for Web Workers, but the same pattern can be applied to Service Workers as well. The resulting API looks like this: const workerResponse = await sendToWorker(data); I first used this approach in Pulsar, because I wanted to parse and execute the user's code in a Web Worker, but also wait for the worker to finish before providing data for the next frame. Implementation # The idea is fairly simple - before sending a message to the worker, we create a unique id and a promise. We store the promise in a map using the id as the key. Then we send an event to the worker, including both the data and the id, and return the promise to the caller. When the worker finishes its calculation, it sends back a message that includes the result and the same id. In the main thread, we listen for these messages. When one arrives, we use the id to find the corresponding promise in our map. Finally, based on the worker's result, we resolve or reject that promise. It might sound like a lot, but the code is actually quite straightforward: send-to-worker.jsCopy // Worker initialization const worker = new Worker("./path-to-your-worker.js"); // Map of promises const promises = {}; worker.addEventListener("message", (e) => { // Listen to worker messages and find the correct promise matching the id // Then resolve or reject it depending on the response if (e.data.error) { promises[e.data.id].reject(e.data.error); } else { promises[e.data.id].resolve(e.data.data); } // Remove the resolver reference delete promises[e.data.id]; }); // For identifiers it is safe to use a simple integer // whic

## Moon - Art

DevFeed: [Moon - Art](<https://devfeed.tech/articles/moon-art-37214.md>)

Original publisher: [Read original article](<https://muffinman.io/art/moon-white/>)

Author: Stanko

Published: 2025-10-23T00:00:00Z

Content type: article

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [plotting](<https://devfeed.tech/topics/plotting.md>), [Code](<https://devfeed.tech/topics/code.md>), [GitHub](<https://devfeed.tech/topics/github.md>)

Tags: [art](<https://devfeed.tech/tags/art.md>), [code](<https://devfeed.tech/tags/code.md>), [github](<https://devfeed.tech/tags/github.md>), [plotting](<https://devfeed.tech/tags/plotting.md>), [project](<https://devfeed.tech/tags/project.md>)

### AI overview

The author describes reviving and publishing the Moon plotting project after nearly two years. A technical pen added detail to the image, and the project's code is available on GitHub so others can generate their own version.

### Source excerpt

After almost two years (life and other projects happened), I finally plotted something new. I resurrected the Moon project, cleaned it up and published it online. Using a technical pen allowed me to add more detail to the image. It reminded me why I love pen plotting so much, and I hope to plot more in the near future. The code is available on my GitHub, and you can generate your own Moon here. Created: October 2025Size: 30x30cmPaper: Fabriano Black Black 300gsmPens: rOtring variant technical pen, Aristo white ink

## How the Space Invader Generator Works

DevFeed: [How the Space Invader Generator Works](<https://devfeed.tech/articles/how-to-draw-a-space-invader-37293.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/invaders/>)

Author: Stanko

Published: 2025-08-15T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [creative coding](<https://devfeed.tech/topics/creative-coding.md>), [Code Challenge](<https://devfeed.tech/topics/code-challenge.md>), [3D](<https://devfeed.tech/topics/3d.md>)

Tags: [code-challenge](<https://devfeed.tech/tags/code-challenge.md>), [creative-coding](<https://devfeed.tech/tags/creative-coding.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [interactive](<https://devfeed.tech/tags/interactive.md>)

### AI overview

An interactive tutorial about a Space Invader Generator made for a Creative Coding Amsterdam code challenge. It describes the project's origins, using the Rayven vector 3D renderer, and the author's research and pixel-art sketches for generating invaders.

### Source excerpt

This is an interactive article. To fully experience it, you'll need to turn JavaScript on. I recently made the Space Invader Generator for Creative Coding Amsterdam code challenge. I made it for fun of course... and galactic domination too! You can see how it looks below and in this post I'll show you how it works using an interactive animation. Here are a few invaders it can generate: While showing friends how it works, I realized the process would look great animated. So I decided to write another interactive blog post. I'll give you some background first, but if you are eager to see the process, feel free to jump straight to the interactive part. How it started # I was working on a new version of Rayven, my vector 3D renderer. Sometimes I get stuck working on tools - they turn into never-ending projects and I never actually use them to create something. At some point I became aware of this pattern, and I think I've gotten better at wrapping projects up, releasing them in one form or another, and moving on. So I thought it would be cool to do a few plots using Rayven instead of endlessly tweaking the renderer itself. I wanted something simple that I could whip up quickly. It would be a meaningful milestone, even if I didn't finish everything I planned for Rayven. Then I thought of Space Invaders. They are small, easy to render with 3D blocks, and instantly recognizable as part of video game history. I did a few renders of the classic space invader and started thinking that it would be fun to generate random ones and create a series of plots. That sounded like a good idea to share as a code challenge. The code challenge # I was pleasantly surprised that people liked the idea. We drafted some rules and the Space Invaders code challenge was on! At the time of writing, the challenge is still ongoing, but once it wraps up, I'll link to all the submissions. I've already seen some works in progress and there is some really cool stuff coming - stay tuned! From doodles to

## CSS only counter component

DevFeed: [CSS only counter component](<https://devfeed.tech/articles/css-only-counter-component-37256.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/css-only-counter/>)

Author: Stanko

Published: 2025-08-05T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [CSS](<https://devfeed.tech/topics/css.md>), [HTML](<https://devfeed.tech/topics/html.md>), [Code](<https://devfeed.tech/topics/code.md>), [Web Development](<https://devfeed.tech/topics/web-development.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [css](<https://devfeed.tech/tags/css.md>), [html](<https://devfeed.tech/tags/html.md>), [interactive](<https://devfeed.tech/tags/interactive.md>)

### AI overview

A tutorial explaining how to build a counter component using only CSS. It uses pre-rendered HTML radio inputs, labels, and the :has selector to show the checked, previous, and next values, with additional sections on buttons, looping, and hover behavior.

### Source excerpt

Before we start, here is a demo of the counter (you can also check it out on CodePen): 12345678910 - + This idea started with a space invaders generator I recently made. If you look at the randomize button, you'll notice the number on the dice changes from five to three when you hover over it. A friend then said, "It would be really cool if you showed a different number every time you hover." That got me thinking, could I make this using CSS only?It's trivial to do in a few lines of JavaScript, which I'll probably do at some point. Before diving deeper, I decided to simplify the problem by first making a basic counter component. Since the solution had to be CSS-only, we'd need to render all the numbers before hand and then select one at a time using CSS - which felt a lot like how radio inputs work. So I decided to try radio inputs. After a bit of experimenting, I ended up with this HTML structure: <div class="counter"> <input id="counter-1" type="radio" value="1" name="counter" checked /> <label for="counter-1">1</label> <input id="counter-2" type="radio" value="2" name="counter" /> <label for="counter-2">2</label> <!-- ... --> <input id="counter-10" type="radio" value="10" name="counter" /> <label for="counter-10">10</label> </div> Solution # To make a counter, we need to somehow select the checked input's label, as well as the previous and next ones, using CSS. Lucky for us, we live in the future where the :has selector exists. If you had shown me :has back when we were still dealing with IE6, it would have completely blown my mind. Anyway, we can use this fancy selector to target the inputs we need, and it's fairly simple: /* Checked label */ input:checked + label {} /* Prev label */ label:has(+ input:checked) {} /* Next Label */ input:checked + label + input + label {} I hope this code is clear as it is, but to make things easier to grasp here is an interactive demo: 123456 This demo uses the exact code we have above (plus a ::before element for labels) to high

## Preserving text size when scaling SVGs

DevFeed: [Preserving text size when scaling SVGs](<https://devfeed.tech/articles/preserving-text-size-when-scaling-svgs-37331.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/preserving-text-size-when-scaling-svgs/>)

Author: Stanko

Published: 2025-06-03T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [SVG](<https://devfeed.tech/topics/svg.md>), [CSS](<https://devfeed.tech/topics/css.md>), [JavaScript](<https://devfeed.tech/topics/javascript.md>)

### AI overview

The article explains how to keep SVG text at a consistent visual size while the SVG is resized. It uses a CSS variable and ResizeObserver-based JavaScript to counteract the SVG's scale factor.

### Source excerpt

SVGs support non-scaling strokes using the vector-effect attribute, which we can even use to draw non-scaling rectangles and circles. For example, in graphs and charts, text can become too small or too large, so it would be really nice to make it non-scaling. But unfortunately, there is no native solution - text will always scale together with the SVG. We can manually define different font sizes on different breakpoints, but text is still going to be scaled within a single breakpoint. If we need truly non-scalable text, we'll have to use JavaScript. Luckily, not a lot of it - ten lines will do. But before we dive into the solution, here is an example for you (try resizing the wrapper): Hello World!I'll stay 16px on all screen sizes How it works # The idea is to use a CSS variable and a resize observer to counteract SVG scaling. The variable stores the information about how much the SVG is scaled compared to its natural size. Then we can set a resize observer on our SVG, and every time it is resized, we update the CSS variable. That will ensure the font size remains consistent. In order for the CSS variable to have an effect, we have to define font size like thisYou can also use rem or other font size units, as well as media or container queries.: text { font-size: calc(16px * var(--text-factor)); } This means that if we want to keep the font size 16px, and the SVG is rendered at twice its natural size, --text-factor has to be set to 2. To achieve this, we need to divide rendered width by natural width. Let's see how we can get these values. The rendered width is directly accessible as svg.clientWidth. Natural width is a bit trickier, but we can use viewBox to get it. In general, I think it is a good practice to define viewBox on SVGs. View box is a string consisting of four numbers. The third number represents the width of the SVG. We need to parse the string to get the widthIf you don't have viewBox defined, you'll have to update this line to fit your needs.: svg.g

## Apply blur to iOS status bar in PWA

DevFeed: [Apply blur to iOS status bar in PWA](<https://devfeed.tech/articles/apply-blur-to-ios-status-bar-in-pwa-37332.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/pwa-ios-status-bar-blur/>)

Author: Stanko

Published: 2025-04-11T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [PWA](<https://devfeed.tech/topics/pwa.md>), [CSS](<https://devfeed.tech/topics/css.md>), [iOS](<https://devfeed.tech/topics/ios.md>), [Web Development](<https://devfeed.tech/topics/web-development.md>)

Tags: [background](<https://devfeed.tech/tags/background.md>), [code](<https://devfeed.tech/tags/code.md>), [css](<https://devfeed.tech/tags/css.md>), [ios](<https://devfeed.tech/tags/ios.md>), [pwa](<https://devfeed.tech/tags/pwa.md>)

### AI overview

This tutorial describes a CSS-based workaround for applying a blurred overlay to the iOS status bar area in a standalone PWA. The workaround uses a fixed element positioned outside the viewport and backdrop filtering, but an August 2026 update states that it no longer works on recent iOS versions because of WebKit changes.

### Source excerpt

Update August 2026: This workaround no longer works on recent iOS versions. WebKit changed how standalone PWAs handle the status bar area. The fixed overlay positioned outside the viewport no longer renders under the status bar. I haven't found a workaround for this yet. If you find a solution please let me know. On my current project, I'm making a Progressive Web App (PWA) and I was really annoyed that the status bar on iOS was completely transparentAlthough the option is called black-translucent. When the content scrolls behind it, it blends with the status bar elements, and it doesn't look great. I couldn't find a native solution, so I tried using CSS instead. To my surprise, my idea worked on the first try. Here is my solution next to the default iOS status bar: After applying the CSS solutionDefault If you are impatient, feel free to jump to the demo. The solution # I think the solution is pretty simple - a fixed div that covers the status bar area and applies a blur effect to the background. But there's a catch, the div needs to be positioned outside of the viewport. Here is the code, HTML first: <div class="statusbar"></div> and the CSS: body { --bg-color: 186 230 253; background-color: rgb(var(--bg-color)); } .statusbar { position: fixed; left: 0; right: 0; top: -80px; height: 80px; overflow: hidden; z-index: 100; } .statusbar::before { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 150%; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); background-color: rgb(var(--bg-color) / 0.6); } The CSS can be even simpler - we can remove the ::before element and just apply the blur to the .statusbar element itself. But this gives a nicer, more natural blur effect - check Josh Comeau's blog post in which he explains it in detail. Demo # You can check the live demo, just remember that you'll need an iOS device to see the effect. Not just that - for the effect to be visible, you'll need to add the app to your home screen. If you don't w

## CSS-only glitch effect

DevFeed: [CSS-only glitch effect](<https://devfeed.tech/articles/css-only-glitch-effect-37255.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/css-image-glitch/>)

Author: Stanko

Published: 2025-04-03T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [CSS](<https://devfeed.tech/topics/css.md>), [CSS animations](<https://devfeed.tech/topics/css-animations.md>), [HTML](<https://devfeed.tech/topics/html.md>), [html elements](<https://devfeed.tech/topics/html-elements.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [animation](<https://devfeed.tech/tags/animation.md>), [css](<https://devfeed.tech/tags/css.md>), [css-animations](<https://devfeed.tech/tags/css-animations.md>), [html](<https://devfeed.tech/tags/html.md>), [javascript](<https://devfeed.tech/tags/javascript.md>)

### AI overview

This tutorial explains how to create an image glitch effect using only HTML and CSS. It describes representing an image as vertically shifted strips, varying strip heights, displacing the strips, altering colors, and using closely spaced CSS keyframes to create abrupt movement. JavaScript is used only to generate the HTML and CSS, not in the final effect.

### Source excerpt

Let me show you how I created a CSS-only image glitch effect. I was working on the robot poet and wanted my robotic bard to glitch - because it felt fitting given the quality of poetry it generates. Here's the final result: The effect involves quite a bit of HTML and CSS but no JavaScript. I did use JavaScript to generate the HTML and CSS, but it is not used in the final version. To be clear, there's nothing wrong with using JavaScript for this kind of thing. I just saw it as a fun challenge to make a pure CSS version. The idea # In the words of Daft Punk: Slice It Move It Hue-Rotate It We'll have to slice the image into strips and randomly displace them while altering colors at the same time. Slice it # I wanted to use a single image without having to slice it manually. To achieve that, we need to create a bunch of divs. Each div represents one strip and has the image set as a background, but the image is shifted vertically. When stacked on top of each other, the divs look the same as the original image. To make the glitch effect more believable, we'll use a random height for each strip. We could do this by hand, but that would be tedious, so let's use code: const getStripHTML = (top: number, stripHeight: number): string => { const duration = random(5, 10); const name = `glitch-${duration}`; return ` <div class="strip" style="height: ${stripHeight}px; background-position: 0 -${top}px;" />`; }; const getGlitchHTML = (height: number): string[] => { let i = 0; const html: string[] = []; while (1) { const stripHeight = random(1, 6); if (i + stripHeight < height) { const strip = getStripHTML(i, stripHeight); html.push(strip); } else { // Last strip const strip = getStripHTML(i, height - i); html.push(strip); break; } i = i + stripHeight; } return html; }; Show codeHide code This gives us a list of divs with the image inside. When we render them all, we get the original image in a bunch of HTML elements we can manipulate individually. Toggle gap Now that we have our stri

## Make regular expressions easier to read

DevFeed: [Make regular expressions easier to read](<https://devfeed.tech/articles/make-regular-expressions-easier-to-read-37309.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/make-regular-expressions-easier-to-read/>)

Author: Stanko

Published: 2025-03-31T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [formatting](<https://devfeed.tech/topics/formatting.md>), [Maintainability](<https://devfeed.tech/topics/maintainability.md>)

Tags: [example](<https://devfeed.tech/tags/example.md>), [extra](<https://devfeed.tech/tags/extra.md>), [join](<https://devfeed.tech/tags/join.md>), [maintainability](<https://devfeed.tech/tags/maintainability.md>), [readability](<https://devfeed.tech/tags/readability.md>), [regular-expressions](<https://devfeed.tech/tags/regular-expressions.md>), [value](<https://devfeed.tech/tags/value.md>)

### AI overview

The article presents a formatting technique for making complex regular expressions easier to read: split the expression into multiple string components, join them, and construct the final regex. The approach adds code and requires escaping backslashes, but enables scanning and comments that can improve readability and maintainability.

### Source excerpt

This is a simple formatting trick I use to make regular expressions more readable. The secret? Break them into multiple lines. To achieve this, format the regex as an array of strings and then concatenate the array into a single regex string. Example # Compare this example, written in a single line: const FILTER_REGEXP = /(?<name>blur|brightness|contrast|grayscale|hue-rotate|invert|opacity|saturate|sepia)\((?<value>-?\d*(?:\.\d*)?)(?<unit>\w*?)\)/g; with the multi-line version: const SUPPORTED_FILTERS = [ 'blur', 'brightness', 'contrast', 'grayscale', 'hue-rotate', 'invert', 'opacity', 'saturate', 'sepia', ].join('|'); const FILTER_REGEXP = new RegExp( [ `(?<name>${SUPPORTED_FILTERS})`, // filter name `\\(`, `(?<value>\-?\\d*(?:\\.\\d*)?)`, // value `(?<unit>\\w*?)`, // unit if any `\\)`, ].join(''), 'g' ); The multi-line version has a bit more code, but it's easier to scan and read. It also allows us to write comments for each section, clarifying the purpose of each part of the regex. I've found that complex expressions are much easier to write this way. I believe it greatly reduces the cognitive load for both the writer and the reader. Caveats # You'll need to escape the backslashes in regex strings. While this is a minor inconvenience, the readability benefits easily outweigh it. Conclusion # It boils down to personal preference, but I believe the extra code is worth it, as it improves readability and maintainability. This is especially true when dealing with notoriously difficult-to-parse complex regular expressions.

## Image comparison slider in 6 lines of JavaScript

DevFeed: [Image comparison slider in 6 lines of JavaScript](<https://devfeed.tech/articles/image-comparison-slider-in-6-lines-of-javascript-37287.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/image-comparison-slider/>)

Author: Stanko

Published: 2025-03-02T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [JavaScript](<https://devfeed.tech/topics/javascript.md>), [CSS](<https://devfeed.tech/topics/css.md>), [HTML](<https://devfeed.tech/topics/html.md>), [Code](<https://devfeed.tech/topics/code.md>), [Accessibility](<https://devfeed.tech/topics/accessibility.md>)

Tags: [accessibility](<https://devfeed.tech/tags/accessibility.md>), [browser](<https://devfeed.tech/tags/browser.md>), [chrome](<https://devfeed.tech/tags/chrome.md>), [code](<https://devfeed.tech/tags/code.md>), [css](<https://devfeed.tech/tags/css.md>), [firefox](<https://devfeed.tech/tags/firefox.md>), [html](<https://devfeed.tech/tags/html.md>), [javascript](<https://devfeed.tech/tags/javascript.md>)

### AI overview

A tutorial showing how to build an image comparison slider with two stacked images, a native HTML range input, JavaScript, and a CSS variable. The slider value controls the width of the top image and the separator position. The article also discusses browser support and accessibility considerations.

### Source excerpt

While I was writing this post, I wanted to create an image comparison component. I made one with just a few lines of JavaScript, but I didn't include it in the post. Here is the finished slider, with images from the book Letters from Sarajevo. If you want to play with the code, you can find it on CodePen. Toggle debug Try out the debug modeI'm quite proud of it! The shadow effect is my favorite detail.. It reveals the structure in 3D and might give you a clue as to how I managed to create the slider with only a few lines of JavaScript. Here's a tip - the blue element is actually a native HTML range input. It's in the name # Image comparison slider. Slider, you say? We already have a native slider component - input [type=range]. Could we use it to make an image comparison slider? Turns out we can. I think that the solution I came up with is clever, yet simple to understand. This is the base idea: We have two images and the range slider, stacked on each other. The range input goes from 0 to 100. As the slider is moved, we update a CSS variable to match the slider value. We use this variable to set the width of the top image. Here is a simplified, unstyled example. Try moving the slider to see how it works. JavaScript # As we saw in the example above, everything is about keeping the slider value synced with the CSS variable. This variable controls the width of the top image and the position of the separator. Here is the JavaScript code that keeps the --slider-value variable in sync with the slider value: // Set element variables const compareSlider = document.querySelector('.comparison-slider'); const input = compareSlider.querySelector('.comparison-slider__input'); // Update the CSS variable on input change input.addEventListener('input', () => { compareSlider.style.setProperty('--slider-value', `${input.value}%`); }); // Update the CSS variable on load // to ensure the slider starts in sync with image's width. compareSlider.style.setProperty('--slider-value', `${inpu

## 3D-Printed Frame Repairs a Broken Bunny Brooch

DevFeed: [3D-Printed Frame Repairs a Broken Bunny Brooch](<https://devfeed.tech/articles/bunny-jumps-again-37247.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/bunny-jumps-again/>)

Author: Stanko

Published: 2025-02-23T00:00:00Z

Content type: opinion

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [3D](<https://devfeed.tech/topics/3d.md>)

Tags: [3d-printing](<https://devfeed.tech/tags/3d-printing.md>)

### AI overview

The author describes repairing a broken bunny ski-jumping brooch by designing and 3D-printing a frame that holds its broken pieces together. They traced a photo in Inkscape, extruded the outline in TinkerCad, and tested several prints until one achieved a tight press fit.

### Source excerpt

I love 3D printing. It feels like magic - we are able to design and create physical things in a matter of hours, in our homes. I understand the underlying technology, but it still blows my mind when I think about it. It makes me a bit sad that more people aren't fascinated by it. Let's see what my love for 3D printing has to do with bunnies. Ski jumping bunnies to be exact. My wife has a brooch that she really likes - of a bunny ski jumping. She wears it on her backpack, and when she's in the mountains, on her ski jacket. But unfortunately it broke - the skies snapped off. So she asked me, Can you fix it somehow? Maybe 3D print something? This was right up my alley. After some thought, I decided the best approach would be to design a frame for the broken pieces, with slightly offset edges to keep them in place. But how could I design it when the outline was so irregular? After overthinking it, I returned to a simple solution - I took a photo of the brooch, imported it into Inkscape, and traced it by hand. Here is the result: I extruded the outline using TinkerCad and did a test print. I was pleasantly surprised, because the print was almost perfect. There were a few points that needed tweaking, but before making changes, I wanted to see if simply adding an edge would work. And it did! To be fair I printed four in total. I'm a bit embarrassed to admit, but I printed the first one mirrored. Then printed three more with slightly different measurements for the offset and edge height. One of them fit perfectly. And I mean - perfectly - it is a very tight press fit. Oh joy! Bunny bunny jumps again! My wife was thrilled to see her favorite brooch fixed. But the real point I wanted to share is that 3D printing is amazing, and sometimes, the simplest ideas work best!

## The Tiny Book of Great Joys

DevFeed: [The Tiny Book of Great Joys](<https://devfeed.tech/articles/the-tiny-book-of-great-joys-37361.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/the-tiny-book-of-great-joys/>)

Author: Stanko

Published: 2025-02-10T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Artificial Intelligence](<https://devfeed.tech/topics/ai.md>), [Figma](<https://devfeed.tech/topics/figma.md>), [3D](<https://devfeed.tech/topics/3d.md>)

Tags: [3d-printer](<https://devfeed.tech/tags/3d-printer.md>), [ai](<https://devfeed.tech/tags/ai.md>), [figma](<https://devfeed.tech/tags/figma.md>), [generate](<https://devfeed.tech/tags/generate.md>)

### AI overview

A personal process report about making a tiny illustrated book using AI-generated images, Figma, a pen plotter, and a 3D printer. The author describes developing the idea, creating and editing drawings, and producing a handcrafted book for their wife.

### Source excerpt

If you are interested in how I over-engineered the process of making a tiny book for my wife, using AI, a pen plotter, a 3D printer, and a lot of time, you are in the right place. The book is titled The Tiny Book of Great JoysMala Knjiga Velikih Radosti in Serbian, and here is how it turned out: My wife is delighted with it, so it was worth all the effort. This post will take you through the process. It will be a long one, but please stick around - I promise there will be a lot of pretty pictures. Here is the outline of the post: The idea Drawings Text Plotting Bookbinding The finished book Timeline Conclusion The idea # I had this idea for a while after seeing something similar somewhere on the internet.. Since then, I always wanted to make one for my wife - a physically small book with a bunch of small drawings of our memories together, inside jokes, and little things she likes. I wanted the illustrations to be hand-drawn, and I had a plan to ask my friend to do them. But I knew he would refuse any kind of payment, so I felt bad adding more work to his plate. So I shelved the idea, but every now and then, it would pop up in my head. Fast forward a few years - we got a kid, and our routine completely changed. We are enjoying it a lot, but it can be very exhausting, and every day seems identical to the last. That's why I decided I needed to do something for her to break the routine. The book idea seemed perfect - personal and handcrafted - so I gave it a try. To be able to do everything myself, I went to create digital drawings and then draw them on paper using my trusty pen plotter. With the idea in place, I moved on to creating the drawings - which turned out to be a challenge of its own. Drawings # For pen plotting, one needs vector files, so I started drawing in Figma. Unfortunately, I quickly realized that my drawing skills would not get me the result I had envisioned. Determined to do it this time, I decided to try using AI to generate images. Midjourney # I g

## Change font-weight based on the user's screen DPI

DevFeed: [Change font-weight based on the user's screen DPI](<https://devfeed.tech/articles/change-font-weight-based-on-the-user-s-screen-dpi-37273.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/font-weight-based-on-dpi/>)

Author: Stanko

Published: 2025-02-03T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Font](<https://devfeed.tech/topics/font.md>), [CSS](<https://devfeed.tech/topics/css.md>), [Media Queries](<https://devfeed.tech/topics/media-queries.md>), [pixel](<https://devfeed.tech/topics/pixel.md>), [User Experience](<https://devfeed.tech/topics/user-experience.md>), [Web Development](<https://devfeed.tech/topics/web-development.md>)

Tags: [accessibility](<https://devfeed.tech/tags/accessibility.md>), [browser](<https://devfeed.tech/tags/browser.md>), [css](<https://devfeed.tech/tags/css.md>), [fonts](<https://devfeed.tech/tags/fonts.md>), [pixel](<https://devfeed.tech/tags/pixel.md>), [user-experience](<https://devfeed.tech/tags/user-experience.md>)

### AI overview

This tutorial explains that thin font weights can become blurry and difficult to read on low-DPI screens. It demonstrates progressive enhancement with CSS media queries: use a more readable default weight for low-DPI displays and apply a thinner weight on high-DPI displays. The technique can also be applied to font size and icon line width.

### Source excerpt

A lot of us as developers have hi-DPI screens, and we can easily forget to test the websites we build on low-DPI screens. One common issue I noticed is that thin font weights can be hard to read on low-DPI screens. Since there are fewer pixels to render details, fine lines can appear blurry due to anti-aliasing. Here is an example of the same text rendered on two screens with different device pixel ratios. At the top is a hi-DPI screen (with a pixel ratio of 2), and below is a low-DPI screen (with a pixel ratio of 1). The font used is Inter, 24px tall, with a font weight of 100. This problem is a great example of how we can use progressive enhancement to improve the user experience. We'll set a default font weight that is readable on low-DPI screens, then use CSS media queries to target hi-DPI screens and apply thinner fonts. Here is a code example: // Default font weight for low-DPI screens h1 { font-weight: 300; } // Progressive enhancement for hi-DPI screens // Making font thinner and more elegant @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { h1 { font-weight: 100; } } This will set the font weight to 300 on low-DPI screens and 100 on hi-DPI screens. Feel free to adjust these values as needed. Additional applications # This is an example using font weight, but you can apply the same technique to other properties, such as font size or icon line width. Simulating low-DPI on Mac # This is a great tip from StackOverflow: Open System Settings > Accessibility > Zoom > Advanced > Uncheck "Smooth Images" Zoom out your browser to 50% Turn on the system Zoom (the default shortcut is Option + ⌘ + 8) This should give you a good idea of how your website appears on a low DPI screen. Sorry, Windows and Linux users! If you have a good solution for your system, please open a GitHub issue, and I'll add it here.

## Why I Created a Personal Blog and Chose Zola with GitHub Pages

DevFeed: [Why I Created a Personal Blog and Chose Zola with GitHub Pages](<https://devfeed.tech/articles/blog-questions-challenge-37245.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/blog-question-challenge/>)

Author: Stanko

Published: 2025-01-18T00:00:00Z

Content type: opinion

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Jekyll](<https://devfeed.tech/topics/jekyll.md>), [GitHub Pages](<https://devfeed.tech/topics/github-pages.md>), [Website](<https://devfeed.tech/topics/website.md>), [static-site-generator](<https://devfeed.tech/topics/static-site-generator.md>), [hosting](<https://devfeed.tech/topics/hosting.md>), [Programming](<https://devfeed.tech/topics/programming.md>), [GitHub](<https://devfeed.tech/topics/github.md>), [WordPress](<https://devfeed.tech/topics/wordpress.md>)

Tags: [blog](<https://devfeed.tech/tags/blog.md>), [github](<https://devfeed.tech/tags/github.md>), [github-pages](<https://devfeed.tech/tags/github-pages.md>), [hosting](<https://devfeed.tech/tags/hosting.md>), [jekyll](<https://devfeed.tech/tags/jekyll.md>), [programming](<https://devfeed.tech/tags/programming.md>), [static-site-generator](<https://devfeed.tech/tags/static-site-generator.md>), [website](<https://devfeed.tech/tags/website.md>), [wordpress](<https://devfeed.tech/tags/wordpress.md>)

### AI overview

The author explains why they created a personal blog, describing it as a way to maintain a personal website and share programming projects outside social networks. They discuss moving from Jekyll to Zola, keeping the site on GitHub Pages, and their interest in eventually building a static site generator with interactive posts and JSX.

### Source excerpt

I've seen this challenge on Herman's blog. I liked it, so I decided to do my own version, even though I'm not using the bear blog. For the same reason, I slightly adapted the original questions. Why did you make the blog in the first place? # Since I first got online, I've wanted a personal website - a piece of internet I can call my own. I had a few websites over the years, but none of them are online anymore (and I don't have backups). Then, in my late twenties, I decided to try again. As someone who loves programming and making things, I've gathered plenty of material to share over the years. I also wanted to change the fact that I hadn't written much since high school. I've never been a fan of social networks, so starting a blog felt like the perfect thing for me -- I could have my own website and share the things I'm working on. This blog has been up since 2016, and I'm really proud of it. While the frequency of my posts has gone down, I like to think the quality has gone up. Why did you choose Bearblog Zola and GitHub Pages? # Before Zola, I used Jekyll, which is tightly coupled with GitHub Pages. GitHub Pages restricts you to the default Jekyll configuration, so I couldn't customize all the stuff I wanted. I started looking for a replacement and stumbled on Zola. It seemed very nice -- fast, a single binary, with a sane templating language. After trying it, I really liked it and decided to stick with it. I kept it deployed on GitHub Pages because I think they're great. Free and fast hosting, and the fact that I don't have to mess with deployments myself -- thanks, GitHub folks! However, for a long time now, I've wanted to write my own small static site generator. It would support interactive posts/components and use JSXI think that JSX is a great templating language. If I ever do it, I'll open-source it. Have you blogged on other platforms before? # As mentioned above, this blog used to be a Jekyll blog. Before that, I tried keeping a blog a few times, but only

## Native dual-range input

DevFeed: [Native dual-range input](<https://devfeed.tech/articles/native-dual-range-input-37318.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/native-dual-range-input/>)

Author: Stanko

Published: 2024-11-18T00:00:00Z

Content type: release

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [HTML](<https://devfeed.tech/topics/html.md>), [Library](<https://devfeed.tech/topics/library.md>), [Requirements](<https://devfeed.tech/topics/requirements.md>), [JavaScript](<https://devfeed.tech/topics/javascript.md>), [CSS](<https://devfeed.tech/topics/css.md>), [Accessibility](<https://devfeed.tech/topics/accessibility.md>)

Tags: [accessibility](<https://devfeed.tech/tags/accessibility.md>), [browsers](<https://devfeed.tech/tags/browsers.md>), [css](<https://devfeed.tech/tags/css.md>), [html](<https://devfeed.tech/tags/html.md>), [javascript](<https://devfeed.tech/tags/javascript.md>), [library](<https://devfeed.tech/tags/library.md>)

### AI overview

The article introduces @stanko/dual-range-input, a library that creates a dual-range slider from two native HTML range inputs. It explains the requirements, synchronization logic, midpoint-based min and max updates, accessibility benefits, and the CSS and width calculations used to style the control.

### Source excerpt

I just released @stanko/dual-range-input - a native dual-range input. Here is how it looks with the default styles: The "native" part is somewhat open for discussion. I call it native because the library uses two native HTML range inputs. This means that all of the native interactions and accessibility features are preserved. Native inputs allow us not to reinvent the wheel. There is about fifty lines of JavaScript to synchronize the inputs, along with some CSS to ensure everything looks polished. In my book, that is native enough. Why # When I create my generative drawings, I use a tool I built myself. This tool includes a UI for tweaking parameters, and I often have minimum and maximum sliders for certain parameters. I thought it would be nice to have a dual-range slider for these. However, most existing solutions rely heavily on JavaScript and reimplement dragging and accessibility features. So, I set my own set of requirements: It should use native HTML range inputs. When you click on the track, the closer of the two thumbs should jump to that value. Hopefully, after you read these two requirements, my solution will make sense. How it works # There are two inputs placed next to each other. When either of the inputs is changed, the library calculates a midpoint between the two selected values. Then the min and max attributes are set to the midpoint, and the width of both inputs is updated to match. Here is an unstyled example, which will hopefully illustrate this well: Even like this, it works reasonably well. We'll style it later to make it look nicer. Resizing the inputs # There's a small trick involved in calculating input widths. This is because the range input's track is actually shorter than the input's total width. All browsers leave enough space on the sides so the thumb doesn't stick out. Here is a screenshot from Firefox (other browsers work similarly), where you can see that the track is shorter than the width. I've emphasized the space the browser lea

## CSS fix to prevent orphan icons dropping to a new line

DevFeed: [CSS fix to prevent orphan icons dropping to a new line](<https://devfeed.tech/articles/css-fix-to-prevent-orphan-icons-dropping-to-a-new-line-37254.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/css-fix-to-prevent-orphan-icons/>)

Author: Stanko

Published: 2024-11-12T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [CSS](<https://devfeed.tech/topics/css.md>), [Web Development](<https://devfeed.tech/topics/web-development.md>), [HTML](<https://devfeed.tech/topics/html.md>), [browser](<https://devfeed.tech/topics/browser.md>)

Tags: [browser](<https://devfeed.tech/tags/browser.md>), [css](<https://devfeed.tech/tags/css.md>), [element](<https://devfeed.tech/tags/element.md>), [legibility](<https://devfeed.tech/tags/legibility.md>), [property](<https://devfeed.tech/tags/property.md>)

### AI overview

This tutorial explains how CSS text wrapping can prevent short text or icons from becoming orphaned on a separate line. It presents text-wrap: balance and text-wrap: pretty, noting that pretty uses a slower layout algorithm and is not supported in Firefox or Safari at the time of writing.

### Source excerpt

When an HTML element becomes too narrow, its content starts to wrap into multiple lines. This is intended behavior and works well in many cases. However, for short text, it doesn't look great when the last word or icon drops to the next line, becoming an orphan. For example, you might see something like this: Click here for more info It doesn't look great when the icon is left alone on its own row. Luckily, there's a simple CSS solution. Solution # Only thing we need to add is a single line of CSS: text-wrap: balance; This property tells the browser to wrap the text in a way that best balances the number of characters on each line, enhancing layout quality and legibility. The browser will calculate this for us, preventing orphaned icons or words. text-wrap: pretty # There is also the pretty value for text-wrap, which is even better. It works in a similar way, but the browser will use a slower algorithm that prioritizes better layout over speed. Unfortunately, at the time of writing, pretty is not supported in Firefox nor Safari. However, you can define both values, and browsers that don't support pretty will fall back to balance. text-wrap: balance; text-wrap: pretty; /* This will be ignored by browsers that don't support it. */ Demo # Here's a simple demo. Use the handle on the right to resize the element and see how text breaks with and without the balance property applied. Defaulttext-wrap: balancetext-wrap: pretty Unfortunately your browser doesn't support text-wrap: pretty. Click here for more info A somewhat longer text that will break into multiple lines

## Open source mac apps I love

DevFeed: [Open source mac apps I love](<https://devfeed.tech/articles/open-source-mac-apps-i-love-37328.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/open-source-mac-apps-i-love/>)

Author: Stanko

Published: 2024-11-09T00:00:00Z

Content type: article

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Open Source](<https://devfeed.tech/topics/open-source.md>), [App](<https://devfeed.tech/topics/app.md>), [GUI](<https://devfeed.tech/topics/gui.md>), [Homebrew](<https://devfeed.tech/topics/homebrew.md>), [dropbox](<https://devfeed.tech/topics/dropbox.md>), [keyboard](<https://devfeed.tech/topics/keyboard.md>)

Tags: [apps](<https://devfeed.tech/tags/apps.md>), [bash](<https://devfeed.tech/tags/bash.md>), [dropbox](<https://devfeed.tech/tags/dropbox.md>), [gui](<https://devfeed.tech/tags/gui.md>), [keyboard](<https://devfeed.tech/tags/keyboard.md>), [mac](<https://devfeed.tech/tags/mac.md>), [open-source](<https://devfeed.tech/tags/open-source.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [tools](<https://devfeed.tech/tags/tools.md>)

### AI overview

The article recommends a selection of free, open-source Mac applications that the author uses regularly, including menu-bar utilities, image optimization software, keyboard customization, clipboard management, Dropbox access, terminal integration, window tiling, and command-line tools. It also provides Homebrew installation commands for the listed applications.

### Source excerpt

I want to share some really nice open-source applications I use on a daily basis. I did a similar post about six years ago, so I felt there is a need for an updated one. I focused on the apps that I feel are really convenient but less known. All of the applications listed are free and open source. For each app, I included a brew install command. If you happen to like and use them, please consider donating to their respective authors. Here are all of the apps in alphabetical order: GUI Applications Hidden Bar ImageOption Itsycal Karabiner-Elements Keeping You Awake Maccy Maestral OpenInTerminal Pearcleaner Pika Rectangle Bash programs dust ripgrep tio zoxide GUI Applications # Hidden Bar # GitHub brew install hiddenbar Hidden Bar allows you to hide icons from the menu bar. It seems that every app nowadays wants to be in the menu bar, and this helps declutter it. ImageOptim # GitHub | Website brew install imageoptim As its name suggests, ImageOptim optimizes images. It is a UI for a bunch of lossless image optimization tools. Just drop your images and it will compress them without losing any quality. Itsycal # GitHub | Website brew install itsycal A small calendar that lives in your menu bar. Why is this not built into the operating system? Karabiner-Elements # GitHub | Website brew install karabiner-elements I just can't get used to Apple's international keyboard layout and the tilde being in the bottom left. Karabiner solves that. It's a keyboard customizer that allows you to remap keys and create complex modifications. Keeping You Awake # GitHub | Website brew install keepingyouawake Prevents your Mac from going to sleep by clicking on its icon in the menu bar. I use it when I'm running my pen plotter to make sure the laptop doesn't go to sleep. Maccy # GitHub | Website brew install maccy A clipboard manager. It saves your clipboard history and allows you to quickly access it. Maestral # GitHub | Website brew install maestral A lightweight Dropbox client. The offic

## Node.js script to run multiple commands in parallel

DevFeed: [Node.js script to run multiple commands in parallel](<https://devfeed.tech/articles/node-js-script-to-run-multiple-commands-in-parallel-37322.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/node-script-to-run-multiple-commands-in-parallel/>)

Author: Stanko

Published: 2024-06-13T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Node.js](<https://devfeed.tech/topics/node-js.md>), [JavaScript](<https://devfeed.tech/topics/javascript.md>), [Command-line interface](<https://devfeed.tech/topics/cli.md>), [Scripting](<https://devfeed.tech/topics/scripting.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>)

Tags: [bash](<https://devfeed.tech/tags/bash.md>), [commands](<https://devfeed.tech/tags/commands.md>), [concurrently](<https://devfeed.tech/tags/concurrently.md>), [javascript](<https://devfeed.tech/tags/javascript.md>), [node-js](<https://devfeed.tech/tags/node-js.md>), [parallel](<https://devfeed.tech/tags/parallel.md>), [script](<https://devfeed.tech/tags/script.md>)

### AI overview

This tutorial presents a small Node.js script for running multiple commands in parallel. It explains the requirements, including stopping all commands when one fails and prefixing each command's output with color-coded names, and shows how to use and implement the script.

### Source excerpt

If you encountered a case where you wanted to run multiple commands in parallel, the usual suggestion is to use the shell's & operator to send commands to the background. This approach kind of works, but it has its quirks. I often ended up with a process hanging in the background, multiple outputs being mangled, or the output of some commands completely missing. Bash scripting wizards can probably solve all of these issues, but I turned to JavaScript, as it is the language I know best. If you're eager to see the code, feel free to jump to it. Why not an existing library? # In my professional projects, I would probably just use concurrently. However, this time I decided to write a poor man's version of it. Although simple and basic, it covers my specific use case. It was mostly for learning purposes, but sometimes I create things from scratch for fun or to avoid installing a large library for a tiny piece of it. My requirements # Run multiple commands in parallel. Terminate all of the commands if any of them fail. Prefix each command's output with its color-codedIn the finished version, I added an option to disable colors, as I know some people really don't like colors in their terminals name. I also decided to keep it simple: No CLI version to avoid parsing the arguments. Name (prefix) should be a mandatory input. Usage # To use the script, you need to import it and pass the list of your commands (along with their names) to it. Like this: import { Runner } from './runner.js'; const tasks = [ { name: 'sass', command: 'npm run sass' }, { name: 'build', command: 'npm run build' }, ]; new Runner(tasks); This is how the script looks in action: Source code # Here is the complete script: import { spawn } from 'child_process'; export class Runner { tasks = []; exiting = false; colors = [ '\x1b[33m', // yellow '\x1b[34m', // blue '\x1b[35m', // magenta '\x1b[36m', // cyan ]; /** * Create a new runner. * @param {Object[]} tasks - List of tasks to run in parallel. * @param {st

## HTML inert property and React fallback

DevFeed: [HTML inert property and React fallback](<https://devfeed.tech/articles/html-inert-property-and-react-fallback-37283.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/html-inert-property/>)

Author: Stanko

Published: 2023-12-21T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [HTML](<https://devfeed.tech/topics/html.md>), [React](<https://devfeed.tech/topics/react.md>), [Web Development](<https://devfeed.tech/topics/web-development.md>)

Tags: [aria](<https://devfeed.tech/tags/aria.md>), [browser](<https://devfeed.tech/tags/browser.md>), [code](<https://devfeed.tech/tags/code.md>), [component](<https://devfeed.tech/tags/component.md>), [focus](<https://devfeed.tech/tags/focus.md>), [html](<https://devfeed.tech/tags/html.md>), [mutation](<https://devfeed.tech/tags/mutation.md>), [react](<https://devfeed.tech/tags/react.md>), [tabbing](<https://devfeed.tech/tags/tabbing.md>)

### AI overview

This tutorial explains how the HTML inert property disables user interaction, keyboard tabbing, and screen-reader access for an element. It also presents a React fallback that uses tabindex changes and a mutation observer to support older browsers.

### Source excerpt

HTML inert is a relatively new property, but it is supported in all major browsers since April this year. When you set inert on an element, the browser will ignore all user events on it, including tabbing into elements. It will also hide it from screen readers. I like to think of it as a "reversed focus trap". But we can use it to create focus traps for modals by setting inert on the main content. This div has inert property set and if your browser supports it, you won't be able to interact with the button and link below. You can't click meNor me! React fallback component # Before I learned about inert, I built a relatively simple component to achieve the same result. Now I prefer to use the native solution, but on most projects, we still have to support older browsers. My approach is to handle it in the wrapper component, which finds all focusable elements and sets tabindex="-1". After mounting, the mutation observer starts listening and re-sets the tabindex when content is changed. The wrapper itself has aria-hidden="true", which hides it from screen readers. You can try it out on CodePen and see the source code below: const focusableElementsSelector = [ "a[href]", "input", "select", "textarea", "button", "audio[controls]", "video[controls]", "details > summary:first-of-type", "details", "[contenteditable]:not([contenteditable=\"false\"])", "[tabindex]:not([tabindex=\"-1\"])" ].join(", "); const addTabIndex = ($wrapper) => { $wrapper.querySelectorAll(focusableElementsSelector).forEach(($element) => { $element.setAttribute("tabindex", -1); }); }; const removeTabIndex = ($wrapper) => { $wrapper.querySelectorAll(focusableElementsSelector).forEach(($element) => { $element.removeAttribute("tabindex"); }); }; const Inert = ({ enabled, children, ...props }) => { const wrapperRef = useRef(null); const observerRef = useRef( new MutationObserver(() => addTabIndex(wrapper.current)) ); useEffect(() => { if (enabled) { if (wrapperRef.current) { // Add tabindex addTabIndex(wrap

## Moon Phases - Art

DevFeed: [Moon Phases - Art](<https://devfeed.tech/articles/moon-phases-art-37215.md>)

Original publisher: [Read original article](<https://muffinman.io/art/moon/>)

Author: Stanko

Published: 2023-11-25T00:00:00Z

Content type: article

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [color](<https://devfeed.tech/topics/color.md>), [GitHub](<https://devfeed.tech/topics/github.md>)

Tags: [art](<https://devfeed.tech/tags/art.md>), [code](<https://devfeed.tech/tags/code.md>), [color](<https://devfeed.tech/tags/color.md>), [github](<https://devfeed.tech/tags/github.md>)

### AI overview

A moon phases artwork plotted with five different color markers, with code available on GitHub. The creator notes that the metallic color reflections are difficult to capture in photographs.

### Source excerpt

It is incredibly hard to take a good photo of these. Colors have metallic reflection which I wasn't able to capture, but it is very prominent in person. They are plotted using five different color markers. I framed them separately and plan to take a better photo once they are on the wall. Code is available on my GitHub. Created: November 2023Size: 14.5x14.5cmPaper: Fabriano Black Black 300gsmPens: UniBall Signo and Sakura Jelly Rolls

## Using CSS animations instead of JavaScript timers

DevFeed: [Using CSS animations instead of JavaScript timers](<https://devfeed.tech/articles/using-css-animations-instead-of-javascript-timers-37252.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/css-animations-instead-of-js-timers/>)

Author: Stanko

Published: 2023-08-04T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [CSS animations](<https://devfeed.tech/topics/css-animations.md>), [JavaScript](<https://devfeed.tech/topics/javascript.md>), [web animation](<https://devfeed.tech/topics/web-animation.md>), [Document Object Model (DOM)](<https://devfeed.tech/topics/dom.md>)

Tags: [animations](<https://devfeed.tech/tags/animations.md>), [api](<https://devfeed.tech/tags/api.md>), [css](<https://devfeed.tech/tags/css.md>), [css-animations](<https://devfeed.tech/tags/css-animations.md>), [javascript](<https://devfeed.tech/tags/javascript.md>)

### AI overview

This tutorial explains how to build timers with CSS animations and class changes instead of JavaScript timer functions. It covers pausing, resuming, restarting, animation events, repeated timers, chaining timers, and using the approach for an autoplaying carousel. It also notes that precise progress tracking requires the Web Animations API.

### Source excerpt

What if I told you that we can make a timer without using setTimeout, setInterval or requestAnimationFrame? JavaScript is still necessary, but we can create the timer just by toggling some CSS classes. While I was working on an autoplay feature for a carousel, I thought to myself - CSS animations are kinda like timers. They have animationstart and animationend events and an ability to pause them. On top of that, we get the animation loop for free, which we would have to implement manually in JavaScript. Implementation # To make the timer, we'll need four CSS classesPlease note that we could create a minimal example with only two classes (.timer and .timer--running), but it is pretty limiting and therefore we are going to skip it.: .timer - initial styles .timer--running - starts the animation .timer--paused - pauses the animation (can only be used in combination with .timer--running) .timer--done - final state of the animation We'll start a timer by adding a .timer--running class. In the case that we are restarting it, we also need to remove the .timer--done class. // Start the timer $timer.classList.add('timer--running'); // $timer is a reference to the timer's DOM element $timer.classList.remove('timer--done'); To pause it we'll add .timer--paused class. Resume it by removing the class. // Toggle the pause class $timer.classList.toggle('timer--pause'); Once animationend event is triggered, we know the animation is done, so we need to add .timer--done and to remove .timer--running class. // Update classes so the timer can be restarted $timer.classList.add('timer--done'); $timer.classList.remove('timer--running'); When we put it all together, we get a minimal working example: Start / stop Code is also available on CodePen for you to play with. This timer works similarly to setTimeout, but it comes with it's own animation loop and an easy way to pause it. animationiteration # To get a behavior similar to setInterval we are going to switch to animationiteration instea

## CSS only floating labels

DevFeed: [CSS only floating labels](<https://devfeed.tech/articles/css-only-floating-labels-37257.md>)

Original publisher: [Read original article](<https://muffinman.io/blog/css-only-floating-input-labels/>)

Author: Stanko

Published: 2023-07-05T00:00:00Z

Content type: tutorial

Language: en

Sources: [Stanko Tadić](<https://devfeed.tech/sources/stanko-tadic.md>)

Topics: [CSS](<https://devfeed.tech/topics/css.md>), [HTML](<https://devfeed.tech/topics/html.md>), [Code](<https://devfeed.tech/topics/code.md>), [Demo](<https://devfeed.tech/topics/demo.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [css](<https://devfeed.tech/tags/css.md>), [demo](<https://devfeed.tech/tags/demo.md>), [focus](<https://devfeed.tech/tags/focus.md>), [html](<https://devfeed.tech/tags/html.md>), [input](<https://devfeed.tech/tags/input.md>), [safari](<https://devfeed.tech/tags/safari.md>), [state](<https://devfeed.tech/tags/state.md>)

### AI overview

This tutorial explains how to use the CSS :placeholder-shown pseudo-class and :not() to detect whether an input is empty or has a value without JavaScript. It demonstrates floating labels and conditionally displayed clear buttons, and notes a Safari requirement for the placeholder attribute.

### Source excerpt

I recently learned about the pseudo CSS class :placeholder-shown. Obviously, it is a class that is added only when input placeholder is shown. But what that also means is that the input is empty: /* Input is empty */ input:placeholder-shown By negating it with :not() we can detect if the input has value: /* Input has value */ input:not(:placeholder-shown) I created a demo that uses these two CSS snippets to highlight input's current state. There is no JavaScript involved. Input has value Input is empty Focused Real world use cases # I recently used this to conditionally display a clear button next to an input. But it can also be used to create floating labels. However, it's important to note that anything you want to style based on the input's state needs to be positioned after the input element. Floating labels # For a floating label, the HTML structure should look something like this: <input /> <label>Floating label</label> The floating label needs to be repositioned in two scenarios: when the input is focused and when it has a value. /* Input has value */ input:focus + label, input:not(:placeholder-shown) + label { /* Move the label above the button and scale it down */ transform: translateY(-100%) scale(0.75); } Clear button # Similarly, we'll put the clear button after the input: <input /> <button>Clear</button> and hide it when input is empty: /* Input is empty */ input:placeholder-shown + button { /* Hide the clear button */ display: none; } Demo # Focus an input to make its label float, and type something to make the clear button appear. Name Email You can also play with the code on CodePen. Safari gotcha # Be aware that in Safari the :placeholder-shown pseudo class will only be added if the input has the placeholder attribute explicitly defined. Which means that we have to define it, but if we don't need the placeholder, we can easily hide it using CSS: input::placeholder { color: transparent; }

[Next page](<https://devfeed.tech/sources/stanko-tadic.md?cursor=WyIyMDIzLTA3LTA1VDAwOjAwOjAwKzAwOjAwIiwgIjM0Mzc0ZTk0LTZhNTAtNGNiYy1hNDE2LTFkY2Y1ZDRjMTM1OCJd>)