Full Width [alt+shift+f] Shortcuts [alt+shift+k]
Sign Up [alt+shift+s] Log In [alt+shift+l]
27

a11y-syntax-highlighting has been updated

from Eric Bailey [alt+shift+b] in programming

I created the a11y-syntax-highlighting library seven years ago, forked from xiaozi’s solarized-prism-theme for PrismJS. To not bury the lede, the new update: Supports Forced Colors mode, Is encapsulated in a Cascade Layer, Uses Custom Properties, Groups its selectors using the :where() pseudo-class function, and Normalizes color value declarations to all use hsla notation. It also offers options for supporting Operating System dark and light color modes: For a dark code background color for dark mode and light code background color for light mode, use a11y-light-on-light-dark-on-dark.css. For a dark code background color for light mode and a light code background color for dark mode, use a11y-dark-on-light-light-on-dark.css. There are also standalone dark and light code background offerings that do not adapt when the OS mode changes. These stylesheets are called a11y-dark.css and a11y-light.css. Background The project was started in response to a question Michael Ball asked on the web-a11y Slack instance. He was asking if SC 1.4.3 Contrast (Minimum) applies to code syntax highlighting themes. The answer is yes. Code syntax highlighting themes need to meet minimum color contrast values to be conformant. I then realized there weren’t a lot of syntax highlighting themes that were fully conformant. Many of them fell apart with the colors they use for comments. I understand that there may be a desire for code comments to look less visually emphasized. However, code comment color—like all other text content—still needs to be able to be read. Naming the problem means owning the solution. Because of this, I created the library to address this gap in support. I also put a lot of effort into selecting color values that did more than just conform. Accessible experiences can be beautiful experiences, and I wanted this to reflect that. I initially targeted the PrismJS project because of its popularity. highlight.js support soon followed. I also added themes for Carbon, as...
9th Sep 2024

Stay updated

Get a weekly newsletter with the top 5 articles worth reading every week.

More from Eric Bailey

GitHub repository landing pages now show an accessibility tab, if provided

My last official contribution to GitHub was something I’ve wanted for a long time: Writing the code to display an ACCESSIBILITY.md file’s contents on the repository landing page. This content lives in the same tab component that the README, License, Code of Conduct, Security, and important information is surfaced. For example, I’m using an ACESSIBILITY.md file located in ./github to communicate my accessibility statement on my a11y-webring.club repository. Here’s an image of it in action: The file only appears if it is supplied, so it is not a required part of creating or maintaining a repository. However, it is my hope that the act of providing one becomes more commonplace the same way providing those other special kinds of files are. Another broader hope I have is that this promotion of content helps to normalize accessibility as a consideration and practice in some small way—something that helps to send a signal of a mature software project. I’m excited to see how people use this new addition to the platform. I would also like to extend a huge thank you to Jan Maarten and Maria Lamardo for their help getting this effort across the finish line.

2 weeks ago • 1 votes
CSS-Tricks could be a co-op

I owe a lot of my professional identity and success to CSS-Tricks. CSS-Tricks repeatedly gave me the opportunity to write for them. In doing so, they helped to both socialize and normalize accessibility as a mainstream frontend concern. I’m deeply thankful to them for this. The team was also a joy to work with, notably Geoff Graham. He’s a mensch, and one of the nicest people you can interact with in the frontend web space. If you have not been following the news about the site, Kevin Powell has a good video about the whole situation: Content skipped. I’m not speaking on behalf of Geoff, Chris, or others involved with running the current version of CSS-Tricks. I’ve got skin in the game as an author. This is my personal opinion, born of my feelings and beliefs. I think a lot of the web’s infrastructure should be co-ops, and CSS-Tricks is knowledge infrastructure. To that point, I should also point out that the website covers far more than just CSS. The corporate model of ownership can be a risk. If infrastructure is not part of a corporation’s core strategy, it is not a priority. As Kevin’s video touched on, it seems like promotion via owning the frontend content space isn’t part of Digital Ocean’s strategy anymore. It is not that CSS-Tricks does not have value. It is that Digital Ocean cannot see it. It is deeply, tragically ironic to me that Digital Ocean allowed this to transpire. This is because I know for a fact that the techniques and philosophies shared by CSS-Trick authors helped to shape iterations of their product’s UI. Some may be quick to point out that this knowledge now—illegally—exists inside of LLM training data, so the risk of the website going away is mitigated. To this, know that we should be striving to keep resources like CSS-Tricks going. Human creativity is the force that creates new techniques, strategies, and technologies. The web will calcify without voices sharing what they know, forever locking us into endless permutations of a fixed point in time. Unlike corporations, co-ops don’t have to be motivated by profit. By not needing to prioritize growth at all costs it means co-ops can instead prioritize and incentivise things like preservation and cultivation. It is also a successful model of operation, one that even already exists, and flourishes in the tech space. Collective ownership can also serve as checks and balances for, and protection against hierarchical decision-making. I only need to point to the chaotic and aberrant decisions many CEOs in the technology space have been making as of late to demonstrate the value of this approach. Paddy Srinivasan, if you somehow wind up reading this: Save some face and take a big swing. Give CSS-Tricks back to the people who love it.

