Jim Nielsen’s Blog

You found my HTML feed — I also have an XML feed and a JSON feed.

I ♄ HTML

Subscribe to my blog by copy-pasting this URL into your RSS reader.

(Learn more about RSS and subscribing to content on the web at aboutfeeds.)

Recent posts

Making o(m)g:image, Part III: The HTML

View

This is part three of my series of posts describing how I made my quiz game o(m)g:image.


o(m)g:image is presented like a quiz:

  • You get one question at a time
  • When you choose an answer, it shows you if you got it right (and, if you didn’t, what the right answer is)
  • You go to the next question

To do this, I generate an HTML page for every question and for every possible question’s answer (correct or incorrect).

In my source code I have a file that outlines all the questions and their answers, e.g.

- id: 1
  answerId: 2
  answersById:
    1: The Ultimate Guide to Developer Happiness
    2: The Key to Building High-Performing Teams
    3: Woman Wins $500,000 at Georgia/Alabama Football Game
    4: A Guide to Sizing Wedding Rings
- id: 2
  # more data here

I use Web Origami as my build tool to loop over all this data and output an HTML page for 1) each question, and 2) each answer for each question. The URLs for accessing these pages follow this pattern:

/questions/:question-id/answers/:answer-id

So, for example, question 1 has 4 possible answers and answer number 2 (in the source data) is the correct one. So for that question, I create an HTML page for:

  • /questions/1
    • e.g. “Here’s the question and its possible answers”
  • /questions/1/answers/1, /questions/1/answers/3, and /questions/1/answers/4
    • e.g. “Sorry, you got it wrong. Answer 2 was right.”
  • /questions/1/answers/2
    • e.g. “You got it right!”

Because the game is structured this way, I have a pretty good idea how people will flow through the game:

  1. Question 1, then
  2. Question 1: answer 1, 2, 3, or 4, then
  3. Question 2, then
  4. Question 2: answer 1, 2, 3, or 4, then
  5. Etc.

So when a user lands on a question page, e.g.

/questions/1

And they click on an answer, rather than go fetch that page with JavaScript and insert it into the current page, I go ahead and let the browser’s default take over which is to do a full page reload.

However, I optimize for this by preloading the HTML pages where the user will go next. So if they’re on /questions/1, I preload each answer page for that question:

<!-- /questions/1 -->
<link rel="preload" href="/questions/1/answers/1/" as="fetch">
<link rel="preload" href="/questions/1/answers/2/" as="fetch">
<link rel="preload" href="/questions/1/answers/3/" as="fetch">
<link rel="preload" href="/questions/1/answers/4/" as="fetch">

Then, when they click on an answer, the browser already has that HTML page. It loads fast! For example, here’s a question page and you can see in the Network tab of the Developer Tools how it preloaded each answer’s HTML page.

Similarly, when someone lands on an answer page for a question — like /questions/1/answers/2 — I have a pretty good idea where they’ll go next (the next question!) so I preload that:

<!-- /questions/1/answers/2 -->
<link rel="preload" href="/questions/2/" as="fetch">

Once again, things load fast!

This is possible, in part, because every HTML page is small. Here’s a screenshot of “View source” on the first question:

Because these pages are so small in size, it’s totally negligible to just load four or five of them in anticipation of a click.

Side note: I considered inlining all my CSS as a <style> tag for each HTML page. But then as I thought about how I wanted to preload answers, I realized using a <link> to a single CSS stylesheet across all pages would be even better, because while it’s one extra request it gets cached for every subsequent HTML page — trade-offs! That’s, in part, how every HTML page can be so small.

What I love about all of this is that I don’t have to write any JavaScript. Because the UI is so small, and I designed it so each element on screen doesn’t shift in layout from one page to the next, it can feel like a SPA with in-place transitions but it’s not! It requires zero JavaScript to achieve.

