RSSAmplifier

Blog

Schalk Neethling - Open Web, Open Source, and Web Accessibility

My thoughts, ideas, experiences, and ramblings about code, life, and the open web

schalkneethling.comRSS feed ↗117 posts

Latest posts

Introducing Ephemeral Pages Action v1

Ephemeral Pages Action publishes a self-contained HTML document from a pull-request workflow and posts the temporary link back as a pull-request comment. Version 1.0.0 is now available.

The release process is part of the product

A release is a product workflow. It has users, interfaces, failure states and recovery semantics. Automating eighteen packages onto trusted publishing took four prereleases to get right.

Do We No Longer Care About the Code?

We do. We care about it differently. The attention that used to go into reading the code now goes into the specification, and into the deterministic checks that make non-deterministic tools dependable.

image-orientation: How CSS Solved the EXIF Rotation Problem

In 2012, EXIF orientation handling varied wildly across browsers and web services. The image orientation CSS specification has since standardized how browsers honor that data by default, but there are still edge cases that bite.

Throwing Confetti with CSS Random

Throwing some confetti while exploring the CSS random() function through its specification and its current implementations, finding both the beauty and the pitfalls along the way.

Instantly Get Feature Specific Baseline Component Embed Code

Search the web-features catalog, preview the baseline-status component, and generate the CDN or bundler snippet, all from one small web app.

Because I Want It to Exist

It's been a while since I have listened to a talk and found a real connection with the speaker and what they were sharing. This streak was broken a couple of days ago when I listened to a talk by Ryo Lu at Cursor's Compile 26 conference.

You Might Not Need chalk Anymore

Node.js now ships with util.styleText(), a built-in alternative to chalk for terminal text styling. Here is what it can do, when it is enough, and when you might still reach for a dependency.

Unicode character class escapes. A Hidden JavaScript Superpower

Unicode character class escapes turn regular expressions from English-only ASCII tools into something that understands the whole of human writing. A look at how `\p{L}`, `\p{N}`, `\p{Sc}`, and the `v` flag's properties of strings make this possible.

Contributing a Calavera integration

Project Calavera is a CLI tool that scaffolds linters, formatters, AI tooling, and common project infrastructure for web projects. Calavera ❤️ Vite. This post walks through the full contribution path for a new integration, using the Varlock PR as a concrete example.

How To Think About Unit Tests, With Vitest

A practical guide to thinking about what to test and why, using Vitest as my tool of choice. Covers the happy path, conditionals, purity, and the limits of code coverage as a measure of test quality.

css-expect: browser-backed unit tests for CSS custom functions

css-expect enables you to write unit tests for your CSS @functions using the browser engine itself as the source of truth.

@function — Native Custom Functions in CSS

CSS now has user-defined functions. No preprocessor, no JavaScript, but native @function with typed parameters, local variables, and conditional logic built right into your CSS.

Lowering the Barrier to CSS @property Adoption

CSS @property has been Baseline for almost two years, but most existing projects still do not use it. A small experiment in the CSS Property Type Validator generates a reviewable first draft of @property registrations from the custom properties you already have.

Introducing the CSS Property Type Validator Stylelint Plugin

The first beta of the Stylelint plugin for CSS Property Type Validator brings typed custom property validation directly into your existing CSS linting workflow.

Live Page Content Updates with Supabase Realtime and Web Sockets

How to use Supabase Realtime and Web Sockets to live-update page content in a single-page app.

Announcing Axe Aggregate Reporter: run, report, view, and share a11y results

A Playwright reporter paired with a dependency-free viewer that turns axe accessibility results into one report your team can actually read, share, and act on.

The Security of Ephemeral Pages

A walkthrough of the security vulnerabilities flagged by an AI agent skill review of Ephemeral Pages, and the mitigations put in place as a result.

The day CSS made me learn algebra again, and I liked it

A carousel overlay bug led me to a deep dive into fluid typography, container queries, and understanding clamp().

Branded Types in TypeScript: Making the Compiler Care About Meaning

TypeScript's structural typing means two types with the same shape are interchangeable, but sometimes this is not what you want. Branded types fix that by adding a phantom property the compiler tracks, but that vanishes at runtime. 👻

Announcing the CSS Property Type Validator Extension for VSCode

A new editor extension that validates your CSS @property registrations and catches incompatible var() usage as you type.

The First Real Autoresearch Run Was Expensive, Messy, and Extremely Useful

I pointed the skills autoresearch harness at a real frontend security project. It cost roughly four dollars, failed before completing a full improvement loop, and taught me more than any of the earlier test runs combined.

Refined Plan Mode: Reviewing AI Coding Plans Like Pull Requests

A small local web app for reviewing AI-generated coding plans with inline comments, anchored feedback, and structured JSON output, bringing the pull request review experience to plan mode.

CSS Property Type Validator Is Getting Much Closer to Real-World CSS Workflows

An update on the CSS Property Type Validator, focusing on recent improvements that make it better suited to practical, real-world CSS development workflows.

Targeting SVG Images with CSS Attribute Selectors and filter: invert()

When you cannot inline an SVG or use it as a mask-image, a combination of the ends-with attribute selector and filter: invert() offers a clean, CSS-only solution for adapting icon colours across themes.

Building a 3D Climate News Globe with HTML in Canvas and Three.js