18th Sep 2026
Here’s yet another metaphor about tech debt

The city next to the town I grew up in had a shopping center that was built atop a sanitary landfill. For those unfamiliar, creating a sanitary landfill involves taking landfill waste, spreading it into thin layers, compacting it, then paving over it. It enjoyed popularity as a practice in the 60s and 70s. I’m all but sure this shopping center was built in the mid-to-late 70s. It was the 90s when I was a kid and started going to it. Of note was a Kmart that I’d frequent with my parents when running errands. At some point, the certain parts of the tile floor of the Kmart started to buckle and bubble—their edges tinged with an ominous yellowish brown color. The reason for this is that is that the landfill was sealed improperly—accumulating methane and carbon dioxide gasses was pushing decomposing waste upwards and outwards. The employees put up some warning signage around the worst of it, but that was pretty much it. They did not have the expertise, nor the incentives to do anything past indicating the problem. One day we tried to go to the Kmart, and it was closed for good. A few years later the entire shopping center had to be demolished and the landfill had to be dug up and disposed of.

4th Aug 2026 • 1 votes
Announcing What Can’t I Press?

I made an app! What Can’t I Press? is an app that allows you to: Read, search, and filter through screen reader keyboard shortcuts. Scan open apps and add their keyboard shortcuts to the collection. Copy a keyboard shortcut to your clipboard, with modifier keys to format the keyboard shortcut in different ways. Export the list of keyboard shortcuts in its current state as JSON. It is intended to be both a reference and a discovery tool. Here’s a quick demo of it in action: Two open apps placed side-by-side on macOS: TextEdit and What Can't I Press? TextEdit is open to a blank document. What Can't I Press? shows a search input, an expand/collapse all toggle button, a list of 4 disclosures in a collapsed state, a notification message, a shortcut filter input, a download icon, and two buttons labeled "Scan all open apps" and "Scan last focused app". The disclosures are labeled, "JAWS", "Narrator", "NVDA", and "VoiceOver" and each has a badge tallying how many shortcuts are present. The notification message reads, "What Can't I Press cannot detect all possible keyboard shortcuts. Be sure to also check manually." The mouse cursor clicks the "Scan last focused app" button and a brief scan happens. The list of disclosures updates to show global keyboard shortcuts and shortcuts for TextEdit. All disclosures are set to an expanded state, and links to jump to the next section are also revealed. The mouse cursor then clicks on the search input, where the word "save" is entered. It then briefly scrolls through the list to show what apps have functionality related to saving. The search input is cleared by clicking a clear button, then focus is placed on the filter input, where Commandkbd> + s is entered. The list of keyboard shortcuts filters to show all shortcuts that incorporate these keystrokes. The cursor then clicks on the Commandkbd> + S save row button, and places focus on the TextEdit document. The content "⌘S" is inserted into the document via pasting. The app is also available as a web experience, and can be installed as a Progressive Web App. This form of the experience only allows viewing and filtering screen reader keyboard shortcuts, as scanning open apps is not possible using current web technologies. Why did I make it? App and webapp keyboard shortcuts are an often overlooked area of user experience, especially when it comes to working nicely with assistive technology. As much as possible we should not put the burden on the person using assistive technology to use workarounds. In other words: what is added as a convenience for someone who doesn’t require assistive technology should not impair someone who does require assistive technology functionality to get what they want or need. I made this app to help speed up and streamline the process of adding keyboard shortcuts in a safe and responsible way. For more background on this act, reference my post, How an accessibility designer adds keyboard shortcuts to a web app. Limitations What Can’t I Press? cannot detect all keyboard shortcuts used by an app. Consider this as a tool that helps as a first pass, but always be sure to also manually check. There are specific ways of declaring keyboard shortcuts in code that can be picked up by a scan, but not everyone uses those methods. Microsoft is an especially poor actor in this regard. The app is also currently unsigned. This means you’ll have to bypass operating system warnings about installing unsigned apps. All app source code is on GitHub and set to public, so you can review exactly what you’re signing up for. Getting the app signed is on the roadmap, so consider this more of a soft-launch announcement. Is it free? Yes. This kinda reads like you think all keyboard shortcuts should be rebindable Also yes. Looks like you used a LLM to make this A third yes. I honestly couldn’t have made this without it, and I have complicated feelings about that. Believe me, there was a ton of human intervention required. What’s with the icon? It’s a stovetop gas burner. You shouldn’t press it with your hand. I’m really funny, I know. And what about this anecdote that I couldn’t resist sharing? A friend mentioned one of their coworkers uses an app whose main mode of operation is text entry. For whatever reason, pressing Command + b toggles open a navigation drawer, and not, you know, apply bold formatting. This isn’t even an accessibility issue, it’s straight-up bad design. Is this app helpful? Let me know!

