Everything posted by Blogger
-
We Completely Missed width/height: stretch
by: Daniel Schwarz Fri, 10 Oct 2025 14:03:52 +0000 The stretch keyword, which you can use with width and height (as well as min-width, max-width, min-height, and max-height, of course), was shipped in Chromium web browsers back in June 2025. But the value is actually a unification of the non-standard -webkit-fill-available and -moz-available values, the latter of which has been available to use in Firefox since 2008. The issue was that, before the @supports at-rule, there was no nice way to implement the right value for the right web browser, and I suppose we just forgot about it after that until, whoops, one day I see Dave Rupert casually put it out there on Bluesky a month ago: Layout pro Miriam Suzanne recorded an explainer shortly thereafter. It’s worth giving this value a closer look. What does stretch do? The quick answer is that stretch does the same thing as declaring 100%, but ignores padding when looking at the available space. In short, if you’ve ever wanted 100% to actually mean 100% (when using padding), stretch is what you’re looking for: div { padding: 3rem 50vw 3rem 1rem; width: 100%; /* 100% + 50vw + 1rem, causing overflow */ width: stretch; /* 100% including padding, no overflow */ } CodePen Embed Fallback The more technical answer is that the stretch value sets the width or height of the element’s margin box (rather than the box determined by box-sizing) to match the width/height of its containing block. Note: It’s never a bad idea to revisit the CSS Box Model for a refresher on different box sizings. And on that note — yes — we can achieve the same result by declaring box-sizing: border-box, something that many of us do, as a CSS reset in fact. *, ::before, ::after { box-sizing: border-box; } I suppose that it’s because of this solution that we forgot all about the non-standard values and didn’t pay any attention to stretch when it shipped, but I actually rather like stretch and don’t touch box-sizing at all now. Yay stretch, nay box-sizing There isn’t an especially compelling reason to switch to stretch, but there are several small ones. Firstly, the Universal selector (*) doesn’t apply to pseudo-elements, which is why the CSS reset typically includes ::before and ::after, and not only are there way more pseudo-elements than we might think, but the rise in declarative HTML components means that we’ll be seeing more of them. Do you really want to maintain something like the following? *, ::after, ::backdrop, ::before, ::column, ::checkmark, ::cue (and ::cue()), ::details-content, ::file-selector-button, ::first-letter, ::first-line, ::grammar-error, ::highlight(), ::marker, ::part(), ::picker(), ::picker-icon, ::placeholder, ::scroll-button(), ::scroll-marker, ::scroll-marker-group, ::selection, ::slotted(), ::spelling-error, ::target-text, ::view-transition, ::view-transition-image-pair(), ::view-transition-group(), ::view-transition-new(), ::view-transition-old() { box-sizing: border-box; } Okay, I’m being dramatic. Or maybe I’m not? I don’t know. I’ve actually used quite a few of these and having to maintain a list like this sounds dreadful, although I’ve certainly seen crazier CSS resets. Besides, you might want 100% to exclude padding, and if you’re a fussy coder like me you won’t enjoy un-resetting CSS resets. Animating to and from stretch Opinions aside, there’s one thing that box-sizing certainly isn’t and that’s animatable. If you didn’t catch it the first time, we do transition to and from 100% and stretch: CodePen Embed Fallback Because stretch is a keyword though, you’ll need to interpolate its size, and you can only do that by declaring interpolate-size: allow-keywords (on the :root if you want to activate interpolation globally): :root { /* Activate interpolation */ interpolate-size: allow-keywords; } div { width: 100%; transition: 300ms; &:hover { width: stretch; } } The calc-size() function wouldn’t be useful here due to the web browser support of stretch and the fact that calc-size() doesn’t support its non-standard alternatives. In the future though, you’ll be able to use width: calc-size(stretch, size) in the example above to interpolate just that specific width. Web browser support Web browser support is limited to Chromium browsers for now: Opera 122+ Chrome and Edge 138+ (140+ on Android) Luckily though, because we have those non-standard values, we can use the @supports at-rule to implement the right value for the right browser. The best way to do that (and strip away the @supports logic later) is to save the right value as a custom property: :root { /* Firefox */ @supports (width: -moz-available) { --stretch: -moz-available; } /* Safari */ @supports (width: -webkit-fill-available) { --stretch: -webkit-fill-available; } /* Chromium */ @supports (width: stretch) { --stretch: stretch; } } div { width: var(--stretch); } Then later, once stretch is widely supported, switch to: div { width: stretch; } In a nutshell While this might not exactly win Feature of the Year awards (I haven’t heard a whisper about it), quality-of-life improvements like this are some of my favorite features. If you’d rather use box-sizing: border-box, that’s totally fine — it works really well. Either way, more ways to write and organize code is never a bad thing, especially if certain ways don’t align with your mental model. Plus, using a brand new feature in production is just too tempting to resist. Irrational, but tempting and satisfying! We Completely Missed width/height: stretch originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
-
LHB Linux Digest #25.30: New Systemd Automation Course, LoggiFly, Docker Storage and More
by: Abhishek Prakash Fri, 10 Oct 2025 16:36:22 +0530 Our latest course, Advanced Automation With Systemd, is available now. Believe it or not, systemd is the future of automation on Linux. Its automation framework lets you precisely schedule task, create complex, dependent workflows and sandbox risky jobs for security. You can even create containers with systemd. Advanced Automation with systemdTake Your Linux Automation Beyond CronLinux HandbookUmair KhurshidThe idea is to focus on small, niche topics and provide you a streamlined learning. Next, we are working on adding videos to the Docker course (I think I already told you about that), a micro course 'Linux Networking at Scale' and a tutorial series on building an open source product from scratch and publishing it to CNCF-level standards. I have not forgotten core Linux stuff. There are additional series and microcourse ideas around them, too. Stay tuned 😄 This post is for subscribers only Subscribe now Already have an account? Sign in
-
412: 2.0 Embedded Pens
by: Chris Coyier Thu, 09 Oct 2025 15:45:43 +0000 Or just “Embeds” as we more frequently refer to them as. Stephen and Chris talk about the fairly meaty project which was re-writing our Embeds for a CodePen 2.0 world. No longer can we assume Pens are just one HTML, CSS, and JavaScript “file”, so they needed a bit of a redesign, but doing as little as possible so that existing Embed Themes still work. This was plenty tricky as it was a re-write from Rails to Next.js, with everything needing to be Server-Side Rendered and as lightweight as possible (thank urql!). Time Jumps 00:06 Welcome back to CodePen Land 00:35 What’s new about Pens in CodePen 2.0 05:20 Designing with custom themes in mind 10:40 What the editor looks like in the 2.0 Editor 16:09 Converting old Pens to new Pens 17:20 Debating using Apollo in embeds
-
FOSS Weekly #25.41: Windows 11 Fiasco, Ubuntu 25.10 Releasing, Joplin Tips, NeoVim Journals and More Linux Stuff
by: Abhishek Prakash Thu, 09 Oct 2025 04:35:13 GMT Microsoft is all set to kill existing methods to set up a local account on fresh Windows 11 installs. I am not really surprised. This is Microsoft being Microsoft. Microsoft Kills Windows 11 Local Account Setup Just as Windows 10 Reaches End of LifeLocal account workarounds removed just before Windows 10 goes dark.It's FOSS NewsSourav RudraAnd this comes just days before Windows 10 support is scheduled to end. And that is a pivotal moment for us desktop Linux users. I have seen an influx of people migrating to Linux when Windows XP and 7 support ended. Some of those went back to Windows with newer systems, whereas some became lifelong Linux users. We are reorganizing and also creating new guides to make the Windows 10 to Linux migration smooth for new users. Please provide your suggestions on what difficulties a new user may face when they switch to Linux and what kind of questions that might have about switching to Linux. Let's work to a broader Linux userbase 💪 💬 Let's see what you get in this edition: A new openSUSE Leap release.Codes of Conduct being called a disaster.Linus being unhappy with some Rust code.And other Linux news, tips, and, of course, memes!📰 Linux and Open Source NewsLinus Torvalds recently called out Rust format checking.openSUSE Leap 16 is here with major modernization work.The FSF has turned 40 and has launched the LibrePhone initiative.Amazon launches the 'Linux-based' Vega OS for its Fire TV devices.Wikidata has launched an open source vector database for use with AI.By the way, Ubuntu 25.10 will be releasing today. Do check out the new features it is getting. Ubuntu 25.10: Release Date and New Features in Questing QuokkaTake a look at the new features and changes you’ll see in the upcoming Ubuntu 25.10 release.It's FOSS NewsSourav Rudra🧠 What We’re Thinking AboutOpen Source legend, Eric S. Raymond, says Codes of Conduct are a disaster. The Man Who Started Open Source Initiative Advocates for Abolishing Codes of ConductBetween Anarchy and Bureaucracy: The Code of Conduct Debate Ignited by Eric Raymond.It's FOSS NewsSourav RudraYou can balance cost and effort if you go the FOSS way as a creative. Beyond Free: The Value Proposition of Open Source for CreativesFOSS is free as in cost, but not free as in effort. The loss of convenience is real, especially at the start. But for creatives who are willing to invest, the long-term rewards—flexibility, control, and a workflow built to last—are more than worth the price.It's FOSS NewsTheena Kumaragurunathan🧮 Linux Tips, Tutorials, and LearningsObsidian + Git = simple version control for ideas.Learn the pros and cons of using Btrfs on a Linux system.Skip the syntax and focus on writing with WYSIWYG Markdown editors for Linux.Speaking of Obsidian and Markdown editors, the popular open source notes software Joplin can be made more effective with these tips. Mastering Joplin Notes: Tips and TweaksJoplin is an awesome open source note taking application. Here’s how you can make the best of it.It's FOSSSreenath👷 AI, Homelab and Hardware CornerIBM has launched Granite 4.0, their hybrid AI model that beats rivals twice its size. IBM Unveils Granite 4.0 Hybrid Model That Competes with Rivals Twice Its SizeThese models sure pack a punch.It's FOSS NewsSourav Rudra✨ Project Highlightstelekasten.nvim is a Neovim Lua plugin that lets you manage a markdown-based zettelkasten/wiki + journal inside Neovim. GitHub - nvim-telekasten/telekasten.nvim: A Neovim (lua) plugin for working with a markdown zettelkasten / wiki and mixing it with a journal, based on telescope.nvimA Neovim (lua) plugin for working with a markdown zettelkasten / wiki and mixing it with a journal, based on telescope.nvim - nvim-telekasten/telekasten.nvimGitHubnvim-telekasten📽️ Videos I Am Creating for YouI don't usually do rant videos but this is a first. An argument against 'sudo apt update' and 'sudo apt upgrade'. Is it time to unify these two into a single command? Please take this opinion video lightly even if you disagree (and you have every right to disagree and express your opinion). Subscribe to It's FOSS YouTube Channel Desktop Linux is mostly neglected by the industry but loved by the community. For the past 13 years, It's FOSS has been helping people use Linux on their personal computers. And we are now facing the existential threat from AI models stealing our content. If you like what we do and would love to support our work, please become It's FOSS Plus member. It costs $24 a year (less than the cost of a McDonald's burger a month), and you get an ad-free reading experience with the satisfaction of helping the desktop Linux community. Join It's FOSS Plus 💡 Quick Handy TipIn the GNOME Files app (Nautilus), you can left-click and drag to select multiple items. To add more items to your selection, hold the CTRL key while dragging; this lets you include additional files lower in the list without losing your previous selection. 🎋 Fun in the FOSSverseTake this personality quiz to find out what kind of terminal user you are. What Type of Terminal User Are You? [Personality Quiz]Find out which terminal persona you are because your Linux habits say more about you than your horoscope ever could.It's FOSSAbhishek Prakash🤣 Meme of the Week: Linux, the savior of old hardware and those wronged by Microsoft and Apple. 🗓️ Tech Trivia: On October 06, 1942, Chester Carlson patented electrophotography, a way to make dry copies of text and images on paper without using ink or chemicals. A few years later, the Haloid Company licensed his patent, renamed the process xerography, and eventually became Xerox, turning document copying into a global industry. 🧑🤝🧑 From the Community: FOSSers are talking about the planned Android sideloading policy change from Google. Got any insights to add? About Android Sideloading Apps Policy ChangesI’ve been reading and seeing videos about some Google policy changes that would affect side-loading of apps on Android in the next few years. Doesn’t sound like it’s going to be a positive change for developers or Free and Open Source projects like F-Droid. I’m wondering what others think of the situation and if they’ve come across any interesting work-arounds to keep side-loaded apps on their phones.It's FOSS CommunityLaura_Michaels❤️ With lovePlease share it with your Linux-using friends and encourage them to subscribe (hint: it's here). Share the articles in Linux Subreddits and community forums. Follow us on Google News and stay updated in your News feed. Opt for It's FOSS Plus membership and support us 🙏 Enjoy FOSS 😄
-
The thing about contrast-color
by: Geoff Graham Wed, 08 Oct 2025 14:52:58 +0000 One of our favorites, Andy Clarke, on the one thing keeping the CSS contrast-color() function from true glory: Word. White and black are two very safe colors to create contrast with another color value. But the amount of contrast between a solid white/black and any other color, while offering the most contrast, may not be the best contrast ratio overall. This was true when added a dark color scheme to my personal website. The contrast between the background color, a dark blue (hsl(238.2 53.1% 12.5%), and solid white (#fff) was too jarring for me. To tone that down, I’d want something a little less opaque than what, say hsl(100 100% 100% / .8), or 20% lighter than white. Can’t do that with contrast-color(), though. That’s why I reach for light-dark() instead: body { color: light-dark(hsl(238.2 53.1% 12.5%), hsl(100 100% 100% / .8)); } Will contrast-color() support more than a black/white duo in the future? The spec says yes: I’m sure it’s one of those things that ‘s easier said than done, as the “right” amount of contrast is more nuanced than simply saying it’s a ratio of 4.5:1. There are user preferences to take into account, too. And then it gets into weeds of work being done on WCAG 3.0, which Danny does a nice job summarizing in a recent article detailing the shortcomings of contrast-color(). The thing about contrast-color originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
-
Getting Creative With shape-outside
by: Andy Clarke Mon, 06 Oct 2025 15:45:40 +0000 Last time, I asked, “Why do so many long-form articles feel visually flat?” I explained that: Then, I touched on the expressive possibilities of CSS Shapes and how, by using shape-outside, you can wrap text around an image’s alpha channel to add energy to a design and keep it feeling lively. There are so many creative opportunities for using shape-outside that I’m surprised I see it used so rarely. So, how can you use it to add personality to a design? Here’s how I do it. Patty Meltt is an up-and-coming country music sensation. My brief: Patty Meltt is an up-and-coming country music sensation, and she needed a website to launch her new album and tour. She wanted it to be distinctive-looking and memorable, so she called Stuff & Nonsense. Patty’s not real, but the challenges of designing and developing sites like hers are. Most shape-outside guides start with circles and polygons. That’s useful, but it answers only the how. Designers need the why — otherwise it’s just another CSS property. Whatever shape its subject takes, every image sits inside a box. By default, text flows above or below that box. If I float an image left or right, the text wraps around the rectangle, regardless of what’s inside. That’s the limitation shape-outside overcomes. shape-outside lets you break free from those boxes by enabling layouts that can respond to the contours of an image. That shift from images in boxes to letting the image content define the composition is what makes using shape-outside so interesting. Solid blocks of text around straight-edged images can feel static. But text that bends around a guitar or curves around a portrait creates movement, which can make a story more compelling and engaging. CSS shape-outside enables text to flow around any custom shape, including an image’s alpha channel (i.e., the transparent areas): img { float: left; width: 300px; shape-outside: url('patty.webp'); shape-image-threshold: .5; shape-margin: 1rem; } First, a quick recap. For text to flow around elements, they need to float either left or right and have their width defined. The shape-outside URL selects an image with an alpha channel, such as a PNG or WebP. The shape-image-threshold property sets the alpha channel threshold for creating a shape. Finally, there’s the shape-margin property which — believe it or not — creates a margin around the shape. Interactive examples from this article are available in my lab. Multiple image shapes When I’m adding images to a long-form article, I ask myself, “How can they help shape someone’s experience?” Flowing text around images can slow people down a little, making their experience more immersive. Visually, it brings text and image into a closer relationship, making them feel part of a shared composition rather than isolated elements. Columns without shape-outside applied to them Patty’s life story — from singing in honky-tonks to headlining stadiums — contains two sections: one about her, the other about her music. I added a tall vertical image of Patty to her biography and two smaller album covers to the music column: <section id="patty"> <div> <img src="patty.webp" alt=""> [...] </div> <div> <img src="album-1.webp" alt=""> [...] <img src="album-2.webp" alt=""> [...] </div> </section> A simple grid then creates the two columns: #patty { display: grid; grid-template-columns: 2fr 1fr; gap: 5rem; } I like to make my designs as flexible as I can, so instead of specifying image widths and margins in static pixels, I opted for percentages on those column widths so their actual size is relative to whatever the size of the container happens to be: #patty > *:nth-child(1) img { float: left; width: 50%; shape-outside: url("patty.webp"); shape-margin: 2%; } #patty > *:nth-child(2) img:nth-of-type(1) { float: left; width: 45%; shape-outside: url("album-1.webp"); shape-margin: 2%; } #patty > *:nth-child(2) img:nth-of-type(2) { float: right; width: 45%; shape-outside: url("album-2.webp"); shape-margin: 2%; } Columns with shape-outside applied to them. See this example in my lab. Text now flows around Patty’s tall image without clipping paths or polygons — just the natural silhouette of her image shaping the text. Building rotations into images. When an image is rotated using a CSS transform, ideally, browsers would reflow text around its rotated alpha channel. Sadly, they don’t, so it’s often necessary to build that rotation into the image. shape-outside with a faux-centred image For text to flow around elements, they need to be floated either to the left or right. Placing an image in the centre of the text would make Patty’s biography design more striking. But there’s no center value for floats, so how might this be possible? Patty’s image set between two text columns. See this example in my lab. Patty’s bio content is split across two symmetrical columns: #dolly { display: grid; grid-template-columns: 1fr 1fr; } To create the illusion of text flowing around both sides of her image, I first split it into two parts: one for the left and the other for the right, both of which are half, or 50%, of the original width. Splitting the image into two pieces. Then I placed one image in the left column, the other in the right: <section id="dolly"> <div> <img src="patty-left.webp" alt=""> [...] </div> <div> <img src="patty-right.webp" alt=""> [...] </div> </section> To give the illusion that text flows around both sides of a single image, I floated the left column’s half to the right: #dolly > *:nth-child(1) img { float: right; width: 40%; shape-outside: url("patty-left.webp"); shape-margin: 2%; } …and the right column’s half to the left, so that both halves of Patty’s image combine right in the middle: #dolly > *:nth-child(2) img { float: left; width: 40%; shape-outside: url("patty-right.webp"); shape-margin: 2%; } Faux-centred image. See this example in my lab. Faux background image So far, my designs for Patty’s biography have included a cut-out portrait with a clearly defined alpha channel. But, I often need to make a design that feels looser and more natural. Faux background image. See this example in my lab. Ordinarily, I would place a picture as a background-image, but for this design, I wanted the content to flow loosely around Patty and her guitar. Large featured image So, I inserted Patty’s picture as an inline image, floated it, and set its width to 100%; <section id="kenny"> <img src="patty.webp" alt=""> [...] </section> #kenny > img { float: left; width: 100%; max-width: 100%; } There are two methods I might use to flow text around Patty and her guitar. First, I might edit the image, removing non-essential parts to create a soft-edged alpha channel. Then, I could use the shape-image-threshold property to control which parts of the alpha channel form the contours for text wrapping: #kenny > img { shape-outside: url("patty.webp"); shape-image-threshold: 2; } Edited image with a soft-edged alpha channel However, this method is destructive, since much of the texture behind Patty is removed. Instead, I created a polygon clip-path and applied that as the shape-outside, around which text flows while preserving all the detail of my original image: #kenny > img { float: left; width: 100%; max-width: 100%; shape-outside: polygon(…); shape-margin: 20px; } Original image with a non-destructive clip-path. I have little time for writing polygon path points by hand, so I rely on Bennett Feely’s CSS clip-path maker. I add my image URL, draw a custom polygon shape, then copy the clip-path values to my shape-outside property. Bennett Feely’s CSS clip path maker. Text between shapes Patty Meltt likes to push the boundaries of country music, and I wanted to do the same with my design of her biography. I planned to flow text between two photomontages, where elements overlap and parts of the images spill out of their containers to create depth. Text between shapes. See this example in my lab. So, I made two montages with irregularly shaped alpha channels. Irregularly shaped alpha channels I placed both images above the content: <section id="johnny"> <img src="patty-1.webp" alt=""> <img src="patty-2.webp" alt=""> […] </section> …and used those same image URLs as values for shape-outside: #johnny img:nth-of-type(1) { float: left; width: 45%; shape-outside: url("patty-1.webp"); shape-margin: 2%; } #johnny img:nth-of-type(2) { float: right; width: 35%; shape-outside: url("img/patty-2.webp"); shape-margin: 2%; } Content now flows like a river in a country song, between the two image montages, filling the design with energy and movement. Conclusion Too often, images in long-form content end up boxed in and isolated, as if they were dropped into the page as an afterthought. CSS Shapes — and especially shape-outside — give us a chance to treat images and text as part of the same composition. This matters because design isn’t just about making things usable; it’s about shaping how people feel. Wrapping text around the curve of a guitar or the edge of a portrait slows readers down, invites them to linger, and makes their experience more immersive. It brings rhythm and personality to layouts that might otherwise feel flat. So, next time you reach for a rectangle, pause and think about how shape-outside can help turn an ordinary page into something memorable. Getting Creative With shape-outside originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
-
Chris’ Corner: Discontent
by: Chris Coyier Mon, 06 Oct 2025 15:16:00 +0000 Nothing is above a little healthy criticism. Here’s Den Odell’s article We Keep Reinventing CSS, but Styling Was Never the Problem. If I can critique the critique, it makes some good and astute points, but pitting CSS evolution as the enemy up front doesn’t sit right. CSS itself, in my opinion, is doing great. It’s not the job of CSS to chase trends or bend toward fickle developer tooling trends. To be fair, Den also says it’s not really the fault of CSS, it’s a matter of choosing trade-offs with your eyes open, which I fully agree with. Jono Alderson isn’t pleased, really, with modern web development entirely. I’ll quote some of his intro: Go look around at “modern” media-driven sites and you’ll see he’s not wrong. We all see it every day. It’s almost embarrassing these days to tell people you make websites, because everybody knows websites are pretty rough these days. If I can, again, critique the critique, it’s that nobody (you, me, Jono) need to do this. The web isn’t forcing us to do this. The web is amazingly backward compatible. If you are nostalgic for some way of building websites gone by, well, just start doing it that way again, because it will still work. Jono does mention this, but misses naming the real enemy: the companies themselves that put up with this and hire specifically to enforce it. I can and do say you don’t need to build websites with the latest in JavaScript cargo-culting, but in order to get a decent paying job in web development, well, you just might have to. That’s the real shame here. Yes this is a problem, and we’re not going to fix it unless companies start writing checks to employees to remove cruft and remove complexity and give freedom to developers who care to improve the situation. For a random little bonus… ain’t it a shame the lack of love for sin() and cos() in CSS? Most hated?! Jeepers.
-
Can't Recall the Syntax? Try These WYSIWYG Markdown Editors on Linux
by: Community Mon, 06 Oct 2025 15:05:57 GMT From GitHub repositories to technical documentation, Markdown is an extremely popular lightweight markup language. Basically, markdown files are plain text, but they follow certain syntax and when they are rendered, you see a beautiful document with headings, bullet points, code boxes and more. There are many Markdown editors available for Linux users but mostly they are two paned editors where you write in Markdown syntax in left and it gets rendered on the other side. Though lightweight and easy to begin with, you still have to get yourself familiar with Markdown syntax. That might be out of the comfort zone for many. This is why I have compiled a list of markdown editors with WYSIWYG feature. WYSIWYG sounds like one of those 2000s terms that didn't succeed, but actually is an acronym for an extremely convenient category of editing software. WYSIWYG stands for "What You See is What You Get" and these editors render the Markdown code in real time and shows the output immediately as the code is typed in. Best of all, you get a toolbar that you can use to easily create formatted text. WYSIWYG editors come with toolbar and you don't need to remember syntax, although you can still use themThis makes things a lot easier, especially for people who have to work with Markdown once in a while. Let's see what WYSIWYG Markdown editors you can use on Linux. ✋Non-FOSS Warning! Some of the applications mentioned here are not open source. They have been included in the context of Linux usage.1. MarkTextMarkText is an Electron based modern-looking editor that offers a simple and clean working environment. The features are: Interface: Custom, minimal, desktop-environment-independent single-pane interface.Highlight features: Several writing modes (such as Focus mode, Typewriter mode, Source Code mode, each with a different emphasis), options for formatting and block options on the menu.Navigation: Sidebar for file tree and table of contents, tab bar for open files; all optional.Exports to: HTML, PDFCustomizability: 6 inbuilt themesMisc.: A searchable Command Palette for easy access to keyboard shortcuts for all possible commands that can be given to the editor and the text blocks.MarkText is your ideal choice if what you need is a no-fuss editor that gets the job done. Another advantage is that the DE-independent Electron interface works consistently in any OS, leaving you not to worry about visual inconsistencies. Install MarkText on LinuxMarkText is easy to install because it comes in both AppImage and Flatpak formats, which makes it available straight from the software store in certain distributions. AUR contains the package for direct installation, too. If none of these option are suitable, the binary file is available on the GitHub page as well. 2. MarknoteA part of the KDE software ensemble, Marknote is a great option if you're on a KDE distribution. It comes with a structure where you can create multiple notebooks and notes within them for better organization. Interface: Qt graphic kit, KDE style.Highlight features: Easily accessible bottom panel for quickly formatting text and adding blocks.Navigation: The notes are organized in notebooks, which shows on a sidebar. Focus Mode that hides all navigation options except for the note being edited, for a cleaner view.Exports to: HTML, ODT, PDFCustomizability: Inbuilt Qt Breeze themesMisc.: A Command Bar that gives easy access to some general operations such as making/deleting notes, etc.🚧Marknote seems to support a limited set of Markdown code, such as headings, italics, bold, lists etc. There is a lack of support for code-blocks and quotations and so on. Some inspection is required to check if it might fit your needs or not.Marknote should be your go-to option if you want to get straight to work with all options within very easy grasp. It is worth noting that it is not as customizable as KDE software usually is. Another important reminder is that it might not look great or very native on a DE like GNOME or Cinnamon. Install Marknote on LinuxInstalling Marknote is easier through either Flatpak or the Snapstore. There are binaries available, too, which can be found on the product page under releases. 3. MarkFlowyMarkFlowy is a modern, rising Markdown editor that flaunts a slick interface and AI capabilities. Interface: Custom independent design with a very clean look.Highlight features: There is an easy access toolbar on top for various formatting and code-block options. There are Source Code and WYSIWYG modes both available, and an AI input feature in the side panel.Navigation: Optional, toggle-able file tree on the left and table of contents on the right.Exports to: HTML, JPGCustomizability: A bright and a dark inbuilt theme with the option for custom CSS themes.Misc.: There are customizable keybindings, and the AI interface settings can be configured as well. There is an optional autosave feature, that might come in handy for a lot of users.While MarkFlowy is still in the beta stage at the time of writing this, the application shows a lot of promise and is quite stable and lightweight as it is. Install MarkFlowy on LinuxMarkFlowy is available in DEB, RPM and AppImage formats, available on the release page. I had some issues with AppImage but the RPM package worked flawlessly on Fedora. 4. NotesnookNotesnook is foremost a note-taking app that looks more like a document editor than a note-making app, which might be more comfortable for certain users. It is great in terms of organization of ideas. Interface: The interface is designed like a notebook with all formatting and code-block options on the menu on top.Highlight features: Multiple notebooks can be made, with the possibility to make an account and syncing them across devices. There is a Focus mode that hides the everything apart from the active note.Navigation: There is a categorical notebook panel on the left, with notes within it in the panel in the middle. The notes can be opened in multiple tabs like a browser.Exports to: HTML, Text, but only all notes at once.Customizability: There are light and dark modes built in for multiple theme styles by default, and more can be added over that.Misc.: End-to-end encryption of notes is available for synced notes, with bidirectional note linking, and an app lock is available as well.There are paid tiers available as well for the app which provide more features and storage for the online storage, such as an unlimited amount of notebooks as opposed to the free tier's 20 limit. Install Notesnook on LinuxNotesnook is available as Flatpak, AppImage as well as on the Snapstore on the official website. ✋Non-FOSS Warning! Some of the applications mentioned here are not open source. They have been included in the context of Linux usage.5. Znote (not FOSS)Znote is another up-and-coming freemium-type model Markdown note making app that puts emphasis on AI and organization. WYSIWYG is one of the available options with a Source Code Mode, or a panned view as well. I liked it for the fact that is the effort of a lone developer. Interface: The interface is modern and peppy with important options well within the view of the note itself. It is easily accessible and editable, with the AI asking option on the bottom of the window.Highlight features: Apart from the usual note-making, there is a unique option of audio recording. The notes can be synced with an internal Znote account across devices. Keybinding menu can be accessed very easily using a button on the bottom.Navigation: A collapsible menu on the left shows a file tree as well as bookmarks. The notes appear in a tabbed view.Exports to: HTML, PDF, TXTCustomizability: There are several options for the light and dark themes separately within the application.Misc.: AI features like copying responses and summarizing notes is available. You can even run code for certain languages within the app itself. Many of these features come with the paid version, though.While there are paid versions that provide more features, the free plan gets the job done as well, and that too, quite smoothly. Install Znote on LinuxThe app is only available as an AppImage on Linux, right on the official website. 6. Typora (not FOSS)Typora, albeit not FOSS, is one of the most popular Markdown editors that has been around for a while. It is designed to be very simple, elegant and feature-rich. That's one of the reasons why I included in this list. Interface: Fairly streamlined interface with a top menu and a status bar.Highlight features: There are Focus and Typewriter modes for more efficient workflow.Navigation: Optional, toggle-able side bar with a file tree and outline menu.Exports to: HTML, ODT, PDF, DOCX, LaTeX, ePub, etc.Customizability: 5 inbuilt themes, all with very different looks, fonts and feel. Other than that, a plethora of themes are available on the website.Misc.:Typora has a free trial of 15 days, after which a license needs to be bought, which is a major drawback. Install Typora on LinuxThere is a Flatpak available, which is the simplest option. Other than that, the install page provides an option to add a repository on Debain based distributions, a DEB file for direct installation, as well as binary files. 7. Octarine (not FOSS)Another non-FOSS entry but Octarine is a really loaded Markdown editor with interesting features left and right. It has a free tier plan that has most of the necessary features. Interface: Clean interface but with all the extra options within easy reach for the users.Highlight features: Multiple workspaces, easily searchable keyboard shortcuts.Navigation: The file is opened in a tabbed view, with a file tree on a panel on the left, with collapsible code blocks in the file itself.Exports to: No export options, the text remains within the app.Customizability: 3 inbuilt themes for the free version, with 4 more with the paid one.Misc.: There are a lot of extra features, such as syncing with a Git repository, a Graph View (similar to Obsidian), Writing Assistant, Calendar Planner, Command Bar as well as tagging to stitch notes together, but many of these features are for paid versions only.The free tier of Octarine is enough to get a lot of work done but not being able to export them is a big drawback, except when you only have to make personal notes in which case, you can sync them across with Git. There are many more features available with the app that can be explored on the website. Install Octarine on LinuxOctarine provides an AppImage and also DEB, RPM as well as binary files to install on Linux on their [official website](Download Octarine). Embeddable WYSIWYG Markdown Editors for Web DevelopersIn place of a desktop application to write Markdown documents, if you're looking for something you can embed within a web-based project to easily upload and manage formatted text, or even demonstrate the usage of Markdown, you can utilize one of these applications: Toast UI Editor: Toast UI Editor is a ready-to-use JavaScript Markdown editor that can be embedded as a React/Vue wrapper. It boasts a simple workflow with both source code and WYSIWYG options. TUI focuses on an extensible approach with a lot of plugins to access different kinds of features such as UML rendering, colored syntax highlighting etc.Milkdown: Milkdown is an editor engine built on ProseMirror which lets you build your own Markdown editor, with bindings for React and Vue. It is inspired by Typora, and is also very plugin-driven, for things like modifying the syntax, UI, themes, embedding math, etc.MDXEditor: MDXEditor is a React component that works on simplicity and consistent output across all use cases and devices. The code blocks have syntax highlighting and autocomplete among other practical features listed on the website.ConclusionThe ease of usage of Markdown has brought about several options in the market, each offering something that it does better than the others. While I hope that this post has helped you narrow down the choices, I would still encourage trying the applications out yourself. Which one do you think is the best contender on the list? Did we miss the one that you favor? Let us know in the comments below. Cheers! I also feel a little guilty for including some non-open source apps here but those are popular and good and I could not find more open source WYSIWYG Markdown editors. Perhaps you can help me out by suggesting a few? Please mind the WYSIWYG feature. That's what we are looking for here. Article submitted by community member Pulkit Chandak.
-
Module 6: Debugging Automated Services
by: Umair Khurshid Mon, 06 Oct 2025 13:10:10 +0530 This lesson is for paying subscribers only This post is for paying subscribers only Subscribe now Already have an account? Sign in
-
Module 5: Sandboxing Systemd Directives for Safer Automation
by: Umair Khurshid Mon, 06 Oct 2025 13:03:22 +0530 This lesson is for paying subscribers only This post is for paying subscribers only Subscribe now Already have an account? Sign in
-
Module 4: Automated Resource Management With Systemd
by: Umair Khurshid Mon, 06 Oct 2025 12:41:06 +0530 This lesson is for paying subscribers only This post is for paying subscribers only Subscribe now Already have an account? Sign in
-
Module 3: Systemd-nspawn and Machinectl for Repeatable Environments
by: Umair Khurshid Mon, 06 Oct 2025 11:29:31 +0530 This lesson is for paying subscribers only This post is for paying subscribers only Subscribe now Already have an account? Sign in
-
How I am Using Git and Obsidian for Note Version Management
by: Sreenath Sun, 05 Oct 2025 07:22:20 GMT Git is a powerful tool that helps you keep track of changes in your files over time. While it is highly popular among the developer community, you can use Git as a note storage vault. In this case, the source files are Obsidian markdown files. When you use Obsidian for note-taking, Git can be very useful to manage different versions of your notes. You can easily go back to previous versions, undo mistakes, and even collaborate with others. In this tutorial, I'll share how I set up Git with Obsidian on a Linux system, connect it with GitHub or GitLab, and use the Obsidian Git plugin to make version control simple and accessible right inside your notes app. This is all at the beginner level, where all you are doing is setting up Git for your knowledge base version management. 🚧I am assuming you are taking simpler markdown notes, where individual note and file sizes are less. If you are using large notes, you may want to try GitHub Large File Storage, which is out of scope of this article.Step 1: Create a remote repository📋I am going to use GitHub in the examples here. If you use a GitHub alternative repository like GitLab, similar steps should also be valid.Go to the GitHub official webpage and log in to your account. Now, on the profiles page, click on the "Create repository" button. Create a new repositoryProvide all the details. Make sure you have set the repository to private. Once you've entered the necessary details, click on the Create Repository button. Enter Details and CreateThat's it. You have a new private repository, which only you can access. Step 2: Create a simple READMEYou need to create a simple README file in the newly created repo. For this, click on the Create a new file button. Create a new file On the next page, enter the name of the file and add placeholder text. Enter file contents Click on Commit changes and add a message when asked. Done! You have added a simple README to your repo. Step 3: Install Git in your systemNow, let's install Git on your system. I also suggest installing the GitHub or GitLab CLI plugin. Since you are into version control, these CLI tools can greatly improve your experience. 💡With the GitHub or GitLab CLI tool, you can commit and push changes to GitHub/GitLab from the terminal also, in case there is a failure in the Obsidian GUI.In Ubuntu, you can install both Git and the GitHub CLI using the command: sudo apt install git gh For Fedora, use: sudo dnf install git gh For Arch Linux, the package name is a bit different. sudo pacman -S git github-cli If you are using GitLab instead of GitHub, instead of the gh/github-cli package, install glab package. The name is the same on all three of the above Linux distributions. Step 4: Authenticate GitHubOnce you have Git and the GitHub tool installed, you need to authenticate it with user credentials. First, you need to make sure the GitHub credentials are properly saved. For this, you can use libsecret. git config --global credential.helper libsecret Now, let's set the username and email so that Git can understand who is committing changes. Open a terminal and run: git config --global user.name "your username" git config --global user.email "your email" Add username and emailRun the GitHub CLI: gh auth login If you are using GitLab, use: glab auth login 🚧For the rest, I am using GitHub. So. GitLab users should follow their on-screen instructions.It will ask some questions, and you can select a choice and press enter. This is shown in the screenshot below: Initial choicesWhen you press enter, it will open in the browser. You will be prompted to continue as the logged in account. Continue website loginOn the next page, enter the code you are provided in the terminal. Enter the codeThis will ask you to verify the details before proceeding. Check once again and press Authorize github. Confirm loginThat's it. Your device is connected. Close the browser. You can view the terminal got updated with the successful login message. Device connection successStep 5: Clone the repositoryNow that you have set up GitHub, it's time to clone the private notes repo to somewhere convenient for you. I am cloning the repo on my ~/Documents directory. cd ~/Documents git clone git clone https://your-git-remote-repo-link.git You will get a message that you have cloned into an empty repo. This is what we need. Cloned the repositoryYou can open it in file manager to see that the only content in the cloned directory is a .git directory and a README file. Step 6: Copy contentsNow, you have to copy your markdown notes from the earlier location to this new vault location. You can do this using your file manager. While copying, make sure that you copy the .obsidian folder as well. Because your rest of plugins and settings are in the .obsidian directory. The folder is hidden, so use CTRL+H to enable the hidden items and then select all. Copy all contents from existing vaultStep 7: Create a .gitignoreOnce you copy all the contents to the new section, you will notice that you have a .obsidian folder that contains all the plugins and cache files. Usually, this does not need to be pushed to GitHub. So, we will create a .gitignore file in the root vault location. Inside this file, add the content: # to exclude Obsidian's settings (including plugin and hotkey configurations) .obsidian/ # to only exclude plugin configuration. Might be useful to prevent some plugin from exposing sensitive data .obsidian/plugins # OR only to exclude workspace cache .obsidian/workspace.json # to exclude workspace cache specific to mobile devices .obsidian/workspace-mobile.json # Add below lines to exclude OS settings and caches .trash/ .DS_Store 📋The above gitignore code is directly taken from the git plugin documentation.Step 8: Open a new vault in ObsidianOpen Obsidian and click on your vault name in the bottom and select Manage Vaults. Select ManageFrom the new window, select the open button adjacent to "Open a folder as vault". Open an existing vaultIn the file chooser, select the directory you have cloned recently. A new Obsidian is opened with notes in the new location, which is empty as of now. You will be asked to trust the author. This is because you have copied all the contents, including plugins, from previous notes. So, in order for the plugin to work, you need to enable the community plugins, and that needs user permission. Accept that you trust the plugins and continue. Trust authorStep 9: Install the Obsidian Git PluginWe need to get plugins in Obsidian for Git version control. Click on the settings button in Obsidian. Click on the settings button.Go to Community plugins. Click on browse. Here, search for the Git plugin and install it. Search and Install GitOnce installed, enable it. Enable Git PluginYou have set the basics of Git with Obsidian. Click on the Git button in Obsidian to see the Git status. Obsidian Git StatusAs you can see, there is a .gitignore file under changes. Step 10: Stage changesI suggest you stage changes in batches and commit. To stage a file, you can either press the + button adjacent to that file or use the + button on the top menu to stage all. Stage ChangesEverything is under staged now for me: Stage everythingStep 11: Commit and Push🚧I am assuming you are the only one managing the notes, and there is no other collaborator.If you are a solo user of your personal notes, then you can commit the changes and push them to the remote repository. For this, once all changes are staged, use the commit button. Commit all staged changes When commit is finished, use the Push button. Push ChangesStep 12: Pull ChangesLet's say you have edited the notes in another system and pushed the changes to GitHub from there. In this case, when you start on the original system, you should pull the item first from GitHub. Use the Pull button in the Obsidian Git control panel. Pulled files from remoteNow that your local copy is in sync with the main, you can work effortlessly. Wrapping UpThe Git plugin also allows you to automatically commit/pull/push at pre-defined times. But I prefer keeping things under my control and thus prefer following the manual method of handpicking my files. But it's up to you how you want to go about it. Integrating Git with Obsidian is a great way of syncing your notes in the cloud without additional cost.
-
LHB Linux Digest #25.29: Git for DevOps eBook, getfacl, Crontab Recovery and More
by: Abhishek Prakash Fri, 03 Oct 2025 17:22:02 +0530 The Git for DevOps course has been converted into an eBook. Considering that it is less hands-on and more theory, it makes sense to read it as book. LHB Pro members can download the ebook for free from the resources page (scroll down a bit). If you are not a Pro member yet, either opt for one and get access to everything we create or just purchase this eBook. One more chapter has been added to the systemd automation course. I plan to publish the entire course by next week. After that, I'll work to add videos to the Docker course. Stay tuned for more educational content. ⭐If you think your Linux/devops knowledge and experience can be shared in micro-course format, please reach out to me. Remember, some of our courses have been contributed by readers like you. I help with editing so that the courses are easy to understand. This post is for subscribers only Subscribe now Already have an account? Sign in
-
Module 2: Automating Complex Workflows with Targets
by: Umair Khurshid Fri, 03 Oct 2025 15:53:16 +0530 This lesson is for paying subscribers only This post is for paying subscribers only Subscribe now Already have an account? Sign in
-
FOSS Weekly #25.40: Fedora 43 Features, Kernel 6.17, Zorin OS 18, Retro Gaming Setup and More Linux Stuff
by: Abhishek Prakash Thu, 02 Oct 2025 04:43:03 GMT Last month, Austria's armed forces ditched Microsoft Office for LibreOffice. This is surely positive news, but it also makes us think about something crucial. The move to switch to open source is often driven by monetary benefits. Since these organizations often save a hefty amount, should they not contribute some part of their savings back to the open source project they are relying on? What do you think? Austria’s Armed Forces Gets Rid of Microsoft Office (Mostly) for LibreOfficeThe Austrian military prioritizes independence over convenience.It's FOSS NewsSourav Rudra💬 Let's see what you get in this edition: ZimaOS adding a paid tier.A new Linux kernel release.GUI apps in terminal.Fedora floating a proposal on AI.Revamped Proton Mail mobile apps.And other Linux news, tips, and, of course, memes!📰 Linux and Open Source NewsCalibre eBook reader has introduced its first AI feature.Kali Linux 2025.3 is a packed release with many new tools.The mobile apps for Proton Mail have received a major revamp.Austria's armed forces have moved away from Microsoft Office.Linux 6.17 has landed with many performance and reliability buffs.Homelab focused ZimaOS 1.5 adds a paid tier while keeping the core features untouched.The Fedora Project is looking for feedback on its policy for AI-assisted contributions.Fedora 43 is due soon. Here are the new features arriving with it: Fedora 43 Release Date and New FeaturesA close look at the new features coming in Fedora 43.It's FOSS NewsSourav Rudra🧠 What We’re Thinking AboutFOSS is an important consideration for creatives in 2025. From Disillusionment to Freedom: Why Creatives Need FOSS Now More Than EverMore than ever, creative professionals need to exert control over their digital footprint. Big tech will not give us control—we have to take it. Free and Open Source (FOSS) software gives us a path forward. The path isn’t easy, but I argue nothing worthwhile is.It's FOSS NewsTheena KumaragurunathanRuby's ecosystem is under threat from corporations. 🧮 Linux Tips, Tutorials, and LearningsExplore terminal shortcuts to enhance your efficiency. I have shared it in the past too but it's worth a reshare. Speaking of enhancing efficiency, here are a few tips Linux users can use to be more productive. I understand that not everyone is a keyboard shortcut maestro, so here are a few tips to master the finger swipe gesture in GNOME desktop environment. 👷 AI, Homelab and Hardware CornerThese 3D-printed cases for the Raspberry Pi will not disappoint. 13 Amazingly Innovative 3D Printed Cases for Raspberry Pi I Came AcrossSo what if I don’t have a 3D printer to print these cases. I can at least appreciate the creativity.It's FOSSAbhishek KumarRaspberry Pi has quietly launched the 500+, a blingy, faster version of the original 500 model. WebScreen is a crowdfunded secondary display for gamers and creators. The Raspberry Pi can be used for retro gaming, you know. The other Abhishek shows it with his latest work. ✨ Project HighlightsI recently discovered Sync-in, an open source platform that facilitates file sharing, sync, and collaboration. Sync-inThe secure, open-source platform for file storage, sharing, collaboration, and syncing. - Sync-inGitHubAnother interesting tool I discovered is term.everything which allows you to run 'any' GUI app in the terminal. I am still exploring it and will be doing a full review soon. GitHub - mmulet/term.everything: Run any GUI app in the terminal❗Run any GUI app in the terminal❗. Contribute to mmulet/term.everything development by creating an account on GitHub.GitHubmmulet🛍️ Deal worth a lookThis ebook bundle from No Starch is a curated collection of titles to help you explore embedded electronics with Raspberry Pi and Arduino. Plus, your purchase supports the Electronic Frontier Foundation. Humble Tech Book Bundle: Electronics for the Curious by No StarchPay what you want to deepen your knowledge of video games and technology with our latest Tech Book Bundle: Electronics for the Curious.Humble Bundle📽️ Videos I Am Creating for YouZorin OS 18 is coming up with new features specially planned for new Linux users who are migrating from Windows 10. I discuss those features in the latest video. Subscribe to It's FOSS YouTube Channel Desktop Linux is mostly neglected by the industry but loved by the community. For the past 13 years, It's FOSS has been helping people use Linux on their personal computers. And we are now facing the existential threat from AI models stealing our content. If you like what we do and would love to support our work, please become It's FOSS Plus member. It costs $24 a year (less than the cost of a McDonald's burger a month), and you get an ad-free reading experience with the satisfaction of helping the desktop Linux community. Join It's FOSS Plus 💡 Quick Handy TipIn Firefox, you can forget about one site, by erasing its browsing history, download history, cookies, login, etc. First, go to Menu → History → Manage History. Here, locate the website you want to forget about (one of those spicy ones, perhaps?), right-click on the website, and then select "Forget About This Site..." When asked, click on "Clear data" to clear any data related to that website. Following this method means that the website will be gone forever from your history, unless you visit it again. 🎋 Fun in the FOSSverseSeeing Halloween is close, are you in the mood to hunt a Daemon in our latest crossword? Daemon Hunter: Crossword EditionBackground processes, foreground fun! Can you summon all the daemons and solve this Linux crossword?It's FOSSAbhishek Prakash🤣 Meme of the Week: One of the worst crimes in the world of Linux. 🗓️ Tech Trivia: On October 2, 1955, the ENIAC, the world’s first general-purpose electronic computer, was retired. Built by John Mauchly and J. Presper Eckert, it could perform 5,000 operations per second. 🧑🤝🧑 From the Community: Pro FOSSer Neville asked a really important question in the forum a few days ago, and the replies on that so far have been wonderful. Why do people come to this forum? Feedback pleaseLets see if we can find out what aspects of this forum are most appreciated by our members. I will start it off. What I mostly appreciate from this forum is some mental challenge helping to solve computing issues inspiration… the flow of new ideas Can each of you attempt to summarize what you see as important or rewarding in our forum.?It's FOSS CommunitynevjFellow Pro FOSSer Xander started a thread, asking for ideas to make the most unusable desktop environment. ❤️ With lovePlease share it with your Linux-using friends and encourage them to subscribe (hint: it's here). Share the articles in Linux Subreddits and community forums. Follow us on Google News and stay updated in your News feed. Opt for It's FOSS Plus membership and support us 🙏 Enjoy FOSS 😄
-
411: The Power of Tree-Sitter
by: Chris Coyier Wed, 01 Oct 2025 13:24:46 +0000 Alex and Chris hop on the show to talk about a bit of technology that Alex calls “The 2nd best technological choice he’s ever made.” That technology is called Tree-sitter. It’s a code parsing tool for building ASTs (Abstract Syntax Trees) out of code. GitHub uses it to power search and “go to” functionality. The creators now work on Zen, where a code parser is paramount. We use it to understand an entire Pen very quickly so we can understand how it all links together (among other things) and make a plan for how to process the Pen (a “build plan”). It’s fast, accurate, forgiving, and extensible. Just a heck of a learning curve. Jump Links 00:07 CodePen 2.0 is more than just a fresh coat of paint 03:00 Treesitter explained 12:04 Making the right choices with technology 21:50 How we parse your code 26:10 We don’t want you to have to be in config hell 28:48 Type type type stop see what happens
-
Same Idea, Different Paint Brush
by: Geoff Graham Wed, 01 Oct 2025 13:02:47 +0000 There’s the idiom that says everything looks like a nail when all you have is a hammer. I also like the one about worms in horseradish seeing the world as horseradish. That’s what it felt like for me as I worked on music for an album of covers I released yesterday. I was raised by my mother, a former high school art teacher (and a gifted artist in her own right), who exposed me to a lot of different tools and materials for painting and drawing. I’m convinced that’s what pointed me in the direction of web development, even though we’re talking years before the internet of AOL and 56K dial-up modems. And just as there’s art and craft to producing a creative 2D visual on paper with wet paint on a brush, there’s a level of art and craft to designing user interfaces that are written in code. You might even say there’s a poetry to code, just as there’s code to writing poetry. I’ve been painting with code for 20 years. HTML, CSS, JavaScript, and friends are my medium, and I’ve created a bunch of works since then. I know my mom made a bunch of artistic works in her 25+ years teaching and studying art. In a sense, we’re both artists using a different brush to produce works in different mediums. Naturally, everything looks like code when I’m staring at a blank canvas. That’s whether the canvas is paper, a screen, some Figma artboard, or what have you. Code is my horseradish and I’ve been marinating in this horseradish ocean for quite a while. This is what’s challenging to me about performing and producing an album of music. The work is done in a different medium. The brush is no longer code (though it can be) but sounds, be them vibrations that come from a physical instrument or digital waves that come from a programmed beat or sample. There are parallels between painting with code and painting with sound, and it is mostly a matter of approach. The concepts, tasks, and challenges are the same, but the brush and canvas are totally different. What’s in your stack? Sound is no different than the web when it comes to choosing the right tools to do the work. Just as you need a stack of technical tools to produce a website or app, you will need technical tools to capture and produce sounds, and the decision affects how that work happens. For example, my development environment might include an editor app for writing code, a virtual server to see my work locally, GitHub for version control and collaboration, some build process that compiles and deploys my code, and a host that serves the final product to everyone on the web to see. Making music? I have recording software, microphones, gobs of guitars, and an audio interface that connects them together so that the physical sounds I make are captured and converted to digital sound waves. And, of course, I need a distributor to serve the music to be heard by others just as a host would serve code to be rendered as webpages. Can your website’s technical stack be as simple as writing HTML in a plain text editor and manually uploading the file to a hosting service via FTP? Of course! Your album’s technical stack can just as easily be a boombox with a built in mic and recording. Be as indie or punk as you want! Either way, you’ve gotta establish a working environment to do the work, and that environment requires you to make decisions that affect the way you work, be it code, music, or painting for that matter. Personalize your process and make it joyful. It’s the “Recording Experience” (EX) to what we think of as Developer Experience (DX). What’re you painting on? If you’re painting, it could be paper. But what kind of paper? Is college-rule cool or do you need something more substantial with heavier card stock? You’re going to want something that supports the type of paint you’re using, whether it’s oil, water, acrylic… or lead? That wouldn’t be good. On the web, you’re most often painting on a screen that measures its space in pixel units. Screens are different than paper because they’re not limited by physical constraints. Sure, the hardware may pose a constraint as far as how large a certain screen can be. But the scene itself is limitless where we can scroll to any portion of it that is not in the current frame. But please, avoid AJAX-based infinite scrolling patterns in your work for everyone’s sake. I’m also painting music on a screen that’s as infinite as the canvas of a webpage. My recording software simply shows me a timeline and I paint sound on top of time, often layering multiple sounds at the same point in time — sound pictures, if you will. That’s simply one way to look at it. In some apps, it’s possible to view the canvas as movements that hold buckets of sound samples. Same thing with code. Authoring code is as likely to happen in a code editor you type into as it is to happen with a point-and-click setup in a visual interface that doesn’t require touching any code at all (Dreamweaver, anyone?). Heck, the kids are even “vibe” coding now without any awareness of how the code actually comes together. Or maybe you’re super low-fi and like to sketch your code before sitting behind a keyboard. How’re people using it? Web developers be like all obsessed with how their work looks on whatever device someone is using. I know you know what I’m talking about because you not only resize browsers to check responsiveness but probably also have tried opening your site (and others!) on a slew of different devices. ⚠️ Auto-playing media It’s no different with sound. I’ve listened to each song I’ve recorded countless times because the way they sound varies from speaker to speaker. There’s one song in particular that I nearly scrapped because I struggled to get it sounding good on my AirPods Max headphones that are bass-ier than your typical speaker. I couldn’t handle the striking difference between that and a different output source that might be more widely used, like car speakers. Will anyone actually listen to that song on a pair of AirPods Max headphones? Probably not. Then again, I don’t know if anyone is viewing my sites on some screen built into their fridge or washing machine, but you don’t see me rushing out to test that. I certainly do try to look at the sites I make on as many devices as possible to make sure nothing is completely busted. You can’t control what device someone uses to look at a website. You can’t control what speakers someone uses to listen to music. There’s a level of user experience and quality assurance that both fields share. There’s a whole other layer about accessibility and inclusive design that fits here as well. There is one big difference: The cringe of listening to your own voice. I never feel personally attached to the websites I make, but listening to my sounds takes a certain level of vulnerability and humility that I have to cope with. The creative process I mentioned it earlier, but I think the way music is created shares a lot of overlap with how websites are generally built. For example, a song rarely (if ever) comes fully formed. Most accounts I read of musicians discussing their creative process talk about the “magic” of a melody in which it pretty much falls in the writer’s lap. It often starts as the germ of an idea and it might take minutes, days, weeks, months, or even years to develop it into a comprehensive piece of work. I keep my phone’s Voice Memos app at the ready so that I’m able to quickly “sketch” ideas that strike me in the moment. It might simply be something I hum into the phone. It could be strumming a few chords on the guitar that sound really nice together. Whatever it is, I like to think of those recordings as little low-fidelity sketches, not totally unlike sketching website layouts and content blocks with paper and pencil. I’m partial to sketching websites on paper and pencil before jumping straight into code. It’s go time! And, of course, there’s what you do when it’s time to release your work. I’m waist-deep in this part of the music and I can most definitely say that shipping an album has as many moving parts, if not more, than deploying a website. But they both require a lot of steps and dependencies that complicate the process. It’s no exaggeration that I’m more confused and lost about music publishing and distribution than I ever felt learning about publishing and deploying websites. It’s perfectly understandable that someone might get lost when hosting a website. There’s so many ways to go about it, and the “right” way is shrouded in the cloak of “it depends” based on what you’re trying to accomplish. Well, same goes for music, apparently. I’ve signed up for a professional rights organization that establishes me as the owner of the recordings, very similar to how I need to register myself as the owner of a particular web domain. On top of that, I’ve enlisted the help of a distributor to make the songs available for anyone to hear and it is exactly the same concept as needing a host to distribute your website over the wire. I just wish I could programmatically push changes to my music catalog. Uploading and configuring the content for an album release reminds me so much of manually uploading hosted files with FTP. Nothing wrong with that, of course, but it’s certainly an opportunity to improve the developer recording experience. So, what? I guess what triggered this post is the realization that I’ve been in a self-made rut. Not a bad one, mind you, but more like being run by an automated script programmed to run efficiently in one direction. Working on a music project forced me into a new context where my development environment and paint brush of code are way less effective than what I need to get the job done. It’s sort of like breaking out of the grid. My layout has been pretty fixed for some time and I’m drawing new grid tracks that open my imagination up to a whole new way of work that’s been right in front of me the entire time, but drowned in my horseradish ocean. There’s so much we can learn from other disciplines, be it music, painting, engineering, architecture, working on cars… turns out front-end development is like a lot of other things. So, what’s your horseradish and what helps you look past it? Same Idea, Different Paint Brush originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
-
When Should Testing Start in the Development Process? – Complete Guide
by: Neeraj Mishra Wed, 01 Oct 2025 07:33:55 +0000 Typically speaking, developing software is a long series of stages that starts with requirements gathering to development to testing, to final release. Each stage requires the respective members to contribute to the final development of the product in their own capacity. The business analyst’s job is to collect requirements from the client and validate their feasibility with a technical architect. The technical architect studies the whole environment and performs the impact analysis of placing a new solution in it. Based on feasibility, they may recommend changes in the requirements. After long discussions and to and fro of requirements, the development of the product begins. Then the development team faces its own challenges. They encounter unforeseen events while building the software that may require either updating the design or a change in the requirements themselves. Then the next stage of testing arrives when the product is tested against different criteria. Even this stage may push back the software to any of the previous stages based on the nature of the defects found. So, what we understand from all this is that software development is not a linear process. It goes back and forth between many stages that are required to give it a final shape. And hence, the question arises, when should the testing ideally begin? This is what we will explore in detail in the further sections. Why the Timing of Testing Matters? Testing is surely needed to develop a product that is reliable and safe. There’s no doubt about it. But what matters most is the timing when the defect is found. This timing has a direct impact on both the vendor and the clients. If the defect is found in production, it immediately breaks customer trust. Your brand reputation falters instantly in the customer’s eyes. On the other hand, studies have shown that the later a defect is discovered, the more expensive it is to fix it. It is because a software solution is built on a large set of algorithms and logic. Each has an impact on others in terms of data exchange, dependent logic, and the sequence of its flow. A defect found at one spot can leave all other dependent programs and subroutines to fail as well. It may disrupt the complete flow of the code. A wrong logic in generating a value that is used at multiple places can have cascading effects. Hence, it becomes exponentially costly and laborious to fix the defect later than sooner. So, the conclusion is, the sooner you discover a bug, the better it is in all terms. And that leads us to the question: what is the ideal timing when the testing should begin? Of course, it makes no sense to start testing until there’s not enough substance generated. On the other hand, it is equally risky to postpone it to be discovered later, when it will create a higher impact on the overall solution. The Role of Testing in Each Stage of Development To understand the role of testing in each stage, let’s categorize the stages into three phases of development: requirements gathering and design, code development, and integration and deployment. Requirement Gathering and Design In this stage, the testing is applicable to not catch the bugs because there’s no code developed yet. It is mostly about testing the assumptions. Requirements raised by the client must be validated against technical feasibility and alignment with business goals. This kind of testing is at the functional level, where the requirements are tested for their impact on other related processes, both at the business and technical levels. For example, a change in the workflow of the process that follows after a customer places an order may impact the downstream events, like updating the database, customer notification process, and product delivery. A business analyst validates the workflow at the functional level while a technical architect checks for the feasibility of developing such a solution. The earlier the assumptions are uncovered, the less impact it has on the process that follows. Code Development and Unit Testing This is the stage when testing becomes more tangible. In this stage, a unit of functionality is developed, like a stand-alone program, and it can be tested against its expected outputs. The dependent programs’ data and functional exchange need not be developed yet, as the transaction with them can be simulated through hard-coded values. Unit testing intends to check how a single unit of functionality works independently, and if it generates the expected outcome in both ideal and negative scenarios. For effective unit testing, using an automation framework is wiser. testRigor, as a software testing tool, is one such product that can perform this task through simulated scenarios. The ideal testing practice in this stage is to create test cases even before the program has been coded. Its responsibility falls on the developer himself, who is expected to not just write the code but also validate its results honestly. Integration and Deployment After unit testing, which validates the functionality of each component, the integration process comes into play. In this stage, all the different components that were developed and tested separately are brought together, and their performance is tested in relation to each other. While unit testing was about testing a component individually, integration testing tests their relationship. It validates whether the whole is greater than the sum of its parts or not. Once the integration works flawlessly, its usability is checked against customer expectations. This part includes testing the software from a human perspective. All the technical aspects are useful only as long as they can finally meet users’ expectations. This testing can be done on a User Acceptance environment, which is almost a replica of production. Closing Statement: When Should Testing Begin? Having understood the various stages of testing, it is justifiable to ask when the ideal time to start testing is. The simple answer to that is as soon as possible. Before you start testing your product, you must cultivate a mindset of quality within your team at all levels. Testing is not just about finding defects, but primarily about developing a critical outlook towards every stage of development. How fool-proof this requirement is, how robust the code is, will it stand against adverse scenarios? These are the questions that do not require a set stage to begin with. These criteria should be validated right from the start till the deployment phase. So, the final answer is, testing starts right at the moment we start imagining a product. Every requirement must be met with a “What if?” question. Every assumption should be unearthed, and every functionality should be tested against tangible results. Once you cultivate a critical mindset in your team, all your testing endeavours will be its manifestation that will have a deeper impact on the quality of the product. The post When Should Testing Start in the Development Process? – Complete Guide appeared first on The Crazy Programmer.
-
Utilizing My Raspberry Pi 4 for Retro Gaming With RetroPie
by: Abhishek Kumar Wed, 01 Oct 2025 05:59:24 GMT Do you remember the thrill of powering up your old console, the satisfying clunk of the cartridge clicking into place, and the vibrant, pixelated characters that transported you to another realm? Whether you were a Mario fanatic (like me), a Sonic speedster, or a Pokémon trainer, those retro games hold a special place in our hearts. Thanks to RetroPie, you can dive back into your favorite classic games. This is one of the easier projects you can build with Raspberry Pi. Since I use Pi 5 for my homelab setup, I thought of utilizing my older Raspberry Pi 4 for the retro gaming project. In this guide, I will show you how I set up RetroPie on my Raspberry Pi 4. I'll also share some tips for that authentic retro gaming experience. What is RetroPie, again?🚧RetroPie only works till Raspberry Pi 4 and has not seen a new release since 2022. It still works fine with Pi 4.Before I share the setup, let's talk about what RetroPie is. It’s a collection of emulators that enables you to play games from a wide range of classic consoles such as GameBoy, Game Cube, SNES, and PlayStation 1 & 2. You can even play some Microsoft DOS games as well. Think of it as a pre-built package that turns your Pi into a retro gaming console with minimal setup. But there are a few things to understand here. You won't just get access to hundreds of retro games. You'll have to get the game ROMs (digital file of the old classic games) and then upload them to the appropriate emulator folder inside the RetroPie. There are websites that let you download the retro games of your choice. The problem is that downloading ROMs could be illegal in your country. That's the thing about corporate greed. Even if they have not been selling those games and devices for years, they won't let you enjoy that little piece of your childhood. The pure legal way is that if you have those old game cartridges, you can build ROMs on your own. There are specialized devices that let you create ROMs from old cartridges. Retrode 2Stone Age GamerPosted by Aaron Wilson on Nov 25th 2024For more details on retro game ROMs, watch the video below. Ready to get started? Here’s how to set up RetroPie on your Raspberry Pi. What you’ll need: A Raspberry Pi (ideally a Pi 3 or 4 for better performance but could work with Zero as well)A microSD card (at least 16 GB recommended)Official power supply for the Raspberry PiMonitor & HDMI cable (or composite video cable for CRT TVs)Keyboard and mouseController or joysticks (Optional)An internet connection (Optional) ✋The official RetroPie image for the Raspberry Pi 5 isn’t available yet, but you can use Batocera (tutorial coming soon).RetroPie installationThere are two ways of getting RetroPie on a Raspberry Pi: You can install RetroPie from a standalone image by flashing it onto your microSD card.If you’re already running an operating system like Raspberry Pi OS, you can install RetroPie right on top of it.Method 1: Installing from pre-built RetroPie imageI have already downloaded the image on my system from the RetroPie's downloads page. RetroPie pre-built image downloads pageNext, burn it in a microSD card. I am using Raspberry Pi Imager tool but you can use Balena Etcher or even Rufus (if you are on Windows). Select your device (as shown in the image below): I have selected 'No filtering' for my Pi 3Select your "Custom Image": Browse to the downloaded RetroPie image: Choose the installation medium (microSD card): Hit "Next" That's it. Wait for the process to complete and then take out the SD card. Method 2: Installing RetroPie on top of existing Raspberry Pi OS Updating Raspberry Pi OS is the most basic thing you should do first: sudo apt update && sudo apt upgrade -yInstalling necessary packagesWith your Raspberry Pi’s OS updated, it's time to install a couple of essential packages for RetroPie. First, you'll need the “dialog” package, which the RetroPie setup script uses to create dialog boxes in the terminal. Next, the “git” package is crucial as it allows us to clone the setup script repository directly to the Raspberry Pi. You can install both packages by running the following command: sudo apt install -y git dialogCloning the RetroPie setup scriptNow that we’ve got the required packages, let's move on to cloning the RetroPie setup script. This script will install RetroPie on your Raspberry Pi. Switch to your home directory: cdNow, use the commands below to clone the RetroPie setup script into your home directory: git clone --depth=1 https://github.com/RetroPie/RetroPie-Setup.gitRunning the RetroPie setup scriptNext, navigate to the “RetroPie-Setup” directory that was created when you cloned the repository. cd RetroPie-SetupOnce inside the directory, you can start the setup script. This script will handle the installation of all the necessary packages for a few basic emulators. sudo ./retropie_setup.shStarting the installation processYou should now see the RetroPie setup dialog on your screen. Just press OK. The next menu offers several options, but for now, focus on the “Basic Install” option. This will install the core and main packages needed to get RetroPie up and running. Navigate to “Basic Install” using the arrow keys, and press Enter to select it. Confirming the installationYou'll be prompted to confirm whether you want to install the “Core” and “Main” components of RetroPie. Select “Yes” to proceed. 📋Keep in mind that this step might take a while since the Raspberry Pi needs to download and install numerous packages.Once the installation is complete, you’ll return to the main menu of the RetroPie setup script. Final Steps: RebootingFinally, to ensure everything is working correctly, reboot your Raspberry Pi. In the main menu, select the “Perform reboot” option. 💡To have EmulationStation start automatically with your Raspberry Pi, head to the “Configuration / Tools” menu in RetroPie, find the “autostart” option, and select “Start Emulation Station at boot.” This way, it’ll launch on its own every time you power up!Adding Games (ROM's) to RetroPie🚧This guide is for educational purposes only. We’re not liable for any legal issues or promoting piracy. Because it seems that downloading classic game ROMs is illegal even if these games are no longer being sold anywhere. It is up to you to decide if you want to download and use ROMs.So, you've set up RetroPie on your Raspberry Pi, and now you're ready for the fun part- adding games, aka ROMs! What are ROMs?ROMs are essentially digital copies of games from old consoles. They allow you to play your favorite classics on modern hardware, like our little friend Pi here. 📋A quick reminder again - Only download and use ROMs for games you legally own.How to add game ROMs to RetroPieAdding ROMs to your RetroPie setup is easier than you might think. Here's how you can do it: Method 1: Transferring ROM's via USB DriveThis is the most straightforward method. Just format a USB drive to FAT32. I'm doing a Quick format in Windows: In Linux, you can use 'GNOME Disks' utility or a Command line tool like this: sudo mkfs -t vfat /dev/sda1mkfs is a command use to format block storage devices.-t ensures the type of file system /dev/sda1 is the location of my storage device.Create a folder, I named it as "retropie" and plug it into your Pi. RetroPie will automatically create sub-folders for each console. Next, copy your ROM files into the appropriate folders and plug the USB back into your Pi, and RetroPie will handle the rest. Here is the unzipped version of the ROM: Method 2: Transferring ROMs via network transferIf your Raspberry Pi is connected to your home network, you can transfer ROMs directly over WiFi using Samba, SFTP, etc. Here I'm using WinSCP to transfer my ROMs using SFTP: After login, just go to the RetroPie directory or where you want to save your games. I'm saving my ROMs in this directory: /home/user/RetroPie/roms/n64: That's it! Now that your ROMs are added, you're ready to boot up and start gaming. First boot of RetroPieYou'll see the RetroPie splash screen on the first boot, followed by EmulationStation's welcome message. Sorry for the image quality as I don't have a HDMI capture deviceNext, you will be prompted to configure your controller. This only takes a minute, and once it's done, you'll have full control over the system. Once your controller is set up, you'll be taken to the main EmulationStation menu. Here, you'll see a list of all the systems for which you've added ROMs. In my case, it's for Nintendo 64: The interface is clean and easy to navigate. You can use your controller to scroll through the different consoles, select a game, and dive straight into the action. Here I have added the Super Mario 64, a true classic that never gets old. It's showing 2 copies because I've added one compressed and the other one direct. When we select it from the menu, you'll see the familiar startup screen: and there he is - Mario himself, ready for action! The game loads a bit slow but manageable, and with just a press of a button, you are back in the colorful world of Mario. Final Thoughts:While RetroPie is an amazing way to bring back the nostalgia of classic gaming, it's not without its quirks, especially if you are using older Pi models like Pi 3. If you are aiming for a smooth, lag-free experience, I'd highly recommend using a Raspberry Pi 4. RetroPie may not have seen a new release in the last few years but it still works. I'm curious. What does your retro gaming setup look like? What games are you playing? Share your setups and experiences in the comments below.
-
Chris’ Corner: Word Search
by: Chris Coyier Mon, 29 Sep 2025 17:01:13 +0000 My daughter had a little phase of being into Word Searches. I found it to be a cool dad moment when I was like “I’ll make you a tool to make them!”. That’s what she was into. She liked doing them OK, but she really liked the idea of making them. So my tool starts with a blank grid where you can type in your words, then fill in the blanks with random letters, then print it. Perhaps unsurprisingly, this type of simple game with simple well-defined interactions is rife for front-end developer experimentation. Interestingly, I’ve found most takes on HTML/CSS/JavaScript Word Searches to be more about the experience of solving them, which is just as interesting! Let’s look at some. Christian Collosi’s Version on <canvas> Canvas is nice here as lines and arcs can be drawn at really specific coordinates to “circle” the words as you interact with it, and stay circled when you find a correct word. Mads Stoumann’s Pure CSS Version You click on the letters individually, and if the ones you have clicked on match a word, it changes background to let you know you’ve got it. This all happens with <input type="checkbox">s and simpler-than-you’d-think :has(:checked + :checked ...) selectors. Kevin Newcombe’s Responsive word search The responsive-ness of Kevin’s approach here is actually really cool. It doesn’t just scale, it literally changes the columns/rows of the puzzle itself. But I’m actually even more into the SVG-drawn lines where you make guesses and the SVG-drawn circles around the successful guesses. Some sort of similar work here. Kit Jenson’s Word Search in Color Gotta love the aesthetics here! Just not a game you usually see a lot of color in, so nice to see some playing in that direction. Part of what makes me so damn proud of the CodePen community is that this is really the tip of the iceberg of experimentation in this very niche thing. Go around exploring for this sort of thing and you’ll find loads more.
-
Touring New CSS Features in Safari 26
by: Juan Diego Rodríguez Mon, 29 Sep 2025 14:31:16 +0000 A couple of days ago, the Apple team released Safari 26.0! Is it a big deal? I mean, browsers release new versions all the time, where they sprinkle in a couple or few new features. They are, of course, all useful, but there aren’t usually a lot of “big leaps” between versions. Safari 26 is different, though. It introduces a lot of new stuff. To be precise, it adds: 75 new features, 3 deprecations, and 171 other improvements. I’d officially call that a big deal. The WebKit blog post does an amazing job breaking down each of the new (not only CSS) features. But again, there are so many that the new stuff coming to CSS deserves its own spotlight. So, today I want to check (and also try) what I think are the most interesting features coming to Safari. If you are like me and don‘t have macOS to test Safari, you can use Playwright instead. What’s new (to Safari)? Safari 26 introduces several features you may already know from prior Chrome releases. And… I can’t blame Safari for seemingly lagging behind because Chrome is shipping new CSS at a scarily fast pace. I appreciate that browsers stagger releases so they can refine things against each other. Remember when Chrome initially shipped position-area as inset-area? We got better naming between the two implementations. I think what you’ll find (as I did) that many of these overlapping features are part of the bigger effort towards Interop 2025, something WebKit is committed to. So, let’s look specifically at what’s new in Safari 26… at least that’s new to Safari. Anchor positioning Anchor positioning is one of my favorite features (I wrote the guide on it!), so I am so glad it’s arrived in Safari. We are now one step closer to widely available support which means we’re that much closer to using anchor positioning in our production work. With CSS Anchor Positioning, we can attach an absolutely-positioned element (that we may call a “target”) to another element (that we may call an “anchor”). This makes creating things like tooltips, modals, and pop-ups trivial in CSS, although it can be used for a variety of layouts. Using anchor positioning, we can attach any two elements, like these, together. It doesn’t even matter where they are in the markup. <div class="anchor">anchor</div> <div class="target">target</div> Heads up: Even though the source order does not matter for positioning, it does for accessibility, so it’s a good idea to establish a relationship between the anchor and target using ARIA attributes for better experiences that rely on assistive tech. CodePen Embed Fallback We register the .anchor element using the anchor-name property, which takes a dashed ident. We then use that ident to attach the .target to the .anchor using the position-anchor property. .anchor { anchor-name: --my-anchor; /* the ident */ } .target { position: absolute; position-anchor: --my-anchor; /* attached! */ } This positions the .target at the center of the .anchor — again, no matter the source order! If we want to position it somewhere else, the simplest way is using the position-area property. With position-area, we can define a region around the .anchor and place the .target in it. Think of it like drawing a grid of squares that are mapped to the .anchor‘s center, top, right, bottom and left. For example, if we wish to place the target at the anchor’s top-right corner, we can write… .target { /* ... */ position-area: top right; } CodePen Embed Fallback This is just a taste since anchor positioning is a world unto itself. I’d encourage you to read our full guide on it. Scroll-driven animations Scroll-driven animations link CSS animations (created from @keyframes) to an element’s scroll position. So instead of running an animation for a given time, the animation will depend on where the user scrolls. We can link an animation to two types of scroll-driven events: Linking the animation to a scrollable container using the scroll() function. Linking the animation to an element’s position on the viewport using the view() function. Both of these functions are used inside the animation-timeline, which links the animation progress to the type of timeline we’re using, be it scroll or view. What’s the difference? With scroll(), the animation runs as the user scrolls the page. The simplest example is one of those reading bars that you might see grow as you read down the page. First, we define our everyday animation and add it to the bar element: @keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } } .progress { transform-origin: left center; animation: grow linear; } Note: I am setting transform-origin to left so it the animation progresses from the left instead of expanding from the center. Then, instead of giving the animation a duration, we can plug it into the scroll position like this: .progress { /* ... */ animation-timeline: scroll(); } Assuming you’re using Safari 26 or the latest version of Chrome, the bar grows in width from left to right as you scroll down the viewport. CodePen Embed Fallback The view() function is similar, but it bases the animation on the element’s position when it is in view of the viewport. That way, an animation can start or stop at specific points on the page. Here’s an example making images “pop” up as they enter view. @keyframes popup { from { opacity: 0; transform: translateY(100px); } to { opacity: 1; transform: translateY(0px); } } img { animation: popup linear; } Then, to make the animation progress as the element enters the viewport, we plug the animation-timeline to view(). img { animation: popup linear; animation-timeline: view(); } If we leave like this, though, the animation ends just as the element leaves the screen. The user doesn’t see the whole thing! What we want is for the animation to end when the user is in the middle of the viewport so the full timeline runs in view. This is where we can reach for the animation-range property. It lets us set the animation’s start and end points relative to the viewport. In this specific example, let’s say I want the animation to start when the element enters the screen (i.e., the 0% mark) and finishes a little bit before it reaches the direct center of the viewport (we’ll say 40%): img { animation: popup linear; animation-timeline: view(); animation-range: 0% 40%; } CodePen Embed Fallback Once again, scroll-driven animations go way beyond these two basic examples. For a quick intro to all there is to them, I recommend Geoff’s notes. I feel safer using scroll-drive animations in my production work because it’s more of a progressive enhancement that won’t break an experience even if it is not supported by the browser. Even so, someone may prefer reduced (or no) animation at all, meaning we’d better progressively enhance it anyway with prefers-reduced-motion. The progress() function This is another feature we got in Chrome that has made its way to Safari 26. Funny enough, I missed it in Chrome when it released a few months ago, so it makes me twice as happy to see such a handy feature baked into two major browsers. The progress() function tells you how much a value has progressed in a range between a starting point and an ending point: progress(<value>, <start>, <end>) If the <value> is less than the <start>, the result is 0. If the <value> reaches the <end>, the result is 1. Anything in between returns a decimal between 0 and 1. Technically, this is something we can already do in a calc()-ulation: calc((value - start) / (end - start)) But there’s a key difference! With progress(), we can calculate values from mixed data types (like adding px to rem), which isn’t currently possible with calc(). For example, we can get the progress value formatted in viewport units from a numeric range formatted in pixels: progress(100vw, 400px, 1000px); …and it will return 0 when the viewport is 400px, and as the screen grows to 1000px, it progresses to 1. This means it can typecast different units into a number, and as a consequence, we can transition properties like opacity (which takes a number or percentage) based on the viewport (which is a distance length). There’s another workaround that accomplishes this using tan() and atan2() functions. I have used that approach before to create smooth viewport transitions. But progress() greatly simplifies the work, making it much more maintainable. Case in point: We can orchestrate multiple animations as the screen size changes. This next demo takes one of the demos I made for the article about tan() and atan2(), but swaps that out with progress(). Works like a charm! CodePen Embed Fallback That’s a pretty wild example. Something more practical might be reducing an image’s opacity as the screen shrinks: img { opacity: clamp(0.25, progress(100vw, 400px, 1000px), 1); } Go ahead and resize the demo to update the image’s opacity, assuming you’re looking at it in Safari 26 or the latest version of Chrome. CodePen Embed Fallback I’ve clamp()-ed the progress() between 0.25 and 1. But, by default, progress() already clamps the <value> between 0 and 1. According to the WebKit release notes, the current implementation isn’t clamped by default, but upon testing, it does seem to be. So, if you’re wondering why I’m clamping something that’s supposedly clamped already, that’s why. An unclamped version may come in the future, though. Self-alignment in absolute positioning And, hey, check this out! We can align-self and justify-self content inside absolutely-positioned elements. This isn’t as big a deal as the other features we’ve looked at, but it does have a handy use case. For example, I sometimes want to place an absolutely-positioned element directly in the center of the viewport, but inset-related properties (i.e., top, right, bottom, left, etc.) are relative to the element’s top-left corner. That means we don’t get perfectly centered with something like this as we’d expect: .absolutely-positioned { position: absolute; top: 50%; left: 50%; } From here, we could translate the element by half to get things perfectly centered. But now we have the center keyword supported by align-self and justify-self, meaning fewer moving pieces in the code: .absolutely-positioned { position: absolute; justify-self: center; } Weirdly enough, I noticed that align-self: center doesn’t seem to center the element relative to the viewport, but instead relative to itself. I found out that can use the anchor-center value to center the element relative to its default anchor, which is the viewport in this specific example: .absolutely-positioned { position: absolute; align-self: anchor-center; justify-self: center; } CodePen Embed Fallback And, of course, place-self is a shorthand for the align-self and justify-self properties, so we could combine those for brevity: .absolutely-positioned { position: absolute; place-self: anchor-center center; } What’s new (for the web)? Safari 26 isn’t just about keeping up with Chrome. There’s a lot of exciting new stuff in here that we’re getting our hands on for the first time, or that is refined from other browser implementations. Let’s look at those features. The constrast-color() function The constrast-color() isn’t new by any means. It’s actually been in Safari Technology Preview since 2021 where it was originally called color-contrast(). In Safari 26, we get the updated naming as well as some polish. Given a certain color value, contrast-color() returns either white or black, whichever produces a sharper contrast with that color. So, if we were to provide coral as the color value for a background, we can let the browser decide whether the text color is more contrasted with the background as either white or black: h1 { --bg-color: coral; background-color: var(--bg-color); color: contrast-color(var(--bg-color)); } CodePen Embed Fallback Our own Daniel Schwarz recently explored the contrast-color() function and found it’s actually not that great at determining the best contrast between colors: It sucks because there are cases where neither white nor black produces enough contrast with the provided color to meet WCAG color contrast guidelines. There is an intent to extend contrast-color() so it can return additional color values, but there still would be concerns about how exactly contrast-color() arrives at the “best” color, since we would still need to take into consideration the font’s width, size, and even family. Always check the actual contrast! So, while it’s great to finally have constrat-color(), I do hope we see improvements added in the future. Pretty text wrapping Safari 26 also introduces text-wrap: pretty, which is pretty (get it?) straightforward: it makes paragraphs wrap in a prettier way. You may remember that Chrome shipped this back in 2023. But take notice that there is a pretty (OK, that’s the last time) big difference between the implementations. Chrome only avoids typographic orphans (short last lines). Safari does more to prettify the way text wraps: Prevents short lines. Avoids single words at the end of the paragraph. Improves rag. Keeps each line relatively the same length. Reduces hyphenation. When enabled, hyphenation improves rag but also breaks words apart. In general, hyphenation should be kept to a minimum. The WebKit blog gets into much greater detail if you’re curious about what considerations they put into it. Safari takes additional actions to ensure “pretty” text wrapping, including the overall ragging along the text. This is just the beginning! I think these are all the CSS features coming to Safari that you should look out for, but I don’t want you to think they are the only features in the release. As I mentioned at the top, we’re talking about 75 new Web Platform features, including HDR Images, support for SVG favicons, logical property support for overflow properties, margin trimming, and much, much more. It’s worth perusing the full release notes. Touring New CSS Features in Safari 26 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
-
Simulating and Detecting Malware Attacks on Linux With ClamAV
by: Hangga Aji Sayekti Mon, 29 Sep 2025 13:43:24 +0530 Linux may feel secure, but it’s not immune to malware. Servers, VPS, and even IoT devices can be targeted by malicious actors. The good news? You can detect and defend against some threats using ClamAV, an open-source antivirus engine. Now, ClamAV is not your typical antivirus, as it may throw plenty of false positives and you need to analyze if there are actual threats. In this guide, I’ll show you how to simulate malware attacks safely using the EICAR test file (don’t worry, it’s completely harmless!) and how to detect them on your Linux system. By the end, you’ll know how to integrate ClamAV into your workflow for continuous protection. Step 1: Using ClamAVClamAV is an open-source antivirus engine designed for detecting malware, trojans, viruses, and other malicious threats on Linux and Unix systems. Linux servers often host websites, applications, or shared directories. Even though Linux is generally secure, malware can still sneak in via uploads, compromised repos, or misconfigured services. ClamAV helps detect malicious files before they cause damage, acting as a first line of defense in a multi-layered security strategy. How ClamAV works: Signature updates: ClamAV downloads the latest malware definitions via freshclam.Scanning: You scan files or directories with clamscan or clamdscan.Detection: If a file matches a known signature, ClamAV reports it as infected.Optional removal: You can remove or quarantine infected files automatically.Installing ClamAV is straightforward. On Debian-based systems, run: sudo apt update sudo apt install clamav clamav-daemon -y clamav : the main scanning engineclamav-daemon : keeps ClamAV running in the background for faster scansStart the daemon if you want it running continuously: sudo systemctl start clamav-daemon Step 2: Update Virus SignaturesBefore scanning anything, make sure your virus definitions are up-to-date: sudo freshclam ClamAV relies on a signature database. If it’s outdated, it might miss newer malware. Step 3: Simulate a Malware AttackBefore you test ClamAV, you need a “fake malware” file. Enter EICAR. Think of EICAR as a “fake virus” that is completely safe. It was created specifically to test antivirus software without putting your computer at risk. EICAR is not a real virus. it cannot harm your files or steal your data.Antivirus programs, including ClamAV, will detect this file as if it were malware.This allows you to check whether your antivirus is working correctly. A good way for demonstrating malware detection in labs or tutorials. Download the EICAR test file: curl -O https://secure.eicar.org/eicar.com.txt There are other types of test files too: Step 4: Scan the Test FileScan the file manually: clamscan eicar.com.txt Scan the directories: clamscan -r /<directory> 🚧You can also choose to automatically delete files if malware is detected. I advise against it. You must be careful about auto deletion.clamscan --remove /<directory> Step 5: Automate Scans with CronYou can use cron jobs to schedule scans to run automatically. For example, to scan /var/www every day at 3 AM and log results: 0 3 * * * clamscan -r /var/www --log=/var/log/clamav/scan.log 💡Regular scans catch new files before they can cause harm, especially in upload directories.ConclusionClamAV is signature-based, meaning it works best for malware that’s already known and included in its database. It won't work with zero-day malware, fileless attacks, obfuscated/polymorphic malware. Still, it is good to have some sort of defense, especially for scanning new uploaded files and cloned repositories. Of course, up your defenses with firewalls & log monitoring, sandbox the uploaded files and follow best practices.
-
13 Amazingly Innovative 3D Printed Cases for Raspberry Pi I Came Across
by: Abhishek Kumar Sat, 27 Sep 2025 11:22:07 GMT There are plenty of cool cases you can buy for your Raspberry Pi. But here's the thing. Mass-produce products often restrict creativity. And I am glad to live in a connected creative internet where people share their creations with each other. I am going to share some of my favorite 3D printed Raspberry Pi cases I have come across. You may not necessarily purchase them but most of them share their models and files. This gives you an opportunity to test your and your 3D printer's DIY skills. 1. Industrial design Pi caseSource: musicalbigfoot via PrintablesThis case feels like it belongs on the bridge of a spaceship. With its sharp, geometric edges and rugged profile, it looks both futuristic and industrial without going over the top. It’s practical, too: built to snap together cleanly and handle a 40 mm fan without fuss. Features: Ventilation-ready with fan supportPrinted in five pieces, no supports neededRemovable sections for ribbon cable accessHeld together with screws and heat-set inserts for extra strengthPrintables2. Desktop powerhouse with UPSSource: dafa1 via MyMiniFactoryIs it a mini PC? Is it a Raspberry Pi? This case says: why not both. Designed to mimic a high-end gaming rig, it comes complete with a see-through side panel and enough room to tuck in a UPS module for portable or critical-use builds. Features: Acrylic side panel for showcase-worthy buildsSpace for UPS backup batteryOptional OLED display integrationPC-style heatsink support for serious coolingMyMiniFactoryAlthough, you can purchase a tower case like this for your Pi. Pironman 5 Case With Tower Cooler and Fan This dope Raspberry Pi 5 case has a tower cooler and dual RGB fans to keep the device cool. It also extends your Pi 5 with M.2 SSD slot and 2 standard HDMI ports. Explore Pironman 5 3. Mini tower with neon vibesSource: JISpal01 via ThingiverseThis one’s for people who believe tiny tech deserves big style. Designed to house a real heatsink and twin fans, this tower case lights up with neon flair that looks straight out of a cyberpunk anime. Features: Dual-fan duct system with efficient airflowDesigned to reduce filament wasteEasy to assemble with YouTube video supportBuilt to house a functional Ice Tower coolerThingiverse4. The Black (Pi) holeSource: OutpostKodelia via ThingiverseThis might be the most mysterious Pi case ever made. A black hole case for Pi-hole. It's not sleek that can be seen, a bit compact, and definitely complex. And it's not for the faint of heart. Think of it as a black box from space: powerful, but you’ll need some build skills and patience to unlock its potential. Features: Requires thermal insert installationDetailed build guide includedGreat for intermediate to advanced usersThingiverse5. Sci-fi caseSource: aggie6801 via ThingiversePart sculpture, part science experiment, this design is packed with personality. It looks like it teleported in from a parallel timeline where art and engineering are best friends. Best of all? It’s easy to print and assemble. Features: Stylish and functional blendRevised to fit larger heatsinksRequires just six screwsBold look with practical coolingThingiverse6. Art Deco retro shellSource: theprintedcow via PrintablesThis one brings back the glamour of early tech design. Inspired by Art Deco, it combines sweeping lines with modern geometry and works perfectly with dual-color filament to make the design pop. Features: Supports Raspberry Pi 5Snap-fit lid, no screws or supports requiredWorks with the official cooling fanGPIO access preservedPrintables7. Folding caseSource: WalterHsiao via CultsMinimal without being boring, this folding case is perfect for people who move their Pi around a lot. It prints flat and folds into shape, like origami for hardware lovers or like the old-fashioned cigarette cases we see in classic detective shows and movies. Features: Prints flat, wraps around boardNo support material neededGreat for swapping SD cards or quick accessAvailable for multiple Pi modelsCults8. Spaceship dockSource: tipam via ThingiverseThis one’s pure sci-fi goodness. Shaped like a spacecraft, it brings a galactic charm to your Raspberry Pi setup. It’s relatively easy to print, despite its detailed shape. Features: Compatible with Raspberry Pi 3, 4, and 5Printed with flat bottom for support-free setupRequires minimal hardware to assembleLooks fantastic with a metallic filamentPrintables9. Pac-Man & Ghost DuoSource: tomvdb via MyMiniFactoryNostalgia incoming! These two are straight out of the arcade era, one shaped like Pac-Man, the other like his ghostly nemesis. They’re fun, loud, and absolutely not trying to blend in. Features: Built-in vents for passive coolingPerfect for gaming emulator setupsSupports Raspberry Pi 3Just add paint or stickers for the finishing touchMyMiniFactory10. PlayingStation 5Source: Ubermeisters via PrintablesThis isn't just a Raspberry Pi case, it’s a mini console with serious flair. Styled after the PS5, this case is ideal for turning your Pi into a dedicated gaming station. Features: Full "console" enclosure with detailed stylingDesigned for Raspberry Pi 4 and 5Includes magnet slots for satisfying case snapComes with STEP file for mods and upgradesPrintables11. Pi 64Source: elhuff via ThingiverseBuilt to mimic the iconic Nintendo 64, this case hits all the right notes for retro gaming fans. The design even includes suggested colors and detailed assembly instructions. Just add RetroPie and prepare to time travel. Features: N64-inspired design with SD card accessDesigned for Raspberry Pi 3 and 4Includes color suggestions for full nostalgia effectWidely loved with thousands of downloadsThingiverse12. Mini NESSource: serzi via ThingiverseIf you missed the NES Classic Edition craze, no worries, this 3D printed case lets you build your own. Designed to hold a Raspberry Pi 3, it’s perfect for an emulation setup and can be color-customized to your heart’s content. Features: NES-inspired enclosurePrints easily, no supports requiredWorks great with RetroPiePersonalize it with your own paint schemeThingiverseAlthough you can buy a similar case for just $11 from SunFounder. SunFounder Retrogame Case for Raspberry Pi 5Features * Retro Design: Classic design replicating traditional gaming consoles, providing protection and a nostalgic gaming experience.* High-Quality Materials: Durable ABS material with meticulous craftsmanship ensures sturdiness and protection for your Raspberry Pi 5.* Easy Port Access: Provides easy access to all RSunFounderSunFounder13. Appleberry G5Source: MroznyHipis via PrintablesThis one’s a cheeky blend of Apple’s G5 design and Raspberry Pi smarts. Styled after the "cheese grater" Mac Pro, it’s compact and has a clever drawer-slide system for mounting the Pi inside. Features: Snap-in internal drawer designUses just four M2 screwsMagnet slots for secure slide-in actionLooks sleek on any deskPrintablesFinal ThoughtsThis is definitely not an exhaustive list. There are plenty more interesting Raspberry Pi cases you can 3D print. Look at the case below that my outie loves. I know what you might be thinking, these cases aren’t all about practicality, or keeping the Pi small and discreet. But that’s not the point of this article. This was about exploration. About expression. About finding joy in a tiny computer that can wear whatever outfit we imagine for it. And honestly, I find these projects absolutely delightful. What you just saw are some of the most imaginative, playful, and downright fascinating Raspberry Pi cases out there. The creativity of the community never fails to surprise and inspire me. I’m sure I’ve missed a few fan favorites, o if you’ve designed or printed your own custom Pi cases, I’d love to see them. Share your creations with us! We’ll be back with more fascinating Raspberry Pi projects soon. Stay tuned.
-
Recreating Gmail’s Google Gemini Animation
by: John Rhea Fri, 26 Sep 2025 14:45:13 +0000 I always see this Google Gemini button up in the corner in Gmail. When you hover over it, it does this cool animation where the little four-pointed star spins and the outer shape morphs between a couple different shapes that are also spinning. I challenged myself to recreate the button using the new CSS shape() function sprinkled with animation to get things pretty close. Let me walk you through it. Drawing the Shapes Breaking it down, we need five shapes in total: Four-pointed star Flower-ish thing (yes, that’s the technical term) Cylinder-ish thing (also the correct technical term) Rounded hexagon Circle I drew these shapes in a graphics editing program (I like Affinity Designer, but any app that lets you draw vector shapes should work), outputted them in SVG, and then used a tool, like Temani Afif’s generator, to translate the SVG paths the program generated to the CSS shape() syntax. Now, before I exported the shapes from Affinity Designer, I made sure the flower, hexagon, circle, and cylinder all had the same number of anchor points. If they don’t have the same number, then the shapes will jump from one to the next and won’t do any morphing. So, let’s use a consistent number of anchor points in each shape — even the circle — and we can watch these shapes morph into each other. I set twelve anchor points on each shape because that was the highest amount used (the hexagon had two points near each curved corner). Something related (and possibly hard to solve, depending on your graphics program) is that some of my shapes were wildly contorted when animating between shapes. For example, many shapes became smaller and began spinning before morphing into the next shape, while others were much more seamless. I eventually figured out that the interpolation was matching each shape’s starting point and continued matching points as it followed the shape. The result is that the matched points move between shapes, so if the starting point for one shape is on opposite side of the starting point of the second shape, a lot of movement is necessary to transition from one shape’s starting point to the next shape’s starting point. CodePen Embed Fallback Luckily, the circle was the only shape that gave me trouble, so I was able to spin it (with some trial and error) until its starting point more closely matched the other starting points. Another issue I ran into was that the cylinder-ish shape had two individual straight lines in shape() with line commands rather than using the curve command. This prevented the animation from morphing into the next shape. It immediately snapped to the next image without animating the transition, skipping ahead to the next shape (both when going into the cylinder and coming out of it). I went back into Affinity Designer and ever-so-slightly added curvature to the two lines, and then it morphed perfectly. I initially thought this was a shape() quirk, but the same thing happened when I attempted the animation with the path() function, suggesting it’s more an interpolation limitation than it is a shape() limitation. Once I finished adding my shape() values, I defined a CSS variable for each shape. This makes the later uses of each shape() more readable, not to mention easier to maintain. With twelve lines per shape the code is stinkin’ long (technical term) so we’ve put it behind an accordion menu. View Shape Code :root { --hexagon: shape( evenodd from 6.47% 67.001%, curve by 0% -34.002% with -1.1735% -7.7% / -1.1735% -26.302%, curve by 7.0415% -12.1965% with 0.7075% -4.641% / 3.3765% -9.2635%, curve by 29.447% -17.001% with 6.0815% -4.8665% / 22.192% -14.1675%, curve by 14.083% 0% with 4.3725% -1.708% / 9.7105% -1.708%, curve by 29.447% 17.001% with 7.255% 2.8335% / 23.3655% 12.1345%, curve by 7.0415% 12.1965% with 3.665% 2.933% / 6.334% 7.5555%, curve by 0% 34.002% with 1.1735% 7.7% / 1.1735% 26.302%, curve by -7.0415% 12.1965% with -0.7075% 4.641% / -3.3765% 9.2635%, curve by -29.447% 17.001% with -6.0815% 4.8665% / -22.192% 14.1675%, curve by -14.083% 0% with -4.3725% 1.708% / -9.7105% 1.708%, curve by -29.447% -17.001% with -7.255% -2.8335% / -23.3655% -12.1345%, curve by -7.0415% -12.1965% with -3.665% -2.933% / -6.334% -7.5555%, close ); --flower: shape( evenodd from 17.9665% 82.0335%, curve by -12.349% -32.0335% with -13.239% -5.129% / -18.021% -15.402%, curve by -0.0275% -22.203% with -3.1825% -9.331% / -3.074% -16.6605%, curve by 12.3765% -9.8305% with 2.3835% -4.3365% / 6.565% -7.579%, curve by 32.0335% -12.349% with 5.129% -13.239% / 15.402% -18.021%, curve by 20.4535% -0.8665% with 8.3805% -2.858% / 15.1465% -3.062%, curve by 11.58% 13.2155% with 5.225% 2.161% / 9.0355% 6.6475%, curve by 12.349% 32.0335% with 13.239% 5.129% / 18.021% 15.402%, curve by 0.5715% 21.1275% with 2.9805% 8.7395% / 3.0745% 15.723%, curve by -12.9205% 10.906% with -2.26% 4.88% / -6.638% 8.472%, curve by -32.0335% 12.349% with -5.129% 13.239% / -15.402% 18.021%, curve by -21.1215% 0.5745% with -8.736% 2.9795% / -15.718% 3.0745%, curve by -10.912% -12.9235% with -4.883% -2.2595% / -8.477% -6.6385%, close ); --cylinder: shape( evenodd from 10.5845% 59.7305%, curve by 0% -19.461% with -0.113% -1.7525% / -0.11% -18.14%, curve by 10.098% -26.213% with 0.837% -10.0375% / 3.821% -19.2625%, curve by 29.3175% -13.0215% with 7.2175% -7.992% / 17.682% -13.0215%, curve by 19.5845% 5.185% with 7.1265% 0% / 13.8135% 1.887%, curve by 9.8595% 7.9775% with 3.7065% 2.1185% / 7.035% 4.8195%, curve by 9.9715% 26.072% with 6.2015% 6.933% / 9.4345% 16.082%, curve by 0% 19.461% with 0.074% 1.384% / 0.0745% 17.7715%, curve by -13.0065% 29.1155% with -0.511% 11.5345% / -5.021% 21.933%, curve by -26.409% 10.119% with -6.991% 6.288% / -16.254% 10.119%, curve by -20.945% -5.9995% with -7.6935% 0% / -14.8755% -2.199%, curve by -8.713% -7.404% with -3.255% -2.0385% / -6.1905% -4.537%, curve by -9.7575% -25.831% with -6.074% -6.9035% / -9.1205% -15.963%, close ); --star: shape( evenodd from 50% 24.787%, curve by 7.143% 18.016% with 0% 0% / 2.9725% 13.814%, curve by 17.882% 7.197% with 4.171% 4.2025% / 17.882% 7.197%, curve by -17.882% 8.6765% with 0% 0% / -13.711% 4.474%, curve by -7.143% 16.5365% with -4.1705% 4.202% / -7.143% 16.5365%, curve by -8.6115% -16.5365% with 0% 0% / -4.441% -12.3345%, curve by -16.4135% -8.6765% with -4.171% -4.2025% / -16.4135% -8.6765%, curve by 16.4135% -7.197% with 0% 0% / 12.2425% -2.9945%, curve by 8.6115% -18.016% with 4.1705% -4.202% / 8.6115% -18.016%, close ); --circle: shape( evenodd from 13.482% 79.505%, curve by -7.1945% -12.47% with -1.4985% -1.8575% / -6.328% -10.225%, curve by 0.0985% -33.8965% with -4.1645% -10.7945% / -4.1685% -23.0235%, curve by 6.9955% -12.101% with 1.72% -4.3825% / 4.0845% -8.458%, curve by 30.125% -17.119% with 7.339% -9.1825% / 18.4775% -15.5135%, curve by 13.4165% 0.095% with 4.432% -0.6105% / 8.9505% -0.5855%, curve by 29.364% 16.9% with 11.6215% 1.77% / 22.102% 7.9015%, curve by 7.176% 12.4145% with 3.002% 3.7195% / 5.453% 7.968%, curve by -0.0475% 33.8925% with 4.168% 10.756% / 4.2305% 22.942%, curve by -7.1135% 12.2825% with -1.74% 4.4535% / -4.1455% 8.592%, curve by -29.404% 16.9075% with -7.202% 8.954% / -18.019% 15.137%, curve by -14.19% -0.018% with -4.6635% 0.7255% / -9.4575% 0.7205%, curve by -29.226% -16.8875% with -11.573% -1.8065% / -21.9955% -7.9235%, close ); } If all that looks like gobbledygook to you, it largely does to me too (and I wrote the shape() Almanac entry). As I said above, I converted them from stuff I drew to shape()s with a tool. If you can recognize the shapes from the custom property names, then you’ll have all you need to know to keep following along. Breaking Down the Animation After staring at the Gmail animation for longer than I would like to admit, I was able to recognize six distinct phases: First, on hover: The four-pointed star spins to the right and changes color. The fancy blue shape spreads out from underneath the star shape. The fancy blue shape morphs into another shape while spinning. The purplish color is wiped across the fancy blue shape. Then, after hover: The fancy blue shape contracts (basically the reverse of Phase 2). The four-pointed star spins left and returns to its initial color (basically the reverse of Phase 1). That’s the run sheet we’re working with! We’ll write the CSS for all that in a bit, but first I’d like to set up the HTML structure that we’re hooking into. The HTML I’ve always wanted to be one of those front-enders who make jaw-dropping art out of CSS, like illustrating the Sistine chapel ceiling with a single div (cue someone commenting with a CodePen doing just that). But, alas, I decided I needed two divs to accomplish this challenge, and I thank you for looking past my shame. To those of you who turned up your nose and stopped reading after that admission: I can safely call you a Flooplegerp and you’ll never know it. (To those of you still with me, I don’t actually know what a Flooplegerp is. But I’m sure it’s bad.) Because the animation needs to spread out the blue shape from underneath the star shape, they need to be two separate shapes. And we can’t shrink or clip the main element to do this because that would obscure the star. So, yeah, that’s why I’m reaching for a second div: to handle the fancy shape and how it needs to move and interact with the star shape. <div id="geminianimation"> <div></div> </div> The Basic CSS Styling Each shape is essentially defined with the same box with the same dimensions and margin spacing. #geminianimation { width: 200px; aspect-ratio: 1/1; margin: 50px auto; position: relative; } We can clip the box to a particular shape using a pseudo-element. For example, let’s clip a star shape using the CSS variable (--star) we defined for it and set a background color on it: #geminianimation { width: 200px; aspect-ratio: 1; margin: 50px auto; position: relative; &::before { content: ""; clip-path: var(--star); width: 100%; height: 100%; position: absolute; background-color: #494949; } } CodePen Embed Fallback We can hook into the container’s child div and use it to establish the animation’s starting shape, which is the flower (clipped with our --flower variable): #geminianimation div { width: 100%; height: 100%; clip-path: var(--flower); background: linear-gradient(135deg, #217bfe, #078efb, #ac87eb, #217bfe); } What we get is a star shape stacked right on top of a flower shape. We’re almost done with our initial CSS, but in order to recreate the animated color wipes, we need a much larger surface that allows us to “change” colors by moving the background gradient’s position. Let’s move the gradient so that it is declared on a pseudo element instead of the child div, and size it up by 400% to give us additional breathing room. #geminianimation div { width: 100%; height: 100%; clip-path: var(--flower); &::after { content: ""; background: linear-gradient(135deg, #217bfe, #078efb, #ac87eb, #217bfe); width: 400%; height: 400%; position: absolute; } } Now we can clearly see how the shapes are positioned relative to each other: CodePen Embed Fallback Animating Phases 1 and 6 Now, I’ll admit, in my own hubris, I’ve turned up my very own schnoz at the humble transition property because my thinking is typically, Transitions are great for getting started in animation and for quick things, but real animations are done with CSS keyframes. (Perhaps I, too, am a Flooplegerp.) But now I see the error of my ways. I can write a set of keyframes that rotate the star 180 degrees, turn its color white(ish), and have it stay that way for as long as the element is hovered. What I can’t do is animate the star back to what it was when the element is un-hovered. I can, however, do that with the transition property. To do this, we add transition: 1s ease-in-out; on the ::before, adding the new background color and rotating things on :hover over the #geminianimation container. This accounts for the first and sixth phases of the animation we outlined earlier. #geminianimation { &::before { /* Existing styles */ transition: 1s ease-in-out; } &:hover { &::before { transform: rotate(180deg); background-color: #FAFBFE; } } } Animating Phases 2 and 5 We can do something similar for the second and fifth phases of the animation since they are mirror reflections of each other. Remember, in these phases, we’re spreading and contracting the fancy blue shape. We can start by shrinking the inner div’s scale to zero initially, then expand it back to its original size (scale: 1) on :hover (again using transitions): #geminianimation { div { scale: 0; transition: 1s ease-in-out; } &:hover { div { scale: 1; } } CodePen Embed Fallback Animating Phase 3 Now, we very well could tackle this with a transition like we did the last two sets, but we probably should not do it… that is, unless you want to weep bitter tears and curse the day you first heard of CSS… not that I know from personal experience or anything… ha ha… ha. CSS keyframes are a better fit here because there are multiple states to animate between that would require defining and orchestrating several different transitions. Keyframes are more adept at tackling multi-step animations. What we’re basically doing is animating between different shapes that we’ve already defined as CSS variables that clip the shapes. The browser will handle interpolating between the shapes, so all we need is to tell CSS which shape we want clipped at each phase (or “section”) of this set of keyframes: @keyframes shapeshift { 0% { clip-path: var(--circle); } 25% { clip-path: var(--flower); } 50% { clip-path: var(--cylinder); } 75% { clip-path: var(--hexagon); } 100% { clip-path: var(--circle); } } Yes, we could combine the first and last keyframes (0% and 100%) into a single step, but we’ll need them separated in a second because we also want to animate the rotation at the same time. We’ll set the initial rotation to 0turn and the final rotation 1turn so that it can keep spinning smoothly as long as the animation is continuing: @keyframes shapeshift { 0% { clip-path: var(--circle); rotate: 0turn; } 25% { clip-path: var(--flower); } 50% { clip-path: var(--cylinder); } 75% { clip-path: var(--hexagon); } 100% { clip-path: var(--circle); rotate: 1turn; } } Note: Yes, turn is indeed a CSS unit, albeit one that often goes overlooked. We want the animation to be smooth as it interpolates between shapes. So, I’m setting the animation’s timing function with ease-in-out. Unfortunately, this will also slow down the rotation as it starts and ends. However, because we’re both beginning and ending with the circle shape, the fact that the rotation slows coming out of 0% and slows again as it heads into 100% is not noticeable — a circle looks like a circle no matter its rotation. If we were ending with a different shape, the easing would be visible and I would use two separate sets of keyframes — one for the shape-shift and one for the rotation — and call them both on the #geminianimation child div . #geminianimation:hover { div { animation: shapeshift 5s ease-in-out infinite forwards; } } Animating Phase 4 That said, we still do need one more set of keyframes, specifically for changing the shape’s color. Remember how we set a linear gradient on the parent container’s ::after pseudo, then we also increased the pseudo’s width and height? Here’s that bit of code again: #geminianimation div { width: 100%; height: 100%; clip-path: var(--flower); &::after { content: ""; background: linear-gradient(135deg, #217bfe, #078efb, #ac87eb, #217bfe); width: 400%; height: 400%; position: absolute; } } The gradient is that large because we’re only showing part of it at a time. And that means we can translate the gradient’s position to move the gradient at certain keyframes. 400% can be nicely divided into quarters, so we can move the gradient by, say, three-quarters of its size. Since its parent, the #geminianimation div, is already spinning, we don’t need any fancy movements to make it feel like the color is coming from different directions. We just translate it linearly and the spin adds some variability to what direction the color wipe comes from. @keyframes gradientMove { 0% { translate: 0 0; } 100% { translate: -75% -75%; } } One final refinement Instead of using the flower as the default shape, let’s change it to circle. This smooths things out when the hover interaction causes the animation to stop and return to its initial position. And there you have it: CodePen Embed Fallback Wrapping up We did it! Is this exactly how Google accomplished the same thing? Probably not. In all honesty, I never inspected the animation code because I wanted to approach it from a clean slate and figure out how I would do it purely in CSS. That’s the fun thing about a challenge like this: there are different ways to accomplish the same thing (or something similar), and your way of doing it is likely to be different than mine. It’s fun to see a variety of approaches. Which leads me to ask: How would you have approached the Gemini button animation? What considerations would you take into account that maybe I haven’t? Recreating Gmail’s Google Gemini Animation originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.