It feels akin to those tricks they use in film, like forced perspective, where you can achieve the illusion of something without the cost of special effects (very useful on small budgets). For example, I love this explanation of how they made the actors for Gandalf and Frodo in The Lord of the Rings appear in the same scene and, even though they’re both full-sized humans, one appeared much more hobbit-sized purely via some tricks of cameras, tracks, and props — zero computerized special effects required!

It feels a bit analogous to web development, where personal-sized projects don’t want to pull out the big “special effects” JavaScript used by big studios. You can achieve a similar, perhaps even better, effect using a few little tricks.


Reply via: Email :: Mastodon :: Bluesky

Tagged in: #omgImg

Making o(m)g:image, Part II: As Little JS As Possible

View

This is part two of my series of posts describing how I made my quiz game o(m)g:image.


One of my goals when making this project was to use as little JavaScript as possible.

In retrospect, I have to admit that was a pretty ambitious goal. Not because it was hard from a technical point of view, but because it was hard from the point of view of human nature.

Allow me to explain.

I write a lot of JS for my day job. And I write a lot of JS for other small projects (not necessarily websites, but scripting data, tools, etc.) And when you have the great and might hammer of JS, every solution looks like a nail.

So it required a lot of self-discipline to avoid mindlessly falling into the practice of throwing JS at every problem I wanted to solve.

For example, I could’ve made this whole site as a “single page react app”. But I’ve done that on prior personal projects and now I don’t want to ever touch any of those projects (I also hope I won’t have to). I mean, we’re talking projects with React before its major version jump, like React 0.14.x with webpack/babel/etc. (Oh young Jim, you didn’t understand as well back then.) But I’m a little smarter now, so my goal on this project was: as little JS as possible.

But JavaScript is like a smartphone: as much as you don’t want to use it, you can’t help yourself. Again, it required a constant, mindful willingness to keep stepping back and asking myself, “Can I do this without JavaScript — if possible?”

In the end, I like where I landed. Every “question” is an HTML page. Every “answer” is an HTML page. Even the “navigation” where you can see how all the questions, is an HTML page.

For example, at one point I wanted to have some navigation on each page. My first thought was something interactive on the page, like a widget that says “Question 4 of 12”, you click on it, then it expands and shows you all the questions on the quiz, including which ones you’ve answered and whether you got them right or wrong.

How do you do that without using JavaScript?

At first I thought, “Use a <details> element, it won’t require JavaScript!” But as I thought through the ramifications, I wasn’t in love with the solution.

The more I thought about it, the more I wanted to reach for JavaScript: a fancy slide out drawer, a slick popup menu, an in-place expand. So! Many! Options!

But I wanted to avoid JS as much as possible — ”only for what’s absolutely critical” I told myself. Could I show/hide navigation with only HTML?

What I landed on was navigation as an HTML page. Every page has a little piece of information that tells you what question you’re looking at, e.g. “Question 1 of 12”.

Screenshot of o(m)g:image with an image, 4 possible answers, and a title at the top that says “Guess the article” and a subtitle that says “Question 1 of 12” with a little down-pointing arrow next to it.

If you click on it, rather than expanding the navigation inline, or popping out a drawer with the navigation, or doing something else that requires JavaScript to reveal the information, it simply takes you to a new HTML page with the information. (The browser’s back button serves as the equivalent of a “close drawer” or “collapse this” JavaScript solution.)

An interface displaying a grid of 12 numbered square buttons, arranged in three rows and four columns. Above the grid, the word ‘Questions’ is displayed in bold with a subtitle indicating ‘12 total.’

The only enhancement to the game that actually uses JS is the part that keeps track of which questions have been answered and whether the answer was correct or not. If you have JavaScript enabled, you will see this information additionally layered onto this navigational page’s UI.

An interface displaying a grid of 12 numbered square buttons, arranged in three rows and four columns. Above the grid, the word ‘Questions’ is displayed in bold with a subtitle indicating ‘12 total.’ Questions 1, 2, and 3 are in red with a little “x” in the bottom right corner of the box indicating they were answered incorrectly. Question 4 is green with a checkmark, indicating it was answered correctly.