15th Jun 2026 • 1 votes
Evolved antennas, LLM-generated code, and a potential antifuture

I think about evolved antennas a lot. If you’re not familiar, an evolved antenna is created when you set an evolutionary algorithm on the task of producing a structure that is as efficient at its intended function as possible. Past that there’s no human input, the algorithm just does its thing. It: Modifies elements of the initial design, Evaluates how well the design would perform according to a set of requirements, Adds or discards the changes accordingly, then Repeats until a success threshold has been achieved via iteration. Some evolved antenna practices also create a series of designs in parallel. They then pit the outputs against each other as a final layer of proving out efficacy. This process mimics natural selection. Here, mutations that are beneficial to surviving in an environment are passed through generations. It also creates absolutely wild, alien outputs: Source: Human-Competitive Results: Evolved Antennas for Deployment on NASA’s Space Technology 5 Misson - SlideServe. An evolved antenna looks the way it does because the algorithm that creates it is focused on the efficiency of the artifact it produces. It has no concept of what antennas are “supposed to look like”. That’s a bias that is inherent to us humans. Structural limitations I also have a light fascination with early programming. Specifically, the creativity involved with how programmers accommodated limitations inherent with the medium. Early mainframe programmers were constrained to the point where there would be a limit on the number of characters you could use, which led to cryptic names that oftentimes required a physical dictionary to look up the human-friendly meaning of something. There was also a long tail of this practice even after the hardware-imposed restrictions of the mainframe era. This was likely built on muscle memory, “best practice”, and a DRY mindset taken too far. Fortunately, contemporary practice—where computational power is far more luxurious—favors clarity over brevity. Profusion and proliferation Nowadays function and variable names are long and luxurious. We’re inundated with text. Flooded by it, even. In fact, we’ve gotten so good at using text that we built software to produce it for us, on demand and at volume. There have been some good things to come out of this development if you make digital experiences for a living. Concerns such as documentation, design systems, styleguides, and other vital-yet-neglected areas of the practice are suddenly critical for operations. It turns out that written words that help to explain things and create consistency are extremely important. Who knew! Here, I must confess: As someone who has long-favored these downplayed and underfunded areas of the trade, I have found myself ugly laughing at this tragicomic phenomenon. I also know that being able to feel this smug ruefulness is on borrowed time. Returning to this sudden explosion of text content—as well as other factors—we now have words for everyone who wants, or may eventually need them. Well, anyone who can pay. Decoupling and system gaming Many contemporary LLM-providing companies operate under a model where you pay them proportionate to how much computational power you utilize. This is sold via tokens, which is an abstract representation of a segment of content to be processed. Money is something people are reluctant to part ways with. This creates incentives to get creative. I’ve read all sorts of clever techniques, tricks, optimizations, and hacks people have created to lower token expenditure. The one that stands out to me most is the caveman prompt. It promises to “[cut] 65% of tokens by talking like caveman”. Of note is its ability to specify the level of “grunt”: Futurecasting The caveman prompt is a signal. Right now we live in a space where full, complete words and sentences are still desirable for us humans, and LLMs work with it. This space is in competition with a few intractable realities: LLM companies are continuing to operate at a loss. The real cost of using their services may manifest sooner than later, as promises of profitability need to be kept. Human language is an inefficient medium for transmitting data, and largely lacks the precision needed to describe the logic that powers contemporary software. Consider concepts like Robot Interaction Language and ggwave as ways we’ve attempted to address this fact. LLM-based product development is focused more on what is produced compared to how it is made. Given these considerations, one can imagine a future where human-friendly language is a liability. The forces of cost and efficiency are difficult to overcome, especially if results can be generated with minimal effort. One can also imagine that code returns to its infant state of being terse, cryptic, and near-impenetrable due to efforts to optimize how LLMs operate. Here, human language sets the parameters and LLMs act as the dictionary. This LLM optimization might even go a step further. In the pursuit of efficiency its code output becomes a language completely decoupled from a human’s ability to follow. In the torrential downpour that is everyone saying the quiet part out loud, the CEO of OpenAI’s horrifying comment about selling our intelligence back to us is a raindrop worth paying attention to. This possible outcome may mean that this time around there is no dictionary to reference. Or there is a dictionary, but it is sold back to you at a premium. It’s easy to foresee a proprietary language that only a LLM vendor can compile, decode, and otherwise change—it’s not like there’s a lack of prior art. Preventative measures Science fiction author Vernor Vinge wrote a brilliant book titled Rainbow’s End. In it, a character named Robert Gu is cured of his Alzheimer’s and brought into a post-singularity world. Gu—a former English professor and avowed technophile—struggles to adapt to a radically changed world. In one notable scene from the book, Gu rages when dismantling a device. He finds all its internal components are sealed and labeled, informing him that there are “no user-serviceable parts within”. Code may be poised to follow this direction. Imagine a world where attempting to open up any piece of software reveals a dense forest of evolved antennas, each constructed using inscrutable, black box language. Gu's outburst of anger is valid. It stems from understanding that intentionally preventing someone from making modifications is a method of enacting control. Another notable part of the future Rainbow’s End posits is the mass-proliferation of augmented reality. Here, people can access different “layers” of perception, with paid tiers of information. Looking with your naked eyes is free, but the more information you want about something the more you need to spend. Craft and cost As someone who cares about craft, I am deeply worried about this potential future. How something is built is just as important as the results it produces—reference LLMs' bias towards producing inaccessible code as an immediate concern. Inaccessible output by default is a case of implicit and unwitting control, in that it shapes who can—and cannot—use the web. The companies that provide these models could hypothetically be compelled to address that. However, the much-needed regulation needed to prevent this systemic digital exclusion is unlikely to happen with the current status quo. Or more realistically, will happen in a way that is more in-line with the regressive path the United States is currently traveling down. Some here may argue that these systems are performing better than how human developers have, and that will increase as LLM-generated code becomes more prevalent. Here, know that: As of now, homepage accessibility errors and complexity are both on the rise, and This increase in inaccessible code will continue to be enshrined, codified, and amplified as the source code is re-scraped and fed back into model data training efforts. Websites are being built via LLM-generated code and populated LLM-generated content at an exponential pace. This, in turn, raises more concerns: Overcoming this ever-increasing inaccessible default becomes progressively more resource-intensive. This makes it something only larger organizations can afford to take on, yet will be unwilling to due to a proportionately scaling cost. Inaccessible outputs become increasingly more normalized. This makes it ever more unlikely to be questioned as something that needs intervention. Command and control More distant—yet more relevant—fears center around explicit control. We're already seeing this manifest with refusals to communicate facts that may be inconvenient for LLM providers’ success. More abstractly, this entire model of operation is antithetical to one of the most radical and equalizing forces humans have ever invented. And subversion of this model is deliberate. You must imagine Sam Altman holding a knife to Tim Berners-Lee's throat. Anil Dash The public internet has been available for 35 years, and open source for 28. Both are revolutionary ideas that upended traditional ways of how knowledge is distributed. The lifespan of these ideas are also tiny blips compared to the centuries of traditional power structures and systems that came before them. It’s also enough time for said structures and systems to figure out how to address these existential threats and return things to how they prefer to operate. Being robbed of the profound openess and transparency we have become accustomed to means that we place control of reality in the hands of closed, unaccountable organizations. Here, we need to think deeper than code. Antifuture There is a potential future where we are lead down a path that works against our own self-interests, amnesic to how we wound up where we are and without the language to communicate it. Dominant players are contemptuously bypassing the standards process. We are already seeing attempts to manipulate LLM output to serve political agendas. Even further, this manipulation can occur with the providers themselves. Also recall that the more unaccountable LLM output is normalized the less we will question its outputs. Now be the villain and imagine what is possible if these agendas feel threatened. Before the internet there was Usenet. Before Usenet there was ARPANET. Through this lens, the browser is just another place information is stored. Here, we should be worried about the wolf-in-sheep’s-clothing threat of monopolistic vertical interoperability—interfacing what came before as a method to subsume it. You may be reading this post as a paranoid fear response. I should point out that these fears are cultivated. Here, know that I am not feeling fear as much as anger and a desire to preserve what is boring and works. You can open Notepad and type whatever you want into it. You can open Paint and draw whatever you can imagine. You can publish whatever you want online with a small degree of technical know-how. This all costs nothing past the hardware, software, and connection fee. We take this for granted, to our own detriment. Being open and transparent is a radical strength, not a weakness. We should not throw this away in the pursuit of a convenient perceived inevitability.