A deep dive into Blue Earth, an experiment that plots positive climate news stories on a rotating 3D globe using the HTML in Canvas API, Three.js, and a build-time pipeline powered by Claude and Geoapify.

Introducing masonry-gridlanes-wc: A Native-First Masonry Web Component

A light-DOM custom element for CSS masonry layouts that uses display: grid-lanes when available and falls back to a spec-aligned JavaScript placement engine. Version 0.1.0 is ready for real projects.

CSS Property Type Validator: Assignment-Site Validation

The CSS property type validator now catches type mismatches at the point of assignment, not just at var() usage.

Pushing to GitHub and Codeberg Simultaneously with Git

Learn how to configure Git to push your code to both GitHub and Codeberg with a single command, including SSH key setup and a handy shell alias for branch-specific control.

TypeScript 6.0 and CSS Side-Effect Imports: What Changed and How to Fix It

TypeScript 6.0 enables noUncheckedSideEffectImports by default, which causes a TS2882 error for CSS side-effect imports like import './style.css'. Here is what changed, why, and how to fix it.

Panozoom: The Accidental Web App

What started as a question about a free macOS image viewer turned into a deep dive into pan and zoom math, pointer events, WheelEvent quirks, and a TypeScript web component. Here is everything we learned along the way.

The Process of Shipping The CSS Media Pseudo Classes Polyfill

The CSS Media Pseudo Classes Polyfill is now available on npm. This post covers what shipped, what I learned about the CSSOM and unsupported CSS, how you can try it, and what comes next.

CSS @property Deserves Better Tooling — So I Am Building a Validator

CSS @property gives authors a type contract for custom properties, but no tooling enforces it at the consumption site. CSS Property Type Validator is an attempt to close this gap.

Aligning Variable Content Across Columns. It Seems Impossible Until You Discover Subgrid

A layout that seems impossible; aligning titles and dividers across sibling cards regardless of content length. No JavaScript, no table layouts, just CSS subgrid.

Semantic HTML Just Might Make Your CSS Less Fragile

A real-world exploration of how choosing the right HTML elements for interview transcripts solves both semantic and styling challenges in one cascading swoop.

The What And The How: What Building A Polyfill Is Teaching Me About Web Standards

What happens when you try to implement two seemingly straightforward CSS features as a JavaScript polyfill? You discover that specifications are simple because they made hard decisions, and the complexity does not disappear; it just moves.

Comparing Sets in JavaScript With difference() and symmetricDifference()

How the new Set methods difference() and symmetricDifference() can replace verbose Set comparisons with clear, expressive code.

Timelapse: A PWA - Putting Cursor's Composer 2 To The Test

Timelapse is a progressive web app (PWA) with acollection of widgets that shows how much time has elapsed in the day, week, month, quarter, and year. Widgets and timezone are configurable.

Auto-Improving an Agent Skill: Applying Karpathy's Autoresearch Pattern to Semantic HTML

How I built an eval-judge-improve loop to autonomously refine a semantic HTML agent skill, taking it from 2.46 to 2.89 out of 3.0 across four iterations and what I learned about the limits of automated improvement.

Accessible Text Colour with the CSS contrast-color() Function

The CSS contrast-color() function lets the browser pick the most readable text colour for any background. Here is what it does, how it works, and why it matters for accessibility and the web.

The Prompt is the Product: Writing Effective Prompts for AI Coding Agents

How I structure prompts for AI coding agents to get considered implementation plans instead of premature code.

Freeze Your Object Constants for Better Type Inference

How combining JSDoc annotations with Object.freeze gives you literal type inference, runtime immutability, and better IDE support for JavaScript constant objects.

Stop Storing Secrets on Disk — Replace Your .env With Varlock and 1Password

How I replaced my local .env file with Varlock and 1Password, gaining type safety, validation, secret scanning, and a single source of truth for environment variables.

Cleaner Temp Directory Cleanup in Node.js With mkdtempDisposable

Working with temporary directories in Node.js just became cleaner and more intentional with mkdtempDisposable and explicit resource management.

Writing Cross-Platform Hooks for AI Coding Agents

How to write a single hook script that works across Claude Code and Cursor, giving you deterministic control over agent behaviour when it matters most.

AI Gave Me Working Code. Questioning It Gave Me Better Code.

Working code isn't understood code. When AI-generated code feels hard to parse, that's a signal to ask questions, and sometimes, the answer leads to something better.

Three Reasons Your scroll-snap Container May Be Overflowing on Mobile

Take a fieldset, pour some radio buttons and visually hidden labels into it, wrap it in scroll-snap, and you have a clean, semantic horizontal scroller on mobile. What could go wrong? Well... there is nuance we need to talk about.

Git: Recovering When You Branched From the Wrong Branch

A practical walkthrough for when you realise your feature branch was created from the wrong base, covering git log, merge parents, cherry-pick, and bypassing commit hooks.

CSS Anchor Positioning: Scoping, Implicit Anchors, and Conditional Hiding

Manage anchor relationships with anchor-scope, leverage the Popover API's implicit anchors, and hide positioned elements gracefully with position-visibility.

Mocking Browser Image Loading in Vitest: Property Descriptors, Prototypes, and WeakMap

A deep dive into the JavaScript concepts behind mocking HTMLImageElement behaviour in Vitest, including Object.defineProperty, Object.getOwnPropertyDescriptor, prototype manipulation, and WeakMap for per-instance state tracking.