With this approach, I’m truly using JavaScript for what JavaScript alone can do which is keep track of client state (you might argue I could have a server with a session here, but another constraint of the project was no server, so yeah).

This HTML-first approach really drove the design of the site. I had to ensure that navigational elements always stayed at the top of the page in consistent places across pages to ensure the UI didn’t jump as you navigated around (from the top of the page). My goal was to make the site so lean and so fast, that multi-page navigations felt as close as possible to in-place, on-page interactions.

I’m pretty happy with where the project ended up technically. I think it holds a great tension of low-cost maintenance for me over time, but still a great, solid experience for end users across a wide variety of devices — and, hopefully, across a long period of time.

The whole exercised really impressed on me once again that sometimes we just need to build simpler UIs. If your frontend is hard to build, it’s probably hard to use. If you make it easier and simpler to use, it’ll likely be easier and simpler to build and maintain.

That said, the irony here is that it’s actually quite hard to build something like this because you have to make ruthless choices about cutting things that aren’t absolutely necessary.

In other words, building websites backed by MBs of JavaScript is hard. You know what’s even harder? Questioning whether you actually need to build what you’re building, and cutting it down to the essentials. (HTML is really good at essentials.)

It reminds me of that old saying about how shorter writing requires more time, except for websites, i.e. “My website is lots of JavaScript. If I’d had more time, I would’ve made it lots of HTML.”


Reply via: Email :: Mastodon :: Bluesky

Tagged in: #omgImg

Related posts linking here: (2024) Making o(m)g:image, Part I: Design Iterations ::(2024) Making o(m)g:image, Part III: The HTML

Making o(m)g:image, Part I: Design Iterations

View

This is part one of my series of posts describing how I made my quiz game o(m)g:image.


I blogged about my recent project omgimg.jim-nielsen.com and I figured I’d write more details about my process behind making it.

When the idea first struck, I jumped into Figma and started working out the idea. I had a pretty good idea of what I wanted: a quiz-like website that showed one question per page.

Quiz interface asking ‘Can you guess the article?’ with an image of a football game scene and four multiple-choice options below, including humorous and unrelated article titles. On the right, a logo for ‘omg:image’ with the text ‘Every article in the world doesn’t need an image to summarize it. Hot take.’

Once you answered it gave you the result and prompted you to continue to the next question. Pretty basic stuff. In no time, I had something in Figma that fit the bill.

Quiz interface with the message ‘Sorry, but that guess was incorrect!’ displayed in red. The image shows a football game scene, and below it, the correct answer, ‘The Ultimate Guide to Developer Happiness,’ is highlighted in green. An incorrect guess, ‘A Guide to Sizing Wedding Rings,’ is marked in red. A ‘Next’ button is visible at the bottom. On the right, the logo ‘omg:image’ appears with the text ‘Every article in the world doesn’t need an image to summarize it. Hot take.’

From there I was anxious to jump into the code, so I built the Figma mockup in code. (I built it using Web Origami, more technical details later.)

I am hosting the site on Netlify, which has atomic builds for each commit. That means I am lucky enough to go back through my deploy history and view the site at different commit iterations, so I nabbed some screenshots for this post.

The first version was pretty close to the Figma mock.

Side note: Figma, for me, is a tool for settling on the direction of a website’s design and structure, not a “implement this screenshot pixel-for-pixel” tool, so I knew things were going to change and evolve as I built the site in the browser. Building the site is part of the design process.

Screenshot of iteration number one for o(m)g:image, showing how the layout changed somewhat from the original Figma mock as the surface the quiz lives on, for example, does not extend to the full heiht of the browser window like it did in the Figma mock.

That worked, but I didn’t love it. The relationships between elements didn’t quite feel right, so I started playing with layout and other small things.

Screenshot of iteration number one for o(m)g:image, showing how the layout changed. For example, the entire question became one big visual chunk, isntead of discrete UI pieces.

From there, I started clicking around and going through each question. This gave me a feel for the experience of answering questions, seeing the result, and moving on to the next question.