11th May 2026 • 1 votes

More in programming

BazelCon 2026 recap

My now-traditional “summary” of the conference along with my own commentary and thoughts.

36 minutes ago • 1 votes
The Future of CSS ✨

Every year, browser vendors collaborate via the Interop project to synchronize their efforts on new HTML/CSS/JS features. This year, there’s a ton of super exciting features being considered! In this blog post, we’ll explore the CSS of the future, to get a glimpse of what we’ll soon be able to do.

yesterday • 1 votes
Speeding up code review with `small-change`

Imprint’s average engineer is merging 4x more PRs than 2 years ago. Yay. Aggregated behind the average is something even more interesting: we have two teams that are merging 10x their PRs over that period. One engineer is merging 25x the PRs per week of our average engineer two years ago, and a number are merging 10x. That’s pretty neat, and the slope of the line suggests our average in a year is going to look much closer to today’s p90 than today’s p50. Even more importantly, we aren’t just shipping more, our quality has improved: incidents are down 42% half-over-half, and critical incidents are down 78% half-over-half. I think we’ve always known the quality/velocity tradeoff wasn’t a particularly useful construct, but that’s undeniable today. As we’ve walked this path, we–like everyone else progressing down it–have run into the problem of pull request review. The p50 pull request review took about 33 minutes to complete 2 years ago, but now takes us about 77 minutes. The slope here correlates tightly with the number of pull requests getting merged. Tightly enough that addressing it became one of my priorities for the week. We solved it! Just kidding, we’ve absolutely not solved it, but I think our current approach is an interesting one, which we call the small-change. The work discussed here was shaped and done by many folks at Imprint including Dan, Joy, Daniel, Lenny, Taylor, Ted, and Annie, among many others. Why review pull requests? There are four reasons we review pull requests: Knowledge sharing between author and reviewer – software engineering is generally learned via apprenticeship, and reviews are a primary mechanism of experienced engineers teaching others what good software looks like. We believe the current volume means that this knowledge sharing will have to move towards operating on clusters of pull requests, rather than individual pull requests Preventing errors – review has always been an expensive time to catch errors, and we believe that effective CICD along with harness verification techniques like poteto’s pstack are more effective mechanisms for preventing errors than review Preventing malicious behavior – my experience is that even careful code review will generally miss competent malicious behavior, although fortunately most malicious behavior is incompetent. We believe both sorts of behavior are best identified using a combination of fixed rules (modifying these specific objects/classes/files requires review), anti-abuse mechanisms that we’ve refined in our LLM-based member support experiences, auditing, and audit log inspection Compliance obligations in our documented controls – these can be changed, but today they require that an independent human reviews changes in a subset of our repositories In the modern development paradigm, we think there is a better solution for each of these problems. But, we also want to make these changes very cautiously. Small steps with small-change We believe we move fast by finding narrow, contained ways to validate new practices, so to iterate our way into an effective solution, we’ve developed the concept of a small-change. Here’s how it works: When a pull request is marked ready, CICD determines whether it is eligible to be a small-change. This is represented as a passing Github check. There is also a label for visibility, but it is the check itself, managed by the build and not human modifiable, that determines eligibility. (The label is used for initial filtering, but the check is still independently verified.) Something is a small-change if it meets all of these criteria: It is less than 1,000 lines of code There are no p1 or p2 findings from our ai-code-review automated review bot The author has “experience” in the service or application, defined as 10+ prior merged pull requests into that service or application’s directories. For changes working across multiple services or applications, the author must have experience in all of them to qualify Impacts fewer than N distinct services or applications. N is 1 on our frontend monorepo, and N is 3 in our backend monorepo, where typical changes will modify both a gRPC service and a common HTTP gateway Shared libraries and utilities files are not eligible for small-change Each repository has a .small_change file which allows per-path customization while we continue to tune the behaviors. For example, a service dealing with money movement can be excluded Our Slack automation tags every reference to a pull request with reacji labeling the state of that pull request, for example if it has failing tests, if it has been approved but tests are still running, or if it is ready to merge. We added a small-change reacji that indicates which of those pull requests meet the small-change criteria In our internal skills repository, we created two skills that have been distributed across harnesses: review-small-change which takes a list of repositories and reviews all open, non-draft, small-changes, including providing approval if they meet the review’s criteria (all checks pass including small-change check, and not touching on sensitive topics such as payments and security) review-pr-cluster which reviews batches of pull requests to identify common themes that came up, and suggest opportunities for discussion and adding verifications We set the social expectation that any error caused by a small-change is a failure in our system, and has to be solved at the system level: improvements to ai-code-review, to our verification mechanisms, to our CICD, to our harness, etc. This took about two days of infrequent attention to implement and rollout, although I imagine we will be tuning the knobs here for a long time. Maybe forever. fleet: centrally orchestrated harness I’ll briefly mention our other approach to reducing code review volume, which anchors on our centrally-orchestrated harness, fleet. (Which is similar to Stripe’s Minions although not following the one-shot approach in particular). We rely on fleet to implement and verify software in a highly controlled harness running in the cloud, with independent evaluation mechanisms to identify the correct number of independent reviewers for any given change. That number can be as low as one (e.g. fleet writes, one human reviews) for changes evaluated as safe. Results / next steps / reception I’ll be honest, it’s too early to give a useful result here. From early results, about 10% of changes qualify as a small-change. Those are now eligible for very fast approval, and generally get it unless they trip a flag, generally due to touching a security or money adjacent topic. While 10% is a small percentage, the core concept here is working, and ultimately will succeed or fail based on our ability to expand that percentage over the next few months in tandem with expanding our verification mechanisms to be increasingly comprehensive. This is ultimately going to fail or succeed depending on our ability to improve our verifications, which does require more difficult sorts of techniques to accomplish in low scale-complexity, high domain-complexity software than in the high scale-complexity, low domain-complexity products where many techniques like incremental rollouts are exceptionally effective. (Don’t get me wrong, they still work, they just provide less coverage when most users have different configuration and behavior.) Folks have not been uniformly excited about this, it’s a substantial change from how we’ve learned to be good engineers, and it’s uncomfortable to reevaluate whether a long-held best practice has become merely dogma. The most energizing part of the current cycle is that we get to reevaluate these practices we grew up on every week; the most painful part of the current cycle is that we’re likely to fall behind if we ever stop reevaluating them.