I had figured out (in my mind’s eye) how this would work in Figma, but only once I had a working prototyping in a web browser could I really get a feel for how the Figma design held up. This gave me a chance to say to myself, “Oh well that doesn’t work, and I’ll have to change this, and this thing over here...”

That's how I ended up on another iteration where I tweaked element positioning to try and better the experience of: seeing a question, answering it, then viewing the result.

Screenshot of iteration number three for o(m)g:image. More elements have been moved around, including the “Guess the article” title is now left-aligned with the question count to the right. That way, when the page changes, they reveal new information but stay in the same spot.

Screenshot of iteration number three for o(m)g:image for the answer page, where the incorrect answer is crossed out and the title “Guess the article” has been replaced with the text “Incorrect”.

After I got the navigational elements to a place that felt better (and indicating your progress through the quiz), I went back to layout and played with the overall positioning of elements. I also continued to refine and tweak the elements that helped you navigate through the questions of the game (and their corresponding answer pages).

Screenshot of iteration number four for o(m)g:image where the article heading has changed to be laid out top-to-bottom, heading then quesion status.

Screenshot of iteration number four for o(m)g:image answer page where the article heading has changed to be laid out top-to-bottom, heading then quesion status. On the left is a control to restart the question. On the right a control to go to the next one.

At this point I ended up taking a detour on the navigation front.

I kept waffling between the idea of minimal representation of the number of questions in the game (e.g. “1/10 questions”) and something more robust that would let you jump to any question at any point. So I built a version to test out that idea.

Screenshot of iteration number five for o(m)g:image where there’s a numer for every question in the quiz that you can click on.

creenshot of iteration number five for o(m)g:image answer page where there’s a numer for every question in the quiz that you can click on and the currently active answer page is red because the question was answered incorrectly.

Then I ended up on a side quest of multi-page view transitions, because it was cool to be able to design the navigation in such a way that I could have multiple HTML pages that transitioned visually when navigating between them.

Animated gif showing numbers 1 through 8, the active one with a circle around it and as each one is clicked and becomes active the circle eases over to that position in an animation.

But I ended up deciding I didn’t want to go in that direction, so I went back to a minimal representation of question status/progress. I also changed the layout (yet again). These were all decisions I made after repeated usage of the game, just clicking through things over and over and over until I found an experience that felt seamless and fast.

Final version of the question page. Quiz interface titled ‘Guess the article,’ labeled as ‘Question 1 of 12.’ It features an image of a football game scene at the top, with four multiple-choice options below, such as ‘The Ultimate Guide to Developer Happiness’ and ‘Woman Wins $500,000 at Georgia/Alabama Football Game.’ At the bottom, the text ‘o(mg):image - Can you identify these articles from the web by their social share images?’ appears, with a credit link to ‘Made by Jim Nielsen.’

Final version of the answer page. Quiz interface with the title ‘Incorrect’ and the label ‘Question 1 of 12.’ The image of a football game scene is displayed at the top, and below it, the correct answer, ‘The Key to Building High-Performing Teams,’ is highlighted in green, while the incorrect guess, ‘The Ultimate Guide to Developer Happiness,’ is crossed out in red. The other two options remain unselected. A forward arrow button is visible on the right. At the bottom, the text ‘o(mg):image - Can you identify these articles from the web by their social share images?’ appears, with a credit link to ‘Made by Jim Nielsen.’

I also decided that, rather than have all questions laid out in the navigation for every single question, I would have a single page with all the questions represented on it. As an enhancement, people with JavaScript would see their progress on that page including the correctness of their answer for each question.

Quiz results page titled ‘Questions’ with a grid showing the status of 12 questions. Correct answers are marked with green checkmarks (e.g., questions 2 and 5), and incorrect answers are marked with red Xs (e.g., questions 1, 3, and 4). The remaining questions are unattempted. A ‘Reset results’ button is centered below the grid. At the bottom, the text ‘o(mg):image - Can you identify these articles from the web by their social share images?’ appears, with a credit link to ‘Made by Jim Nielsen.’

That felt good to me, so I shipped it and that’s the state of the site at the time of this writing.

It’ll probably change in the future because every time I use it I think, “Oh I could tweak this, and move that...”

That’s the curse of building these things yourself.


Reply via: Email :: Mastodon :: Bluesky

Tagged in: #omgImg

Related posts linking here: (2024) Making o(m)g:image, Part II: As Little JS As Possible ::(2024) Making o(m)g:image, Part III: The HTML

Introducing o(m)g:image

View

I was popping off on Mastodon with an idea for a physical board game then decided to just make a digital version. It’s called “o(m)g:image” and you can play it now:

omgimg.jim-nielsen.com

Here’s the idea:

  • You have a bunch images
  • Each image is a real-life og:image pulled from an online article
  • You try to guess the title of the article based solely off the social share image

For example, can you guess the title of the article for this image?

Screenshot of a shared link preview user interface, where the image depicts a woman, wearing a white Dr Pepper jersey with the number 23, appears emotional and ecstatic as she stands on a football field during a competition. In front of her, there are footballs and large containers used for a throwing challenge. A cameraman captures her reaction, while cheerleaders and a crowd of spectators in the background cheer her on. The atmosphere is lively and celebratory, suggesting she may have won or completed a successful challenge.

Is it:

  1. The ultimate guide to developer happiness
  2. Florida woman wins $500,000 at Georgia/Alabama football game
  3. A guide to sizing wedding rings
  4. The key to building high-performing teams

Answer: it’s an article from slack.com and its real title is number 4 above.

Did you get it right?

Without question, we seem to have accepted (and stretch ourselves to support) this idea that every web page in the entire world should should be annotated with an image that encapsulates its contents into a single, visual expression.

This game is meant to illustrate the absurdity of this notion in both principle and real-world execution.

Why Make The Game?

I often vent about social share imagery to anyone who will listen — both in person and on my blog.

Sometimes a satirical game can convey the idea better than words.

What’s Wrong With Social Share Images?

Nothing inherently.

But because they’re possible, everyone feels like they’re leaving clicks and pageviews on the table if they don’t implement them.

“You’re not going to have an image for every post? Are you a crazy person?! People are 1,267% more likely to click through to your website if you have one!”

So everyone makes them, and as a result they end up stretching themselves — and the meaning between the image the content — to come up with these images.

That article has a picture of a clock? It could be about anything, such as:

  • Time management & productivity
  • History of clocks and time keeping
  • Time dilation and physics
  • Aging and mortality
  • Technological advancements in timekeeping
  • Time travel and fiction
  • Biological clocks

It could also have nothing to do with clocks and just be an article for a technical blog where nobody could come up with a better idea of how to visually express “Latest news from our release of [insert codebase name here]”.

For anybody who has done it, the task of coming up with a good image for every article is a tough one. The web has turned everyone into a publisher, but not everyone is backed by a large media corporation that employs people to do this task as their full-time job. If you as an individual or a small group of people try to compete with the quality of social share imagery from media publications, it’ll never be as good. Full stop. In other words: you’ll never be as good at the game as the companies who do it for a living, so the only way to win is not to play the game.

Or, you can try to compete and then you reach for automation. As Nicholas Carr says, “The endless labor of self-expression cries out for the efficiency of automation.” But automated social share images have their downfalls:

  • They’re bland and generic (e.g. stock photography or AI-generated imagery)
  • They’re unrelated to the content (e.g. abstract computer-generated patterns and shapes)
  • They’re duplicative (e.g. an image with text for the title and description of the article, which is already included in og:title and og:description and, on many social sites, displayed under the image itself)

So What Are They Good For?

Social share images are basically billboards on the information superhighway. Perhaps they were intended to convey additional context about the article, but in practice they’re really just screaming to catch your eye (and attention) and hopefully make you click.