4 days ago • 1 votes
Building a Chestnut Launcher

The park near my house has lots of chestnuts and my kids have been collecting them like crazy (it’s actually their favorite post-school activity). We accumulated quite a hoard. I thought it would be fun to make a launcher so we had something to do with our new chestnut collection. I wanted to go with a very simple crossbow-style design (like the famous D2 item) using latex tubing and a leather pouch for holding the chestnuts. This is what I came up with. It launches chestnuts about 220 feet, and it’s simple enough to build in an afternoon. The frame is a 42 inch 2x2 and a spare IKEA bed slat for the crossbeam, glued and screwed together. A 3/8 inch eye bolt goes through each end of the crossbeam, and the latex tubing is tied to those and to the pouch from a leather shepherd’s sling. Tying the tubing was the fiddliest part. It has to be stretched while you wrap it with butcher’s twine, so I clamped a couple of scrap blocks to my workbench to hold it. I like this design because the tubing can be wrapped around the eye bolts to easily add more tension and power. The Trigger My favorite part of the design was that I decided to use an archery release like this one for the trigger. It provides a safe and reliable way to hold the tubing back, and it’s made to let go cleanly. I 3D printed a little housing that mounts the release securely to the back of the stock, and the release clips onto a loop of archery D-loop cord on the back of the pouch. Then I added a dowel for a rear grip and an old handle I had previously removed from my shop vac. How Well Does It Work? We tried it at the park and it works surprisingly well. Aimed at about 35 to 40 degrees, it sends our chestnuts (on the small side, about 10 to 15 grams) about 220 feet. Thanks to the archery release, we haven’t had a single misfire. I got curious and did some rough math. To go that far with air drag, the chestnuts are leaving at somewhere around 85 to 100 mph, which works out to about the same energy as a paintball. So safety glasses are important and you never point it at anyone. You can find the 3D print on Printables and a full build guide on Instructables. Make sure to always use it with adult supervision :)

4 days ago • 1 votes
Organising my cross-stitch patterns

I have a lot of digital cross-stitch patterns and until recently they were a mess. My “collection” was a series of several hundred PDFs, disorganised and spread across my disk. Recently, I was looking for a pattern and it took me several minutes to find it. I had a brief moment of panic, thinking that I’d lost it, and the website this pattern came from is long since gone. Fortunately it did turn up, but it was clear I had to organise my pattern collection. Some people would use apps like Pattern Keeper or Flosshaven, but I just created another static website on my media drive. This is what it looks like: The patterns are arranged in a masonry layout with a preview thumbnail for each pattern, which is normally the first page of the PDF. If a pattern has multiple files – for example, different files for colour and black-and-white printing – there’s a list of links below the thumbnail. I can also add a source link to where I bought the pattern, if I want to find more patterns by the same author. Internally, it’s structured like my other static websites. The metadata for the patterns is stored in a JavaScript file, and then I have an HTML page which renders that metadata in this visual design. My pattern collection doesn’t change very often, so I’m adding new files by hand. There are no sorting or filtering options, because my collection is small enough that they’re unnecessary. I can scroll through the entire list in less than a minute and find whatever I need. I’d like to start making my own clothes soon, and I expect to copy this design to store clothing patterns. This collection now sits alongside my saved bookmarks, podcasts, TV shows, and more. I can keep all my patterns organised, and I won’t lose them in the depths of my hard drive. Technical tricks There are a couple of technical pieces I’m quite pleased with in this process: Masonry layout. I love the cascading grid style of a masonry layout, and I think they’re great when you have variable-sized content – like my pattern cards. I’ve been using them for over a decade; screenshots of my early web apps show my experiments with David Desandro’s Masonry.js library. Masonry layouts are now a native feature of CSS called “Grid Lanes”, which is simpler and more performant than the JavaScript approach. I’m excited to use these layouts in even more places. Thumbnails of PDFs. Most digital postage patterns are shipped as PDFs, and I’m creating the thumbnail images with my create_thumbnail tool. I had to extend my tool to support PDFs, which turned out to be straightforward with the pdf_oxide crate. I’d not come across Oxide before, but it’s a cross-language library for working with PDFs, and I can imagine using it in future. A coloured stripe for the palette. In the metadata for each project, I have the complete list of DMC thread colours and the pattern dimensions. I have a lookup table that converts DMC thread colours to hex codes, and then I’m able to create a linear gradient in CSS to render a coloured stripe of the pattern colours. Here’s an example from a pattern with four colours: border-bottom: 12px solid transparent; border-image: linear-gradient( to right, #7a451f 0%, #7a451f 25%, #985e33 25%, #985e33 50%, #e4bb8e 50%, #e4bb8e 75%, #361f0e 75%, #361f0e 100% ) 1; Building the HTML, CSS, and JavaScript was very quick – I have notes on how I build my media sites, and I’ve done it plenty of times before. I threw together the initial prototype in less than 15 minutes. The longer part was finding all the PDFs scattered across my disk – but now that’s done, and I know exactly where to find my patterns. [If the formatting of this post looks odd in your feed reader, visit the original article]

a week ago • 1 votes
📚 BoredReading

You seem to be enjoying this.

Join free to unlock everything.

Create free account

Already have an account? Sign in