Perhaps even better than a contextual image summarizing the content of the article, these images should just have some flamboyant visual with giant, bold type set in Impact that says, “BET YOU COULD NEVER GUESS WHAT IS HERE! CLICK TO FIND OUT!!!"

Look I get it. Social platforms are giving you the chance to have a free billboard, one that might grab the attention of all the people passing it by in their feeds. Why wouldn’t you leverage a free billboard?

I mean this game, which makes fun of social share images, even has one. So who the hell am I to say anything?

Nobody really, just another person on the internet.

Again, you can check out the game at: omgimg.jim-nielsen.com


Reply via: Email :: Mastodon :: Bluesky

Tagged in: #omgImg

Related posts linking here: (2024) Making o(m)g:image, Part I: Design Iterations ::(2024) Making o(m)g:image, Part II: As Little JS As Possible ::(2024) Making o(m)g:image, Part III: The HTML

Contrast Is Clarifying

View

Which is best?

  • Generalist or specialist?
  • Native or web?
  • Web site or web app?
  • JavaScript or Typescript?
  • Framework or library?
  • Server side or client side?
  • Photoshop or Sketch or Figma?
  • Designing in a tool or design in the browser?
  • Skueomorphic or flat?
  • Mac or PC or Linux?

This list could go on forever. Zoom in to just the JavaScript ecosystem and its overwhelming:

  • Modules: ESM, CJS, AMD, UMD
  • Package managers: npm, yarn, pnpm, bower
  • Bundlers: Webpack, Rollup, Parcel, Bun, Vite
  • Compilers: Babel, TypeScript, esbuild, swc
  • Runtimes: Node, Deno, Bun
  • UI frameworks: React, Vue, Angular, Svelte, Lit

Even here, the list could go on forever: db libraries, task runners, testing libraries, UI metaframeworks, server frameworks, state management libraries, etc.

Module systems — ESM, CJS, AMD, UMD — are a great example: how could we truly understand any of them individually without having had all of them?

We need opposing options. They exist not solely in opposition to one another but as contrast.

We must have a diversity to understand and discuss which is most fit for a given context. The web is big! “It depends”!

How do you understand one thing without the contrast of its opposite? What is white without black? How do you understand salty without sweet? One, by definition, excludes the other, which gives form and shape to the definition of each.

And guess what? Whichever you choose, you’ll likely choose poorly. That’s ok. Choosing poorly is where growth happens — if you let it.

Silver bullets are for killing werewolves not building technology.


Reply via: Email :: Mastodon :: Bluesky

Nothing Is Something

View

There’s a post on htmx.org about why htmx wasn’t the right fit for a particular project (which is dope, we need more websites that admit their thing might not be the right thing all the time).

The bit on AI being unfamiliar with their tool choice piqued my interest:

It’s worth noting that AI tools are intimately familiar with Next.js and not so much with htmx, due to the lack of open-source training data. This is similar to the issue Rails faces. While not a dealbreaker, it did impact our development speed and the ease of finding solutions to problems. When we encountered issues, the wealth of resources available for React/Next.js made troubleshooting much faster.

That’s an interesting phenomenon: a big part of tool choice is popularity because it shapes your experience finding support. The more popular the tool, the more probable your question has already been answered.

“How to get started with Next.js” likely has tons of search results — and therefore, one can assume, a large set of training data to inform the LLM’s answer.

But that same question for an obscure tool yields far fewer search results (if any) — and therefore, one can assume, a sparse set of training data to inform the LLM’s answer.

The point I’m getting to is this: the experience of asking a question on a niche topic or tool is different with an LLM than it is with a search engine.

With a search engine, fewer quality results means something. But an LLM is going to spit back a response regardless of the quality of training data. When the data is thin, a search engine will give you nothing. An LLM will give you an inaccurate something.

For example, an LLM may have no idea how to generate code for a novel syntax on top of JavaScript, but because it looks a lot like JavaScript and borrows a lot of the same idioms, it’ll go ahead and generate something for you — accuracy be damned.

This seems like a case where nothing is better than something because nothing means something.

LLMs — at least in my experience — haven’t really cued in on this. They’ll try their darnedest to give you something when nothing would be more instructive. (What’s that famous quote? “Better to remain silent and be thought a fool than to speak out and remove all doubt.” LLMs didn’t get the memo on that one.)

Rather than saying “I don’t know, there’s not enough on this subject to formulate a working answer” — which is what you could infer from an empty search results page — an LLM will give you something that looks right. Then you have to go shoot yourself in the foot to learn it’s not right, because you didn’t know enough to know it was wrong.


Reply via: Email :: Mastodon :: Bluesky

Nabbing macOS Icon Artwork

View

I keep a personal collection of beautiful macOS app icons, which might make you ask: “How does he get those icons?”

Apps in the App Store

For apps in the Mac App Store, I have my ways. I don’t necessarily want to write about them because I’m semi-afraid Apple would frown on my doings and close off my ways.

Don’t get me wrong, I’m not being nefarious. If you spent 30 minutes browsing through the publicly-accessible contents of a link from the App Store, you could probably figure out what I’m doing.

I’ll just leave it at that.

DMG Apps

For apps that aren’t in the Mac App Store, I’ll show you a few of the ways I grab icon artwork.

First off, you need the app itself. If that means you have to pay for it to download the DMG file, well sorry, I have no magic trick there. You just have to pay for it — or email the developer and ask for it.

But once you get your hands on the DMG, you can open that and do some sleuthing.

Opening a DMG will often get you a standard macOS app install screen, like this:

Screenshot of an application installion screen on macOS for TableTool, which shows the application icon on the left and an icon for the macOS Applications folder on the right and an arrow between them, denoting you should drag and drop the app.

From there you can right click and “Get Info”:

Then click-to-focus the application icon in the upper-right of the “Get Info” panel and CMD+C:

Beautifully, this will copy the application’s .icns file to your clipboard. From there, you can open Preview and go “File -> New From Clipboard” and it will open the .icns file in Preview with all the different icon sizes!

For me, I want the biggest one (1024×1024 pixels), so I find that and then go “File -> Export” to save it as a transparent PNG to disk.

And violĂĄ, the app icon in a format I want!

However! Sometimes this won’t get you exactly what you want.

For example, I downloaded the wonderful TablePlus app, opened the DMG, did “Get Info”, and found an app icon that was different from the install app (and the one that shows in your dock).

Sometimes this can happen. Sometimes you won’t be able to find the icon you want using this method.

When I hit this roadblock, I turn to finding the Assets.car file and plugging it into a tool like Asset Catalog Tinkerer by Guilherme Rambo.

With this method, you can right click the app and instead of “Get Info” do “Show Package Contents” and find .car files (I’m not a Mac developer, but it seems like the convention is to stick it at “Contents -> Resources -> Assets.car”). Then you can drag them into Asset Catalog Tinkerer and hopefully find what you’re looking for. In my case, with TablePlus, I was able to find the 1024 pixel icon I was looking for.

The End

If you ever find yourself needing to nab the icon for a macOS app, hopefully this little guide is helpful.

And if you’re just reading this because you love poking around at the internals of things, good on you. I love that stuff too!


Reply via: Email :: Mastodon :: Bluesky

Tagged in: #iconGalleries

Captchas Turned Notification Exploits

View

When my site analytics reported a large number of inbound traffic from Hacker News clones, I got curious and started clicking links.[1]

I like to visit links. I am connoisseur of it. I love the feeling of landing on something you didn’t expect — which is precisely what happened.

I landed on a site that had one of those Cloudflare-esque “prove you're human” captchas. That didn’t seem particularly abnormal. Lots of website owners these days use them for protection against malicious activities like DDoS attacks.

Anyhow, the page had a little graphic that said: “Press ‘Allow' to prove you are not a robot.”

Illustration of a fanciful, friendly robot head with the text “Press ‘Allow' to prove you are not a robot.” underneath.

I sat there for a moment looking for a button, but couldn’t find one. “Where’s the “Allow” button?” I thought.

A few seconds later, Safari’s native permission dialog popped up asking for permission to send me notifications!

I immediately thought, “Ah, hell no!” and ran away from that website. That’s sneaky, leveraging tools site owners use to protect themselves — and therefore normalize for their users — as a weapon.

I hate this crap.

But one of the beautiful things about browser security is that a lot of people work really hard to make visiting any website in the world safe. Granted there are caveats to this statement, but it’s cool you can mostly sleep at night doing a GET to any domain. (Whereas, for example, it is very much not safe to install any package in the world from npm.) That’s great news for link hoppers like me.

THANK YOU browser makers!


  1. I initially posted this train of thoughts on Mastodon, but still haven’t been able to stop thinking about it so I wanted to post it on my blog for more permanence. ⏎

Reply via: Email :: Mastodon :: Bluesky

Tagged in: #grateful

Named Blogs

View

I think it’s endearing when people name their blog.

I’m not talking about branding, like people do with professional blogs or newsletters.

I’m talking about personal blogs that people name out of care and idiosyncrasy.

It’s endearing, because you brand things you own, you name things you cherish.

We didn’t brand our family cat. And we don’t call him “The Nielsen’s cat” (though that’s probably what our neighbors call him). We named him. We call him “Fluffy”.

Don’t get me wrong, I like how personal it is when a personal blog is just someone’s name (that’s what mine is).

But I also love when folks add a little name or subtitle to communicate their personal feelings about their blog, e.g. “Little nothings: the blog of so-and-so”.

Here’s a few examples out in the wild of people I follow:

My sister had a blog for a long time — though sadly not anymore [insert comment here from old man yelling at cloud about the demise of blogging in the wider public].

I can’t remember the name of her blog, but the subtitle was “tasting life twice; in the moment and in retrospection” which was a nod to Anaïs Nin. I think about that quote probably once a year — I love stuff like that!

Yeah, I know, I’m one to talk. My blog is titled “Jim Nielsen’s Blog” which, hey, at least it’s clear. Maybe I’d name it if I could land on a name I like, but I’m a fickle namer so don’t hold your breath. Perhaps I could start with a subtitle first, something like:

  • “Jim’s Blog: Dialogues With Myself”
  • “Jim’s Blog: A Refinery For Coarse Feelings”
  • “Jim’s Blog: Opinions With a Shelf Life”

Oooof. Maybe I better leave this art to others.

You have a blog you follow whose name you love? Let me know — or even better, blog about it!


Reply via: Email :: Mastodon :: Bluesky

Reading and Writing as Human Expression & Connection

View

Why do we write?

We write, in part, because our own reading was given as a gift to us and we want to extend that same magic we received to others. Here’s Mandy Brown (and my notes) in a recent article:

The more compelling and interesting reason that most writers seek out readers is, I think, less utilitarian: we receive our writing as a gift, and so it must be given in turn. We write because something needs to be expressed through us, and only by giving the writing to a reader is that need fulfilled

You write because something needs to be expressed through you, which is something nobody else in the world can do.

(Contrast this with writing that is expressed through an LLM that everyone else in the world has access to.)

By giving our writing to a reader its is purpose fulfilled.

In other words, reading and writing has traditionally been an act that takes place in the context of people. Its purpose is fulfilled through humans. AI bots could read and write to each other all day long, and what is being “fulfilled” in that scenario?

Reading and writing is for expression and connection between humans. Its purpose is fulfilled in that context. Anything other than this and it is purposeless; that is, done in a way that violates the reason for its existence in the first place.

Does that make sense? I’m trying to make sense of it myself. Maybe there’s something here — maybe not. But Mandy’s piece got me thinking.

Reading and writing is a human-centric exercise because it deals with the interpretation, exchange, and expression of consciousness which is an attribute that machines do not possess — “yet” some will say, and to that I say “lol”.


Reply via: Email :: Mastodon :: Bluesky