├── .gitignore ├── .npmrc ├── .prettierignore ├── README.md ├── README.notes.md ├── netlify.toml ├── package.json ├── posts ├── 2012-11-28-understanding-comes-in-stages.md ├── 2012-11-30-safari-tab-preview.md ├── 2012-12-04-reading-notes-november.md ├── 2012-12-11-calculate-the-ios-border-radius.md ├── 2012-12-12-said-no-user-ever.md ├── 2013-01-08-science-of-typography.md ├── 2013-01-21-unicode-symbols-and-font-stacks.md ├── 2013-01-29-quick-change-and-the-web.md ├── 2013-01-31-modularize-your-psds.md ├── 2013-02-12-freebie-resources.md ├── 2013-02-19-teamcolors.md ├── 2013-03-08-coming-to-appreciate-art.md ├── 2013-03-26-unintended-visual-relationships.md ├── 2013-05-05-an-analysis-of-infinite-scroll.md ├── 2013-05-15-why-do-we-sketch.md ├── 2013-05-17-the-frustration-of-google-glass.md ├── 2013-05-22-stop-direct-spam-comments-in-wordpress.md ├── 2013-05-29-scriptogram-vector-logo.md ├── 2013-06-10-max-upload-filesize-restart-apache.md ├── 2013-06-11-seemly-selectors.md ├── 2013-06-27-advertising-for-the-buyer.md ├── 2013-07-08-scriptogram-posts-in-json-with-php.md ├── 2013-07-15-thoughts-from-on-writing-well.md ├── 2013-07-22-preserving-css-comments-during-compression.md ├── 2013-07-24-things-to-be-informed-about.md ├── 2013-07-29-sass-variable-interpolation-workarounds.md ├── 2013-08-12-putting-the-user-first.md ├── 2013-09-23-automating-feelings.md ├── 2013-09-26-kinda-sorta-looks-like-the-internet.md ├── 2013-09-26-kindlingapp-home-page-redesign.md ├── 2013-10-14-ostentatious-design-and-profanity.md ├── 2013-10-21-wireframes-and-gravity.md ├── 2013-11-06-evolution-of-creativity.md ├── 2013-12-18-ben-franklin-open-source-contributor.md ├── 2014-03-03-logo-the-image-of-a-company.md ├── 2014-03-11-defining-beauty-on-the-web.md ├── 2014-09-02-logo-integrity.md ├── 2014-10-23-kindling-rubber-stamp.md ├── 2014-10-28-creating-apple-touch-icons.md ├── 2014-11-04-successful-transaction-receipt.md ├── 2014-11-19-innovation-talk-page.md ├── 2015-01-16-team-colors-2-0.md ├── 2015-02-05-everything-but-visual-design.md ├── 2015-05-04-conceiving-blog-post-artwork.md ├── 2015-05-20-skinning-the-idea-poster-anew.md ├── 2015-06-29-a-web-of-people.md ├── 2015-08-26-designing-kindlings-pricing-page.md ├── 2015-08-31-reading-notes-august.md ├── 2015-09-11-marketing2.md ├── 2015-10-05-reading-notes-october.md ├── 2015-10-17-one-algorithm-to-rule-them-all.md ├── 2015-11-02-reading-notes-november.md ├── 2015-12-01-reading-notes-december.md ├── 2015-12-03-assignment-desk-logo.md ├── 2015-12-30-innovation-sales-sheet.md ├── 2016-01-28-designing-and-building-assignment-desk.md ├── 2016-03-02-going-the-extra-mile-with-tasks-and-feature-requests.md ├── 2016-05-17-designing-developing-dcp-application.md ├── 2016-07-09-acr90-work-page-design-updates.md ├── 2016-07-11-paul-rand-on-logos.md ├── 2016-08-08-reading-notes-july-2016.md ├── 2016-09-08-reading-notes-september.md ├── 2016-09-27-sassme-v2.md ├── 2016-10-01-reading-notes-october.md ├── 2016-11-18-reading-notes-november.md ├── 2016-11-24-text-as-ui.md ├── 2016-12-09-redesigning-and-engineering-timshel-admin.md ├── 2017-01-06-designing-and-engineering-color-usage.md ├── 2017-01-11-migrating-away-from-compass-and-susy.md ├── 2017-01-17-the-art-of-the-side-project.md ├── 2017-01-31-reading-notes-january.md ├── 2017-03-08-designing-login-screens-and-business-relationships.md ├── 2017-03-27-the-analog-web.md ├── 2017-04-07-reading-notes-april.md ├── 2017-04-17-stop-using-the-term-pixel-perfect.md ├── 2017-04-19-designing-integrations-at-timshel.md ├── 2017-05-09-reading-notes-may.md ├── 2017-06-22-reading-notes-june.md ├── 2017-06-28-notes-from-fluent-conference.md ├── 2017-07-03-notes-functional-lite-js.md ├── 2017-08-11-designing-and-engineering-event-management-at-timshel.md ├── 2017-08-16-i-liked-this-podcast.md ├── 2017-08-26-limitations-in-software.md ├── 2017-10-02-the-world-wide-web-of-people-at-my-disposal.md ├── 2017-10-28-reading-notes-october.md ├── 2017-11-04-the-value-of-visual-design.md ├── 2017-11-27-creating-ios-icon-masks-in-the-browser.md ├── 2018-01-05-reading-notes-january.md ├── 2018-02-23-url-design-and-automated-redirects-in-jekyll.md ├── 2018-03-13-reading-notes-march.md ├── 2018-03-23-writing-as-iterative-problem-solving.md ├── 2018-04-10-installing-and-building-an-npm-package-from-github.md ├── 2018-04-13-short-perspective-on-hiring.md ├── 2018-05-04-reading-notes-may.md ├── 2018-05-22-blog-redesign-again.md ├── 2018-06-19-detecitve-work-for-app-icon-book.md ├── 2018-06-25-reading-notes-june.md ├── 2018-07-28-reading-notes-july.md ├── 2018-08-02-choosing-a-static-site-generator.md ├── 2018-08-09-cabin-of-logo-integrity.md ├── 2018-08-24-reading-notes-august.md ├── 2018-09-30-reading-notes-september.md ├── 2018-10-16-netlibox-my-guest-post-on-netlify.md ├── 2018-10-25-dark-mode-on-the-web.md ├── 2018-10-29-reading-notes-october.md ├── 2018-11-14-pathnames-to-subdomains.md ├── 2018-11-21-bookmarklet-deploys-with-netlify.md ├── 2018-11-26-reading-notes-november.md ├── 2018-12-08-book-review-the-pun-also-rises.md ├── 2018-12-18-supporting-css-variables-in-sass.md ├── 2018-12-27-reading-notes-december.md ├── 2018-12-28-icon-galleries-dark-mode.md ├── 2018-12-29-css-network-performance.md ├── 2019-01-04-difference-between-substr-and-substring-in-javascript.md ├── 2019-01-07-conditionally-load-material-icons.md ├── 2019-01-08-designing-the-quick-quote-experience.md ├── 2019-01-17-building-a-progressively-enhanced-site.md ├── 2019-01-29-how-apple-engineers-decided-the-app-icon-size-for-the-original-iphone.md ├── 2019-01-30-reading-notes-january.md ├── 2019-01-31-generating-shades-of-color-using-css-variables.md ├── 2019-02-28-reading-notes-february.md ├── 2019-03-06-book-notes-creative-selection.md ├── 2019-03-06-the-power-of-prototypes-in-the-creative-process.md ├── 2019-03-11-trigger-build-in-netlify-from-aws-iot-button.md ├── 2019-03-18-improving-server-side-rendering-react.md ├── 2019-03-26-reading-notes-march.md ├── 2019-03-27-down-the-rabbit-hole-of-image-optimization-tooling.md ├── 2019-04-01-moving-from-ejs-to-jsx.md ├── 2019-04-10-thoughts-on-jeremy-keiths-split.md ├── 2019-04-16-conditional-syntax-highlighting-in-dark-mode-with-css-imports.md ├── 2019-04-18-applying-multiple-background-colors-with-css.md ├── 2019-04-29-your-product-doesnt-have-to-look-the-same-on-every-platform.md ├── 2019-05-28-reading-notes-may.md ├── 2019-06-19-how-to-create-a-macos-menu-bar-app-for-netlify.md ├── 2019-06-24-notes-rethinking-asynchronous-programming-in-javascript.md ├── 2019-06-30-reading-notes-june.md ├── 2019-07-03-saying-no.md ├── 2019-07-10-batch-rename-dates.md ├── 2019-07-12-dynamically-darken-a-color-in-css.md ├── 2019-07-16-jsx-like-syntax-for-tagged-template-literals.md ├── 2019-07-27-yesterdays-questions-answered-in-todays-platform-apis.md ├── 2019-08-12-designing-and-engineering-progressive-disclosure.md ├── 2019-08-13-good-things.md ├── 2019-08-27-reading-notes-august.md ├── 2019-08-30-dealing-with-uncertainty-in-art-and-life.md ├── 2019-09-03-thoughts-on-rich-harris-talk.md ├── 2019-09-05-design-principles-applied-to-sf-fonts.md ├── 2019-09-16-i-love-rss.md ├── 2019-10-21-book-notes-mathematicians-lament.md ├── 2019-10-28-reading-notes-october.md ├── 2019-11-25-es-modules-in-node-my-own-rabbit-hole.md ├── 2019-11-25-reading-notes-november.md ├── 2019-12-04-netlify-public-folder-part-i-what.md ├── 2019-12-04-netlify-public-folder-part-ii-why.md ├── 2019-12-04-netlify-public-folder-part-iii-how.md ├── 2019-12-20-common-js-equivalent-of-dirname-in-es-modules.md ├── 2019-12-20-stuff-to-say-on-twitter.md ├── 2019-12-30-reading-notes-december.md ├── 2020-01-14-follow-your-values-not-your-passions.md ├── 2020-01-24-reading-notes-january.md ├── 2020-01-27-proptypes-outside-of-react-in-template-literal-components.md ├── 2020-01-27-switching-from-react-to-js-for-templating.md ├── 2020-02-06-texting-is-cerebral.md ├── 2020-02-13-programming-pairs-well-with-other-disciplines.md ├── 2020-02-21-reading-notes-february.md ├── 2020-02-24-the-spirit-of-view-source.md ├── 2020-02-25-software-and-home-rennovation.md ├── 2020-03-02-50-blog-posts-in-2020.md ├── 2020-03-05-progressively-enhancing-a-small-widget.md ├── 2020-03-09-switching-from-cjs-to-esm.md ├── 2020-03-11-design-systems-and-airplanes.md ├── 2020-03-16-using-netlify-analytics-to-build-list-of-popular-posts.md ├── 2020-03-18-empowering-the-few.md ├── 2020-03-20-credentials-in-urls.md ├── 2020-03-23-writing-vs-coding.md ├── 2020-03-30-reading-notes-march.md ├── 2020-04-02-agency-website-design-inspiration-and-other-observations.md ├── 2020-04-13-perception-and-balancing-idealism-with-pragmatism.md ├── 2020-04-30-reading-notes-april.md ├── 2020-05-07-transferring-text-files-with-dropbox-js-sdk.md ├── 2020-05-12-musings-on-the-documentary-for-everyone.md ├── 2020-05-18-user-controlled-system-level-aesthetic-preferences.md ├── 2020-05-27-notes-on-design-systems-by-mark-boulton.md ├── 2020-05-28-reading-notes-may.md ├── 2020-05-29-color-scheme-property.md ├── 2020-05-30-sass-color-functions-in-css.md ├── 2020-06-30-reading-notes-june.md ├── 2020-07-06-the-web-as-an-information-system.md ├── 2020-07-13-import-es-modules-from-github.md ├── 2020-07-15-git-info-in-node-for-babel-config.md ├── 2020-07-16-letter-case-on-the-web.md ├── 2020-07-17-book-notes-mlk.md ├── 2020-07-20-email-replies-in-rss.md ├── 2020-07-21-css-naked.md ├── 2020-07-23-google-vs-netlify-analytics.md ├── 2020-07-27-notes-coders.md ├── 2020-07-29-reading-notes-july.md ├── 2020-08-03-the-meaning-of-view-source.md ├── 2020-08-04-the-resiliency-of-the-internet.md ├── 2020-08-07-remote-work-is-a-craft.md ├── 2020-08-10-web-technologies-and-syntax.md ├── 2020-08-18-growth-creativity-and-you.md ├── 2020-08-20-predispositions-of-inexperienced-talent.md ├── 2020-08-24-make-me-think.md ├── 2020-08-25-deploying-a-wannabe-monorepo-in-netlify.md ├── 2020-08-31-es-modules-there-is-no-registry.md ├── 2020-08-31-reading-notes-august.md ├── 2020-09-21-economics-of-the-front-end.md ├── 2020-09-22-indexing-my-blogs-links.md ├── 2020-09-28-reading-notes-september.md ├── 2020-10-08-cheating-entropy-with-native-web-tech.md ├── 2020-10-12-automatically-resize-a-textarea-on-user-input.md ├── 2020-10-15-export-to-html-from-javascript-using-blob-urls.md ├── 2020-10-19-ten-anti-principles-of-good-design.md ├── 2020-10-21-book-notes-demand-side-sales.md ├── 2020-10-28-reading-notes-october.md ├── 2020-11-11-react-without-build-tools.md ├── 2020-11-17-the-organic-web.md ├── 2020-11-23-system-fonts-on-the-web.md ├── 2020-11-30-reading-notes-november.md ├── 2020-12-09-the-missing-hit-and-the-open-web.md ├── 2020-12-15-a-cors-proxy-with-netlify.md ├── 2020-12-26-reading-notes-december.md ├── 2021-01-11-writing-in-2020-and-2021.md ├── 2021-01-13-custom-style-sheet-in-safari.md ├── 2021-01-20-feat-new-style.md ├── 2021-01-25-fav-excerpts-from-the-postlight-podcast.md ├── 2021-01-28-reading-notes-january.md ├── 2021-02-01-graphing-blog-post-goals.md ├── 2021-02-02-codbase-collaboration-between-humans-and-robots.md ├── 2021-02-06-ikea-and-javascript.md ├── 2021-02-08-judo-throw-the-hype.md ├── 2021-02-16-doing-web-design.md ├── 2021-02-18-reverse-dns.md ├── 2021-02-23-incomplete-designs.md ├── 2021-02-24-expectations-and-reality.md ├── 2021-02-26-reading-notes-february.md ├── 2021-03-01-sites-v-apps.md ├── 2021-03-02-book-notes-parker-palmer-vocation.md ├── 2021-03-15-speculative-prefetching.md ├── 2021-03-17-progressively-enhanced-search.md ├── 2021-03-22-css-is-in-fact-awesome.md ├── 2021-03-25-reading-notes-collection.md ├── 2021-03-29-reading-notes-march.md ├── 2021-04-05-web-languages-as-compile-targets.md ├── 2021-04-07-styling-select-option-values.md ├── 2021-04-09-reflecting-on-digital-experience-for-vaccine.md ├── 2021-04-12-svg-stroke-positioning-ios-masks-browser.md ├── 2021-04-15-this-is-the-internet-folks.md ├── 2021-04-20-fetch-and-3xx-redirect-status-codes.md ├── 2021-04-26-custom-elements-without-js.md ├── 2021-04-28-reading-notes-april.md ├── 2021-05-02-shadow-dom-and-the-styling-api.md ├── 2021-05-10-reintroducing-readlists.md ├── 2021-05-12-automatically-discoverable-rss-feeds.md ├── 2021-05-17-designing-between-the-lines.md ├── 2021-05-19-useful-and-usless-code-comments.md ├── 2021-05-28-reading-notes-may.md ├── 2021-06-01-reflections-on-html.md ├── 2021-06-03-css-system-colors.md ├── 2021-06-14-displaying-favicons-for-any-domain.md ├── 2021-06-17-unseen-work-of-design.md ├── 2021-06-22-font-size-and-control.md ├── 2021-06-29-courting-webp.md ├── 2021-06-30-reading-notes-june.md ├── 2021-07-01-recursive-citation.md ├── 2021-07-06-theme-color-in-css.md ├── 2021-07-08-css-gap.md ├── 2021-07-12-deno-is-webby.md ├── 2021-07-14-conditional-style-loading-not-so-fast.md ├── 2021-07-19-things-i-learned-reading-webkits-ua-stylesheet.md ├── 2021-07-26-propagating-up-in-css.md ├── 2021-07-28-quibbles-with-social-share-imagery.md ├── 2021-07-29-reading-notes-july.md ├── 2021-08-06-browsers-and-representation.md ├── 2021-08-09-cool-uris-and-image-hotlinking.md ├── 2021-08-10-confirm-a-prompt-we-stay-alert.md ├── 2021-08-16-canistilluse.com.md ├── 2021-08-19-thank-you-for-reading.md ├── 2021-08-27-reading-notes-august.md ├── 2021-08-30-feed-urls.md ├── 2021-09-07-defining-basic-javascript-terms.md ├── 2021-09-09-book-notes-think-again-by-adam-grant.md ├── 2021-09-11-learning-and-being-wrong.md ├── 2021-09-13-job-titles-what-you-do-and-are.md ├── 2021-09-15-the-power-of-the-link.md ├── 2021-09-30-reading-notes-september.md ├── 2021-10-06-things-learned-blogging.md ├── 2021-10-07-stacking-contexts.md ├── 2021-10-10-hide-my-mailto-email.md ├── 2021-10-12-a-new-toilet.md ├── 2021-10-14-notes-hammock-driven-development.md ├── 2021-10-19-thoughts-on-avoiding-an-excessive-dom-size.md ├── 2021-10-25-note-to-self-on-churn.md ├── 2021-10-29-reading-notes-october.md ├── 2021-11-01-pseudo-element-syntax.md ├── 2021-11-09-launching-ios-app-icon-book.md ├── 2021-11-15-notes-from-measuring-design.md ├── 2021-11-18-css-relative-colors.md ├── 2021-11-22-a-web-thanksgiving.md ├── 2021-11-30-reading-notes-november.md ├── 2021-12-03-book-notes-eric-gill-typography.md ├── 2021-12-06-notes-on-metadata.md ├── 2021-12-13-javascript-templating.md ├── 2021-12-15-disposition-of-negativity.md ├── 2021-12-23-app-icons-dont-catch-em-all.md ├── 2021-12-28-for-the-love-of-the-web.md ├── 2021-12-29-reading-notes-december.md ├── 2022-01-05-a-web-for-all.md ├── 2022-01-11-talking-app-icons-on-the-postlight-podcast.md ├── 2022-01-18-exporting-and-parsing-emails.md ├── 2022-01-20-increase-reach-into-addressable-market.md ├── 2022-01-26-web-predictions-on-a-whim.md ├── 2022-01-31-reading-notes-january.md ├── 2022-02-02-cluttered-web.md ├── 2022-02-08-the-web-a-mystery-greater-than-our-failures.md ├── 2022-02-14-netlify-analytics-email-digest.md ├── 2022-02-16-book-notes-millions-billions-zillions.md ├── 2022-02-22-things-the-css-spec-folks-got-right.md ├── 2022-02-28-inspecting-web-views-in-macos.md ├── 2022-03-01-me-on-shoptalkshow-504.md ├── 2022-03-02-reading-notes-february.md ├── 2022-03-07-my-mom-and-the-wsj.md ├── 2022-03-10-inline-all-the-things.md ├── 2022-03-14-design-happens-in-an-ecosystem.md ├── 2022-03-15-deno-is-webby-pt-2.md ├── 2022-03-20-what-is-the-web.md ├── 2022-03-23-new-blog-theme-implementation-details.md ├── 2022-03-26-misc-thoughts-from-an-article-on-research.md ├── 2022-03-28-more-to-design-than-data-and-rationality.md ├── 2022-03-30-reading-notes-march.md ├── 2022-04-04-exerting-control-with-media-queries.md ├── 2022-04-05-automate-public-folder-workflow.md ├── 2022-04-10-permeating-principles-of-the-web.md ├── 2022-04-14-the-side-effects-of-tailored-digital-experiences.md ├── 2022-04-16-having-fun-writing-apis-with-glitch.md ├── 2022-04-19-ordering-css-delcarations.md ├── 2022-04-23-notes-from-fred-schott-on-shop-talk-show.md ├── 2022-04-25-progressively-enhanced-builds.md ├── 2022-04-27-trusting-browsers.md ├── 2022-04-28-reading-notes-april.md ├── 2022-05-02-joining-remix.md ├── 2022-05-09-notes-from-michael-jackson-devmode-fm.md ├── 2022-05-09-the-web-beyond-browsers.md ├── 2022-05-10-browser-level-color-scheme-preference.md ├── 2022-05-12-whats-it-worth.md ├── 2022-05-15-principles-of-color-beyond-srgb.md ├── 2022-05-17-netlify-public-folder-part-iv.md ├── 2022-05-18-quick-dirty-text-diffing.md ├── 2022-05-23-loading-parsing-executing-javascript.md ├── 2022-05-26-the-case-for-design-engineers.md ├── 2022-05-27-reading-notes-may.md ├── 2022-05-28-avoiding-flash-of-inaccurate-theme-color.md ├── 2022-06-04-design-systems-and-boundaries.md ├── 2022-06-08-short-history-of-ios-app-icons.md ├── 2022-06-12-visualizing-my-blogs-links.md ├── 2022-06-16-form-data-and-json.md ├── 2022-06-18-the-message-and-medium-of-the-personal-blog.md ├── 2022-06-20-fav-excerpts-from-the-postlight-podcast-part-ii.md ├── 2022-06-23-doing-well.md ├── 2022-06-26-previous-sibling-selector.md ├── 2022-06-28-notes-from-in-and-out-of-style.md ├── 2022-06-30-reading-notes-june.md ├── 2022-07-01-software-over-time.md ├── 2022-07-04-unlocked-possibilities-of-has-selector.md ├── 2022-07-06-visualizing-sf-font-variations.md ├── 2022-07-10-my-office-space.md ├── 2022-07-12-resiliency-in-the-webs-layers.md ├── 2022-07-14-writing-and-waiting.md ├── 2022-07-19-finding-stuff-to-write-about.md ├── 2022-07-21-there-is-no-bar-but-having-one-is-good-too.md ├── 2022-07-24-book-notes-on-writing.md ├── 2022-07-26-html-email-rant.md ├── 2022-07-30-reading-notes-july.md ├── 2022-08-02-multiple-inline-svgs.md ├── 2022-08-03-other-peoples-websites.md ├── 2022-08-03-saying-thank-you.md ├── 2022-08-08-markdown-sans-front-matter.md ├── 2022-08-12-things-you-can-and-cant-do.md ├── 2022-08-14-playing-with-blog-home.md ├── 2022-08-15-well-known-links-resource.md ├── 2022-08-16-old-african-proverb-on-web-design.md ├── 2022-08-18-web-diversity.md ├── 2022-08-19-re-web-harsh-manager-pt-ii.md ├── 2022-08-19-re-web-harsh-manager.md ├── 2022-08-28-stats-page.md ├── 2022-08-30-trying.md ├── 2022-09-02-validating-html.md ├── 2022-09-03-reading-notes-august.md ├── 2022-09-05-generating-epub-file-in-browser.md ├── 2022-09-07-jen-simmons-shoptalk-show.md ├── 2022-09-12-good-design.md ├── 2022-09-13-building-together.md ├── 2022-09-14-building-software-as-translation.md ├── 2022-09-17-font-family-and-supports.md ├── 2022-09-18-flying-j-pies.md ├── 2022-09-19-my-contribution-to-react-router.md ├── 2022-09-21-moving-with-prototypes.md ├── 2022-09-26-custom-rss-feeds.md ├── 2022-09-30-reading-notes-september.md ├── 2022-10-03-remix-react-and-state.md ├── 2022-10-05-patching-open-web.md ├── 2022-10-06-sketch-design-challenge-icons.md ├── 2022-10-11-app-icon-ai-variations.md ├── 2022-10-17-website-fidelity.md ├── 2022-10-19-labels-spectrums-and-the-web.md ├── 2022-10-20-seeing-vs-using.md ├── 2022-10-24-what-work-looks-like.md ├── 2022-10-26-scroll-to-text-fragments.md ├── 2022-10-27-optimize-for-nothing.md ├── 2022-10-29-reading-notes-october.md ├── 2022-10-31-website-fidelity-browser.md ├── 2022-11-06-npm-dependency-queries.md ├── 2022-11-09-browsers-json-formdata.md ├── 2022-11-13-verified-personal-website.md ├── 2022-11-14-obscure-things-power-the-imagination.md ├── 2022-11-16-remix-alternate-timeline-of-web-dev.md ├── 2022-11-20-artistic-prototypes.md ├── 2022-11-22-natural-language-inputs.md ├── 2022-11-27-css-for-urls-and-http-headers.md ├── 2022-11-29-the-word-value-in-css.md ├── 2022-11-30-reading-notes-november.md ├── 2022-12-05-employment-change.md ├── 2022-12-13-music-programming-and-practice.md ├── 2022-12-15-select-the-right-tool.md ├── 2022-12-19-good-design-pt-ii.md ├── 2022-12-23-notes-from-ryan-dahl-on-shop-talk-show.md ├── 2022-12-27-prototypes-and-practice.md ├── 2022-12-31-reading-notes-december.md ├── 2023-01-02-book-notes-pirate-treasure.md ├── 2023-01-04-thinking-systematically.md ├── 2023-01-05-justify-space-between-individual-items.md ├── 2023-01-08-ok-lch-im-convinced.md ├── 2023-01-10-subscribe-wherever-you-get-your-content.md ├── 2023-01-16-curating-human-and-ai-artwork.md ├── 2023-01-17-art-of-knowing-when-to-quit.md ├── 2023-01-18-the-anti-capitalist-web.md ├── 2023-01-23-short-history-of-port-numbers.md ├── 2023-01-24-best-time-to-own-a-domain.md ├── 2023-01-26-digital-preservation-and-the-app-icon-book.md ├── 2023-01-29-nothings-bulletproof.md ├── 2023-01-31-reading-notes-january.md ├── 2023-02-03-hipster-history-of-cors.md ├── 2023-02-06-the-birth-of-disable-javascript.md ├── 2023-02-07-validity-of-custom-element-tag-names.md ├── 2023-02-09-productive-procrastination.md ├── 2023-02-16-css-wishlist.md ├── 2023-02-21-notes-dot-jim-nielsen-dot-com.md ├── 2023-02-22-faux-progress.md ├── 2023-02-27-end-users-over-all-else.md ├── 2023-03-01-logic-of-code-and-illogic-of-creativity.md ├── 2023-03-06-oasis-of-quiet.md ├── 2023-03-09-deadlines-as-technology.md ├── 2023-03-13-figma-to-browser-chasm.md ├── 2023-03-16-alphabet-as-technology.md ├── 2023-03-20-logical-properties-and-ease.md ├── 2023-03-22-human-hype-and-machine-intelligence.md ├── 2023-03-27-types-in-jsdoc-with-zod.md ├── 2023-04-02-more-everything-with-ai.md ├── 2023-04-10-ai-and-the-science-of-creativity.md ├── 2023-04-17-site-search-in-arc-browser.md ├── 2023-04-18-offline-is-online-with-extreme-latency.md ├── 2023-04-23-notes-to-self-on-mastodon.md ├── 2023-04-24-notes-from-richs-talk.md ├── 2023-04-30-circles-and-momentum.md ├── 2023-05-03-gratitude-for-dont-break-the-web.md ├── 2023-05-04-cite-your-sources-ai.md ├── 2023-05-12-domain-handle-blueksy.md ├── 2023-05-14-rich-fast-loops-and-tradeoffs.md ├── 2023-05-16-building-infinite-spreadsheet.md ├── 2023-05-18-date-and-time-in-ssg.md ├── 2023-05-19-practical-accessibility.md ├── 2023-05-22-well-known-avatar.md ├── 2023-05-24-single-line-comments-in-css.md ├── 2023-05-26-link-preload-image.md ├── 2023-05-30-throwaway-browser-defaults.md ├── 2023-06-01-slow-motion-animations-with-chrome-devtools.md ├── 2023-06-12-minute-rice-text-and-websites.md ├── 2023-06-15-imports-under-the-hood.md ├── 2023-06-19-ode-to-aea.md ├── 2023-06-20-thoughts-on-safari-spatial-computing.md ├── 2023-06-24-components-and-legos.md ├── 2023-06-28-apollo-app-icons.md ├── 2023-07-05-language-level-toll-roads.md ├── 2023-07-11-stop-being-fancy.md ├── 2023-07-14-things-i-like-over-things-i-dont.md ├── 2023-07-20-domain-sins-of-my-youth.md ├── 2023-07-24-domain-nuance.md ├── 2023-07-31-user-feedback.md ├── 2023-08-02-knowledge-laundering.md ├── 2023-08-09-stealth-and-best-practices.md ├── 2023-08-14-meaning-in-web-tech-stack-ordering.md ├── 2023-08-18-js-party-288.md ├── 2023-08-20-temporarily-abled.md ├── 2023-08-21-reloading-document-in-html-and-preserve-query-params.md ├── 2023-08-23-counting-to-ten.md ├── 2023-08-26-something-you-need-to-know-about-web-dev.md ├── 2023-08-28-family-tree-wisdom.md ├── 2023-08-31-book-notes-out-of-the-software-crisis.md ├── 2023-09-01-software-crisis-dependencies.md ├── 2023-09-04-software-crisis-garden.md ├── 2023-09-06-software-crisis-making-software.md ├── 2023-09-11-llms-intuition-and-computers.md ├── 2023-09-14-japanese-ios-app-icon-book.md ├── 2023-09-17-precarious-modern-computing.md ├── 2023-09-24-software-by-encountering.md ├── 2023-09-26-software-is-what-we-learned-along-the-way.md ├── 2023-09-27-robots-txt.md ├── 2023-10-01-websites-are-for-normies.md ├── 2023-10-04-notes-on-notes.md ├── 2023-10-08-the-flavors-of-typescript.md ├── 2023-10-10-web-components-icon-galleries.md ├── 2023-10-15-the-cost-of-avoiding-annoyance.md ├── 2023-10-18-naming-things-and-llms.md ├── 2023-10-20-people-and-blogs-and-me.md ├── 2023-10-23-javascript-is-enabled-by-default.md ├── 2023-10-25-cat-and-mouse.md ├── 2023-10-31-advice-on-blogging.md ├── 2023-11-02-embeds-and-quotations.md ├── 2023-11-05-as-good-as-html.md ├── 2023-11-13-html-web-components.md ├── 2023-11-15-html-web-components-an-example.md ├── 2023-11-20-width-and-height-in-css.md ├── 2023-11-28-examples-of-great-urls.md ├── 2023-12-03-how-i-take-and-publish-notes.md ├── 2023-12-05-thats-another-podcast.md ├── 2023-12-13-most-profitable-ui-element-ever.md ├── 2023-12-19-unread-badge-macos-safari-web-app.md ├── 2023-12-28-blogging-and-compositing.md ├── 2024-01-02-fault-tolerance-html-css.md ├── 2024-01-04-cold-blooded-software.md ├── 2024-01-07-notes-from-computing-sustainably.md ├── 2024-01-09-humans-all-the-way-down.md ├── 2024-01-10-idioms-as-code.md ├── 2024-01-12-macos-icon-book-irl.md ├── 2024-01-14-dinner-conversation.md ├── 2024-01-17-rss-in-html.md ├── 2024-01-19-rss-in-html-follow-up.md ├── 2024-01-21-immeasurable-impact.md ├── 2024-01-23-origin-of-online-handles.md ├── 2024-01-28-online-handles-round-up.md ├── 2024-01-30-inbox-o-receipts.md ├── 2024-02-01-treating-the-symptoms.md ├── 2024-02-05-discovering-newsletter-links-with-quadratic.md ├── 2024-02-07-golden-era-blogging.md ├── 2024-02-12-the-case-for-design-engineers-pt-ii.md ├── 2024-02-15-zero-to-unmaintainable.md ├── 2024-02-19-ui-fn-org.md ├── 2024-02-21-two-tips-building-with-react-router.md ├── 2024-02-26-the-subversive-hyperlink.md ├── 2024-02-27-more-files-plz.md ├── 2024-02-29-notes-on-making-software-by-peter-van-hardenberg.md ├── 2024-03-04-ai-is-like-a-lossy-jpeg.md ├── 2024-03-05-shoptalk-show-605.md ├── 2024-03-07-hard-websites.md ├── 2024-03-12-following-links.md ├── 2024-03-19-making-films-and-making-websites.md ├── 2024-03-25-allure-of-sync-engines.md ├── 2024-03-27-the-case-for-design-engineers-pt-iii.md ├── 2024-04-01-expose-platform-apis-over-wrapping-them.md ├── 2024-04-08-netlify-image-cdn.md ├── 2024-04-09-you-are-what-you-read.md ├── 2024-04-15-faster-bandwidth-and-websites.md ├── 2024-04-17-consistent-nav-across-inconsistent-sites.md ├── 2024-04-22-interdisciplinary-website-maker.md ├── 2024-04-24-big-sur-ification-of-macos-icons.md ├── 2024-04-28-cars-motorcycles-websites-seams.md ├── 2024-05-01-bulletproof-problem-solving.md ├── 2024-05-06-errors-arent-all-bad.md ├── 2024-05-13-gist-that-keeps-giving.md ├── 2024-05-20-futuristic-progressive-enhanement.md ├── 2024-05-21-rsc-localfirst-and-coordination-between-computers.md ├── 2024-05-24-thinking-big-and-small.md ├── 2024-05-30-overcomplicating-is-easy.md ├── 2024-06-03-just-one-line.md ├── 2024-06-04-novels-as-prototypes.md ├── 2024-06-07-night-time-sky.md ├── 2024-06-10-hedge-words-and-imaginative-thinking.md ├── 2024-06-17-notes-from-you-are-not-a-gadget.md ├── 2024-06-19-organic-intelligence.md ├── 2024-06-20-custom-elements-only-need-end-with-a-hyphen.md ├── 2024-06-24-local-first-makes-codebases-more-collaborative.md ├── 2024-06-27-cool-uris-and-humans.md ├── 2024-07-01-digital-trees.md ├── 2024-07-08-all-about-that-button.md ├── 2024-07-11-the-value-of-silence.md ├── 2024-07-15-text-prompts-circumscribe-solutions.md ├── 2024-07-17-me-no-like-the-term-ic.md ├── 2024-07-18-amazing-athletes.md ├── 2024-07-22-greatest-strength-is-greatest-weakness.md ├── 2024-08-02-deploying-with-netlify-shortcuts.md ├── 2024-08-05-just-build-websites.md ├── 2024-08-06-deno-de-emphasizes-http-imports.md ├── 2024-08-08-my-failed-peronsal-site-redesign.md ├── 2024-08-11-impressionist-blogging.md ├── 2024-08-14-iterative-building-and-decision-making.md ├── 2024-08-19-blog-vs-social-posts.md ├── 2024-08-21-netlify-public-folder-part-v.md ├── 2024-08-25-notes-site-via-content-in-dropbox.md ├── 2024-08-28-notes-from-pen-and-teller.md ├── 2024-08-29-the-humble-link.md ├── 2024-09-03-sanding-ui.md ├── 2024-09-04-personal-website-vulnerability.md ├── 2024-09-08-seeing-others-in-data-but-not-ourselves.md ├── 2024-09-16-the-ruthless-edit.md ├── 2024-09-17-reading-time-estimation-widgets.md ├── 2024-09-22-blogging-is-listening.md ├── 2024-09-29-wouldnt-recommend-this-algorithm.md ├── 2024-10-02-person-in-personal-website.md ├── 2024-10-04-easy-and-convenient-they-say.md ├── 2024-10-07-ryan-dahl-talks-deno-on-changelog.md ├── 2024-10-09-color-console-log.md ├── 2024-10-14-prototyping-magic-and-software.md ├── 2024-10-16-prompting-the-wrong-question.md ├── 2024-10-21-enabled-by-default.md ├── 2024-10-23-lowest-common-denominator.md ├── 2024-10-25-machine-content-creators.md ├── 2024-10-28-used-domain-clean-title.md ├── 2024-10-30-easy-changes.md ├── 2024-11-02-hacker-news-clones.md ├── 2024-11-04-design-engineer-job-screener.md ├── 2024-11-06-localstorage-recoil.md ├── 2024-11-11-navigations-on-the-web.md ├── 2024-11-13-beauty-of-building.md ├── 2024-11-15-writing-is-human-expression.md ├── 2024-11-18-named-blogs.md ├── 2024-11-20-bad-captchas.md ├── 2024-11-24-nabbing-macos-icons.md ├── 2024-11-27-nothing-is-something.md ├── 2024-12-02-contrast-is-clarifying.md ├── 2024-12-09-omgimg.md ├── 2024-12-12-making-omgimg-pt-i.md ├── 2024-12-15-making-omgimg-pt-ii.md ├── 2024-12-18-making-omgimg-pt-iii.md ├── 2024-12-23-making-omgimg-pt-iv.md ├── 2024-12-29-christmas-day.md ├── 2024-12-30-podcast-notes-talk-show-kagi.md ├── 2025-01-04-subscribe-via-email-now.md ├── 2025-01-06-notification-marshmallows.md ├── 2025-01-07-social-inflation.md ├── 2025-01-09-dont-miss-the-product-for-the-artifacts.md ├── 2025-01-12-view-transition-name-gotchas.md ├── 2025-01-13-local-cli-tools-in-node.md ├── 2025-01-15-tools-as-ways-of-being.md ├── 2025-01-20-relationship-advice-for-ai.md ├── 2025-01-22-overriding-basic-ui-controls.md ├── 2025-01-27-html-minification.md ├── 2025-01-28-missed-connections.md ├── 2025-01-29-javascript-required.md ├── 2025-02-02-ui-pace-layers.md ├── 2025-02-04-blown-away-by-the-unexpected.md ├── 2025-02-07-software-pliability.md ├── 2025-02-10-the-art-of-making-websites.md ├── 2025-02-13-search-without-javascript.md ├── 2025-02-17-aspect-ratio-in-css-view-transitions.md ├── 2025-02-19-css-space-toggles.md ├── 2025-02-24-sanding-ui-pt-ii.md ├── 2025-02-26-limitations-vs-capabilities.md ├── 2025-02-28-get-better-doing-a-bad-job.md ├── 2025-03-02-thoughts-on-ax.md ├── 2025-03-04-lots-of-little-html-pages.md ├── 2025-03-16-ecosystems-vs-artifacts.md ├── 2025-03-20-proving-binaries.md ├── 2025-03-22-thoughts-on-working-draft-to-override-form-controls.md ├── 2025-03-24-book-notes-order-of-time.md ├── 2025-03-26-value-of-experience.md ├── 2025-03-30-dont-forget-meta-theme-color.md ├── 2025-04-02-flow-state-and-surfing.md ├── 2025-04-05-tag-youre-it.md ├── 2025-04-08-background-image-opacity-css.md ├── 2025-04-10-ductility.md ├── 2025-04-14-love-for-interoperability.md ├── 2025-04-16-be-mindful-of-what-you-make-easy.md ├── 2025-04-19-as-strong-as-your-weakest-point.md ├── 2025-04-21-i-dont-see-why-not.md ├── 2025-04-23-job-titles.md ├── 2025-04-27-craft-and-satisfaction.md ├── 2025-04-29-backwards-compat-in-web-but-not-its-tools.md ├── 2025-05-05-tumult-in-design.md ├── 2025-05-07-language-needs-innovation.md ├── 2025-05-12-notes-from-blink-principles-of-web-compat.md ├── 2025-05-14-notes-from-hundred-year-web-service.md ├── 2025-05-18-multiple-computers.md ├── 2025-05-20-product-pseudoscience.md ├── 2025-05-23-better-platform-defaults-color-picker.md ├── 2025-05-25-more-friction-please.md ├── 2025-05-28-tradeoffs-to-continuous-software.md └── 2025-06-02-is-it-javascript.md ├── scripts ├── cache-site-data.js ├── get-hacker-news-posts.js ├── get-trending-posts.js └── parse-markdown.js ├── src ├── routes │ ├── 404.html.js │ ├── _redirects.js │ ├── about │ │ ├── external-links │ │ │ └── index.html.js │ │ ├── index.html.js │ │ └── internal-links │ │ │ └── index.html.js │ ├── archive │ │ └── index.html.js │ ├── feed.html.js │ ├── feed.json.js │ ├── feed.xml.js │ ├── index.html.js │ ├── menu │ │ └── index.html.js │ ├── posts │ │ ├── hacker-news │ │ │ └── index.html.js │ │ ├── index.html.js │ │ ├── index.json.js │ │ ├── personal-favs │ │ │ └── index.html.js │ │ └── trending │ │ │ └── index.html.js │ ├── search │ │ └── index.html.js │ ├── styles.css.js │ ├── subscribe │ │ └── index.html.js │ └── tags │ │ └── index.html.js ├── server │ ├── Layouts.js │ ├── Post.js │ ├── PostsList.js │ ├── PostsNav.js │ ├── ReplyHtml.js │ ├── RssClub.js │ ├── ThemePicker.js │ ├── avatar.png │ ├── getBlogPostsStatus.js │ ├── preferences.js │ ├── styles │ │ ├── basic.css │ │ ├── modern-normalize.css │ │ └── styles.css │ ├── svgs │ │ ├── check-mark.svg │ │ ├── feed-html.svg │ │ ├── feed-json.svg │ │ ├── feed-rss.svg │ │ ├── heroicon-close.svg │ │ ├── heroicon-dark.svg │ │ ├── heroicon-light.svg │ │ ├── heroicon-menu.svg │ │ ├── heroicon-search.svg │ │ ├── heroicon-system.svg │ │ ├── heroicon-x-circle.svg │ │ ├── icons.svg │ │ ├── initial.svg │ │ └── preferences.svg │ ├── theme-picker.js │ ├── theme.js │ └── utils.js ├── site.ori └── static │ ├── 404-pie.jpg │ ├── apple-touch-icon.png │ ├── assets │ └── img │ │ ├── favicon.svg │ │ ├── fidelity-high.svg │ │ ├── fidelity-low.svg │ │ ├── fidelity-med.svg │ │ ├── jimniels.jpg │ │ ├── logo-black.png │ │ ├── logo-white.png │ │ ├── preferences.svg │ │ └── twitter-card.png │ ├── favicon.ico │ └── pagefind.js ├── tsconfig.json └── types.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | .git 3 | .cache 4 | .nova 5 | node_modules/ 6 | build* 7 | atom-one*.css 8 | 9 | .* 10 | !.gitignore 11 | !.prettierignore 12 | !.github 13 | !.npmrc 14 | 15 | # Local Netlify folder 16 | .netlify 17 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.md 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Jim Nielsen’s Blog](https://blog.jim-nielsen.com) 2 | 3 | - Local development: `npm start` 4 | - Production build: `npm run build` 5 | 6 | > writing is nature’s way of letting you know how sloppy your thinking is 7 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "" 3 | publish = "build" 4 | command = "npm run build" 5 | environment = { NODE_VERSION = "22" } 6 | 7 | [[redirects]] 8 | from = "https://jimniels-blog.netlify.com/*" 9 | to = "https://blog.jim-nielsen.com/:splat" 10 | status = 301 11 | force = true 12 | 13 | # How this works: 14 | # 15 | # URL: /.netlify/functions/preferences | FILE: netlify/functions/preferences.js 16 | # This sets/modifies a cookie for the client so Netlify can rewrite requests 17 | # FILE: netlify.toml 18 | # Contains the rewrite rules 19 | # FILE: build/_fidelity/{low|med} 20 | # Contains the same version of the site, but with fidelity stripped out 21 | # of the default version of the site (which lives at `build/`) 22 | # 23 | # Of note: "low" and "med" are the two enumerated values used in: 24 | # - The cookies 25 | # e.g. `fidelity-low=active` or `fidelity-med=active` 26 | # - The redirect rules 27 | # e.g. a request to `/about/` with `fidelity-low=active` rewrites to 28 | # `/_fidelity/low/about/(index.html)` 29 | # - The build directories 30 | # e.g. a version of the site is generated for each fidelity and stuck 31 | # in the `/_fidelity` folder, i.e. `_fidelity/low/` 32 | # [[redirects]] 33 | # from = "/*" 34 | # to = "/_fidelity/low/:splat" 35 | # status = 200 36 | # force = true 37 | # conditions = { Cookie = ["fidelity-low"] } 38 | 39 | # [[redirects]] 40 | # from = "/*" 41 | # to = "/_fidelity/med/:splat" 42 | # status = 200 43 | # force = true 44 | # conditions = { Cookie = ["fidelity-med"] } 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jimniels-blog", 3 | "version": "1.0.0", 4 | "description": "[jim-nielsen.com/blog](http://jim-nielsen.com/blog)", 5 | "main": "metalsmith.js", 6 | "type": "module", 7 | "dependencies": { 8 | "@weborigami/origami": "0.2.9", 9 | "@weborigami/pagefind": "0.0.4", 10 | "highlight.js": "^11.4.0", 11 | "html-minifier": "^4.0.0", 12 | "html-validate": "^7.3.3", 13 | "marked": "^4.0.12", 14 | "psl": "^1.8.0" 15 | }, 16 | "scripts": { 17 | "test": "echo \"Error: no test specified\" && exit 1", 18 | "copy-css": "cp node_modules/highlight.js/styles/atom-one-*.css src/server/styles/", 19 | "pre": "mkdir -p .cache && npm run copy-css && node scripts/cache-site-data.js", 20 | "prestart": "npm run pre", 21 | "start": "ori serve watch src, =debug src/site.ori", 22 | "prebuild": "npm run pre", 23 | "build": "ori copy src/site.ori, clear files:build", 24 | "postbuild": "npm run minify", 25 | "validate": "html-validate build/", 26 | "minify": "html-minifier --input-dir ./build --output-dir ./build --file-ext html --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --remove-tag-whitespace --use-short-doctype --minify-css true --minify-js true" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "git+https://github.com/jimniels/blog.git" 31 | }, 32 | "author": "", 33 | "license": "ISC", 34 | "bugs": { 35 | "url": "https://github.com/jimniels/blog/issues" 36 | }, 37 | "homepage": "https://github.com/jimniels/blog#readme" 38 | } 39 | -------------------------------------------------------------------------------- /posts/2012-11-28-understanding-comes-in-stages.md: -------------------------------------------------------------------------------- 1 | # Understanding Comes in Stages 2 | 3 | In a radio series from the 1940’s, author E.M. Forster [stated](http://www.rzim.org/a-slice-of-infinity/two-staged-miracles/) that the books which truly influence us are the ones we are prepared to read, namely those “which have gone a little further down our particular path than we have yet got ourselves.” Hence a truly moving reading experience is the culmination of not just *what* you read but *when* you read it. 4 | 5 | Personally, I love reading with a pen or highlighter on hand. I’m sure I share this sentiment with many others. Navigating books I’ve annotated reminds me of what I learned while reading. Yet there have been countless times I’ve returned to a previously-read passage only to wonder why in the world I highlighted sentence seven and completely left all of paragraph four unmarked. However, now I realize that as I experience more of life (getting to know myself, my neighbors, my career, my friends, my world) I come to see and understand aspects of life very differently. 6 | 7 | As just one example, I used to gloss over snippets of javascript or terminal commands deeming them the writings of a foreign language. However, I now scrupulously inspect those snippets for nuggets of knowledge I have not yet discovered. 8 | 9 | Seeing, and its ensuing counterpart understanding, come in phases. What you fail to grasp and understand at this point in your development you may later find to be common sense. Be patient. Seeing and understanding come in stages through experience. 10 | -------------------------------------------------------------------------------- /posts/2012-11-30-safari-tab-preview.md: -------------------------------------------------------------------------------- 1 | # Safari 6 Tab Preview: Show Me More! (In Quantity, Not Size) 2 | 3 | Apple's Safari 6 introduced a new tab switching experience. By activating the feature, Safari presents you with a bird's-eye view of open tabs. 100% of the active tab is previewable while only about 15% of it's left and right sibilings are previeweable. 4 | 5 | ![Safari 6 tab preview](https://cdn.jim-nielsen.com/blog/2012/safari6-tab-view.jpg) 6 | 7 | This experience of previewing your tabs is consistent no matter the application's viewport size. You always see 100% of the active tab and about 15% of it's left and right siblings. 8 | 9 | ![Safari 6 tab preview at different resolutions](https://cdn.jim-nielsen.com/blog/2012/safari6-tab-view-resolution-comparison.jpg) 10 | 11 | Wouldn't it be neat to see the preview of the active tab's siblings grow as the viewport grows horizontally? Essentially, if I had a large monitor I would be able to **see more** of the sibling tabs' previews. 12 | 13 | ![New design of Safari 6 tab preview](https://cdn.jim-nielsen.com/blog/2012/safari6-tab-view-new-design.jpg) 14 | 15 | As you can see, as the window grows in size horizontally it would **reveal more** of the sibling tabs' previews **rather than increase** the tab preview sizes. Visually this would help form a more cohesive mental model of the spacial relationship between tabs. It would also help tremendously for any site-comparison a user might be doing. 16 | -------------------------------------------------------------------------------- /posts/2012-12-12-said-no-user-ever.md: -------------------------------------------------------------------------------- 1 | # Said No Normal User, Ever 2 | 3 | > Remember that there are already too many things out there. We don’t need more things, we need things that work well. 4 | 5 | I’ve recently been reading Smashing Magazine’s [Smashing Book #3][1] and found Aral Balkan’s chapter *[Mobile Considerations in User Experience Design: “Web or Native?”][2]* quite intriguing. His arguments might even persuade you to believe the web isn’t the platform of the future so many have predicted it to be, but I won’t argue that point here. 6 | 7 | Balkan’s article reminded me of our feverish platitudes in the tech world that often blind us to users’ needs, wants, and expectations. Talk of open vs. closed systems, why the web is better because of it’s universal accessibility, and other arguments may influence why a *developer* chooses one system or platform over another. However, the rationale and justification that informs the choices we make as creators of technology rarely bears any weight with incognizant users of technology. 8 | 9 | As Balkan points out, who cares what platform your application runs on if it runs badly? Ok some developers and tech evangelists probably care, but outside of them who cares? 10 | 11 | “Crap, my widget crashed and lost all my form data, but that’s ok. These guys built this app using open technology of the web so I’m gonna give this product a break and keep using it.” Said no normal user, ever. 12 | 13 | 14 | 15 | [1]: https://shop.smashingmagazine.com/smashing-book-3.html 16 | [2]: http://mobile.smashingmagazine.com/2012/06/18/mobile-considerations-in-user-experience-design-web-or-native/ 17 | -------------------------------------------------------------------------------- /posts/2013-01-29-quick-change-and-the-web.md: -------------------------------------------------------------------------------- 1 | # Quick Change and the Web 2 | 3 | Can you really change the world over night? 4 | 5 | > In both the web and in our greater community, I see people despair that change doesn’t happen more quickly. That we can’t make the world better overnight. But if this year has taught me anything, it is that we can’t ignore the hard work that needs to be done. And that we all must take up the charge to make the world better than it we found it — both on the web and in our society. - [Jason Grigsby](http://alistapart.com/article/what-we-learned-in-2012) 6 | 7 | What is so great about the web is that , with a single great idea, you **can** often build it overnight. Or at least in a few days. No bureaucracy. No paperwork. No meetings. No board approval.The [Arc90 Hackathon](http://lab.arc90.com/hackathon/2012/) was a good example of this to me. Get a good idea, start a conversation, excite others, build it, release it to the community, and if its great, you'll begin sowing the seeds of change. 8 | 9 | From there you just iterate. 10 | -------------------------------------------------------------------------------- /posts/2013-01-31-modularize-your-psds.md: -------------------------------------------------------------------------------- 1 | #tips 2 | 3 | # Modularize Your PSDs by Embedding Them Inside Each Other 4 | 5 | If you've ever used InDesign you've no doubt used the "Links" panel. It allows you to link and embedd files in your document layout. InDesign keeps track of all the files you've embedded and where they live on your hard drive. This gives you the power to relink files, updated modified files, edit the original files, and so forth. For example, say you embedd a logo in InDesign but then you want to modify it. You can go to the Links panel and click "edit original". Illustrator (or whatever logo editing software you've used) will open the file. You make your changes, save it, and go back to InDesign and the logo's changes will automatically update in your layout. 6 | 7 | ![Links Panel in InDesign](https://cdn.jim-nielsen.com/blog/2013/links-panel-indesign.png) 8 | 9 | I found myself wanting this feature in Photoshop. It would be extremely useful for building websites because you could modularize your PSDs. For example, I could create one PSD called `header.psd` and another called `footer.psd`. When I want to create a PSD for a new page mockup, I can easily "embedd" the header and footer PSDs into my new document. This allows me to easily spin-off new page mockups based on single PSD files. 10 | 11 | So, for example, if I want to change a design element in the header of my website, I only have to change it in one file and it would be replicated in all the PSDs where I've embedded `header.psd`. This is essentially the same thing as creating a file called `header.php` that has all my main navigation and is called into every page template. 12 | 13 | Although InDesign supports this feature, Photoshop does not. However, a Google search led me to these two extensions which have become quite useful. 14 | 15 | 1. [Smart Object Links Panel](http://www.ps-scripts.com/bb/viewtopic.php?f=27&t=3045&sid=90f57aa35b85d5d38fe52ea551ac4a4c) 16 | 2. [CanLinkIt](http://www.canlinkit.com/) 17 | 18 | I'm not sure what the development status of these are anymore, but they worked for me. Try them out! I think they will save you a lot of time. 19 | 20 | Now with PSDs you can edit once and change everywhere! 21 | -------------------------------------------------------------------------------- /posts/2013-02-12-freebie-resources.md: -------------------------------------------------------------------------------- 1 | #tips 2 | 3 | # Freebie Resources - Don’t Assume, Double Check 4 | 5 | Seemingly high-quality freebies, who doesn't love them? They save lots of time. However, be careful to double check and properly adjust any small details that may be misaligned. As they say, design is in the details, and sometimes you can't always rely on someone else having invested in those details. 6 | 7 | Here's a vector freebie I got online today. I imported the shape into Photoshop and noticed a 1px offset in symmetry: 8 | 9 | ![Freebie 1px Offset](https://cdn.jim-nielsen.com/blog/2013/freebie-offset.png) 10 | 11 | I know you might be thinking, "1px offset? Nobody will even notice that." And you know what? You're right. One little 1px offset in an image that's 16x16 pixels probably won't be noticed by many people. However, the accumulation of many 1px offsets in your digital creations **will** be noticed! It's worth practicing some self discipline because it will help avoid sloppy work. 12 | 13 | ![Freebie 1px Offset Shape Selection](https://cdn.jim-nielsen.com/blog/2013/freebie-offset-select.png) 14 | 15 | Ahhh, isn't this much better? 16 | 17 | ![Freebie 1px Offset Correction](https://cdn.jim-nielsen.com/blog/2013/freebie-offset-fix.png) 18 | 19 | Don't assume the freebie is pixel-perfect, especially when transferring it between software applications. Keeping up your guard and not making assumptions will prevent slipshod work. 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /posts/2013-03-08-coming-to-appreciate-art.md: -------------------------------------------------------------------------------- 1 | # Coming to Appreciate Art 2 | 3 | I have a confession: for some time now I've been cynical of art. More specifically modern art. For example, here is a piece of art I encountered at the Museum of Modern Art in New York City: 4 | 5 | ![Modern Art at the MoMA](https://pbs.twimg.com/media/A-wPHGACcAA7xOB.jpg) 6 | 7 | I can't help but ask myself: how is this art? Even more puzzling: how does it have a place in the world-renowned MoMA? At first-glance, this piece seems on par with something my four-year-old nephew could create. Then, as a web designer, I am reminded most people think websites are something their nephews could create too. 8 | 9 | What's my point? I realize I don't understand or appreciate art because I am ignorant of it. People don't understand or appreciate web design because they are ignorant of it. As a general rule of thumb, the more you immerse yourself in something and learn its intricacies and rationales the more you come to appreciate and respect it. That goes for modern art or web design. Get to know the things you criticize. Generally, **the more you know the less you will criticize**. 10 | 11 | ## So Is It Art or Not? 12 | 13 | The question still remains, what is art? Is that scribbled piece of canvas art? Here's a tip from Milton Glaser, a celebrated graphic designer, on determining what is and is not art: 14 | 15 | > you cannot tell art by virtue of medium, or function, or anything else except by the fact of its raising your consciousness to a degree that you are attentive. And so if something produces the state of attentiveness, whether it’s a drawing, or a guy making a cheese sandwich, we can call it art, at least by my description 16 | 17 | According to Glaser, if something "produces a state of attentiveness", whether it's Van Gogh's *Starry Night* or this seemingly scribbled mess, you can call it art. 18 | 19 | As you may have noticed, that scribbled mess at the MoMA brought me an incredible amount of introspection and reflection. It raised my consciousness to a degree that I was attentive. I suppose that is why it has a place at the Museum of Modern "Art". 20 | -------------------------------------------------------------------------------- /posts/2013-05-05-an-analysis-of-infinite-scroll.md: -------------------------------------------------------------------------------- 1 | # An Analysis of Infinte Scrolling 2 | 3 | Have you ever felt exhausted by infinite scrolling? 4 | 5 | > Infinite scrolling merely tempts you to continue reading, wasting time and decreasing productivity in the process ... Even more annoying is that scroll bars do not reflect the actual amount of data available. You’ll scroll down happily assuming you are close to the bottom, which by itself tempts you to scroll that little bit more, only to find that the results have just doubled by the time you get there. 6 | 7 | I've encountered this many times. It's exhausting. The worst part is that you keep telling yourself “just a little further” because you perpetually see the scroll bar two-thirds of the way down the page and don't want to feel as though you're missing out on any information. 8 | 9 | Yogev Ahuvia wrote [a great article over at Smashing Magazine](http://uxdesign.smashingmagazine.com/2013/05/03/infinite-scrolling-get-bottom/) that analyzes the benefits and drawbacks of using infinite scrolling. It's worth a read. 10 | -------------------------------------------------------------------------------- /posts/2013-05-15-why-do-we-sketch.md: -------------------------------------------------------------------------------- 1 | #tips 2 | 3 | # Why Do We Sketch? 4 | 5 | When an idea strikes, what do you do with it? The commonly-held belief is that you sketch the idea on paper, as a sort of refinement process. Why? Because ideas, especially visual ones, are conceptually rough and difficult to articulate. Sketching an idea on paper can be a process of refinement. Through sketching, an idea becomes sufficiently polished to warrant actual implementation. 6 | 7 | However, there is another purpose to sketching that is often overlooked. Sketching isn't always about slowly shaping and fine-tuning a single idea. In Smashing Magazine's recent publication *[The Mobile Book][1]*, Dennis Kardys writes a chapter called “Hands on Design for Mobile” in which he points out this disparate purpose to ideation and sketching: 8 | 9 | > We often think of sketching as a way to generate and communicate ideas, but it can also be a weapon to dismantle them. The goal of sketching ... isn’t to produce drawings that inform the final design ... The goal is to drive out those stubborn, thorny ideas and make room for new ones. Only then can we look anew and achieve a deeper understanding of what we’re designing. 10 | 11 | Sometimes you work with ideas like a mason works with stone. You start with a large, unformed block of stone and slowly chip away at it until you arrive at the finished product. However, sometimes you work with ideas like a farmer doing a controlled burn. You burn everything down to make room for new growth. Only then do you see anew things hidden beforehand. 12 | 13 | 14 | [1]: http://www.the-mobile-book.com/ 15 | -------------------------------------------------------------------------------- /posts/2013-05-22-stop-direct-spam-comments-in-wordpress.md: -------------------------------------------------------------------------------- 1 | #tips 2 | 3 | # Stop Direct Spam Comments in Wordpress 4 | 5 | I recently redesigned my wordpress theme for [iOS Icon Gallery](http://iosicongallery.com) and [Mac Icon Gallery](http://macicongallery.com). 6 | 7 | The old themes provided the ability to comment through the interface. Due to a lack of real comments and a surplus in spam comments, I decided to entirely remove the ability to comment from the interface. 8 | 9 | ## Removing the Ability to Comment From the Interface Is Not Enough to Keep Out Spam 10 | 11 | Once my theme went live, I was still getting spam comments in the Wordpress backend. I asked myself, "how are comments still appearing in the Wordpress backend when I don't have a single comment form on my website?" After some Googling, I discovered this was due to spambots posting data directly using `wp-comments-post.php`. 12 | 13 | ![Sneaky Gif](https://cdn.jim-nielsen.com/blog/2013/sneaky.gif) 14 | 15 | ## Further Stopping Spambots 16 | To prevent spambots from posting to Wordpress via a URL, you can block access to `wp-comments-post.php` via the `.htaccess` file. Simply include these rules in your `.htaccess` file (thanks to [catswhocode](http://www.catswhocode.com/blog/snippets/blockreduce-wordpress-spam-comments-via-htaccess)) 17 | 18 | 19 | RewriteEngine On 20 | RewriteCond %{REQUEST_METHOD} POST 21 | RewriteCond %{REQUEST_URI} .wp-comments-post.php* 22 | RewriteCond %{HTTP_REFERER} !.*yourdomainname.* [OR] 23 | RewriteCond %{HTTP_USER_AGENT} ^$ 24 | RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L] 25 | 26 | 27 | **Note**: Be sure to change the `yourdomainname` part! 28 | 29 | ## That Doesn't Help You? 30 | If this doesn't seem like the best fix for you, try looking at this article from WP Tuts+ detailing [easy and efficient ways to combat spam comments](http://wp.tutsplus.com/tutorials/security/6-easy-and-efficient-ways-to-combat-spam-comments/). 31 | -------------------------------------------------------------------------------- /posts/2013-05-29-scriptogram-vector-logo.md: -------------------------------------------------------------------------------- 1 | # Scriptogram Logo in Vector Form (.svg) 2 | 3 | While working on a recent design, I suddenly needed a vector version of the [scriptogram](http://scriptogr.am/) logo. I couldn't find one on the web, so I made one myself. 4 | 5 | ![Scriptogram Logo](https://cdn.jim-nielsen.com/blog/2013/scriptogram-logo.png) 6 | 7 | If you find yourself needing the [scriptogram logo in vector form](https://cdn.jim-nielsen.com/blog/2013/scriptogram-logo.svg), you can download the version I created. 8 | -------------------------------------------------------------------------------- /posts/2013-06-10-max-upload-filesize-restart-apache.md: -------------------------------------------------------------------------------- 1 | #tips 2 | 3 | # Changes to max_upload_filesize not working in php.ini? Restart Apache! 4 | 5 | I was trying to import a SQL database into a local copy of Wordpress. The SQL file was larger than the standard 2MB upload limit, so Wordpress wouldn't let me upload it. 6 | 7 | After some research, I realized I could change the `max_upload_filesize` in the `php.ini` file. However, after changing the value to 10MB, Wordpress was still indicating the prior upload limit of 2MB. After wasting time trying other fixes, I suddenly realized I had not restarted apache! 8 | 9 | ![Duh!](https://cdn.jim-nielsen.com/blog/2013/duh.gif) 10 | 11 | From the command line `sudo apachectl restart` restarted my local apache server and changed my upload limit to 10MB in Wordpress. 12 | 13 | **Lesson**: if you're tinkering in configuration files, don't forget to restart apache to see your changes! 14 | -------------------------------------------------------------------------------- /posts/2013-06-11-seemly-selectors.md: -------------------------------------------------------------------------------- 1 | #tips #css 2 | 3 | # Seemly Selectors 4 | 5 | Take a look at this: 6 | 7 | `*` 8 | 9 | In CSS terms, that's the universal selector. Are warning sirens relating to performance sounding in your head? Are you feeling emotions of avoidance, like you do when you see `!important`? It's possible you do. The universal selector carries a negative stigma of poor performance. But should it? [Paul Irish answers](http://paulirish.com/2012/box-sizing-border-box-ftw/): 10 | 11 | > Apparently you’ve heard its slow. Firstly, it’s not. It is as fast as `h1` as a selector. It can be slow when you specifically use it like `.foo >` , so don’t do that 12 | 13 | It can be slow, but mostly it's not. Still, that may seem like reason enough in your mind to avoid using (or misusing) it. Stop thinking that way. Turn those "[Danger, Will Robison!](http://en.wikipedia.org/wiki/Danger,_Will_Robinson)" sirens off. Don't be afraid to use it. Why? Paul Irish continues: 14 | 15 | > You are not allowed to care about the performance of `*` unless you concatenate all your javascript, have it at the bottom, minify your css and js, gzip all your assets, and losslessly compress all your images. 16 | 17 | It's important to remember that general rules of thumb, such as: 18 | 19 | - don't use the `*` selector, it's slow 20 | - don't use the `!important` rule 21 | 22 | are rules discovered and shared by developers working on immensely large scale applications and websites, like Google.com. Some rules just don't apply to your ten page Wordpress site. 23 | 24 | The `*` and `!important` rules were invented for a reason. If you find yourself needing them, use them. That's what they were made for. If page performance takes a hit, look into larger-scale optimization techniques first, such as image optimization and concatenation. After that, you can get down to the nit-picky. In general, [optimization of selectors should be the job of the rendering engine](http://calendar.perfplanet.com/2011/css-selector-performance-has-changed-for-the-better/), not the designer. 25 | -------------------------------------------------------------------------------- /posts/2013-07-08-scriptogram-posts-in-json-with-php.md: -------------------------------------------------------------------------------- 1 | #engineering 2 | 3 | # Retrieving Recent Posts from Scriptogram in JSON Format Using PHP 4 | 5 | Do you use [Scriptogr.am](http://scriptogr.am/)? Do you want to programmatically retrieve your most recent posts from the service using PHP? It's not as simple as an API call, but it can be done. 6 | 7 | ## Before We Begin: The Javascript Method 8 | In case you're interested, [Alex at sicanstudios](http://sicanstudios.com/post/recent-posts-scriptogram/) has a great tutorial on how to retrieve and display your most recent Scriptogr.am posts using javascript. 9 | 10 | ## The PHP Method 11 | Scriptogr.am does not have a publicly accessible API. It does, however, provide an XML feed for each user. You can access your feed URL using this format: 12 | 13 | ``` 14 | http://scriptogr.am/USERNAME/feed/ 15 | ``` 16 | 17 | If you use PHP's `file_get_contents()` and pass it your Scriptogr.am feed URL, you'll be returned your most recent posts and accompanying metadata in XML form. 18 | 19 | ### Converting XML to JSON in PHP 20 | Now that we have the data we want, we've got to put it in the format we want (JSON). We can do that using the technique described in [this article from lostechies](http://lostechies.com/seanbiefeld/2011/10/21/simple-xml-to-json-with-php/). 21 | 22 | ## Cut to the Chase: The Code 23 | Here's the final PHP snippet that does everything we've described above. Just change the `$username` value to your own Scriptogr.am username and you're good to go! 24 | 25 | ```js 26 | function get_scriptogram_JSON() { 27 | $username = 'jimniels'; 28 | $url = 'http://scriptogr.am/'. $username .'/feed/'; 29 | $fileContents = file_get_contents($url); 30 | $fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents); 31 | $fileContents = trim(str_replace('"', "'", $fileContents)); 32 | $simpleXml = simplexml_load_string($fileContents); 33 | $json = json_encode($simpleXml); 34 | return $json; 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /posts/2013-07-15-thoughts-from-on-writing-well.md: -------------------------------------------------------------------------------- 1 | # Thoughts from “On Writing Well” 2 | 3 | Fact: the book [*On Writing Well*](http://www.amazon.com/dp/0060891548) by William Zinsser is simply stellar. His advice on writing is insightful and succinct. In addition, his thoughts on writing spill into other areas of life. 4 | 5 | Here's two thoughts I found relevant to design: 6 | 7 | 8 | ## Designing is Not a Contest 9 | 10 | > Every writer is starting from a different point and is bound for a different destination. Yet many writers are paralyzed by the thought that they are competing with everybody else who is trying to write and presumably doing better. 11 | 12 | This feeling of competition is often fostered in designers who see the work of associates being displayed in galleries while their own work gets no recognition. 13 | 14 | Forget everyone else and go at your own pace. Nobody else is solving the exact design problem you are. Your problem is unique; hence your solution should be too. Your only contest is with yourself. 15 | 16 | 17 | ## Just Get Rid of It 18 | 19 | Have you ever tried adding a design element only to find it extremely frustrating to do so? You put the element through all kinds of exertions: you move it to various locations, you resize and reform its structure, you change its colors, you add supporting elements in hopes of clarify its purpose, only to find the overall design worse than where you started? 20 | 21 | Zinsser says writers often encounter a similar impasse in constructing sentences. The solution? Get rid of the problem element. Unfortunately, this is usually our solution of last resort: 22 | 23 | > look at the troublesome element and ask, "do I need it at all?" Probably you don't. It was trying to do an unnecessary job all along - thats why it was giving you so much grief. Remove it and watch the afflicted sentence spring to life and breathe normally. It's the quickest cure and often the best. 24 | 25 | Sometimes, the best solution is to get rid of the design element you're trying so hard to include. 26 | -------------------------------------------------------------------------------- /posts/2013-09-23-automating-feelings.md: -------------------------------------------------------------------------------- 1 | # Automating Feelings 2 | 3 | > It’s been hard not to feel a deepening of the soul as the palette of online emotion signifiers has expanded from sparse typographic emoticons to colorful and animated emoji. (Nicolas Carr, “[Automating the feels](http://www.roughtype.com/?p=3693)”) 4 | 5 | ![Emoji Transformation](https://cdn.jim-nielsen.com/blog/2013/emoji-transformation.png) 6 | 7 | Social networks (and digital products) are now focusing on providing tools to help users express how they feel. Structuring human emotion into a machine-readable format might possibly be the next holy grail of the digital world. 8 | 9 | However, these seemingly innocuous tools have the power to change us by changing the way we express ourselves. If you have have an emotion that cannot be encapsulated in any available emoji, did you really feel it? At least by putting *some* type of graphically-expressible emotional symbol in a post you (and your friends) will know you felt *something*. 10 | 11 | The problem is human emotion is so heterogeneous, nuanced, and penetrating that language itself often falls short of describing it. How many times have you heard, “There are no words to describe this”? 12 | 13 | > The more we rely on finishing ideas with the same limited words (feeling happy) and images (smiley face) available to everyone on a platform, the more those pre-fabricated symbols structure and limit the ideas we express … these expression makes us one-dimensional, living caricatures of G-mail’s canned responses — a style of speech better suited to emotionless computers than flesh-and-blood humans. As Marshall McLuhan observed, just as we shape our tools, they shape us too. It’s a two-way street. - [Evan Selinger](http://www.wired.com/opinion/2013/08/move-over-social-graph-its-time-for-the-mood-graph-and-that-might-not-be-a-good-thing/) 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /posts/2013-09-26-kinda-sorta-looks-like-the-internet.md: -------------------------------------------------------------------------------- 1 | # The “Kinda-Sorta Looks Like the Internet” Internet 2 | 3 | > This is not a watered down version of the internet. Or the “mobile” version of the internet. Or the “kinda-sorta looks like the internet” internet. It’s just the internet. On your phone. 4 | 5 | ![iPhone internet TV ad screenshot](https://cdn.jim-nielsen.com/blog/2013/iphone-commercial.jpg) 6 | 7 | Those are the words from a [2007 TV ad](http://www.youtube.com/watch?v=ldjHqHC6szA) showcasing the capabilities of Apple’s new iPhone which allowed you to browse the internet. Not the stripped-down version so many PDAs and other mobile devices were accessing at the time, but the real internet. The same internet you saw on your desktop computer. That was revolutionary. 8 | 9 | Why? People want the web to be universal. They want the same internet they use everywhere else. They want to see and do the same things on their mobile device that they see and do on their desktop at home. So next time you think about stripping a feature from your responsive website or creating an entirely different “mobile-optimized” version of it remember this ad. 10 | 11 | I‘d venture to say that most people would rather double tap and two-finger pinch their way around the “desktop” web than be short-changed on content or capabilities for a “mobile-optimized” web. 12 | -------------------------------------------------------------------------------- /posts/2013-10-21-wireframes-and-gravity.md: -------------------------------------------------------------------------------- 1 | # Wireframes and Gravity 2 | 3 | Wired recently did [an interview with Alfonso Cuarón](http://www.wired.com/underwire/2013/10/center_of_gravity/), the director of the film *Gravity*. Cuarón relates how making the film took four and a half years. When asked why it was so difficult, he responded: 4 | 5 | > We had to do the whole film as an animation first. We edited that animation, even with sound, just to make sure the timing worked with the sound effects and music. And once we were happy with it, we had to do the lighting in the animation as well. Then all that animation translated to actual camera moves and positions for the lighting and actors. **We did a whole exploration of the screenplay, every single moment; we made judgments about everything.** Once we began shooting, we were constrained by the limitations of that programming. (emphasis added) 6 | 7 | Did you catch that? Before it was filmed the entire movie was, in the terms of web designers, wireframed. 8 | 9 | Now I am not familiar with the world of film production, but I can see “wireframing movies” becoming an extremely popular practice based solely on the explorative, iterative nature of wireframes. This would allow directors to explore timing, camera angles, plot development, and other valuable components that constitute great film making. 10 | 11 | Similarly, as web designers, I think we would do well to imitate this same exploratory process in designing online experiences. Wireframing an entire website or experience can help explore every single moment of interaction and allow you (the designer) to make better, more informed decisions on molding the components of your website, like information architecture, URL design, animatable interactions, and so forth. 12 | -------------------------------------------------------------------------------- /posts/2013-12-18-ben-franklin-open-source-contributor.md: -------------------------------------------------------------------------------- 1 | # Benjamin Franklin, an Open Source Contributor? 2 | 3 | I was recently reading “The Autobiography of Benjamin Franklin” and came across an interesting little story that made me think of Benjamin Franklin as a believer in open source. 4 | 5 | Back in the 1700’s, Franklin invented an open stove that vastly improved the warming of rooms while simultaneously saving more fuel. He presented the model to friends and wrote a pamphlet about it which garnered him a lot of attention and positive publicity. His invention and writing had such a good effect that even the governor of Philadelphia used his stove and loved it. Here’s what happened next: 6 | 7 | > Gov’r Thomas was so pleas’d with the construction of this stove ... that he offered to give me a patent for the sole vending of them for a term of years; but I declin’d it from a principle which has ever weighed with me on such occasions, viz., That, as we enjoy great advantages from the inventions of others, we should be glad of an opportunity to serve others by any invention of ours; and this we should do freely and generously. 8 | 9 | I think we could all do to forget the monetary incentives behind innovative inventions and put human beings and their benefit back at the center of our daily purposes. As Paul Rand says, “It is only when man is not accepted as the centre of human concern that it becomes feasible to create a system of production which values profit out of proportion to responsible public service”. 10 | -------------------------------------------------------------------------------- /posts/2014-03-03-logo-the-image-of-a-company.md: -------------------------------------------------------------------------------- 1 | # A Logo Is an Image, The Image of a Company 2 | 3 | *The following passage is an excerpt that has been rewritten and repurposed from a magazine advertisement by Westinghouse Electric in 1963 describing symbols.* 4 | 5 | A logo is a an image. 6 | It is a symbol, 7 | a sign, 8 | an emblem, 9 | an escutcheon 10 | ...an image. 11 | 12 | Logos assume meaning from reality. 13 | They take meaning from causes... 14 | good or bad. 15 | And they give meaning to causes... 16 | good or bad. 17 | 18 | The vitality of a logo 19 | comes from effective dissemination... 20 | by a company, 21 | by a community, 22 | by a church, 23 | by a corporation. 24 | 25 | A logo needs attending 26 | to garner attention. 27 | It is not a sign of quality, 28 | but a sign of *THE* quality. 29 | 30 | A logo is the blending 31 | of form and content. 32 | The logo for Hostess 33 | tastes as good 34 | as the treats it stands for. 35 | 36 | Logos do not illustrate 37 | they indicate, 38 | not represent 39 | but suggest, 40 | and are stated 41 | with brevity and wit. 42 | 43 | A logo is created 44 | by a designer 45 | but made 46 | by a company. 47 | 48 | A logo is an image 49 | ...the image of a company. 50 | -------------------------------------------------------------------------------- /posts/2019-01-04-difference-between-substr-and-substring-in-javascript.md: -------------------------------------------------------------------------------- 1 | #engineering 2 | 3 | # The Difference Between substring and substr in JavaScript 4 | 5 | ![substring vs. substr](https://cdn.jim-nielsen.com/blog/2019/substring-vs-substr.png) 6 | 7 | I’m always having to lookup stuff like this. Often times I know like 90% of the answer, but that remaining 10% of ambiguity requires I look it up. In this case, Google led me to [a stack overflow answer](https://stackoverflow.com/questions/3745515/what-is-the-difference-between-substr-and-substring) stating: 8 | 9 | > The difference is in the second argument. The second argument to `substring` is the index to stop at (but not include), but the second argument to `substr` is the maximum length to return. 10 | 11 | It also had links to Mozilla’s docs on [`substr`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/substr) and [`substring`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/substring), which helped clarify the answer for me. 12 | 13 | Additionally (and almost equally important) I learned that – according to Mozilla’s docs – `substr` is considered legacy and you should therefore opt to use `substring` whenever possible. 14 | 15 | Being the visual person that I am, I decided to create a visual answer to this question. In part because I thought this particular answer was well suited to being expressed visually; but also because creating the graphic would require me to internalize the answer more concretely (which will make it easier to remember – and explain to others – in the future). 16 | -------------------------------------------------------------------------------- /posts/2019-07-03-saying-no.md: -------------------------------------------------------------------------------- 1 | # Saying No 2 | 3 | I recently came across an article titled [“No Algorightms”](https://inessential.com/2019/07/02/no_algorithms) by Brent Simmons, creator of [NetNewsWire](https://ranchero.com/netnewswire/). 4 | 5 | > I’ve been asked a few times about using algorithms in NetNewsWire to bring articles you wouldn’t otherwise have seen — from outside your feeds list — to your attention. 6 | > 7 | > I’ve also been asked a similar question about using algorithms to bring articles — from inside your feeds list — to the top based on the likelihood that they’ll interest you. 8 | > 9 | > I’m not going to do either. 10 | 11 | I really liked his opinionated stance here. When I read those first two paragraphs, I felt like I had this inner tech-voice saying, “oh yeah, that’s totally sensible, you could easily do that...” I feel like we all have a similar inner tech-voice to some degree, and it’s easy to let that voice run rampant. That voice loves to shout out answers to binary yes/no questions, and it seems to only ever consider the answer in terms of feasibility (“can it be done?”) and never in any existential terms (“should it be done?”). 12 | 13 | I really enjoyed Brent’s opinionated stance for the design of his app at the end of the post: 14 | 15 | > [My] app puts you in control. You choose the sites and blogs you want to read, and the app reliably shows you their articles sorted by time. That’s it. 16 | 17 | I want to do that more with tech, but also just the things I choose to spend my time on in life. It reminds me of something that guy Steve once said: 18 | 19 | > [focus] means saying no to the hundred other good ideas that there are. You have to pick carefully. I’m actually as proud of the things we haven't done as the things I have done. 20 | 21 | Maybe I should start blogging about the things I haven’t done... 22 | 23 | No but seriously, some write-ups about the things I chose _not_ to do and why. If somebody else wrote posts like that, I’d read ‘em. 24 | -------------------------------------------------------------------------------- /posts/2019-12-20-stuff-to-say-on-twitter.md: -------------------------------------------------------------------------------- 1 | #tips #myBlog 2 | 3 | # Twitter Cards and Visually Representing That I’ve Got Stuff To Say 4 | 5 | Have you ever noticed when you post a link on Twitter, it gives you that nice “Twitter card” preview? But if you haven’t setup your website to give hungry Twitter the data it feeds on, you’ll get a default image (and who likes a default image?) 6 | 7 | For example, check out Sketch and me in this screenshot from my timeline. Don’t we look like losers linking to garbage content that’s not tailored to Twitter sharing? 8 | 9 | Screenshot of a twitter feed where my “twitter card” preview has the default fallback image 10 | 11 | Well, I wasn’t about to have links to my website look so sad. I’ve got stuff to say! So I made an image to say as much: 12 | 13 | Screenshot of a twitter feed where my “twitter card” preview has a picture of me with a speech bubble saying “STUFF” (because I have stuff to say) 14 | 15 | Yeah, yeah I know. [Twitter’s docs](https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/summary) on the matter specifically state: 16 | 17 | > You should not use a generic image such as your website logo, author photo, or other image that spans multiple pages. 18 | 19 | But you know what? Twitter is not the boss of me. I do what I want. 20 | -------------------------------------------------------------------------------- /posts/2020-05-27-notes-on-design-systems-by-mark-boulton.md: -------------------------------------------------------------------------------- 1 | #design #generalNotes 2 | 3 | # Notes on “The Ugly Truth about Design Systems” by Mark Boulton 4 | 5 | > The latest think piece on Medium from someone in the design system utopia about what their design system world is like, we hear words like this: 6 | > 7 | > Scale. Repetition. Efficiency. Optimisation. Modularity. Standards. 8 | > 9 | > These are not the words of design. These are the words of manufacturing. We’re not designing products with design system. We’re manufacturing products. 10 | 11 | That’s an excerpt from Mark Boulton’s presentation [“The Ugly Truth about Design Systems”](https://markboulton.co.uk/journal/ugly-truth-of-design-systems/). I really enjoyed his talk and wanted to write down a couple of insights that struck me: 12 | 13 | - Move fast and break things? How about: move slow and remember what broke (those who don’t learn from history are doomed to repeat it). 14 | - Design systems uncover organizational disfunction—and that’s one of the hardest things to address. 15 | - Design system cannot be too tightly coupled to technology because dependencies age out—any minute change would have a huge impact. 16 | 17 | Lastly, I loved this idea that he borrows around designing a system with a “strict grammar” that allows “free, playful expression”, because with strictness only you’re merely manufacturing. 18 | 19 | > Rules, then applications and examples. The point is the rules should be reinterpreted. There should be freedom to express in different verticals and contexts. 20 | 21 | The conclusion? An alternative blueprint to many of today’s prescriptive design systems would be to conceive a strictly defined, well-articulated design grammar which would serve as the foundation to a system allowing free, playful application. 22 | -------------------------------------------------------------------------------- /posts/2020-07-20-email-replies-in-rss.md: -------------------------------------------------------------------------------- 1 | #myBlog #rss 2 | 3 | # Email Replies in Feeds 4 | 5 | [Robin](https://www.robinrendle.com/notes/reply-links-in-rss-feeds) and [Jonnie](https://destroytoday.com/blog/reply-link-in-rss-feed-posts) have both written about adding “reply links” at the bottom of each post in their feeds. I think it’s a neat idea. Honestly, I don’t think I have the kind of following where people are going to actually email me; that said, I would love to hear the thoughts of anyone who subscribes to my feed. Occasionally I do get feedback on posts via email, twitter DMs, etc., and it has always been good. Hopefully this increases that kind of correspondence. 6 | 7 | Doing this was straightforward. My blog is based on a static site generator ([metalsmith](https://metalsmith.io) to be specific). In my JSON/XML feeds, I added an extra template that outputs a divider and a `mailto` link. 8 | 9 | ```html 10 |
11 |

12 | 13 | Reply via email 14 | 15 |

16 | ``` 17 | 18 | You may have noticed I injected info into the subject line and body of the email to help me understand the context of any incoming emails. I figured it’d be nice to have a reference to the post that triggered the reply. This code saves the sender the work of having to do it. That said, they’re always free to edit the email as they please. 19 | 20 | These links render in both my [RSS](https://blog.jim-nielsen.com/feed.xml) and [JSON](https://blog.jim-nielsen.com/feed.json) feeds. 21 | 22 | -------------------------------------------------------------------------------- /posts/2020-11-17-the-organic-web.md: -------------------------------------------------------------------------------- 1 | # The Organic Web 2 | 3 | > If we lived close to nature in an agricultural society, the seasons as metaphor and fact would continually frame our lives. But the master metaphor for our era does not come from agriculture—it comes from manufacturing. We do not believe that we “grow” our lives—we believe that we “make” them. Just listen to how we use the word in everyday speech: we make time, make friends, make meaning, make money, make a living, make love. — Parker Palmer, “Let Your Life Speak” (97) 4 | 5 | You know what else we make? Websites. 6 | 7 | People talk about growing communities and growing brands, but does anyone talk about growing a website? If they do, I’m going to guess it’s steeped in the startup connotations of the word, i.e. growth (exponential at that) and scale. But nobody talks about scaling their garden. That’s not a garden anymore, that’s an industrial farm. But I digress. 8 | 9 | Growing—that’s a word I want to employ when talking about my personal sites online. Like a garden, I’m constantly puttering around in them. Sometimes I plow and sow a whole new feature for a site. Sometimes I just pick weeds. And sometimes I gather fertilizer (a.k.a. horse shit) from others online and try to grow something with it. My websites are my garden: a place to grow and experiment, to cultivate and nurture—the projects themselves, but also myself. 10 | 11 | Most of my favorite websites out there are grown—homegrown in fact. They are corners of the web where some unique human has been nurturing, curating, and growing stuff for years. Their blog posts, their links, their thoughts, their aesthetic, their markup, their style, everything about their site—and themselves—shows growth and evolution and change through the years. It’s a beautiful thing, a kind of artifact that could never be replicated or manufactured on a deadline. 12 | 13 | This part of the web, this organic part, stands in stark contrast to the industrial web where websites are made and resources extracted. 14 | 15 | You can make a website in a day, but it takes years to grow one. So plant one now if you haven’t already. Or go tend to yours. I’ll just be over here weeding and watering. 16 | -------------------------------------------------------------------------------- /posts/2021-03-01-sites-v-apps.md: -------------------------------------------------------------------------------- 1 | # Sites v. Apps: A Reverie 2 | 3 | Websites and web apps: a dichotomy that lives in a fantasy world of well-defined forms of content delivered over the web. 4 | 5 | The document. The application. 6 | 7 | These are predetermined, prescriptive shapes that are packaged up and delivered as generic solutions to specific problems. 8 | 9 | We get to worrying about these shapes before we produce any content or write any code. 10 | 11 | We feel the burden of these formal shapes pressing on us, even though there is no such intrinsic classification. 12 | 13 | We want to believe websites and web apps are formulaic. That they’re governed and shaped by rules. That they’re genres. 14 | 15 | But genres are meaningless here. They are methods of categorization for broad generalizations. 16 | 17 | Nonetheless, we somehow believe the genre we choose dictates the way we write code, structure programs, adopt tooling, and ultimately deliver value to human beings. 18 | 19 | It’s as if the genre has a roadmap. We need merely chose the right genre, and the path to success will unfold before us. 20 | 21 | The genre of a URL doesn’t matter. Forget about classification. 22 | 23 | Keep open possibilities unbounded by genre and you can create anything for the web. Classifications unnecessary. 24 | -------------------------------------------------------------------------------- /posts/2021-03-17-progressively-enhanced-search.md: -------------------------------------------------------------------------------- 1 | #progressiveEnhancement #theMoreYouKnow 2 | 3 | # A Simple Tactic For Progressively-Enhanced Search 4 | 5 | I was reading [this post by Chris Coyier detailing the recent redesign of CSS-Tricks](https://css-tricks.com/design-v18/) and caught something I can’t believe I’d never thought of before. 6 | 7 | Chris described creating a sophisticated client-side search experience whose base HTML markup was a link to a Google site search: 8 | 9 | > [the] search is JavaScript-powered, so to make it more resiliant, it’s also a valid hyperlink to Google search results: 10 | 11 | ```html 12 | 16 | Search 17 | ... 18 | 19 | ``` 20 | 21 | Neat idea. I have a few cases like this where search is powered via JS/client-side scripting. Because of this dependence, I inject the functionality via JavaScript (don’t have JS? You won’t see the search functionality). 22 | 23 | Instead of merely a link, you could also capture the search query on your page and pass it to a search engine via a regular HTML form: 24 | 25 | ```html 26 |
27 | 28 | 29 |
30 | ``` 31 | 32 | Then use JS, where present, to prevent the default behavior of the form from submitting to Google—or the search engine of your choice for the privacy minded—and instead execute whatever client-side search functionality you dream up on your site. 33 | 34 | I like this idea of being able to provide the core search functionality without JavaScript. It requires no additional lift on my part to leverage a search engine that’s already indexing my site. 35 | 36 | Of course, in order for this to work, you better make sure the content of your site is meaningfully indexed by search engines. 37 | -------------------------------------------------------------------------------- /posts/2021-06-17-unseen-work-of-design.md: -------------------------------------------------------------------------------- 1 | # The Unseen Work of Design 2 | 3 | I was reading the (absolutely wonderful) book [_Several short sentences about writing_](https://www.penguinrandomhouse.com/books/93789/several-short-sentences-about-writing-by-verlyn-klinkenborg/) and this passage struck me: 4 | 5 | > A writer’s real work is the endless winnowing of sentences, 6 | > 7 | > The relentless exploration of possibilities, 8 | > 9 | > The effort, over and over again, to see in what you started out to say 10 | > 11 | > The possibility of saying something you didn’t know you could. 12 | 13 | The corollary here to the design process is striking. 14 | 15 | So much of the work in design—like writing, a fusion of art and communication—is unseen. The finished product is the outside perception of “design”. But it’s the process of _how you get there_ that, to me, constitutes “design”—however unseen or unlauded. 16 | 17 | The final product is the result of this “endless winnowing” and “relentless exploration”. So often, at least in my experience, the final product isn’t produced but discovered. When done right, it feels like the inevitable outcome of where you started. 18 | 19 | Adapted to my experience as a designer on the web, I would rephrase the above passage this way: 20 | 21 | The unseen work of a visual designer is the endless refinement of elements and their relationships, 22 | 23 | The relentless exploration of possibilities, 24 | 25 | The effort, over and over again, to see in what you started 26 | 27 | The possibility of communicating something you didn’t know you could in a way you hadn’t conceived as possible. -------------------------------------------------------------------------------- /posts/2021-08-19-thank-you-for-reading.md: -------------------------------------------------------------------------------- 1 | # Thank You For Reading 2 | 3 | I don’t know how many people read what I write. 4 | 5 | Sometimes I think it’s better that way. 6 | 7 | “If it’s not measured it doesn’t exist,” I hear. According to that logic, nobody reads what I write. 8 | 9 | Sometimes I think it’s better that way. 10 | 11 | While I don’t have direct measurements of how many people read what I write, I get intimations. 12 | 13 | I have Netlify analytics, which gives me insight into URL pageviews and referring sources. 14 | 15 | A link on Hacker News might suggest 18,000 pageviews in a single day. But that doesn’t mean _reading_, only visiting (a glance at the comments often reinforce that point). 16 | 17 | I like to think those who actually read my writing come via RSS. How many? Don’t know. Could be a handful. Could be thousands. I have no analytics for gauging. 18 | 19 | But what if I did know, what would that change? If it was few, would that discourage me from writing? If it was many, would visions of a proprietary platform and a measured and monetized audience dance in my head? Would people even pay for my writing if it was no longer free? I have no idea. 20 | 21 | Sometimes I think it’s better that way. 22 | 23 | Occasionally I’ll receive a meaningful metric. A comment on another blog, an email, _some_ communication from a reader reaching out to let me know they enjoyed my writing. The data point there is one, but its value far surpasses the 18k pageviews and innumerable anonymous comments. 24 | 25 | In an economy that seeks to harvest people’s most valuable resource—their attention—I feel privileged that folks offer me that resource when they read my writing. And some offer me even more of it when they write me a kind note. 26 | 27 | Your attentive kindness doesn’t get picked up by any analytical tool I’ve got other than my heart and my memory—however short lived. 28 | 29 | Sometimes I think it’s better that way. -------------------------------------------------------------------------------- /posts/2022-01-11-talking-app-icons-on-the-postlight-podcast.md: -------------------------------------------------------------------------------- 1 | #iconGalleriesBook #podcastAppearance 2 | 3 | # Talking App Icons on the Postlight Podcast 4 | 5 | I enjoy the Postlight Podcast. So much, in fact, I’ve documented some of [my favorite excerpts](https://blog.jim-nielsen.com/2021/fav-excerpts-from-the-postlight-podcast/) here on the blog (and I’ve got another draft of favorite excerpts queued up for another day). 6 | 7 | I also enjoy talking about app icon design to whoever will listen. 8 | 9 | So you can imagine the joy it was to have those two interests intersect when I appeared on [The Postlight Podcast Episode #314: (Icon)ic Design](https://postlight.com/podcast/iconic-design-with-jim-nielsen-and-michael-flarup). 10 | 11 | On it, [Michael](https://twitter.com/flarup) and I talk with the lovely [Chappell Ellison](https://twitter.com/ChappellTracker) and [Nathan Burge](https://postlight.com/about/nathan-burge) at Postlight about the history, craft, and culture of app icon design. 12 | 13 | We also touch on how creating [The App Icon Book](https://www.appiconbook.com) is an act of trying to preserve artifacts from a fleeting digital medium, something that borders on being an act of translation more than it does mere reproduction. Here’s me: 14 | 15 | > [Trying to preserve app icons in a book is] an interesting task because so much of app icon design is a digitally native medium, right? And so when you move it to print, it’s a [form] of translation that we have to make choices in. The color space, for example, is RGB and now we’ve got to do CMYK. How’s that gonna work out in the translation—[what will change and what will be lost?] 16 | 17 | Find links to the podcast for your podcatcher of choice, as well as the transcript, over on [Postlight.com](https://postlight.com/podcast/iconic-design-with-jim-nielsen-and-michael-flarup). 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /posts/2022-01-20-increase-reach-into-addressable-market.md: -------------------------------------------------------------------------------- 1 | # How to Increase Reach Into Your Total Addressable Market With Zero Marketing 2 | 3 | Use progressive enhancement. 4 | 5 | If you don’t, it’s very possible people come to your website, can’t use it, and leave. 6 | 7 | And any JS-powered analytics won’t see these people—or this market. 8 | 9 | With progressive enhancement, at least you know people leaving your website are rejecting you _for you_, not because they never got the chance to know you. -------------------------------------------------------------------------------- /posts/2022-03-01-me-on-shoptalkshow-504.md: -------------------------------------------------------------------------------- 1 | #podcastAppearance 2 | 3 | # My Guest Appearance on ShopTalkShow #504 4 | 5 | I’ve been a big fan of ShopTalkShow since about 2015. The Chris/Dave dynamic is fun and practical. If you ever feel like you’re falling behind on the web tech scene, listen to Chris and Dave each week and I think they’ll make you feel better. They’re experts at building on the web, they’ve been doing it a long time, and even they are often flummoxed by everything that’s going on. I find them reassuring (and comical). 6 | 7 | Anyhow, that’s all to say I am super happy to appear on the show as a guest. We shoot the breeze for an hour on all kinds of topics, including: [The iOS App Icon Book](https://www.appiconbook.com), digital archival, evergreen and not-so-evergreen browsers, blogging workflows, CSS4 colors, and more. 8 | 9 | I even posed a question or two to the group, some more academic than practical. Like how to think about [all these new colors we’re getting in CSS](https://css-tricks.com/new-css-color-features-preview/). I’m a bit cerebral so I could talk for hours and hours about purely academic topics like this, never get to a resolution, and feel satisfied. Chris was as practical as ever with his advice, while I feel Dave tried to find the middle ground between my theoretical purity thinking and Chris’ “just build websites” practicality. This ultimately left Dave with a feeling we all have at one point or another building on the web: 10 | 11 | > [Chris] I hate to burst your bubble, but what your brain wants right now is some general guidelines on what to use and you're just not going to get them. 12 | > 13 | > [Dave] Fine. Burn it all down. 14 | 15 | Go check it out: [ShopTalkShow #504](https://shoptalkshow.com/504/). 16 | -------------------------------------------------------------------------------- /posts/2022-05-12-whats-it-worth.md: -------------------------------------------------------------------------------- 1 | #rssClub 2 | 3 | # What’s It Worth? 4 | 5 | > How much is CI stability worth? Or community happiness? – [@kantrn](https://twitter.com/kantrn/status/1511791402845310977) 6 | 7 | What’s the value of something that can’t be wholly measured? How can it be justified in a world that equates measurement with existence? 8 | 9 | What’s love worth? How do you measure it? Do you enumerate the pronunciations of “I love you” over time to demonstrate an upward trend line? 10 | 11 | I love the web, but how did we come to measuring, monetizing, and extracting the value of its every transaction? A digital manifest destiny. 12 | 13 | I love a web that remains unmeasured, whose value remains unascertained, and whose essence remains [“vague but exciting”](http://info.cern.ch/Proposal.html). -------------------------------------------------------------------------------- /posts/2022-06-18-the-message-and-medium-of-the-personal-blog.md: -------------------------------------------------------------------------------- 1 | # The Message Behind the Medium of a Personal Blog 2 | 3 | I’ve been reading Neil Postman’s _Amusing Ourselves to Death_ . What do I say about that book? It’s a seminal piece, even more relevant today than when it was written in the 80’s. 4 | 5 | In the beginning of the book, he talks about how the form of any communication shapes its content. For example: you can’t use smoke signals to communicate philosophically. 6 | 7 | In today’s world, we have media forms that are well suited to fragmented conversation. 8 | 9 | > Cultures without speed-of-light media…do not have news of the day. Without a medium to create its form, the news of the day does not exist. (8) 10 | 11 | Twitter, anyone? But I digress. 12 | 13 | Each medium of communication — the spoken word, painting, television, social media — influences culture. 14 | 15 | > Each medium…makes possible a unique mode of discourse by providing a new orientation for thought, for expression, for sensibility. [This] is what McLuhan meant in saying the medium is the message. 16 | 17 | When I read this I thought: if “the medium is the message”, what’s the message behind the medium of a personal blog? 18 | 19 | I’m thinking narrowly here. Not a corporate blog run by individuals and backed by an organization. And not an individual blog that’s hosted on a platform, like Medium. I’m asking, specifically, about an “indie” blog—a blog written and run by an individual who owns the domain and controls their own content. 20 | 21 | Given that kind of blog, what’s the intrinsic message communicated in _that_ medium? 22 | 23 | I’m not sure, but these are the thoughts that come to my mind: 24 | 25 | - Each voice is individual and matters 26 | - Slow is ok 27 | - Diversified and independent is good 28 | - Not fitting a pattern is ok 29 | - Not being easily commodified is ok 30 | 31 | If you believe the above, well, it’s time start blogging. You won’t have to _say_ the above to communicate it: the form already carries the message. -------------------------------------------------------------------------------- /posts/2022-08-03-saying-thank-you.md: -------------------------------------------------------------------------------- 1 | # Saying Thank You 2 | 3 | > When thou does thy social interactions, be not as those who love to stand in the corners of the internet and publicly announce, measure, and track their interactions, that they may be seen and extract value from others. I say unto you, they have their reward. 4 | — The Bible, somewhere 5 | 6 | --- 7 | 8 | Eric Bailey recently wrote a wonderful piece about [saying thank you](https://ericwbailey.design/writing/saying-thank-you/) 9 | 10 | > Thank you emails are private, and their goal is as earnest as it is direct. They don’t come with UTM tracking codes, quid pro quo schemes, or linkback spam. 11 | 12 | YES! 13 | 14 | [I’ve](https://blog.jim-nielsen.com/2021/hide-my-mailto-email/) [got](https://blog.jim-nielsen.com/2020/email-replies-in-rss/) a “Reply via email” link at the bottom of my posts. I don’t get messages regularly, but when I do they are nuggets of gold for all the reasons Eric outlines. Something I wrote resonated with someone so much that they took the time to sit down and write me a little note? That’s neat! [Thank you for reading](/2021/thank-you-for-reading/). 15 | 16 | As Eric alludes to, firing off a private email — and the friction it entails — is not a social mechanism easily conducive to tracking or measurement. There’s something _awesome_ about that. 17 | 18 | > A thank you email feels like a personal and selfless act in a web that feels increasingly built to not facilitate this kind of interaction. 19 | 20 | Related: I saw [Muan on Twitter](https://twitter.com/muanchiou/status/1552589989401178114) commenting on this same idea. 21 | 22 | > while we are at it- normalize sending random strangers an email to compliment their websites like “wow your house is beautiful thanks for letting me hang out here” it’s the polite thing to do. 23 | 24 | Agree 💯 -------------------------------------------------------------------------------- /posts/2022-08-16-old-african-proverb-on-web-design.md: -------------------------------------------------------------------------------- 1 | # Old African Proverb on Web Design 2 | 3 | If you want to go fast, go (JavaScript) alone. 4 | 5 | If you want to go far, go (HTML, CSS, & JavaScript) together. -------------------------------------------------------------------------------- /posts/2022-08-19-re-web-harsh-manager-pt-ii.md: -------------------------------------------------------------------------------- 1 | # Re: “The web is a harsh manager”, Pt. II 2 | 3 | One more thought to add to my [previous post](/2022/re-web-harsh-manager/). 4 | 5 | There seems to be a constant redefinition of the term “front-end”. Because of this, it’s easy to feel hesitant about considering yourself a front-end engineer. 6 | 7 | It would be easy to conclude that, since you’re not sure what a “front-end engineer” is — [The person who styles the page or queries the data layer?](https://daverupert.com/2022/08/web-is-a-harsh-manager/) The person who animates things on screen or keeps the bundler and tooling humming along? — you can’t consider yourself a “real” front-end engineer. 8 | 9 | Instead, imposter syndrome sets in because you can’t square the ongoing redefinition of the term with your own talents and the work you’ve done. 10 | 11 | While you might think you’re an imposter, someone “pretending” to be front-end engineer, just remember this: there’s nothing pretend about a functioning website, especially when it serves the needs of somebody else. -------------------------------------------------------------------------------- /posts/2022-08-19-re-web-harsh-manager.md: -------------------------------------------------------------------------------- 1 | # Re: “The web is a harsh manager” 2 | 3 | Dave had [a great post](https://daverupert.com/2022/08/web-is-a-harsh-manager/) about the increasing demand for “front-end”, whatever that means (which is kind of the point). 4 | 5 | Writing about the organizational intersection of design and engineering, he says: 6 | 7 | > If you’re paying money for good design, this makes sense; protect your investment to make sure the designs get engineered well. 8 | 9 | This is a great point I’m not sure I ever fully internalized. 10 | 11 | In fact, I bet you could make a persuasive powerpoint for a C-level audience which hinges on the fiscal argument for design engineers, e.g. “You believe in design, and you’re paying for it, but you are not getting your money’s worth because of the gap between engineering and design.” I know I’ve seen it. 12 | 13 | It’s like a restaurant that believes in sourcing sushi-grade fish, which they pay people to source and purchase, but turns out their cook is just deep frying it and nobody is noticing. Shame. 14 | 15 | There’s a mismatch in talent awareness and dispersion. You believe in it and pay for it, but fail to capitalize on it efficiently and effectively due to imbalances and communication failures in your organization. 16 | 17 | Perhaps we too often equate job titles with jobs-to-done, e.g. “Oh, we have a front-end engineering and a designer, so we’re good.” Per my analogy earlier, “We have sushi-grade fish, and we have someone in the kitchen, boom! We have a sushi restaurant.” 18 | 19 | Like Dave I don’t have answers. Only questions — and observations. Speaking of observations, this one by Dave about job titles for CSS folks is spot on: comedic yet stingingly acute. 20 | 21 | > I’d argue for a “CSS Engineer” title, someone who knows the ins-and-outs of good CSS architecture that can save your app thousands of lines of code. But that title probably wouldn’t pay enough, so it’d need to be more official sounding like “Render Optimization Engineer Level 6” or something. Now that’ll get the Amazon bucks. 22 | 23 | Note: published shortly after, don’t miss [part II of this post](https://blog.jim-nielsen.com/2022/re-web-harsh-manager-pt-ii/). -------------------------------------------------------------------------------- /posts/2022-10-20-seeing-vs-using.md: -------------------------------------------------------------------------------- 1 | # Seeing vs. Using 2 | 3 | Sometimes, gathering constructive feedback on the design of a feature is poorly served by the creation and evaluation of a set of static screens in a tool like Figma. 4 | 5 | In these cases, we often end up providing feedback based on the imagined workings of a highly-dynamic experience with software. 6 | 7 | The critique of a set of static mocks is often an exercise of indirectly-impacted technologists imagining the needs and goals of directly-impacted humans with a dynamic piece of software against a static screen of UI. 8 | 9 | Looking at static mocks, imagining a set of goals, and saying “yeah that _looks_ good” is one thing. A whole other is completing a task with interactive software and saying “yeah that _works_ good”. 10 | 11 | The placement of a specific UI element may seem obtuse in a static mock, but when contrasted with an experience set in tangible goals and tested in a dynamic environment, you may end up with a directly contradictory evaluation — that same placement might seem genius. 12 | 13 | Seeing and using are two distinct methods for evaluation. Reminds me of this [statement from Jason about “distracting” UI elements](https://world.hey.com/jason/distracting-is-it-3b23e5cf): 14 | 15 | > Mockups aren't real. Looking at screens or designs in isolation limits your ability to think about the whole system. Reducing elements to their objective qualities (size, color, etc) flattens them and removes the richness of the situation, the moment, the time, and the context in which they exist. The user isn't evaluating, the user is using for a reason, in a given context, with more going on in their world than just that element, that object, and that screen in front of them. -------------------------------------------------------------------------------- /posts/2022-10-27-optimize-for-nothing.md: -------------------------------------------------------------------------------- 1 | # Optimize For Nothing 2 | 3 | > Anything new is by nature without precedent — meaning, without data to know whether it will work or not. 4 | 5 | I recently read a piece by the folks at The Browser Company about how they are [optimizing for feelings](https://browsercompany.substack.com/p/optimizing-for-feelings): 6 | 7 | > When Olmstead crafted Central Park, what do you think he was _optimizing_ for? Which metric led to Barry Jenkins’ _Moonlight_? What data brought the iPhone into this world? The answer is not numerical. It’s all about the feelings, opinions, experiences, and ideas of the maker themself. 8 | 9 | They ask a good rhetorical question: what products that you love were created in optimization around a metric? 10 | 11 | I like the against-the-grain nature of the piece. They bemoan “the relentless optimization of everything in our world” and conclude: 12 | 13 | > We believe this mindset has led us to a very specific place: one of efficiency, productivity, and profit…but not a place of humanity. 14 | 15 | I’ll buy that. It reminds me of [a quote from Eric Gill](https://blog.jim-nielsen.com/2021/book-notes-eric-gill-typography/) where he says: “We have elected to order manufacture upon inhuman lines; why should we ask for humanity in the product?” 16 | 17 | And yet, after arguing against optimization, they themselves say they are optimizing — albeit for feelings not metrics. 18 | 19 | Maybe that’s inevitable. If you want to run a business, you have to optimize for _something_ to turn a profit? I’m no good at business, so don’t ask me. 20 | 21 | But for argument’s sake, what would push this piece further is to hear a claim like: “We’re not optimizing for anything. Rather than optimize around metrics or feelings from our users, we are building something based on our own sensibilities and opinions of what makes the world more enjoyable to us.” 22 | 23 | What I find profound and universal about anyone’s work is what they observe in themselves and, in turn, reflect in their work to the world — not any one optimization. -------------------------------------------------------------------------------- /posts/2022-11-13-verified-personal-website.md: -------------------------------------------------------------------------------- 1 | # Verified Personal Website 2 | 3 | My blog is Verified (meaning I pay $10/year for the domain). 4 | 5 | --- 6 | 7 | [Max did a funny thing](https://twitter.com/mxbck/status/1590809274808147990) where he verified his personal website. (He also official-ified it, as there appears to be a difference between the two — at least at the time of this writing, who knows that could change…) 8 | 9 | Screenshot of `mxb.dev` with a verified and official checkmark in the style of Twitter (circa Nov. 2022). 10 | 11 | Putting aside whatever it actually means to verify your own website, I thought it was funny. 12 | 13 | And it’s the weekend right now, so I decided: why not give myself the ole’ check mark too? They seem to just be handing them out these days for the right price. 14 | 15 | Meme of Bilbo holding the one ring, but instead a Twitter blue checkmark is superimposed on the ring with Bilbo saying: “After all, why not? Why shouldn’t I have a check mark?” 16 | 17 | I suppose I pay for my check mark. It’s ten dollars per year. That’s what it costs to own the domain for my website. I also own the content too. Seems like a pretty good deal. 18 | 19 | Oh, and my check mark comes in more than just blue. I have a color to match each theme of my website. I can do that because, ya know, it’s my website. Got to get my money’s worth out of that $10/year. 20 | 21 | Screenshot of `blog.jim-nielsen.com` with a verified badge in the style of Twitter. 22 | 23 | Now I’m just being silly. But hey: it’s my website, I can do that. -------------------------------------------------------------------------------- /posts/2022-11-29-the-word-value-in-css.md: -------------------------------------------------------------------------------- 1 | # The Word “Value” in CSS 2 | 3 | I loved [this post by Karl Dubost](https://www.otsukare.info/2022/10/25/css-values-definitions) which outlines how overloaded the word “value” can be in CSS. 4 | 5 | When you say “value” in CSS, you might think you know what it means. But if you look closer — especially at [the spec](https://w3c.github.io/csswg-drafts/css-cascade-5/#value-stages) — you’ll find there are lots of different meanings for the word “value” in CSS, each one different than the next. 6 | 7 | If you say `width: 100px`, it seems readily apparent what the “value” is for `width`. But if you write `width: auto` what would you say if someone asks you, “What’s the value?” Are they referring to what’s written in the CSS, i.e. `auto`? Or are they referring to what `auto` ends up being once the browser calculates it and renders it on screen? You can see how things can get murky really fast (and we haven’t even mentioned how values cascade yet). 8 | 9 | To further illustrate this point, take a look at each of these rules ask yourself: what would I say if somebody asked me, “What’s the value here?” 10 | 11 | - `font-size: 2em` 12 | - `width: calc(100% - 14px)` 13 | - `color: red` 14 | - `background: var(--color-brand)` 15 | - `font-weight: bolder` 16 | 17 | You’d probably say, “Well that depends on what you mean by the word ‘value’!” 18 | 19 | That’s kind of the whole point of the article: there are lots of qualified terms for the word “value” in the spec. These are the ones outlined by Karl: 20 | 21 | - Actual value 22 | - Used value 23 | - Computed value 24 | - Specified value 25 | - Cascaded value 26 | - Declared value 27 | - Initial value 28 | - Resolved value 29 | - Relative value 30 | - Absolute value 31 | 32 | Phew! That’s a lot of values. -------------------------------------------------------------------------------- /posts/2022-12-13-music-programming-and-practice.md: -------------------------------------------------------------------------------- 1 | # Music, Programming, and Practice 2 | 3 | I grew up playing the piano. 4 | 5 | In my 20’s I didn’t practice much because my youthful transience didn’t lend itself to owning a piano. But I have one now I tinker on. 6 | 7 | I also own a guitar which I purchased earlier this year. During [my stint of unemployment](https://blog.jim-nielsen.com/2022/employment-change/) I tried to practice with more discipline, but I mostly I failed at that endeavor. 8 | 9 | It’s hard pick up the guitar, practice, and fail at the most fundamental basics when, instead, I could sit down at the piano and more effortlessly play something that at least sounds like music. 10 | 11 | But honestly, the piano presents the same problem just on another level: practicing, i.e. learning by failing, is hard. 12 | 13 | What strikes me as a common thread between programming and music is the necessity to repeatedly endure failure in order to get something right. It reminds me of [this line from the book _Coders_](https://blog.jim-nielsen.com/2020/notes-coders/): 14 | 15 | > When you meet a coder, you’re meeting someone whose core daily experience is of unending failure and grinding frustration. 16 | 17 | That’s how it feels to practice, piano or guitar. However, there’s an interesting thing about practice. 18 | 19 | I can practice for an hour, look back, and feel like I made little to no progress. But when my timeframe for reflection gets longer — looking back a week, a month, a year — the progress becomes much more readily apparent. 20 | 21 | Writing code can be a lot like that. 22 | 23 | You bang your head on a problem over and over and over, feeling like you’re getting nowhere, making zero progress. And at the end of a fit like that you don’t feel the improvement. Sometimes quite the opposite: you feel _worse_ than when you started. 24 | 25 | But when you look back weeks, months, or years, it’s much easier to see improvement — improvement that came because of a willingness to face the “unending failure and grinding frustration” you experience moment to moment. 26 | 27 | You won’t always see progress, but stick to practicing and the longer the timeframe the more obvious it’ll become. -------------------------------------------------------------------------------- /posts/2022-12-23-notes-from-ryan-dahl-on-shop-talk-show.md: -------------------------------------------------------------------------------- 1 | #deno 2 | 3 | # Notes from Ryan Dahl on Shop Talk Show 4 | 5 | As you may know, I’m a fan of Deno and its pioneering ethos to [align its technological choices with the grain of the web platform](https://blog.jim-nielsen.com/2022/permeating-principles-of-the-web/). 6 | 7 | So I was excited to see Ryan Dahl, creator of Deno, appear on [episode 546 of the Show Talk Show](https://shoptalkshow.com/546/). 8 | 9 | A few points that stood out: 10 | 11 | - JavaScript is pervasively everywhere, and it’s always changing and evolving to the needs of the people worldwide who use it. As Ryan says, “JavaScript is the English of programming languages”. 12 | - Deno is trying to alleviate the problem of choice in today’s JavaScript. With features like a standard library, a native test runner, and built-in typescript support, Deno is trying to combat the problem of too much unnecessary choice that runs rampant in the world of Node. 13 | - V8 is an incredibly robust, battle-tested piece of software and it’s being used to power web experiences everywhere. [JavaScript container-like abstractions are the future](https://tinyclouds.org/javascript_containers) — as Ryan says, “You can think of Node and deno and cloudflare workers as distributions of v8, kind of like there are distributions of the Linux kernel.” 14 | - Javascript is one of the most security-conscious languages that exists — thanks to its origins in the browser whose unique challenges and ties to the web platform’s ethos shape the language — and yet, **ironically**, npm has made server-side JavaScript prone to some of the biggest supply chain vulnerabilities. 15 | - In a browser, you have to be able to visit a website you don’t trust. An incredible amount of energy has been exerted to make that true, including effort in JavaScript. Deno asks: why not leverage all that hard work elsewhere, like in your server side programming language? 16 | 17 | And finally, Dave got to talking about bundlers and front-end practices and I just loved this line: “we do the sharding and the bundling and splitting and the shaking — and then we pray it works”. -------------------------------------------------------------------------------- /posts/2023-01-18-the-anti-capitalist-web.md: -------------------------------------------------------------------------------- 1 | # The Anti-Capitalist Web 2 | 3 | I’m not sure if any idea has stuck in my head over the last year more than [this tweet by Miriam Suzanne](https://twitter.com/terriblemia/status/1198706002419310592): 4 | 5 | > Large companies find HTML & CSS frustrating “at scale” because the web is a fundamentally anti-capitalist mashup art experiment, designed to give consumers all the power. 6 | 7 | Ooooff. Ponder on that for a while. 8 | 9 | I love the web — and what I love about the web, at its core, is something that is individually freeing and runs against the grain of corporate value extraction. How do you make a living ($$$) working on something that you love whose reason for being resists the impulse for capitalization? 10 | 11 | The web is full of puzzling but beautiful dualities. It reminds me of [Nicholas Carr’s writing](https://www.roughtype.com/) where he points out the irony of the web being heralded by early advocates as a tool of liberation but in practice becoming widely (ab)used as an instrument of control. 12 | 13 | Could the web, and everything I love about it, even be built as a platform today? [Craig Mod wonders this aloud](https://mastodon.social/@craigmod/109561306266587786): 14 | 15 | > I still find it fully miraculous that webpage source code is freely viewable, and browsers allow for trivial editing of the source live and inline 16 | > 17 | > Can just imagine the pushback against if someone tried to launch a platform like this today 18 | 19 | It’s quite incredible that the money and power birthed through the advent of the web haven’t yet been able to completely overtake this “mashup art experiment” medium which “gives consumers all the power”. -------------------------------------------------------------------------------- /posts/2023-02-03-hipster-history-of-cors.md: -------------------------------------------------------------------------------- 1 | # CORS, CORB, CORP, COOP, COEP, C… 2 | 3 | You’ve probably heard of CORS, but did you know about [CORB](https://chromium.googlesource.com/chromium/src/+/master/services/network/cross_origin_read_blocking_explainer.md), [CORP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy), [COOP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy), or [COEP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy)? 4 | 5 | I recently watched [“A Hipster History of CORS”](https://www.youtube.com/watch?v=0YJ-yhoJh2I), a talk from Strange Loop 2022 by Devdatta Akhawe, Head of Security at Figma. Devdatta does a great job of taking a complex, even boring, subject like CORS and weaves it into a funny, interesting narrative history. He connected many previously disparate dots in my head, making me go “Ah-ha! That’s why things are the way they are on the web.” 6 | 7 | For example, when working on my [Readlists](https://readlists.jim-nielsen.com) project, I ran into an issue where I couldn’t use JavaScript to read the contents of an image fetched from a third-party website. I couldn’t understand why there was a limitation there. “I fetch images all the time with `` but I guess JavaScript’s not gonna let me?” 8 | 9 | After Devdatta’s talk and an introduction to cross origin read blocking (CORB) I now understand better. 10 | 11 | > [attacker.com can ask for mail.google.com] as an image. The browser doesn’t know that's not an image. For the browser, everything is a URI. So the browser [fill fetch it] and say “here’s mail.google.com (and everything in the body)” and the attacker.com process can just read everything in it. 12 | 13 | It’s a great story condensed into a thirty minute talk. Thank you Devdatta! -------------------------------------------------------------------------------- /posts/2023-02-22-faux-progress.md: -------------------------------------------------------------------------------- 1 | # Faux Progress 2 | 3 | [Eric’s recent post](https://ericwbailey.website/published/modern-health-frameworks-performance-and-harm/) really got me thinking. He shows an all-to-familiar screen he got stuck on: 4 | 5 | Screenshot of the Modern Health website that is mostly blank with a spinner in the middle. 6 | 7 | And notes: 8 | 9 | > Since I make digital experiences for a living, I immediately knew what happened…If you do not make digital experiences for a living, what happened is not obvious at all. All you see is a tiny fake loading spinner that never stops. 10 | 11 | For non-technical folks, the worst part is you don’t even know the spinner is fake! You likely interpret it as a legitimate representation of live feedback. 12 | 13 | I remember when I first started as a designer, I naively created a progress bar for some UI thinking, “We’ll indicate progress as this thing happens!” 14 | 15 | I was quickly informed that an accurate representation of progress was incredibly complex and not in the cards for our feature (’twas then I was introduced to the idea of [polling](https://en.wikipedia.org/wiki/Polling_(computer_science))). 16 | 17 | Since then, posts like Eric’s constantly remind me of the faux authenticity of so many of our digital experiences. I have no doubt progress bars and loading indicators are vastly misinterpreted by non-technical folks as feedback mechanisms which communicate the live, accurate progress of known-quantity computing tasks. 18 | 19 | But I’ve seen behind the curtain, so I am deeply skeptical of most progress indicators. Most of the time I assume them to be, at best, a guesstimate of progress; at worst, a lie — a veneer of sophistication, a sleight of hand. 20 | 21 | At least when a computer freezes, you know. The feedback mechanism of input/output halts completely. But with loading indicators and progress bars you’re left in a state of limbo, unsure whether something is working and at any moment might change, or if you just need to try “turning it off and on again”. -------------------------------------------------------------------------------- /posts/2023-03-06-oasis-of-quiet.md: -------------------------------------------------------------------------------- 1 | # An Oasis of Quiet 2 | 3 | In [John Cleese’s talk on creativity](https://notes.jim-nielsen.com/#2023-02-23T1021), he suggests that it takes time for your mind to quiet down to the point where you can do thoughtful, meaningful, creative work. 4 | 5 | He suggests setting aside 90 minutes for this kind of work: 30 minutes for your mind to calm down and then 60 minutes after that to allow for something to happen. 6 | 7 | I think it’s interesting he doesn’t say: 30 minutes to calm down, 60 minutes to do work. He says: 30 minutes to calm down, 60 minutes to _allow for the possibility_ of doing work. 8 | 9 | You can’t force it, but you can create and nurture an environment for it to happen. 10 | 11 | This is why people like designers and engineers hate those thirty minute blocks between meetings. It’s just enough time to let your mind settle down before you have to jump to the next meeting. 12 | 13 | So, the choices you feel left with are: 14 | 15 | 1. **Go ahead and try to do some thoughtful work.** Get into a thoughtful mode and after 30 minutes, when the next meeting is about to start, either A) forget that you had a meeting because your mind is quiet and focused, or B) get starkly interrupted by a notification to go to your meeting. 16 | 2. **Don’t try to do thoughtful work at all.** Just conceded that those 30 minutes are burned for any thoughtful work and go on a walk or try to do a task like email. 17 | 18 | It can be hard to think of scheduled, blocked-out time on a calendar functioning as a slot for the mere _possibility_ of something to happen. But I like John’s suggestion to create “an oasis of quiet” that allows you to do the kind of work you _want_ to do but are so easily distracted from under the guise of productivity. -------------------------------------------------------------------------------- /posts/2023-03-16-alphabet-as-technology.md: -------------------------------------------------------------------------------- 1 | # The Alphabet as Technology 2 | 3 | Robin has [an interesting post](https://robinrendle.com/notes/the-writing-of-the-gods/) about the technology of words: 4 | 5 | > Thinking of a language as a technology or a product is strange at first but the more you look at them the more they resemble microwaves or dishwashers; incredibly complicated under the hood but also sort of boring on the surface. 6 | 7 | This got me thinking about the alphabet. It seems so rudimentary: twenty-six characters. 8 | 9 | `abcdefghijklmnopqrstuvwxyz` 10 | 11 | What can you do with those twenty-six characters? 12 | 13 | - “Energy equals mass times the speed of light squared.” 14 | - “That’s one small step for man, one giant leap for mankind.” 15 | - “I have a dream that my four little children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character.” 16 | 17 | These famous quotes, and the grandiose ideas condensed into their structure, are all expressions of the same twenty-six letters re-arranged in different order. 18 | 19 | If I was on the alphabet marketing team — and I’m not talking about Google’s parent company here — I’d plug some punchy tagline like, “Twenty-six boring letters, an infinite number of exciting possibilities.” -------------------------------------------------------------------------------- /posts/2023-03-22-human-hype-and-machine-intelligence.md: -------------------------------------------------------------------------------- 1 | # AI Takes Over Because of Human Hype, Not Machine Intelligence 2 | 3 | Geoff, in his recent blog post [“Damn the AI Torpedos”](https://geoffgraham.me/damn-the-ai-torpedos/): 4 | 5 | > The idea that businesses are already waging an “AI arms race”…that one those very companies, Microsoft, can invest $11 billion into OpenAI while laying off the folks responsible for keeping AI, um, responsible…that real (read: not generated) people are already losing jobs to this tooling…and that all of this is happening in an environment that has little-to-no oversight and regulation… 6 | 7 | This struck me as an interesting framing of our current moment — I always love considering the perspective of a traditional narrative flipped on its head. 8 | 9 | We fear AI because we think it’ll take over what we’re currently doing. 10 | 11 | But maybe the reality is we end up losing our jobs to AI because of our own hype around it. 12 | 13 | In other words, “AI” — [whatever that means](https://adactio.com/journal/19899) — takes our jobs, not because it’s going to do what we’re already doing, but because organizations feel compelled to shift resources to the AI industrial complex because “everyone’s doing it” and “it’s the future”. 14 | 15 | From this perspective, AI is less of a watershed moment in computing history and more of a classic human [“Keeping up with the Joneses”](https://en.wikipedia.org/wiki/Keeping_up_with_the_Joneses) moment. 16 | 17 | If I was a good novelist, I’d already have my thesis for another book: AI takes over the world and we all become slaves to it, not because it outpaced humanity in intelligence and capabilities, but because _we propel it to be our master_ in an arms race to try and make it smarter than other people can. In essence, AI is “smarter” than us but not because robots are intelligent but because humans are dumb, lol. -------------------------------------------------------------------------------- /posts/2023-06-12-minute-rice-text-and-websites.md: -------------------------------------------------------------------------------- 1 | # Minute Rice, Minute Text, Minute Websites 2 | 3 | I was reading Baldur’s article (which I took [notes](https://notes.jim-nielsen.com/#2023-06-12T1115) on) and he suggests an interesting overlap between AI enthusiasts and “idea people”: 4 | 5 | > That algogen fans are predominantly idea people—the lot who think that 99% of the value delivered by any given form of media comes from the idea—isn’t a new observation, but it’s apt. If you don’t think the form or structure of the medium delivers any value, then it has to be a uniform commodity that can, and should, be generated algorithmically to save people from the tedious work of pointless creation. 6 | 7 | If all that matters is the idea, then AI is everything and execution doesn’t really matter. From this perspective, when it comes to generating text it’s the destination that matters _not_ the journey. 8 | 9 | Or so some might believe. 10 | 11 | There’s an interesting parallel here, I think, to claims about how fast you can scaffold a website. X framework or Y host allows you to go from zero to a beautiful, functional (probably cloned from a template) website in “three easy steps”. The idea being, however implicit, that “in as little as three easy steps” you’re 90% of the way to something unique and special. 12 | 13 | But if you’ve been doing this for a while, you know that last 10% takes 90% of the time — it is _the everything_ that differentiates you. If anybody can spin up a website in “3 easy steps” then what’s the differentiation? It’s everything after the three easy steps that counts; everything after the “website in minutes” that separates you from the rest. 14 | 15 | It’s kind of like conflating “minute rice” with regular rice. To some people it’s all the same — after all they both have the same name “rice” — but to conflate the two would be folly. The difference is everything. -------------------------------------------------------------------------------- /posts/2023-06-24-components-and-legos.md: -------------------------------------------------------------------------------- 1 | # Components and LEGOs 2 | 3 | “We’re going to build a component library — which are like a bunch of LEGOs — so designers/developers can just pick a prefabricated component off the shelf and build with consistency and coherence.” 4 | 5 | It’s a nice thought, if you don’t think about it too much. But I recently read [Christian Heilmann](https://christianheilmann.com/2023/05/09/the-ongoing-defence-of-frontend-as-a-full-time-job/) talking about “componentisation without big picture planning” and it hit me like a ton of LEGO bricks: 6 | 7 | > Web products these days aren’t built as documents, sites or even includes. They are built as independent components, each flexible enough to be applicable in many different contexts. That’s grand, until people assemble them nilly-willy and as many as they want to. 8 | 9 | We often imagine our system of components looking like this: 10 | 11 | Photograph of a star cruiser lego set with an instruction booklet showing how to put it together. 12 | 13 | But, to Christian’s point, they often look like this: 14 | 15 | Photograph of 6 giant buckets of random legos. 16 | 17 | Granted, two different things with different purposes. 18 | 19 | With a little imagination, the second one can be a horse farm, or a rocket ship, or a castle — or maybe all three at once! The first? Not so much. 20 | 21 | LEGOs are a nice, but often you want more than just prefabrication and composition. Design and intention bring about constraints and coherence — “componentisation _with_ big picture planning”. 22 | 23 | Just a note to self. -------------------------------------------------------------------------------- /posts/2023-07-11-stop-being-fancy.md: -------------------------------------------------------------------------------- 1 | # Stop Being Fancy 2 | 3 | This is a note to self: 4 | 5 | Except where absolutely necessary, stop being fancy. 6 | 7 | When confronted with, “Can this be done?” 8 | 9 | If the answer is an immediate "Yes", go ahead, do that. 10 | 11 | But if the answer is, “Well, you _could_, but you’d have to…" 12 | 13 | Just stop right there. Don’t go do that. 14 | 15 | Where possible, don’t create solutions to work around problems when you can eliminate the need for a solution altogether. 16 | 17 | Quick example: 18 | 19 | For a static file host, I can have URLs like: 20 | 21 | `/things?category=200` 22 | 23 | And then use the `_redirects` file to point query parameters at static files I put on disk, e.g. 24 | 25 | `/things category=:value /things/category/:value/index.html` . 26 | 27 | My advice to self here is: unless you really, really, _really_ need to do that, just don’t. 28 | 29 | Instead, accept and embrace the fact that you’re working with static files and make your URLs work without any special redirects trickery. 30 | 31 | Let the grain of your project show through and eliminate the need for any special solution on your part. 32 | 33 | `/things?category=200` with some redirect rules? No. 👎 34 | 35 | `/things/category/200` Yes! 👍 (the static file server takes over and serves `/icons/category/games/index.html`) 36 | 37 | In this way, you’re being true to the grain of your project and eliminated an extra layer where things can break. 38 | 39 | Because if things can break, they will — ’tis only a matter of time. Especially if you, Jim, coded it. -------------------------------------------------------------------------------- /posts/2023-07-14-things-i-like-over-things-i-dont.md: -------------------------------------------------------------------------------- 1 | # Things I Like Over Things I Don’t 2 | 3 | It was another typical day on the internet: somebody did something, it felt like a big deal to me, and I wanted to blog about why I didn’t like it. 4 | 5 | To vent, I sent [Dave](https://daverupert.com/) a private message — well a couple of them — detailing my frustrations. 6 | 7 | Looking back, I don’t remember what I was worked up about (there’s a lesson there) but I do remember Dave’s response. 8 | 9 | The gist was: “Yeah, I hear you. I feel the same way quite often. But I’ve found there’s value in celebrating good stuff instead of trashing bad stuff.” 10 | 11 | Then, in master blogger style, he linked me to [one of his own posts explaining why he thinks the way he does](https://daverupert.com/2018/11/the-good-path/): 12 | 13 | > I realized that the people I admire most don’t _only_ criticize technology they dislike. Rather, they amplify the things they enjoy. 14 | 15 | For reasons [I’ve noted elsewhere](https://notes.jim-nielsen.com/#2023-01-31T1221), there’s value in critique. But perhaps there’s a rule of thumb here, like a ratio of posts detailing [Good Things](https://blog.jim-nielsen.com/2019/good-things/) to posts detailing bad things of, say, 10 to 1. 16 | 17 | Or, perhaps I can cast this sentiment into a principle. Per [Jeremy’s advice on making good principles](https://adactio.com/journal/18628), it needs a sense of priority. Favor X _over_ Y. Here’s mine: 18 | 19 | **Tend towards blogging about things I like over things I don’t like.** 20 | 21 | There’s so much good stuff out there I could spend my time focusing on — such as folks like Dave, who take the time to A) blog their thoughts, and B) listen and respond to people like me they’ve never met in person. Thanks Dave. And thanks to you people like Dave: your time, attention, and wisdom is very much appreciated. -------------------------------------------------------------------------------- /posts/2023-07-20-domain-sins-of-my-youth.md: -------------------------------------------------------------------------------- 1 | # Domain Sins of My Youth 2 | 3 | I recently received a reminder to renew a domain I use for a rather frivolous side project. 4 | 5 | At the checkout screen, I realized it would cost me $105 to renew this domain for 5 years. 6 | 7 | Why 5 years? 8 | 9 | Right now my disposition is: if I plan on keeping a domain for as long as possible I renew it for as long as possible upon each renewal because I can only foresee the cost of domains increasing over time. (Maybe I’m wrong here — if you think I am, I’d love to know why.) I kinda wish I could renew it for 20 years. 10 | 11 | Why $105? 12 | 13 | You’ll have to ask GoDaddy. 14 | 15 | The point is, many of my side projects could’ve been a subdomain of my personal domain, e.g. instead of: 16 | 17 | `sideprojet.com` 18 | 19 | I could’ve done: 20 | 21 | `sideproject.jim-nielsen.com` 22 | 23 | Sure, it’s not as cool as the top-level domain, but it’s way cheaper over time. 24 | 25 | This is a lesson I wish I knew 15 years ago. 26 | 27 | So my advice to my younger self is this: get a personal domain and start all your side projects as a subdomain of that top-level domain. 28 | 29 | Your personal domain is the one you’ll own the longest, so you can easily upgrade a side project subdomain to a top-level domain if/when it becomes reasonable enough to justify it for X, Y, or Z reasons (simply setup up a long-standing redirect from the subdomain to the top-level domain). 30 | 31 | However, you can’t easily “downgrade” from a top-level domain to a subdomain because eventually you’ll stop paying for the top-level domain and lose the redirects from any residual traffic. 32 | 33 | Also, it won’t be a cool URI anymore because [cool URIs don't change](https://www.w3.org/Provider/Style/URI), which means domain names eventually bankrupt you. 34 | 35 | -------------------------------------------------------------------------------- /posts/2023-08-18-js-party-288.md: -------------------------------------------------------------------------------- 1 | #podcastAppearance 2 | 3 | # My Guest Appearance on JS Party #288 4 | 5 | My frequent ramblings on this blog garnered enough of the attention of [Jerod Santo](https://changelog.social/@jerod) that he graciously invited me to come on the JS Party podcast to talk about, well, my blog posts. 6 | 7 | Which ones? To name a few: 8 | 9 | - [Language-Level Toll Roads](https://blog.jim-nielsen.com/2023/language-level-toll-roads/) 10 | - [The Art of Knowing When to Quit](https://blog.jim-nielsen.com/2023/art-of-knowing-when-to-quit/) 11 | - [Subscribe Wherever You Get Your Content](https://blog.jim-nielsen.com/2023/subscribe-wherever-you-get-your-content/) 12 | 13 | Even just talking about the Deno KV thing (from “Language Level Toll Roads”) helped me clarify where my angst was coming from a bit more. In fact, I even came up with this graphic to illustrate it: 14 | 15 | Screenshot of a code sample for Deno KV asking which lines of code will cost money. 16 | 17 | Check out [JS Party episode 288](https://changelog.com/jsparty/288) wherever you get your podcasts. -------------------------------------------------------------------------------- /posts/2023-08-26-something-you-need-to-know-about-web-dev.md: -------------------------------------------------------------------------------- 1 | # There’s Something You Need to Know About Web Design and Development 2 | 3 | You’re doing great at it. 4 | 5 | (❤️ from [Bluey: Baby Race](https://www.youtube.com/watch?v=xmkCmJtK6X8&t=314s)) -------------------------------------------------------------------------------- /posts/2023-08-28-family-tree-wisdom.md: -------------------------------------------------------------------------------- 1 | # Family Tree Wisdom 2 | 3 | [Chris](https://chriscoyier.net/2023/08/25/what-if-you-did-x-every-single-day/): 4 | 5 | > My grandpa used to say that if you climb a rope every day, you’ll never not be able to do it. 6 | 7 | Ha, I love it! 8 | 9 | It got me thinking: I’d love to hear more folks’ “wisdom from the family tree”. Stuff like Chris shared, “My grandpa used to say…” 10 | 11 | I immediately had a few family members come to mind who repeatedly quoted the same phrase. In fact, I did a quick internet search and turns out some of these are derivative quotes from other people that pre-date any of my in-laws. That said, in my mind these quotes are forever tied to these people. 12 | 13 | - “Nobody ever got to the end of their life and said, ‘I wish I hadn’t been so kind‘.” — Grandma 14 | - “I’m not young enough to know everything.” — Uncle 15 | - “What you’re saying might be true, but I don’t believe a word of it.” — Dad 16 | - “If everybody threw their problems in a pile, once we saw everyone else’s we’d grab ours back fast.” — Grandpa 17 | 18 | Do you have some quotes from family members you always think about? Blog ‘em and [send me a link](https://www.jim-nielsen.com/#contact). -------------------------------------------------------------------------------- /posts/2023-09-04-software-crisis-garden.md: -------------------------------------------------------------------------------- 1 | #bookNotesSoftwareCrisis 2 | 3 | # “Out of the Software Crisis”: Gardening 4 | 5 | _The following is an extension of [my notes from Baldur’s book “Out of the Software Crisis”](https://blog.jim-nielsen.com/2023/book-notes-out-of-the-software-crisis/) including quotes from the author._ 6 | 7 | Great software _grows_ in our minds, we don’t manufacture it on-demand. 8 | 9 | > [Software projects] are grown thought-stuff [but we] treat them like lego blocks. 10 | 11 | As an interesting exercise, put aside the industrial metaphor of software as “legos” or “building blocks” and instead think about gardening as a metaphor for making software. 12 | 13 | It takes time for a gardener to develop a sense for how the plants within their garden connect and affect each other — “what makes them thrive, what kills them off, and how you prompt them to grow.” 14 | 15 | Stuff in the garden grows at its own pace, revealing itself along the way, and it’s the gardener who must notice and respond in kind. This growing happens _together_ — the plants, the gardener, the ecosystem — and drop-in replacements are risky. 16 | 17 | The constitution of _a garden_ is the realization of _the gardener’s_ experience. 18 | 19 | Software is quite similar. 20 | 21 | > Software is the insights of the development team made manifest. 22 | 23 | Love this articulation! And it’s precisely why churn is so costly to organizations. The insights a team of people has over time, and then responds to by evolving their software, is how a product grows and comes to fruition. 24 | 25 | Cut out the people who hold the insights and you tear out the roots of the software. 26 | 27 | The gardener is the garden, and the software is the team people who work on it. 28 | 29 | > code documentation…[is a] mnemonic for what you already know. 30 | 31 | Software is the lessons we learned along the way. 32 | 33 | Great software requires _growing_, a growing together of the team, their insights, and the technological possibilities of the time. -------------------------------------------------------------------------------- /posts/2023-09-11-llms-intuition-and-computers.md: -------------------------------------------------------------------------------- 1 | # LLMs, Intuition, and Working With Computers 2 | 3 | I recently watched Simon’s talk around practical use of LLMs (and [took notes](https://notes.jim-nielsen.com/#2023-09-08T1227)). This slide stood out: 4 | 5 | > For the best [prompt] results, combine: 6 | > - Domain knowledge of the thing you're working on 7 | > - Understanding how the models work 8 | > - Intuition gained from playing around with them _a lot_ 9 | 10 | I am by no means on the leading edge of LLMs. However, one thing I’ve noticed listening to people who are closer to the leading edge than I, is this idea that nobody quite knows why LLMs give the results they do — and the results can’t be repeated either (which is why experience and intuition are key to using them effectively). 11 | 12 | In science, you say you “understand” something when you can describe how it works and reliably predict (and even manipulate) its outcomes. 13 | 14 | The term “computer science” makes sense in this context, but LLMs seem to be introducing a shift away from the kind of determinism I’m familiar with in computers. 15 | 16 | In programming, you learn the rules which allow you to manipulate the computer and get consistent, repeatable, (and debug-able) results. 17 | 18 | In prompting, you play with the computer, see how it responds, and through experimentation and experience learn how to get roughly what you want but never in a repeatable way. 19 | 20 | I almost find it ironic because we can be so “data-driven” in our approach to making software — “We can’t do anything unless we scientifically prove with repeatable results that this thing is a positive net-gain” — but with LLMs we’re just like, “Nah, it’s ok that we don’t fully understand why it works the way it does and because of that we can’t get consistent, repeatable results. Go ahead and release it to the world.” -------------------------------------------------------------------------------- /posts/2023-09-24-software-by-encountering.md: -------------------------------------------------------------------------------- 1 | # Build Great Software By Repeatedly Encountering It 2 | 3 | Robin in [“Vibe driven development”](https://robinrendle.com/notes/vibe-driven-development/) (which [I took notes](https://notes.jim-nielsen.com/#2023-03-08T1210)): 4 | 5 | > the only way to build a great product is to use it every day, to stare at it, to hold it in your hands to feel its lumps. The data and customers will lie to you but the product never will. 6 | 7 | Oof. That lands with me. 8 | 9 | As a professional, it’s easy to become mired in the boundaries we draw around specialization, discipline, and craft. 10 | 11 | For example, “design” is too broad. We need UI design, UX design, service design, visual design, content design, and more. Each comes with its specialities, best practices, rules, and guidelines that demand a role in making software. 12 | 13 | I'm not discounting any of that. 14 | 15 | But, to Robin's point, there’s something in the simplicity of: you just gotta use the thing, every day, over and over and over. 16 | 17 | My brain thinks of it like a rock you want to make smooth. You can discuss how to best smooth its edges, debate what tools will do it best, and so forth. 18 | 19 | Or you can be like a river of water that washes over the rock incessantly day after day after day, smoothing over every last rough edge by _encountering it_ over and over and over again. 20 | 21 | You can get pretty damn far by _incessantly encountering_ a piece of software over and over, fixing everything you find along the way that doesn’t feel right. -------------------------------------------------------------------------------- /posts/2023-09-27-robots-txt.md: -------------------------------------------------------------------------------- 1 | # Robots.txt 2 | 3 | A few weeks ago, I saw a flurry of conversation about how you can now disallow OpenAI from indexing your personal website using `robots.txt`: 4 | 5 | ``` 6 | User-agent: GPTBot 7 | Disallow: / 8 | ``` 9 | 10 | That felt a bit “ex post facto“ as they say. Or, [as Jeremy put it](https://adactio.com/links/20380), “Now that the horse has bolted—and ransacked the web—you can shut the barn door.” 11 | 12 | But folks seemed to be going ahead and doing it anyway and I thought to myself, “Yeah, I should probably do that too…” (especially given how [“fucking rude”](https://chriscoyier.net/2023/04/21/the-secret-list-of-websites/) AI is in [not citing its sources](https://blog.jim-nielsen.com/2023/cite-your-sources-ai/)). 13 | 14 | But I never got around to it. 15 | 16 | Tangentially, Manuel asked: what if you updated your `robots.txt` and blocked all bots? What would happen? Well, he did it and after a week he followed up. [His conclusion](https://manuelmoreale.com/@/page/uwGISnOGX0zwjr7P)? 17 | 18 | > the vast majority of automated tools out there just don't give a fuck about what you put in your robots.txt 19 | 20 | That’s when I realized why I hadn’t yet added any rules to my `robots.txt`: I have zero faith in it. 21 | 22 | Perhaps that faith is not totally based in reality, but this is what I imagine a `robots.txt` file doing for my website: 23 | 24 | Photograph of a “DO NOT ENTER” sign on a rock cliff and people have passed it and are standing out on the edge of the cliff. 25 | 26 | Photograph at a beach with a sign that says “POISONOUS SPECIES DO NOT STEP INTO WATER” and people are all standing in the surf. 27 | 28 | Photograph of a sign painted on the ground that says “NO DOGS ALLOWED” and there’s an adorable puppy sitting on the “NO” looking at the camera. 29 | -------------------------------------------------------------------------------- /posts/2023-10-01-websites-are-for-normies.md: -------------------------------------------------------------------------------- 1 | # Making a Website is for Everyone 2 | 3 | [Dave asked](https://indieweb.social/@davatron5000@mastodon.social/110912189285291743) what makes people excited about building for the web and [Thomas answered](https://indieweb.social/@nachtfunke/110912228740815266) with this wonderful articulation: 4 | 5 | > the web is the only programming platform (that I know of) that considers its builders regular people, not IT Professionals and continues to write standards with that consideration. 6 | 7 | Love this. 8 | 9 | I made my first website as a young teenager because the barrier was so low (and I dropped out of my very first computer science course _after the very first class_ because the barrier seemed so high). 10 | 11 | I realize complexity enters the scene because the web is _world wide_. There are so many people trying to do so many things with it, that it has to be wide and deep to accommodate all those use cases. 12 | 13 | But I absolutely _love_ the idea of actively preserving a low barrier to entry for future generations of people. 14 | 15 | “Would teenage Jim have been able make a website now-a-days?” That’s the question I ask myself every time I write a blog post about new technique X or tool Y. 16 | 17 | Over time, the direction of web technology always trends towards complexity. Simplicity is achieved as a concerted, mindful fight against this. 18 | 19 | The web’s low barrier to entry led me to a career that has been a boon for my life. I hope it can do the same for others. -------------------------------------------------------------------------------- /posts/2023-10-20-people-and-blogs-and-me.md: -------------------------------------------------------------------------------- 1 | # People and Blogs and Me 2 | 3 | If you haven’t seen it, [Manu has a new series called “People and Blogs”](https://manuelmoreale.com/people-and-blogs) centered around a lovely goal: 4 | 5 | > to both highlight wonderful human beings and their blogs, and also to promote a healthier way to inhabit the web and show that traditional social media is not the be all and end all when it comes to having an internet presence 6 | 7 | The format is a standard set of questions across a series of people who run their own personal blogs. 8 | 9 | He’s already interviewed a series of people, most of whom I was unfamiliar with, so it’s exciting to discover how much larger the world of RSS is! 10 | 11 | [His latest interviewee](https://manuelmoreale.com/pb-jim-nielsen) was someone you might be familiar with: yours truly. 12 | 13 | > My name is Jim Nielsen (not to be confused with Jim Nielsen, the California state senator, who still outranks me on Google). 14 | 15 | I talk about my personal history of blogging: 16 | 17 | > my first blog was on Blogger…It mainly consisted of me posting pictures of ridiculous stuff I’d made in Photoshop — what we might call “memes” and “shitposting” now. 18 | 19 | And why I don’t monetize my blog: 20 | 21 | > I grew up in an era when people blogged about web stuff for free and I benefited immensely from their work so I feel a kind of obligation to pay it forward. Thank you blogger peeps from days of yore. 22 | 23 | If you’re not bored of reading about me, [check out my entry in the series](https://manuelmoreale.com/pb-jim-nielsen). 24 | 25 | Or, even better, [subscribe to the whole series](https://peopleandblogs.com) and discover new people to fill your RSS feed. -------------------------------------------------------------------------------- /posts/2023-10-23-javascript-is-enabled-by-default.md: -------------------------------------------------------------------------------- 1 | # JavaScript Is Enabled by Default in Web Browsers 2 | 3 | It’s easy to talk bad about JavaScript (or at least its _abuse_) like it’s some kind of malware. 4 | 5 | But it’s worth remembering that JavaScript is enabled _by default_ in web browsers. 6 | 7 | JavaScript is not so terrible, so harmful, so taboo, so _something you shouldn’t use_ that it’s turned off by default in web browsers. 8 | 9 | Want access to a user’s camera? You have to ask permission. 10 | 11 | Want access to their location? Ask permission. 12 | 13 | Their microphone? Permission. 14 | 15 | But want them to run some JavaScript? This capability is enabled by default, no permission necessary. 16 | 17 | Browsers are pro-JavaScript. 18 | 19 | And progressive enhancement? It’s also pro-javascript. It advocates for experiences enabled exclusively by JavaScript: build the core functionality, then enhance! And leverage JavaScript for what JavaScript alone can do. 20 | 21 | Browsers don’t turn off Javascript by default. And you don’t have to either. What’s important to note is that web experiences can work without it (or _before_ it). 22 | 23 | Building in layers of technology (HTML, CSS, JS — [in that order](https://blog.jim-nielsen.com/2023/meaning-in-web-tech-stack-ordering/)) is how the web is designed to work. It breeds resiliency. 24 | 25 | URLs lead to HTML which leads to CSS and JS. Start at the bottom layer and build up, ensuring new layers enhance on the layers beneath them and core functionality remains working if the technology breaks at any layer. -------------------------------------------------------------------------------- /posts/2023-10-31-advice-on-blogging.md: -------------------------------------------------------------------------------- 1 | # Advice on Blogging 2 | 3 | In Manuel’s series _People and Blogs_, [he asked me](https://manuelmoreale.com/pb-jim-nielsen): 4 | 5 | > Given your experience, if you were to start a blog today, would you do anything differently? 6 | 7 | I gave my answer, but I wanted to expand on it. 8 | 9 | These kinds of questions are interesting to me. 10 | 11 | As readers, I think the answer we’re looking for in a question like this is: “Here’s the few tips I wish I had known when I started blogging.” 12 | 13 | Why? Because we believe we can take these tips, use them, and revel in the thought that we saved ourselves some time and headache through someone else’s (hard-won) experience. 14 | 15 | However — and this is what I try to get across in my original answer — I think the truth is that you don’t get the same satisfaction saving yourself from pain you haven’t experienced. 16 | 17 | The best feeling is saving yourself from the pain you know. 18 | 19 | What my blog is now is a result of me wrestling with what it even means to blog. What I love about “blogging” is how personal it is. Even the word, “blog”, doesn’t give you any classifying genre of what content or experience you’ll get from any one individual’s blog. 20 | 21 | I’m rambling now, but my point is: 22 | 23 | > The best part of blogging is what you discover and learn _experientially_ along the way. 24 | 25 | Anyhow, I ignore a lot of advice because I don’t understand it when I hear it. Only once I’ve dealt with the pain of hard-won experience do I say, “That’s good advice.” -------------------------------------------------------------------------------- /posts/2023-12-28-blogging-and-compositing.md: -------------------------------------------------------------------------------- 1 | # Blogging and Composting 2 | 3 | Here’s a thought: blogging is like composting. 4 | 5 | The banana is what you’re after. 6 | 7 | But as a byproduct of the banana you get the peel. 8 | 9 | And if you compost, you can make good use of the peel. 10 | 11 | Similarly, whatever you’re building is what you’re after. 12 | 13 | But as a byproduct of whatever you’re building you undoubtedly learned, observed, or cursed at something along the way. 14 | 15 | And if you blog, you can make good use of that experience! 16 | 17 | Even if the banana was spoiled when you opened it, you can still compost it. 18 | 19 | Similarly, even if you ship nothing, there’s a blog post in that failure-to-ship. 20 | 21 | Composting recycles organic materials to enrich future plant soil. 22 | 23 | Similarly, blogging recycles experience to enrich future projects (and self) with wisdom. -------------------------------------------------------------------------------- /posts/2024-01-09-humans-all-the-way-down.md: -------------------------------------------------------------------------------- 1 | # It’s Humans All the Way Down 2 | 3 | [On the _Aboard_ podcast, Paul Ford](https://aboard.com/podcast/startup-year-in-review/) half-jokingly notes that everybody thinks everyone else’s job is easy. That’s why “AI” is going to replace so many people. 4 | 5 | Here’s Paul articulating this line of thiking: 6 | 7 | > What is a lawyer? A lawyer is somebody who moves contracts around. 8 | > 9 | > Well, a large learning model can internalize a million contracts. And now I will have a statistical model of every contract ever. [So in that case] what do I need a lawyer for? Right? That is the kind of logic that makes actually perfect sense if you’ve never met a lawyer. 10 | 11 | We can try to make a statistical model for anything, so really who needs anybody? 12 | 13 | But wait, maybe _somebody_ is the point: 14 | 15 | > The desire to get the human out of the loop, frankly, is based on ignorance. And it actually neglects the fundamental truth that the whole point of human existence is to interact with other humans. There is no other point. 16 | 17 | Later in the podcast Rich brings this point home: 18 | 19 | > If you could sum up what we learned in 2023, and I think what tech has learned, too, is that people matter. Even in the wildest of innovations, people still matter, and human relationships still matter, and you can’t shortcut it. 20 | 21 | Crypto failed because its desire was to remove humans. Its biggest failure — or was it a feature? — was that when the technology went awry and you needed _somebody_ to step in, there was _nobody_. 22 | 23 | Ultimately, we all want to appeal to another human to be seen and understood — not to a machine running a model. 24 | 25 | Interacting with each other is the whole point. -------------------------------------------------------------------------------- /posts/2024-01-10-idioms-as-code.md: -------------------------------------------------------------------------------- 1 | # Idioms as Code 2 | 3 | This is silly. 4 | 5 | I wrote code depicting common idioms. You read the code and try to guess the idiom. 6 | 7 | Answers are below the code (and, for clients viewing in supported readers, appear upside down like a children’s book). 8 | 9 | --- 10 | 11 | ``` 12 | pen > sword 13 | >>> true 14 | ``` 15 | 16 | 17 |

The pen is mightier than the sword

18 | 19 | --- 20 | 21 | ```js 22 | injury + insult 23 | ``` 24 | 25 |

Adding insult to injury

26 | 27 | --- 28 | 29 | ```js 30 | let cost = arm + leg 31 | ``` 32 | 33 |

Cost an arm and a leg

34 | 35 | --- 36 | 37 | ```js 38 | let chickens = []; 39 | 40 | // TODO don't do this 41 | chickens.length; 42 | 43 | hatch(); 44 | ``` 45 | 46 |

Don’t count your chickens before they’ve hatched

47 | 48 | --- 49 | 50 | ```js 51 | let your_court = [ball]; 52 | ``` 53 | 54 |

The ball is in your court

55 | 56 | --- 57 | 58 | ```js 59 | if (numOfDancers === 2) { 60 | tango() 61 | } 62 | ``` 63 | 64 |

It takes two to tango

65 | 66 | --- 67 | 68 | ```js 69 | my_madness.method() 70 | ``` 71 | 72 |

There’s a method to my madness

73 | -------------------------------------------------------------------------------- /posts/2024-01-12-macos-icon-book-irl.md: -------------------------------------------------------------------------------- 1 | #iconGalleriesBook 2 | 3 | # “The macOS App Icon Book” IRL 4 | 5 | Guess what I received in the mail today? 6 | 7 | You likely guessed it from the title, but I’ll say it anyway: _The macOS App Icon Book_. 8 | 9 | Photograph of the cover of the “The macOS App Icon Book” which is black, hardbound, and has a iOS-shaped silver foil embossing on the front. 10 | 11 | (If you didn’t catch it, [I’ve written previously](https://blog.jim-nielsen.com/tags/#iconGalleriesBook) about my contribution to its prequel.) 12 | 13 | This one [got funded on Kickstarter](https://www.kickstarter.com/projects/flarup/the-macos-app-icon-book) a few months back and, fast-forward to today, it’s now a real-to-goodness physical book! 14 | 15 | I am not a product photographer — I’ll leave that work to others — but it’s beautiful and I love it. 16 | 17 | Photograph of the inside of “The macOS App Icon Book” showing a bunch of icons. 18 | 19 | Photograph of the inside of “The macOS App Icon Book” showing a bunch of icons. 20 | 21 | With this book, its prequel, and [the prequel’s Japanese edition](https://blog.jim-nielsen.com/2023/japanese-ios-app-icon-book/), I now own the suite — like Pokemon, I’ve caught them all. 22 | 23 | Photograph of “The iOS App Icon Book”, “The macOS App Icon Book” and “The iOS App Icon Book: Japanese Edition”. 24 | 25 | Reminder: wonderful icons are created and introduced to the world every week, but we can’t ship updates to a physical book, so make sure you follow my [iOS](https://www.iosicongallery.com), [macOS](https://www.macosicongallery.com), and [watchOS](https://www.watchosicongallery.com) icon gallery sites for the latest and greatest. -------------------------------------------------------------------------------- /posts/2024-02-26-the-subversive-hyperlink.md: -------------------------------------------------------------------------------- 1 | #openWeb 2 | 3 | # The Subversive Hyperlink 4 | 5 | The web has a superpower: permission-less link sharing. 6 | 7 | I send you a link and as long as you have an agent, i.e. a browser (or a mere HTTP client), you can access the content at that link. 8 | 9 | This ability to create and disseminate links is almost radical against the backdrop of today’s platforms. 10 | 11 | To some, the hyperlink is dangerous and must be controlled: 12 | 13 | - They want to control what you can link to (see: [app stores & external purchase links](https://developer.apple.com/support/storekit-external-entitlement-us/)). 14 | - They want to control how many links you can make (see: [the link-in-bio phenomenon](https://www.theringer.com/2016/10/1/16040398/instagram-link-in-bio-nightmare-tech-8706186b3ec)). 15 | - They want to monetize your links (see: search engines) and give you no credit (see: AI). 16 | 17 | And yet, we keep on linking: 18 | 19 | - To whatever we want (👋 Apple) 20 | - However many times we want (👋 Meta) 21 | - And with no expectation of return (👋 Google/Open AI) 22 | 23 | Why? Because it’s a web. Interconnectedness is the whole point. 24 | 25 | Links form the whole. Without links, there is no whole. No links means no web, only silos. Isolation. The absence of connection. 26 | 27 | Subvert the status quo. Own a website. Make and share links. -------------------------------------------------------------------------------- /posts/2024-02-27-more-files-plz.md: -------------------------------------------------------------------------------- 1 | # More Files Please 2 | 3 | Scott Jenson has a great article called [“The future needs files”](https://jenson.org/files/). 4 | 5 | > The power of files comes from them being powerful nouns. They are temporary holding blocks that are used as a form of exchange between applications. A range of apps can edit a single file in a single location. 6 | 7 | Files as a medium of exchange between applications — I like that. It’s akin to the usefulness of currency. 8 | 9 | > The most powerful aspect of files is that they liberate your data. Any app can see it and do something useful to it. 10 | 11 | Files represent a “data first vs app first organization”. If you’re planning a wedding, you put everything wedding related into a folder. All your data is now in one place vs. strewn across various apps. 12 | 13 | Documents — like a Notion doc — are today’s folders: they contain a list of links to “files” that will open in bespoke applications. 14 | 15 | But there are drawbacks, like interoperability. Do we want to trust our data to the success or failure of a single company? 16 | 17 | > Files encapsulate a ‘chunk’ of your work and allow that chunk to be seen, moved, acted on, and accessed by multiple people and more importantly external 3rd party processes. 18 | 19 | Can you imagine working on a codebase — which is a set of files — but the files were locked to a particular IDE? Craziness. 20 | 21 | Personally, I’m a file guy. I love files. And I wish more products worked in the currency of exchange of files. -------------------------------------------------------------------------------- /posts/2024-03-05-shoptalk-show-605.md: -------------------------------------------------------------------------------- 1 | # My Guest Appearance on ShopTalk Show #605 2 | 3 | Here’s the link: https://shoptalkshow.com/605/ 4 | 5 | I sat down ([again](https://blog.jim-nielsen.com/2022/me-on-shoptalkshow-504/)) with Chris and Dave to talk all things web. 6 | 7 | The conversation was fun and casual, mostly around topics I’ve written about recently — which is good, since those are topics I should (presumably) be able to speak on at least somewhat knowledgeably. 8 | 9 | Big thanks to Chris and Dave for having me on the show! 10 | 11 | After recording, I actually started to think more about this idea of “mouth-blogging”. And, should they ever decide to have me back on the show, here’s my pitch to Chris and Dave for the next episode (or, really, any episode with a future guest): 12 | 13 | - We reach into our list of blog post drafts. 14 | - We pull out a couple drafts — maybe the oldest ones by date? — that we know we’ll never publish but haven’t had the heart to delete. 15 | - We mouth-blog them on the show. 16 | - We then either 1) feel encouraged to finish the draft and publish it, or 2) cathartically delete the draft permanently, knowing we got out what we wanted to say. 17 | 18 | Until then, go check out [episode 605](https://shoptalkshow.com/605/). -------------------------------------------------------------------------------- /posts/2024-03-07-hard-websites.md: -------------------------------------------------------------------------------- 1 | # Is Making Websites Hard, Or Do We Make It Hard? Or Is It Some of Both? 2 | 3 | [Johan Halse has a post called “Care”](https://johan.hal.se/wrote/2024/02/28/care/) where he talks about having to provide web tech support to his parents: 4 | 5 | > My father called me in exasperation last night after trying and failing to book a plane ticket. I find myself having to go over to their house and do things like switch browsers, open private windows, occasionally even open up the Web Inspector to fiddle with the markup, and I hate every second of it. 6 | 7 | Yup. [Been there, done that](https://blog.jim-nielsen.com/2022/a-web-for-all/). 8 | 9 | Why is making websites so hard? 10 | 11 | > the number one cause of jank and breakage is another developer having messed with the browser’s default way of doing things 12 | 13 | So in other words, making websites isn’t hard. _We_ make making websites hard. But why? 14 | 15 | In my experience, using default web mechanics to build websites — especially on behalf of _for-profit_ businesses — takes an incredible amount of disciple. 16 | 17 | Self-discipline on behalf of the developer to not reach for a JavaScript re-implementation of a browser default. 18 | 19 | But also organizational discipline on behalf of a business to say, “It’s ok if our implementation is ‘basic’ but functional.” (And being advocate for this approach, internally, can be tiring if not futile.) 20 | 21 | You think people will judge you if your website doesn’t look and feel like a “modern” website. 22 | 23 | But you know what they’ll judge you even more for? If it doesn’t even work — on the flip side, they’ll appreciate you even more for building something that “just works”. 24 | 25 | At least that’s my opinion. But then again, I’ve never built a business. So what do I know. -------------------------------------------------------------------------------- /posts/2024-03-12-following-links.md: -------------------------------------------------------------------------------- 1 | # Following Links 2 | 3 | I loved [this post from Chris Enns](https://chrisenns.com/2023/11/app-defaults/) (via [Robb Knight](https://rknight.me/blog/the-web-is-fantastic/)) where he outlines the rabbit hole of links he ventured down in writing that post. 4 | 5 | It felt fun and familiar, as that’s how my own browsing goes, e.g. 6 | 7 | “I saw X and I clicked it. Then I saw Y, so I clicked that. But then I went back, which led me to seeing Z. I clicked on that, which led me to an interesting article which contained a link to this other interesting piece. From there I clicked on…” 8 | 9 | [Browsing the web via hyperlinks is fun! That’s surfing!](https://blog.jim-nielsen.com/2024/treating-the-symptoms/) 10 | 11 | Discovering things via links is way more fun than most algorithmically-driven discovery — in my humble opinion. 12 | 13 | As an analogy, it’s kind of like going on vacation to a new place and staying/living amongst the locals vs. staying at a manicured 5-star hotel that gives you no reason to leave. Can you really say you visited the location if you never left the hotel? 14 | 15 | I suppose both exist for a reason and can be enjoyed on their own merits. But personally, I think you’re missing out on something if you stay isolated in the walled garden of the 5-star hotel. 16 | 17 | Similarly, if you never venture outside a social media platform for creation or consumption — [or automated AI browsing and summaries](https://blog.jim-nielsen.com/2024/treating-the-symptoms/) — it’s worth asking what you’re missing. 18 | 19 | Have you ever ventured out via links and explored _the internet_? -------------------------------------------------------------------------------- /posts/2024-04-09-you-are-what-you-read.md: -------------------------------------------------------------------------------- 1 | # You Are What You Read, Even If You Don’t Always Remember It 2 | 3 | Here’s Dave Rupert ([from my notes](https://notes.jim-nielsen.com/#2024-03-22T1029)): 4 | 5 | > the goal of a book isn’t to get to the last page, it’s to expand your thinking. 6 | 7 | I have to constantly remind myself of this. Especially in an environment that prioritizes optimizing and maximizing personal productivity, where it seems if you can’t measure (let alone remember) the impact of a book in your life then it wasn’t worth reading. 8 | 9 | I don’t believe that, but I never quite had the words for expressing why I don’t believe that. Dave’s articulation hit pretty close. 10 | 11 | Then a couple days later my wife sent me this quote from Ralph Waldo Emerson: 12 | 13 | > I cannot remember the books I've read any more than the meals I have eaten; even so, they have made me. 14 | 15 | YES! 16 | 17 | Damn, great writers are sO gOOd wITh wORdz, amirite? 18 | 19 | Emerson articulates with acute brevity something I couldn’t suss out in my own thoughts, let alone put into words. It makes me jealous. 20 | 21 | Anyhow, I wanted to write this down to reinforce remembering it. 22 | 23 | And in a similar vein for the online world: I cannot remember the blog posts I’ve read any more than the meals I’ve eaten; even so, they’ve made me. 24 | 25 | It’s a good reminder to be mindful of my content diet — you are what you ~~eat~~ read, even if you don’t always remember it. 26 | 27 | ## Update 2024-04-12 28 | 29 | [@halas@mastodon.social](https://mastodon.online/@halas#.) shared this story in response, which I really liked: 30 | 31 | > At the university I had a professor who had a class with us in the first year and then in the second. At the beginning of the second year’s classes he asked us something from the material of previous year. When met with silence he nodded thoughtfully and said: “Education is something you have even if you don't remember anything” 32 | 33 | I love stories that stick with people like that, e.g. “something a teacher told me once...” 34 | 35 | [Some impact is immeasurable](https://blog.jim-nielsen.com/2024/immeasurable-impact/). -------------------------------------------------------------------------------- /posts/2024-05-01-bulletproof-problem-solving.md: -------------------------------------------------------------------------------- 1 | # Bulletproof Method to Solving Problems 2 | 3 | **Step 1**: Write down the problem in a message you plan to send to a co-worker. 4 | 5 | Most of the time you’ll solve the problem before you’re done with Step 1. However, if you complete Step 1 and still have the problem, continue to Step 2. 6 | 7 | **Step 2**: Hit the “Send” button. 8 | 9 | Shortly after sending, the solution will present itself. I don’t know why this is. I don’t make the rules. But the solution frequently presents itself after you hit “Send” and no longer need the recipient’s help. 10 | 11 | **Step 3**: Return to message you just sent and follow up with: [“Nevermind. Figured it out.”](https://www.instagram.com/reel/C40w-f3PA7I) 12 | 13 | Ok, ok. This is in jest — a little bit. But it is a good method for getting yourself unstuck. -------------------------------------------------------------------------------- /posts/2024-05-06-errors-arent-all-bad.md: -------------------------------------------------------------------------------- 1 | # Errors Aren’t All Bad 2 | 3 | Adam Silver wrote [“Don’t use the maxlength attribute to stop users from exceeding the limit”](https://adamsilver.io/blog/dont-use-the-maxlength-attribute-to-stop-users-from-exceeding-the-limit/) which seems like one of those obvious things that needn’t be said, but I’m glad he says it. 4 | 5 | > Have you heard of the “error prevention” heuristic? 6 | > 7 | > It means “do everything you can so users don’t make mistakes”. And it’s good advice. But some designers take this to mean “don’t let users see an error” which is bad advice. 8 | 9 | There’s a big difference between helping users with errors and making users avoid errors. 10 | 11 | Errors can be like mistakes: good for you if they help you learn. 12 | 13 | A classic example of this is composing a tweet/toot in a field with a maximum length. 14 | 15 | If I try to _submit_ over 140 characters, that’s an error. It’s not supported by the system. I will be blocked. 16 | 17 | But that doesn’t mean I should be prevented from _inputting_ over 140 characters. 18 | 19 | Don’t block me, inform me. Let me go over 140 chars. Let me cross that boundary into “error” territory. Don’t accept its submission, but allow its composition. 20 | 21 | Allow me to make errors and give me the space to correct them, rather than preventing them altogether. In this case, let me write out my thoughts and pare them down later vs. being rebuked to input anything beyond your threshold. 22 | 23 | Preventing me from going over 140 doesn’t help me. It slaps me on the hand and blocks my thought process. I can’t think about what I’m trying to do because you’re too busy telling me why I’m in the wrong. 24 | 25 | Errors are good if they’re helpful — in UI interaction and life :) -------------------------------------------------------------------------------- /posts/2024-05-20-futuristic-progressive-enhanement.md: -------------------------------------------------------------------------------- 1 | # Futuristic Progressive Enhancement 2 | 3 | Imagine someone came to you in a time machine and said, “In the future we will write software that becomes more capable as time passes without any effort on our part.” 4 | 5 | Wouldn’t that be amazing? Surely you’d want to know what sorcery makes this possible, right? 6 | 7 | Well the future is here. You can do that now. It’s called progressive enhancement. 8 | 9 | Here’s Jeremy in his piece [“Baseline progressive enhancement”](https://adactio.com/journal/21128): 10 | 11 | > Code you’ve already written starts working from one day to the next. 12 | 13 | Wait, what? You write code and, without any effort on your part, it becomes more capable from one day to the next? 14 | 15 | What an antidote to so much of today’s fatigue. 16 | 17 | We’re all tired of: write some code, come back to it in six months, try to make it do more, and find the whole project is broken until you upgrade everything. 18 | 19 | Progressive enhancement allows you to do the opposite: write some code, come back to it in six months, and it’s doing more than the day you wrote it! -------------------------------------------------------------------------------- /posts/2024-06-07-night-time-sky.md: -------------------------------------------------------------------------------- 1 | #rssClub 2 | 3 | # The Night Time Sky 4 | 5 | When I was a kid, my Dad used to take us outside to look for what he called “UFOs”. It’d take a moment, but after enough searching we’d eventually spot one. 6 | 7 | One night, all of us kids were outside with our uncle. We saw a star-like light moving in a slow, linear fashion across the night sky. One of us said, “Look, a UFO!” My uncle, a bit confused, said “That’s not a UFO, that’s a satellite.” 8 | 9 | Dad, you sneaky customer. 10 | 11 | Fast forward to 2024. I was recently in the mountains in Colorado where the night sky was crisp and clear. I squinted and started looking for “UFOs”. 12 | 13 | They were everywhere! 14 | 15 | It seemed as though any patch of sky I looked at, I could spot four to six satellites whose paths were cross-crossing at any given moment. It made me think of Coruscant from _Star Wars_. 16 | 17 | Animated gif showing the planet Coruscant from 'Star Wars' with lots of spaceship traffic traversing the sky. 18 | 19 | It also reminded me of those times as a kid, scouring the night sky for “UFOs”. Spotting a satellite wasn’t easy. We had to look and look for a good chunk of time before anyone would get a lock on one traversing the sky. 20 | 21 | But that night in Colorado I didn’t have to work at all. Point my eyes at any spot in the sky and I’d see not just one but many. 22 | 23 | Knowing vaguely about the phenomenon of night sky and space pollution, I came in and looked up how many satellites are up there now-a-days vs. when I was a kid. 24 | 25 | I found [this site showing trends in satellite launch and use](https://akhilrao.github.io/pages/publpics/launch_summary.html) by Akhil Rao, which links to [data from The Union of Concerned Scientists](https://www.ucsusa.org/resources/satellite-database). **Turns out we’ve ~10x’d the number of satellites in the sky over the last ~30 years!** 26 | 27 | That’s a long way of saying: I’ve heard about this phenomenon of sky pollution and space junk and the like, but it became much more real to me that night in Colorado. -------------------------------------------------------------------------------- /posts/2024-07-01-digital-trees.md: -------------------------------------------------------------------------------- 1 | # Digital Trees 2 | 3 | Trees have many functions: 4 | 5 | - they provide shade, 6 | - they purify air, 7 | - they store carbon, 8 | - they grow fruit, 9 | - and they’re aesthetically pleasing. 10 | 11 | What’s intriguing to me about trees is their return on investment (ROI). 12 | 13 | It takes years, even decades, to grow a tree to the point where you feel like you get to reap its benefits. 14 | 15 | Because of this, many trees end up being cultivated more for others than for ourselves. They can be a living embodiment of giving over extracting. 16 | 17 | With the web going the way it is — what with AI and its extractive penchant, poisoning the well from which it sprang — it makes me wonder: what are the “trees” of the web? Undoubtedly many (metaphorical) trees on the web were planted by others but we enjoy their fruits. 18 | 19 | For me personally, one example is the free and open blogs of folks whose advice and education have gifted me the know-how necessary to be employed as an [interdisciplinary website maker](https://blog.jim-nielsen.com/2024/interdisciplinary-website-maker/). 20 | 21 | Which makes me wonder: what trees am I planting? Trees I will gain little from in my lifetime, but others may revel in their fruits far into the future? 22 | 23 | Pay it forward. Plant a digital tree. -------------------------------------------------------------------------------- /posts/2024-07-11-the-value-of-silence.md: -------------------------------------------------------------------------------- 1 | # Creating Some Noise on Behalf of Silence 2 | 3 | How do you write about the value of silence? 4 | 5 | It’s kind of absurd when you think about it. Do you use words to extol the value of something whose essence is the very absence of words? 6 | 7 | It’s like making a painting of the invisible. Do you use visible means to depict something that exists outside of the visible? 8 | 9 | Nonetheless, here I am with this blog post. 10 | 11 | Via a recommendation from my wife, I recently finished reading [“The Stranger in the Woods: The Extraordinary Story of the Last True Hermit”](https://bookshop.org/p/books/the-stranger-in-the-woods-the-extraordinary-story-of-the-last-true-hermit-michael-finkel/7381267?ean=9781101911532) by Michael Finkel. It’s about Chris Knight, a man who chose to disappear into the woods in Maine and live alone with no human contact for almost three decades. 12 | 13 | Reading the book, you realize, “Damn, this guy led a life that was the very antithesis of our world of hyper-stimulation.” 14 | 15 | When the author asked him to describe his experience of solitary quietude, the best Knight could do is declare that words failed him. “Silence does not translate to words” he said. 16 | 17 | As the author points out, Knight’s observations are inline with other writings praising the value of silence. Emerson said, “He that thinks most, will say least.” The _Tao Te Ching_ states, “Those who know do not tell; those who tell do not know.” 18 | 19 | Anyhow, it’s a good, short read. Now I’m left with the impression that perhaps we could all use a little more silence…[as I generate some more noise in the world with this blog post to say that] -------------------------------------------------------------------------------- /posts/2024-07-22-greatest-strength-is-greatest-weakness.md: -------------------------------------------------------------------------------- 1 | # Your Greatest Strength Is Also Your Greatest Weakness 2 | 3 | Referring to product management, my old boss used to say, “There is no right or wrong, only trade-offs.” This applies to technology too (and, if you really think about it, life generally — but we won’t go that far). 4 | 5 | As an example, what makes npm great? It’s so easy to install a dependency. What makes npm not so great? It’s [too easy](https://www.reddit.com/r/node/comments/higlf0/heaviest_objects_in_the_universe/) to install dependencies. [npm makes it so easy to get a bunch of complexity](https://notes.jim-nielsen.com/#2016-11-18T1230). 6 | 7 | In other words: its greatest strength is also its greatest weakness. 8 | 9 | Nesting in ~~Sass~~ CSS is similar: nesting selectors aids readability, but [do it too much](https://mastodon.social/@jimniels/112830741174375242) and now nothing is readable. Again, a double-edged sword. 10 | 11 | The things you extol about a technology are also going to be the things that get you into trouble because those are the trade-offs. 12 | 13 | So to evaluate a piece of tech, you should ask yourself: what are the downsides of the the very things I love about this? 14 | 15 | The folks at Linear articulated this perfectly in a post-mortem explaining why they were having issues related to speed. To quote [their post](https://linearapp.notion.site/Improving-performance-at-scale-432a23dc5607416cafb5f82360e5f157): 16 | 17 | > These [speed] problems stem from trade-offs in our architecture. The reason Linear is fast is also the reason Linear is slow once workspaces grow in size. 18 | 19 | The reason it’s fast (in certain scenarios) is also the reason it’s slow (in other scenarios). 20 | 21 | The reason it’s great sometimes is also the reason it sucks sometimes. 22 | 23 | Your greatest strength is also your greatest weakness. -------------------------------------------------------------------------------- /posts/2024-08-02-deploying-with-netlify-shortcuts.md: -------------------------------------------------------------------------------- 1 | #myNotesSite 2 | 3 | # Deploying on Netlify with Apple’s Shortcuts 4 | 5 | Just a quick note on a personal workflow thing. 6 | 7 | I’ve written before about [the many different ways I host my personal websites on Netlify](https://blog.jim-nielsen.com/tags#netlify). 8 | 9 | I’ve got a few websites that aren’t the traditional model of: commit to git, push, build triggers on Netlify, website goes live. 10 | 11 | Sometimes I want to manually trigger a site deploy — but I’m lazy and don’t want to open a browser, go to netlify.com, find my site in the UI, find the button to trigger a deploy, etc. 12 | 13 | To make it easier, I’ve setup [build hooks](https://docs.netlify.com/configure-builds/build-hooks/) for the sites where I want to manually trigger deploys. These give me a URL to which I can send a POST request that will trigger a build, e.g 14 | 15 | ``` 16 | curl -X POST -d '{}' https://api.netlify.com/build_hooks/MY_BUILD_HOOK_URL_HERE 17 | ``` 18 | 19 | Using Apple’s Shortcuts app, I can create a shortcut that sends a POST request to my build hook URL. 20 | 21 | Screenshot of the macOS shortcuts app with arrows indicating which shortcut to choose and how to change the request method to a POST 22 | 23 | It’s a super simple shortcut, and I can create as many of these as I want and they should last for...well, as long as I have an account with Netlify. 24 | 25 | Screenshot of my Netlify deploy shortcut in the macOS app. 26 | 27 | And I can access these shortcuts from anywhere on any of my devices. On my Mac, Raycast indexes them so I have quick, easy access to them from the command bar. 28 | 29 | 30 | 31 | I can access them equally as easily on my iPhone, which makes triggering a build on mobile super simple. 32 | 33 | Why would I do this? I have my reasons. I’ll have to write about those later. 34 | -------------------------------------------------------------------------------- /posts/2024-08-29-the-humble-link.md: -------------------------------------------------------------------------------- 1 | # The Humble Link 2 | 3 | I was joking on Mastodon about how the zeitgeist has changed over the years, but its pattern is revealing itself: an acronym which merely drops letters. The Next Big Thing™ is clearly going to be “A”. 4 | 5 | - 2010: Everyone needs an "API" 6 | - 2020: Everyone needs "AI" 7 | - 2030: Everyone needs "A" 8 | 9 | So I just need to figure out what “A” is and I’ll be rich! 10 | 11 | [Annie came back with this response](https://social.lol/@anniegreens/113040651011794507) that won’t get out of my head: 12 | 13 | > `` the magic we already have 14 | 15 | On snap. Mic drop right there. 16 | 17 | It’s pretty wild that so many of the power struggles going on in tech stem from what is ultimately a fight over linking to something. 18 | 19 | - The app store & steering provisions: you cannot `` to an outside website 20 | - AI: it won’t `` to anything and cite its sources. 21 | - Social media: you only get one `` (“link in bio”) 22 | 23 | That Tim-Berners Lee really threw a wrench in things when he made the humble `` tag. 24 | 25 | [Links are incredibly powerful](https://blog.jim-nielsen.com/2021/the-power-of-the-link/). The web’s reputation is often that it’s playing catch up. However, when it comes to links, that original invention is still transforming the world. 26 | 27 | Meme of Boromir from the Lord of the Rings where he’s holding the ring with wonderment. The ring is overlaid with an anchor tag and the caption “tis a strange fate we whould suffer so much feat and doubt over so small a thing” 28 | 29 | -------------------------------------------------------------------------------- /posts/2024-09-04-personal-website-vulnerability.md: -------------------------------------------------------------------------------- 1 | # Personal Websites Are As Vulnerable As Us 2 | 3 | I look at some people’s personal websites and think, “Stupendous! If I ever reach that zenith of personal web design, I will call it quits.” 4 | 5 | Then I read a post by them later and they say something like, “Gah! I just really don’t like where I’m at with my personal website.” 6 | 7 | And in my mind I say, “WHAAAAAATTTT??!?!?” 8 | 9 | To me, they’re living the personal website dream! But they don’t feel that way. They seem to feel…well the same way I feel about my personal website. 10 | 11 | It’s like our personal websites are a mirror to ourselves — a place where the mind’s eye must reconcile with the optical eye’s perception of reality. 12 | 13 | It’s a torturous affair, to be sure. 14 | 15 | And yet, people still publish those personal sites, those redesigns, those half-baked ideas. 16 | 17 | There’s something vulnerable about publishing a personal website for the whole world to see, like standing up before a big crowd. 18 | 19 | And there’s no bigger crowd than the whole internet. -------------------------------------------------------------------------------- /posts/2024-09-17-reading-time-estimation-widgets.md: -------------------------------------------------------------------------------- 1 | # Estimated Reading Time Widgets 2 | 3 | Beware ye who enter, here be personal opinions. 4 | 5 | I’ve never understood reading time estimation widgets. Why did these get so popular? Is it because they’re easy? I mean, you can grab one off npm no problem. 6 | 7 | Screenshot of a large number of search results from npm for the keyword “reading-time”. 8 | 9 | Baldur suggests a theory in his piece about [estimated reading times](https://www.baldurbjarnason.com/2024/on-reading-time/): 10 | 11 | > At some point a programmer read in a study that the average person read 233 words per minute and decided that this would be a great way to estimate reading time for everybody on the fucking planet. 12 | 13 | The “reading time” for an article always felt so personal to me. As Baldur also points out, it can be affected by so many variables, such as: 14 | 15 | - Word count or length 16 | - Writing style 17 | - Design (formatting, typeface, etc.) 18 | - Individual physical factors 19 | - Vocabulary 20 | - Medium 21 | 22 | Because I’ve always seen reading time as such an incredibly personal thing, I’ve never once paid any heed to these widgets. In fact, I’ve been slightly perturbed a service would presume to know how quickly I could read an article. 23 | 24 | That’s to say nothing of the fact that if I come to a text to understand it (or merely enjoy it for that matter), speed is the very last thing on my mind. 25 | 26 | I’ve always viewed any service that sticks a “reading time” widget on its articles as the literary equivalent of fast-food: you’re not here for quality, but for expediency. 27 | 28 | Personally, I think they devalue a text more than they add to it. 29 | 30 | But hey, I’ll grant that’s just like, my opinion, man. -------------------------------------------------------------------------------- /posts/2024-09-22-blogging-is-listening.md: -------------------------------------------------------------------------------- 1 | # Blogging & Listening 2 | 3 | When you read a great blog post, the feeling you often get is: “I already knew this, I just hadn’t been able to express it!” 4 | 5 | In this sense, writing a great blog post is about listening. 6 | 7 | If you’re listening — to others, your coworkers, the people you follow, your own experiences, your users, etc. — there are undertones of something being said collectively. If you can hear it, write it down. 8 | 9 | People convey important things without stating them explicitly. When those unstated things resonate with you, write them down and publish them. 10 | 11 | Other people may love what you write because it resonates with what they’ve been feeling and hearing. It’s both validating and clarifying! 12 | 13 | So if you don’t know what to blog about, listen. Listen to what you hear and write it down. I doubt you’re the only one hearing it, but you _can_ be one of the few writing it down. -------------------------------------------------------------------------------- /posts/2024-09-29-wouldnt-recommend-this-algorithm.md: -------------------------------------------------------------------------------- 1 | # Randomness, Serendipity, and an “I Wouldn’t Recommend This” Algorithm 2 | 3 | Sean Voisen has [a great post](https://sean.voisen.org/marginalia/in-praise-of-randomness-james-bridle) about 1) how we as humans think of randomness, 2) how computers simulate randomness, and the difference between the two. 4 | 5 | He puts forth an intriguing thought: in a world increasingly driven by computation, how does that affect randomness in our lives? Here’s Sean: 6 | 7 | > We could all benefit from more randomness in our lives more than we may realize. By veering off the beaten path, by being exposed to new things we would otherwise never expose ourselves to, we increase the possibilities for serendipitous and creative encounters. But our increasingly computationally-dependent world is fundamentally incompatible with allowing this to happen. 8 | 9 | Be exposed to things we would otherwise never be exposed to? That sounds like the antithesis of the algorithm. 10 | 11 | The algorithm is: “You liked that? I bet you would like this!” 12 | 13 | But where is an algorithm that says: “You liked that? I bet you would never choose this — but here it is anyway!” 14 | 15 | I have to admit, I have a number of things in my life where I could say, “I would have never chosen ____, but it’s been one of the best things in my life!” Many things I would’ve never chosen, yet they came to me, and they’ve changed my perspective and outlook and my life. 16 | 17 | Where’s that algorithm? 18 | 19 | I suppose it’s hard to make money off of, “Here’s some stuff you would never choose for yourself.” 20 | 21 | So, where possible, I like the suggestion to make room for randomness in your life — and that might just mean stepping away from the pseudo-randomness of the computer more often. -------------------------------------------------------------------------------- /posts/2024-10-23-lowest-common-denominator.md: -------------------------------------------------------------------------------- 1 | #webPlatform 2 | 3 | # The Lowest Common Denominator: www 4 | 5 | Native apps are all about control. Don’t like thing X? You can dive in and, with enough elbow grease and persistence, finally get what you want. Write your own C library. Do some assembly code. Even make your own hardware if you have to. 6 | 7 | But on the web you give up that control. Can’t quite do the thing you want? You’re options are: 1) make a native app, 2) make a browser that does what you want (see: Google), or 3) rethink and reset the constraints of your project. 8 | 9 | But when you choose to build for the web instead of native, you’re not just giving up control in return for nothing. It’s a trade-off. You trade control for reach. 10 | 11 | For example, browsers won’t just let any website read and write from disk (who wants to grant that to _any_ website in the world?) You can view that as a loss of control, but I see it as a constraint and a trade-off. In return, you get a number of security and privacy guarantees — and you also get reach: now any computer, even ones without hard drives, can access your website! (The same goes for any hardware feature, like webcams, microphones, geolocation, accelerometers, etc.) 12 | 13 | The baseline assumptions for browsers are incredibly more broad and inclusive than native apps. It’s the “lowest common denominator” of computing. That sounds like a derisive label, but it’s not. Once again, it’s about trade-offs. 14 | 15 | In math, the lowest common denominator is about _simplification_. It makes calculation as simple as possible. And there’s a parallel here to computing: browsers reduce the computing tasks available across a variety of devices to be as simple as possible, which means you can reach more devices — and therefore _people_. 16 | 17 | So while the term “lowest common denominator” can be used in a disparaging manner — like it’s the most crude, basic form of something available — if your primary goal is reach, then basic is exactly what you want. -------------------------------------------------------------------------------- /posts/2024-11-02-hacker-news-clones.md: -------------------------------------------------------------------------------- 1 | # Hacker News Clones 2 | 3 | Every once in a while, I’ll have a post gain traction over on ye ole’ orange site (Hacker News). 4 | 5 | I find out about it because [my analytics digest](https://blog.jim-nielsen.com/2022/netlify-analytics-email-digest/) will get a _yuge_ uptick in page views. 6 | 7 | What’s interesting is all the referral sources that show up in my analytics. _The_ Hacker News is always at the top, but then after it comes a bunch of clones or related “scraped tech news” sites. 8 | 9 | I sometimes click through just to see them and marvel at what an interesting, diverse place the web is and all the people building on it. 10 | 11 | Here’s a list of the ones that showed up in my analytics recently: 12 | 13 | - [hckrnews.com](https://hckrnews.com) 14 | - [hackerweb.app](https://hackerweb.app) 15 | - [hn.premii.com](https://hn.premii.com) 16 | - [hn.algolia.com](https://hn.algolia.com) 17 | - [brutalist.report](https://brutalist.report) 18 | - [hnrss.org](https://hnrss.github.io) 19 | - [hackurls.com](https://hackurls.com) 20 | - [hn.svelte.dev](https://hn.svelte.dev/top/1) 21 | - [news.hada.io](https://news.hada.io) 22 | - [hntoplinks.com](https://hntoplinks.com) 23 | - [progscrape.com](https://progscrape.com) 24 | - [spike.news](https://spike.news) 25 | - [serializer.io](https://serializer.io) 26 | - [news.social-protocols.org](https://news.social-protocols.org) 27 | - [hackernews.betacat.io](https://hackernews.betacat.io) 28 | - [old.thenews.im](https://old.thenews.im) 29 | 30 | While I personally don’t spend a lot of time on Hacker News, I kinda love that the site exists, gets so much traffic, and AFAIK the owners aren’t actively seeking to make every last pageview happen on their domain (`news.ycombinator.com`). 31 | 32 | I kinda love that there are still places on the web where people can explore creating alternative experiences without being shut down because they are outside the officially-sanctioned environment. -------------------------------------------------------------------------------- /posts/2024-11-04-design-engineer-job-screener.md: -------------------------------------------------------------------------------- 1 | #designEngineer 2 | 3 | # Job Screening Blog Post 4 | 5 | Take a look at these two animated gifs. 6 | 7 | First: 8 | 9 | Animated gif of a button being clicked and the UI changing. The text heading in the UI is shifting upwards by 1px. 10 | 11 |

12 | 13 | Second: 14 | 15 | Animated gif of a button being clicked and the UI changing. The text heading in the UI doesn’t shift at all. 16 | 17 | Can you tell the difference between them? 18 | 19 | Do you care? 20 | 21 | If not, we might not be a good fit. 22 | 23 | `#designEngineering` -------------------------------------------------------------------------------- /posts/2024-11-15-writing-is-human-expression.md: -------------------------------------------------------------------------------- 1 | # Reading and Writing as Human Expression & Connection 2 | 3 | Why do we write? 4 | 5 | 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](https://aworkinglibrary.com/writing/peasant-woodland) (and [my notes](https://notes.jim-nielsen.com/#2024-10-21T0936)) in a recent article: 6 | 7 | > 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 8 | 9 | You write because something needs to be expressed _through you_, which is something nobody else in the world can do. 10 | 11 | (Contrast this with writing that is expressed _through an LLM_ that everyone else in the world has access to.) 12 | 13 | By giving our writing to a reader its is purpose fulfilled. 14 | 15 | 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? 16 | 17 | 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. 18 | 19 | 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. 20 | 21 | 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”. -------------------------------------------------------------------------------- /posts/2024-12-02-contrast-is-clarifying.md: -------------------------------------------------------------------------------- 1 | # Contrast Is Clarifying 2 | 3 | Which is best? 4 | 5 | - Generalist or specialist? 6 | - Native or web? 7 | - Web site or web app? 8 | - JavaScript or Typescript? 9 | - Framework or library? 10 | - Server side or client side? 11 | - Photoshop or Sketch or Figma? 12 | - Designing in a tool or design in the browser? 13 | - Skueomorphic or flat? 14 | - Mac or PC or Linux? 15 | 16 | This list could go on forever. Zoom in to just the JavaScript ecosystem and its overwhelming: 17 | 18 | - Modules: ESM, CJS, AMD, UMD 19 | - Package managers: npm, yarn, pnpm, bower 20 | - Bundlers: Webpack, Rollup, Parcel, Bun, Vite 21 | - Compilers: Babel, TypeScript, esbuild, swc 22 | - Runtimes: Node, Deno, Bun 23 | - UI frameworks: React, Vue, Angular, Svelte, Lit 24 | 25 | Even here, the list could go on forever: db libraries, task runners, testing libraries, UI metaframeworks, server frameworks, state management libraries, etc. 26 | 27 | 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? 28 | 29 | We need opposing options. They exist not solely in opposition to one another but as contrast. 30 | 31 | We must have a diversity to understand and discuss which is most fit for a given context. The web is big! “It depends”! 32 | 33 | 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. 34 | 35 | And guess what? Whichever you choose, you’ll likely choose poorly. That’s ok. Choosing poorly is where growth happens — if you let it. 36 | 37 | Silver bullets are for killing werewolves not building technology. -------------------------------------------------------------------------------- /posts/2024-12-29-christmas-day.md: -------------------------------------------------------------------------------- 1 | # Christmas Day 2 | 3 | It’s Christmas circa 2004. 4 | 5 | My teenage brothers, sisters, and I have all finished opening presents and we’re more than content to have absolutely **nothing** to do — it’s Christmas day after all! 6 | 7 | But not Dad. He’s in the bathroom laying tile. 8 | 9 | Again, this is _Christmas day_ and Dad is on his hands and knees, in the bathroom, laying tile. 10 | 11 | We all laugh at him. “Look at this guy, he can’t not do work on Christmas Day. He has a problem.” 12 | 13 | Fast-forward two decades and, when our family gets together, we still get a good laugh poking fun at Dad — “Remember when he was laying tile in the bathroom on Christmas? Lol!” 14 | 15 | And yet. 16 | 17 | Here it is, Christmas day 2024. The kids are all asleep after a hectic day, and where do I find myself? 18 | 19 | Working on my personal website. 20 | 21 | I ask myself, “What am I doing? It’s the end of Christmas day and I’m working on my website? _I_ have a problem!” 22 | 23 | But then I think of Dad on Christmas. 24 | 25 | Maybe we’re more similar than I thought. 26 | 27 | What I saw as “work” I now see as finding solace in doing something he knew how to do well, even if others might laugh at him. 28 | 29 | I used to laugh. 30 | 31 | Now I think I just understand him better. -------------------------------------------------------------------------------- /posts/2025-01-07-social-inflation.md: -------------------------------------------------------------------------------- 1 | # Social Inflation 2 | 3 | Imagine you’re on a social network and you start getting tons of followers. 4 | 5 | You love it! Your follower count is going up! 6 | 7 | Instead of a nobody with a couple hundred followers, you’ve bypassed the 1k+ mark and it keeps going! 8 | 9 | You’re ecstatic! This is the “next step” you were aspiring to. 10 | 11 | But then you start looking around. 12 | 13 | The people you’re following with 1k+ followers are now at 10k+. 14 | 15 | It hits you: everyone else’s follower count is going up too. 16 | 17 | The network owners announce: “We’re having a bot problem at the moment. We’re aware of it and working on it.” 18 | 19 | 1k followers isn’t what it used to be. Now you need 10k. Or 100k. 20 | 21 | Everyone’s follower count is being _inflated_. 22 | 23 | Now when my kids ask, “Why can’t we just print more money?” I think I can analogize currency inflation to their social network following. Your follower count going up makes you feel good, but it’s merely the illusion of growth. What seems like increase is actually dilution, as relative value remains consistent and genuine value hasn’t changed. 24 | 25 | **Economic disclaimer**: this content is for fun only and should not be considered professional economic theory. Please do not send me emails or messages beginning with: “Well, actually…” -------------------------------------------------------------------------------- /posts/2025-01-09-dont-miss-the-product-for-the-artifacts.md: -------------------------------------------------------------------------------- 1 | # Don’t Miss the Product for the Artifacts 2 | 3 | Ever hear that idiom, “Don’t miss the forest for the trees”? [The idea](https://www.merriam-webster.com/dictionary/miss%20the%20forest%20for%20the%20trees) being, you miss the bigger picture because you’re focused on the minutia? 4 | 5 | Feels like the tech equivalent is: Don’t miss the product for the artifacts. 6 | 7 | Here’s [Robin Rendle in a recent piece on design artifacts](https://robinrendle.com/notes/design-artifacts/): 8 | 9 | > There’s a factory-like production of the modern design process which believes that the assets are more important than the product itself. 10 | 11 | Nailed it 🎯 12 | 13 | Too often we confuse 1) the artifact created in support of the deliverable, with 2) the deliverable itself. 14 | 15 | For example, some designers are awesome at Figma. True wizards at the things they can make. But we’re not Figma designers. We’re app designers, web designers, _product_ designers. Figma is just the tool that facilitates creating the thing we actually want to make. Yet we can spend so much time thinking “being good at Figma” is our purpose, when in fact it’s to use Figma to build something great for people! 16 | 17 | Even “website” or “app” can be misleading. A web developer makes what they were hired for: a web site. An app developer makes an app. 18 | 19 | But we’re not making websites or apps. We’re making tools and experiences that help people solve their problems. 20 | 21 | In that sense, delivering a website is still just delivering an artifact. 22 | 23 | And we’re not making artifacts. 24 | 25 | We’re trying to help people make _progress_: solve their problems, find information, complete tasks. 26 | 27 | Artifacts are always in service of progress, not progress itself. -------------------------------------------------------------------------------- /posts/2025-01-15-tools-as-ways-of-being.md: -------------------------------------------------------------------------------- 1 | # Tools As Ways of Being 2 | 3 | [I took notes](https://notes.jim-nielsen.com/#2025-01-08T2145) from [Sean Voisen’s call for more hybrid tools](https://sean.voisen.org/blog/hybrid-tools). He speaks for a moment on generative AI and its inclusion into existing tools, but reading between the lines the insight I found was how our tools can trigger empathy for people and disciplines: 4 | 5 | > One of the greatest goals we can have for [making] tools…is that in expanding all of our respective capabilities, we do not replace our human teammates, but rather we participate more deeply in the creative process together. 6 | 7 | A good tool improves your output. 8 | 9 | A great tool improves your output _and_ your understanding and empathy for others and their disciplines. 10 | 11 | If designing tools is designing ways of being — “we shape our tools and they shape us” — then the tools we use together are shared ways of being. They facilitate us not only getting stuff done together, but _being_ together. And that _being_ can bring a better understanding of each other. 12 | 13 | I don’t think that’s too crazy to assert, especially when you look at communities that coalesce around tools, like Clojure. People love their tools, and they identify with the principles they embody and the communities that support them. 14 | 15 | Our tools are ways of being. How important, then, that we carefully consider their design as well as proliferate their diversity. -------------------------------------------------------------------------------- /posts/2025-01-20-relationship-advice-for-ai.md: -------------------------------------------------------------------------------- 1 | #ai 2 | 3 | # Relationship Advice for AI 4 | 5 | You know what’s really helpful in solving my own problems? Writing them down, sending them to someone, and not hearing back. 6 | 7 | You ever do that? For me, it’s a [bulletproof method to solving problems](https://blog.jim-nielsen.com/2024/bulletproof-problem-solving/). 8 | 9 | It’s akin to those moments when you go to someone with a problem, you talk it through, you find a solution, you thank them for their help, and they say, “Well I didn’t even say anything, but you’re welcome.” 10 | 11 | If I have a friend, co-worker, or collaborator who I know is on the other end of a chat box, typing out my problem and _not_ hearing back from them can be a tremendous help. 12 | 13 | Here’s an example of how it often goes: 14 | 15 | --- 16 | 17 | **Jim Nielsen, Friday at 12:53 PM** 18 | I’m having an issue where the deployment isn’t working. Failiures are coming from lines 123-125 of the build script... 19 | 20 | **Jim Nielsen, Friday at 12:59 PM** 21 | Oh, it looks like something changed in commit abc123e in the lock file... 22 | 23 | **Jim Nielsen, Friday at 1:02 PM** 24 | This is so weird, I hate troubleshooting this crap. Why is everything in the world garbage? 25 | 26 | **Jim Nielsen, Friday at 1:03 PM** 27 | Ok, I can’t figure this out. I'm going to need your help when you have a second. 28 | 29 | **Jim Nielsen, Friday at 1:09 PM** 30 | Oh hey, actually I think I know what the problem is... 31 | 32 | **Jim Nielsen, Friday at 1:11 PM** 33 | Ok, it’s fixed now. Nevermind, I don’t need your help. Thanks! 34 | 35 | **Co-worker, Friday at 4:03 PM** 36 | You're welcome, glad I could help! 37 | 38 | --- 39 | 40 | In contrast, AI is [too eager to respond back with _something_ when _nothing_ would be much more helpful](https://blog.jim-nielsen.com/2024/nothing-is-something/). 41 | 42 | Knowing another human is there to connect with — available, listening, but not speaking — has helped me many times as I express my thinking step-by-step. 43 | 44 | So let me give you some relationship advice, AI. Sometimes you don’t need to say or do anything. You just need to listen. 45 | 46 | Cool? Thanks. -------------------------------------------------------------------------------- /posts/2025-01-28-missed-connections.md: -------------------------------------------------------------------------------- 1 | # Missed Connections 2 | 3 | Let me tell you about one of the best feelings. 4 | 5 | You have a problem. 6 | 7 | You bang your head on it for a while. 8 | 9 | Through the banging, you formulate a string of keywords describing the problem. 10 | 11 | You put those words into a search engine. 12 | 13 | You land on a forum or a blog post and read someone else’s words containing those keywords and more. Their words resonate with you _deeply_. 14 | 15 | They’re saying the exact same things you were saying to yourself in your head. 16 | 17 | You immediately know, “This person gets it!” 18 | 19 | You know they have an answer to your problem. They’ve seen what you’re seeing. 20 | 21 | And on top of it all, they provide a solution which fixes your problem! 22 | 23 | A sense of connection is now formed. You feel validated, understood, seen. They’ve been through what you’re going through, and they wrote about it to reach out to you — across time and space. 24 | 25 | I fell in love with the web for this reason, this feeling of connection. You could search the world and find someone who saw what you see, felt what you feel, went through what you’re going through. 26 | 27 | Contrast that with today. 28 | 29 | Today you have a problem. 30 | 31 | You bang your head on it. 32 | 33 | You ask a question in a prompt. 34 | 35 | And you get back [something](https://blog.jim-nielsen.com/2024/nothing-is-something/). 36 | 37 | But there’s no human behind it. Just a machine which takes human voices and de-personalizes them until [the individual point of view is annihilated](http://blog.jim-nielsen.com/2024/notes-from-you-are-not-a-gadget/). And so too with it the sense of connection — the feeling of being validated, understood, seen. 38 | 39 | Every prompt a connection that could have been. A world of missed connections. -------------------------------------------------------------------------------- /posts/2025-02-04-blown-away-by-the-unexpected.md: -------------------------------------------------------------------------------- 1 | # Blown Away By the Unexpected 2 | 3 | [A friend](https://www.garrettkalleberg.com) gave me a copy of the book [“Perfect Wave” by Dave Hickey](https://press.uchicago.edu/ucp/books/book/chicago/P/bo5387695.html). 4 | 5 | I’ve been slowly reading through each essay and highlighting parts with my red pencil. 6 | 7 | When I got to the chapter “Cool on Cool”, this passage stood out. I want to write it down and share it: 8 | 9 | > there was this perfect, luminous pop single by the Carpenters that just blew me away. And, believe me, the Carpenters were the farthest thing from my kind of thing. But when something that is not your thing blows you away, that’s one of the best things that can happen. It means you are something more and something other than you thought you were. 10 | 11 | I find this beautiful. 12 | 13 | I should take more time to wonder at moments of surprise I did not expect. 14 | 15 | What a beautiful thing that I can be plowing through my existence and suddenly be surprised by something outside my taste, my beliefs, even my identity, that reaches in past all those things and rearranges me. 16 | 17 | Perhaps my boundaries are more porous than I assume. In an instant, I can become something different, something more that I ever believed was possible. 18 | 19 | Just think, that ability is lying there inside all of us. 20 | 21 | I don’t have to think of myself as a walled garden but an open field. Who knows where my boundaries will expand to next. All it takes is someone walking by and tossing out a seed I would’ve never chosen to plant myself. 22 | 23 | (Tangential: I love [this interaction between Jerry Seinfeld and Brian Regan talking about being “blown away”](https://www.youtube.com/watch?v=d-oKrCqvWY4).) -------------------------------------------------------------------------------- /posts/2025-02-07-software-pliability.md: -------------------------------------------------------------------------------- 1 | # Software Pliability 2 | 3 | Quoting myself from former days on [Twitter](https://twitter.com/jimniels/status/1310982709783793669?s=21): 4 | 5 | > Businesses have a mental model of what they do. 6 | > 7 | > Businesses build software to help them do it—a concrete manifestation of their mental model. 8 | > 9 | > A gap always exists between these two. 10 | > 11 | > What makes a great software business is their ability to keep that gap very small. 12 | 13 | I think this holds up. And I still think about this idea (hence this post). 14 | 15 | Software is an implementation of human understanding — people need X, so we made Y. 16 | 17 | But people change. Businesses change. So software _must_ also change. 18 | 19 | One of your greatest strengths will be your ability to adapt and evolve your understanding of people’s needs and implement it in your software. 20 | 21 | In a sense, technical debt is the other side of this coin of change: an inability to keep up with your own metamorphosis and understanding. 22 | 23 | In a way, you could analogize this to the conundrum of rocket science: you need fuel to get to space, but the more fuel you add, the more weight you add, and the more weight you add, the more fuel you need. Ad nauseam. 24 | 25 | It’s akin to making software. 26 | 27 | You want to make great software for people’s needs _today_. It takes people, processes, and tools to make software, but the more people, processes, and tools you add to the machine of making software, the less agile you become. So to gain velocity you add more people, processes, and tools, which…you get the idea. 28 | 29 | Being able to build and maintain _pliable_ software that can change and evolve at the same speed as your mental model is a superpower. [Quality in code means the flexibility to change.](https://blog.jim-nielsen.com/2024/easy-changes/) -------------------------------------------------------------------------------- /posts/2025-02-24-sanding-ui-pt-ii.md: -------------------------------------------------------------------------------- 1 | #designEngineer 2 | 3 | # Sanding UI, pt. II 4 | 5 | Let’s say you make a UI to gather some user feedback. Nothing complicated. Just a thumbs up/down widget. It starts out neutral, but when the user clicks up or down, you highlight what they clicked an de-emphasize/disable the other (so it requires an explicit toggle to change your mind). 6 | 7 | A set of thumbs-up and thumbs-down icons in various states, with some in grayscale and others highlighted in green or red. 8 | 9 | So you implement it. Ship it. Cool. Works right? 10 | 11 | Well, per [my previous article about “sanding” a user interface UI](https://blog.jim-nielsen.com/2024/sanding-ui/) by clicking around a lot, did you click on it _a lot_? 12 | 13 | If you do, you’ll find that doing so selects the thumbs up/down icon as if it were text: 14 | 15 | Animated gif of a thumbs up icon being clicked repeatedly and gaining a text selection UI native to the OS. 16 | 17 | So now you have this weird text selection that’s a bit of an eye sore. It’s not relevant to _text selection_ because it’s not text. It’s an SVG. So the selection UI that appears is misleading and distracting. 18 | 19 | A thumbs up icon that was clicked repeatedly and has a text selection UI native to the OS overlaid on it. 20 | 21 | One possible fix: leverage the `user-select: none` property in CSS which makes it not selectable. When the user clicks multiple times to toggle, no text selection UI will appear. 22 | 23 | A thumbs up icon with a cursor over it and no text selection UI. 24 | 25 | Cool. Great! 26 | 27 | Another reason to click around a lot. You can ensure any rough edges are smoothed out, and any “UI splinters” are ones you get (and fix) in place of your users. -------------------------------------------------------------------------------- /posts/2025-02-28-get-better-doing-a-bad-job.md: -------------------------------------------------------------------------------- 1 | #podcastNotes 2 | 3 | # Can You Get Better Doing a Bad Job? 4 | 5 | [Rick Rubin has an interview with Woody Harrelson on his podcast Tetragrammaton](https://www.tetragrammaton.com/content/woody-harrelson). Right at the beginning Woody talks about his experience acting and how he’s had roles that did’t turn out very well. He says sometimes he comes away from those experiences feeling dirty, like “I never connected to that, it never resonated, and now I feel like I sold myself...Why did I do that?!” 6 | 7 | Then Rick asks him: even in those cases, do you feel like you got better at your craft because you did your job? Woody’s response: 8 | 9 | > I think when you do your job badly you never really get better at your craft. 10 | 11 | Seems relevant to making websites. 12 | 13 | I’ve built websites on technology stacks I knew didn’t feel fit for their context and Woody’s experience rings true. You just don’t feel right, like a little voice that says, “You knew that wasn’t going to turn out very good. Why did you do that??” 14 | 15 | I don’t know if I’d go so far as to say I didn’t get better because of it. Experience is a hard teacher. Perhaps, from a technical standpoint, my skillset didn’t get any better. But from an experiential standpoint, my judgement got better. I learned to avoid (or try to re-structure) work that’s being carried out in a way that doesn’t align with its own purpose and essence. 16 | 17 | Granted, that kind of alignment is difficult. If it makes you feel any better, even Woody admits this is not an easy thing to do: 18 | 19 | > I would think after all this time, surely I’m not going to be doing stuff I’m not proud of. Or be a part of something I’m not proud of. But damn...it still happens. -------------------------------------------------------------------------------- /posts/2025-04-02-flow-state-and-surfing.md: -------------------------------------------------------------------------------- 1 | # Flow State and Surfing 2 | 3 | [Jack Johnson is on Rick Rubin’s podcast Tetragrammaton](https://www.tetragrammaton.com/content/jack-johnson-podcast) talking about music, film making, creativity, and surfing. 4 | 5 | At one point (~24:30) Johnson talks about his love for surfing and the beautiful flow state it puts him in: 6 | 7 | > Sometimes I’ll see a friend riding a wave while I’m paddling out, and the thing I’ll see them do just seems like magic...I’ll think, “How in the world did they just do that?” And then on your next ride you’re doing the exact same thing without thinking but it’s all muscle memory and it’s all in this flow that you get into. That’s a really beautiful state to get into, to do something that feels like a magic trick, like something you shouldn’t be able to do, but all of the sudden you’re doing it. 8 | 9 | I’m not a surfer, and I can’t do effortlessly cool. But I know what a flow state feels like. 10 | 11 | Johnson’s description reminds me of that feeling when you get a little time on a personal project — riding the wave of working on your personal website. 12 | 13 | You open your laptop. You start paddling out. Maybe you see an internet friend who was doing something cool and you want to try it but you have no idea if you’ll be able to do it as well as they did. 14 | 15 | And before you know it, you’re in that flow state where muscle memory takes over and you’re doing stuff without even consciously thinking about it — stuff that others might look at and perceive as magic (_cough_ anything on the command line _cough_) but it’s not magic to you. Intuition and experience just take over while you ride the wave. 16 | 17 | Ok, I’m a nerd. But I don’t care. It’s a great feeling, regardless of whether it’s playing an instrument, or surfing, or programming. That feeling of sinking into a craft you’ve worked at your whole life that you don’t have to think about anymore. -------------------------------------------------------------------------------- /posts/2025-04-29-backwards-compat-in-web-but-not-its-tools.md: -------------------------------------------------------------------------------- 1 | # Backwards Compatibility in the Web, but Not Its Tools 2 | 3 | After [reading an article](https://notes.jim-nielsen.com/#2025-04-22T1310), I ended up on HackerNews and stumbled on [this comment](https://news.ycombinator.com/item?id=43422368): 4 | 5 | > The most frustrating thing about dipping in to the FE is that it seems like literally everything is deprecated. 6 | 7 | Lol, so true. From the same comment, here’s a description of a day in the life of a front-end person: 8 | 9 | > Oh, you used the apollo CLI in 2022? Bam, deprecated, go learn how to use graphql-client or whatever, which has a totally different configuration and doesn’t support all the same options. Okay, so we just keep the old one and disable the node engine check in pnpm that makes it complain. Want to do a patch upgrade to some dependency? Hope you weren’t relying on any of its type signatures! Pin that as well, with a todo in the codebase hoping someone will update the signatures. 10 | > 11 | > Finally get things running, watch the stream of hundreds of deprecation warnings fly by during the install. Eventually it builds, and I get the hell out of there. 12 | 13 | Apt. 14 | 15 | It’s ironic that the web platform itself has an ethos of zero breaking changes. 16 | 17 | But the tooling for building stuff on the web platform? The complete opposite. Breaking changes are a way of life. 18 | 19 | Is there some mystical correlation here, like the tools remain in such flux because the platform is so stable — stability taken for granted breeds instability? 20 | 21 | Either way, as Morpheus says in _The Matrix_: Fate, it seems, is not without a sense of irony. -------------------------------------------------------------------------------- /posts/2025-05-20-product-pseudoscience.md: -------------------------------------------------------------------------------- 1 | # Product Pseudoscience 2 | 3 | In his post about [“Vibe Drive Development”](https://robinrendle.com/notes/vibe-driven-development/), Robin Rendle warns against what I’ll call the pseudoscientific approach to product building prevalent across the software industry: 4 | 5 | > when folks at tech companies talk about data they’re not talking about a well-researched study from a lab but actually wildly inconsistent and untrustworthy data scraped from an analytics dashboard. 6 | 7 | This approach has all the theater of science — “we measured and made decisions on the data, the numbers don’t lie” etc. — but is missing the rigor of science. 8 | 9 | Like, for example, corroboration. 10 | 11 | Independent corroboration is a vital practice of science that we in tech conveniently gloss over in our (self-proclaimed) objective data-driven decision making. 12 | 13 | In science you can observe something, measure it, analyze the results, and draw conclusions, but nobody accepts it as fact until there can be _multiple_ instances of independent corroboration. 14 | 15 | Meanwhile in product, corroboration is often merely a group of people nodding along in support of a Powerpoint with some numbers supporting a foregone conclusion — “We should do X, that’s what the numbers say!” 16 | 17 | (What’s worse is when we have the hubris to think our experiments, anecdotal evidence, and conclusions should extend to others outside of our own teams, despite zero independent corroboration — looking at you Medium articles.) 18 | 19 | Don’t get me wrong, experimentation and measurement are great. But let’s not pretend there is (or should be) a science to everything we do. We don’t hold a candle to the rigor of science. Software is as much art as science. Embrace the vibe. 20 | -------------------------------------------------------------------------------- /scripts/get-hacker-news-posts.js: -------------------------------------------------------------------------------- 1 | // Get data from hacker news search API 2 | // https://hn.algolia.com/api 3 | export default function getHackerNewsPosts() { 4 | return fetch( 5 | "http://hn.algolia.com/api/v1/search?query=blog.jim-nielsen.com&restrictSearchableAttributes=url" 6 | ) 7 | .then((res) => res.json()) 8 | .then((json) => json.hits); 9 | } 10 | 11 | // try { 12 | // console.log(await getHackerNewsPosts()); 13 | // } catch (e) { 14 | // console.log(e); 15 | // } 16 | -------------------------------------------------------------------------------- /src/routes/404.html.js: -------------------------------------------------------------------------------- 1 | import { Page } from "../server/Layouts.js"; 2 | import { html } from "../server/utils.js"; 3 | 4 | export default function Page404(site) { 5 | const title = "404: Page Not Found"; 6 | return Page( 7 | { 8 | site, 9 | page: { 10 | title, 11 | path: "/404/", 12 | }, 13 | }, 14 | html` 15 |
16 |

${title}

17 | 18 |

19 | Whatever you’re looking for doesn’t appear to be available. Sorry. 20 |

21 | 22 |

23 | While I have your attention though, here’s a little tidbit about me: I 24 | love pies. I make them quite frequently. And then I eat them. You can 25 | see some of the ones I’ve made 26 | over on Instagram. 28 |

29 | 30 |

31 | Picture of a pie I made and posted on Instagram 36 |

37 |
38 | ` 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /src/routes/feed.json.js: -------------------------------------------------------------------------------- 1 | import RssClub from "../server/RssClub.js"; 2 | import ReplyHtml from "../server/ReplyHtml.js"; 3 | 4 | export default function JSONFeed(site) { 5 | return JSON.stringify({ 6 | version: "https://jsonfeed.org/version/1", 7 | title: site.name, 8 | home_page_url: site.origin, 9 | feed_url: `${site.origin}/feed.json`, 10 | author: { 11 | name: "Jim Nielsen", 12 | url: "https://jim-nielsen.com/", 13 | }, 14 | items: site.posts.slice(0, 10).map((post) => { 15 | return { 16 | id: post.path, 17 | date_published: post.date, 18 | title: post.title, 19 | url: post.permalink, 20 | tags: post.tags, 21 | content_html: 22 | (post?.tags.includes("rssClub") ? RssClub() : "") + 23 | post.contents.toString() + 24 | ReplyHtml({ post, site }), 25 | }; 26 | }), 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /src/routes/feed.xml.js: -------------------------------------------------------------------------------- 1 | import { html as xml } from "../server/utils.js"; 2 | import ReplyHtml from "../server/ReplyHtml.js"; 3 | import RssClub from "../server/RssClub.js"; 4 | 5 | // prettier-ignore 6 | export default function XMLFeed(site) { 7 | return xml` 8 | 10 | 11 | ${site.name} 12 | 13 | ${site.origin} 14 | 15 | ${site.posts.slice(0, 10).map(post => xml` 16 | 17 | ${escapeXml(post.title)} 18 | ${escapeXml((post?.tags.includes("rssClub") ? RssClub() : "") + post.contents.toString() + ReplyHtml({ post, site }))} 19 | ${new Date(post.date).toUTCString()} 20 | ${post.permalink} 21 | ${post.permalink} 22 | 23 | `)} 24 | 25 | 26 | `; 27 | } 28 | 29 | function escapeXml(unsafe) { 30 | return unsafe.replace(/[<>&'"]/g, function (c) { 31 | switch (c) { 32 | case "<": 33 | return "<"; 34 | case ">": 35 | return ">"; 36 | case "&": 37 | return "&"; 38 | case "'": 39 | return "'"; 40 | case '"': 41 | return """; 42 | } 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /src/routes/index.html.js: -------------------------------------------------------------------------------- 1 | import { PostsList } from "../server/PostsList.js"; 2 | import { Page } from "../server/Layouts.js"; 3 | import { html, toDateUI } from "../server/utils.js"; 4 | import { PostsNav } from "../server/PostsNav.js"; 5 | 6 | const LIMIT = 8; 7 | const page = { 8 | title: "", 9 | path: "/", 10 | }; 11 | 12 | /** @type {import("types").Route} */ 13 | export default function Index(site) { 14 | const posts = site.posts 15 | .filter((post) => !post?.tags.includes("rssClub")) 16 | .slice(0, LIMIT); 17 | 18 | return Page( 19 | { 20 | site, 21 | page, 22 | }, 23 | html`
24 |

Posts

25 | ${PostsNav(page.path)} ${PostsList(posts)} 26 |
` 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /src/routes/posts/hacker-news/index.html.js: -------------------------------------------------------------------------------- 1 | import { PostsList } from "../../../server/PostsList.js"; 2 | import { PostsNav } from "../../../server/PostsNav.js"; 3 | import { Page } from "../../../server/Layouts.js"; 4 | import { html, toDateUI } from "../../../server/utils.js"; 5 | 6 | const page = { 7 | title: "Hacker News Hits", 8 | path: "/posts/hacker-news/", 9 | }; 10 | 11 | /** @type {import("types").Route} */ 12 | export default async function Index(site) { 13 | const hackerNews = site.posts 14 | .filter((post) => post.hackerNews && post.hackerNews.points > 100) 15 | // @ts-expect-error 16 | .sort((a, b) => (a.hackerNews.points > b.hackerNews.points ? -1 : 1)); 17 | 18 | return Page( 19 | { 20 | site, 21 | page, 22 | }, 23 | html`
24 |

Posts

25 | ${PostsNav(page.path)} 26 | ${PostsList( 27 | hackerNews, 28 | // @ts-expect-error 29 | ({ hackerNews: { comments, points } }) => 30 | html`${points.toLocaleString()} points, ${comments.toLocaleString()} 31 | comments` 32 | )} 33 |

34 | “If you don’t get thrashed on whatever the HackerNews of the era is, you 35 | haven’t blogged enough.” — 36 | Dave Rupert 41 |

42 |
` 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /src/routes/posts/index.html.js: -------------------------------------------------------------------------------- 1 | import { Page } from "../../server/Layouts.js"; 2 | import { PostsList } from "../../server/PostsList.js"; 3 | import { PostsNav } from "../../server/PostsNav.js"; 4 | import { html } from "../../server/utils.js"; 5 | 6 | const page = { 7 | title: "Posts", 8 | path: "/posts/", 9 | }; 10 | 11 | /** 12 | * @type {import("types").Route} 13 | */ 14 | export default function Archive(site) { 15 | return Page( 16 | { site, page }, 17 | html`
18 |

Posts

19 | ${PostsNav(page.path)} ${PostsList(site.posts)} 20 |
` 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/routes/posts/index.json.js: -------------------------------------------------------------------------------- 1 | // Used by jim-nielsen.com to pull in all posts...? 2 | export default function ArchiveJSON(site) { 3 | const { origin, posts } = site; 4 | 5 | return JSON.stringify( 6 | posts 7 | .filter((post) => !post?.tags.includes("rssClub")) 8 | .map(({ title, permalink, date, tags }) => ({ 9 | title, 10 | permalink, 11 | date, 12 | tags, 13 | })) 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /src/routes/posts/personal-favs/index.html.js: -------------------------------------------------------------------------------- 1 | import { PostsList } from "../../../server/PostsList.js"; 2 | import { PostsNav } from "../../../server/PostsNav.js"; 3 | import { Page } from "../../../server/Layouts.js"; 4 | import { html, toDateUI } from "../../../server/utils.js"; 5 | 6 | const page = { 7 | title: "Personal Favs", 8 | path: "/posts/personal-favs/", 9 | }; 10 | 11 | /** 12 | * @param {import("types").Site} site 13 | * return {import("types").Page} 14 | */ 15 | export default async function Index(site) { 16 | const posts = site.posts.filter((post) => post.isFav); 17 | 18 | return Page( 19 | { 20 | site, 21 | page, 22 | }, 23 | html` 24 |

Posts

25 | ${PostsNav(page.path)} ${PostsList(posts)} 26 | ` 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /src/routes/posts/trending/index.html.js: -------------------------------------------------------------------------------- 1 | import { PostsList } from "../../../server/PostsList.js"; 2 | import { PostsNav } from "../../../server/PostsNav.js"; 3 | import { Page } from "../../../server/Layouts.js"; 4 | import { html, toDateUI } from "../../../server/utils.js"; 5 | 6 | const page = { 7 | title: "Trending Posts", 8 | path: "/posts/trending/", 9 | }; 10 | 11 | /** @type {import("types").Route} */ 12 | export default async function Index(site) { 13 | const posts = site.posts 14 | .filter((post) => post.hasOwnProperty("pageviews")) 15 | // @ts-expect-error 16 | .sort((a, b) => (a.pageviews > b.pageviews ? -1 : 1)); 17 | 18 | return Page( 19 | { 20 | site, 21 | page, 22 | }, 23 | html`
24 |

Posts

25 | ${PostsNav(page.path)} 26 | ${PostsList( 27 | posts, 28 | ({ pageviews, date }) => 29 | // @ts-expect-error 30 | html` ${pageviews > 1000 31 | ? // @ts-expect-error 32 | Math.round((pageviews / 1000) * 10) / 10 + "k" 33 | : pageviews} 34 | pageviews` 35 | )} 36 |

37 | FYI: pageviews are based on the last 30 days of 38 | analytics data I get from Netlify. 43 |

44 |
` 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /src/routes/styles.css.js: -------------------------------------------------------------------------------- 1 | import { readFile } from "../server/utils.js"; 2 | 3 | export default function () { 4 | return `${[ 5 | "../server/styles/modern-normalize.css", 6 | "../server/styles/styles.css", 7 | ] 8 | .map(readFile) 9 | .join("")} 10 | :root, 11 | :root[data-theme-appearance="light"] { 12 | ${readFile("../server/styles/atom-one-light.css")} 13 | } 14 | :root[data-theme-appearance="dark"] { 15 | ${readFile("../server/styles/atom-one-dark.css")} 16 | }`; 17 | } 18 | -------------------------------------------------------------------------------- /src/server/PostsList.js: -------------------------------------------------------------------------------- 1 | import { toDateUI } from "./utils.js"; 2 | import { html } from "./utils.js"; 3 | 4 | /** 5 | * @param {import("types").Post[]} posts 6 | * @param {(post: import("types").Post) => string} fn 7 | */ 8 | export function PostsList( 9 | posts, 10 | fn = ({ date }) => html`` 11 | ) { 12 | return html` 13 | 28 | `; 29 | } 30 | -------------------------------------------------------------------------------- /src/server/PostsNav.js: -------------------------------------------------------------------------------- 1 | import { html } from "./utils.js"; 2 | 3 | /** @type {readonly {label: string, href: string}[]} */ 4 | const NAV = [ 5 | { label: "Latest", href: "/" }, 6 | { label: "Trending", href: "/posts/trending/" }, 7 | { label: "Hacker News Hits", href: "/posts/hacker-news/" }, 8 | // { label: "Personal Favs", href: "/posts/personal-favs/" }, 9 | { label: "All", href: "/archive/" }, 10 | ]; 11 | 12 | /** 13 | * @param {(typeof NAV)[number]['href']} activeHref 14 | * @returns {string} HTML string for the navigation 15 | */ 16 | export function PostsNav(activeHref) { 17 | return html` 18 | 28 | `; 29 | } 30 | -------------------------------------------------------------------------------- /src/server/ReplyHtml.js: -------------------------------------------------------------------------------- 1 | import { html } from "./utils.js"; 2 | 3 | /** 4 | * The html that appears at the bottom of each post, both on the site 5 | * as well as in the RSS feed. 6 | * @param {import("../../types.js").Post} post 7 | * @param {import("../../types.js").Site} site 8 | */ 9 | export default function ReplyHtml({ post, site }) { 10 | const postTags = post.tags; 11 | const postPath = post.path; 12 | const siteOrigin = site.origin; 13 | const relatedPosts = Object.entries(site.internalLinksByPath).reduce( 14 | (acc, [postPath, linkedPaths]) => { 15 | // If a post has this post’s path in it's list of links, add it's metadata 16 | // to our list of related posts 17 | if (linkedPaths.includes(post.path)) { 18 | acc.push(site.posts.find((p) => p.path === postPath)); 19 | } 20 | return acc; 21 | }, 22 | [] 23 | ); 24 | 25 | return html` 26 |
27 | ${post.footnotes?.length > 0 && html` ${post.footnotes} `} 28 | 29 |

30 | Reply via: 31 | ${ 32 | /* Trippy: we gotta encode the "+" or we get bit by outlook 33 | https://webmasters.stackexchange.com/questions/15920/should-plus-be-encoded-in-mailto-hyperlinks */ 34 | "" 35 | } 36 | 37 | Email 41 | · Mastodon · 42 | 43 | Bluesky 44 |

45 | 46 | ${relatedPosts.length > 0 && 47 | html` 48 |

49 | Related posts linking here: 50 | ${relatedPosts 51 | .map( 52 | ({ title, path, date }) => 53 | html`(${date.slice(0, 4)}) ${title}` 54 | ) 55 | .join(" · ")} 56 |

57 | `} 58 | `; 59 | } 60 | -------------------------------------------------------------------------------- /src/server/RssClub.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Preface to any post published as part of RSS Club. 3 | * @returns {string} 4 | */ 5 | export default function RssClub() { 6 | return /*html*/ ` 7 |

8 | This post is a secret to everyone! Read more about RSS Club. 9 |

10 | `; 11 | } 12 | -------------------------------------------------------------------------------- /src/server/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimniels/blog/028381a5721e60746c432e5b5684b3933ef7f030/src/server/avatar.png -------------------------------------------------------------------------------- /src/server/preferences.js: -------------------------------------------------------------------------------- 1 | // Show/hide the stuff if JS is present 2 | const $root = document.querySelector("#js-color-root"); 3 | const $theme = document.querySelector("theme-color"); 4 | 5 | $root.innerHTML = /*html*/ ` 6 | ${$theme 7 | .getAttribute("supported-values") 8 | .split(" ") 9 | .map((color) => { 10 | const prop = `hsl(var(--c-${color}-h) var(--c-${color}-s) var(--c-${color}-l))`; 11 | return /*html*/ ` 12 | 19 | `; 20 | }) 21 | .join("")} 22 | `; 23 | 24 | // Check the active color in the UI 25 | const $form = document.querySelector("form#js-color"); 26 | $form.querySelector( 27 | "input[value=" + $theme.getAttribute("value") + "]" 28 | ).checked = true; 29 | 30 | // Listen for changes 31 | $form.addEventListener("click", (e) => { 32 | e.stopPropagation(); 33 | // If it's an 34 | if (e.target.value) { 35 | // If we're setting a new value, set it 36 | if (e.target.value !== localStorage.getItem("theme-color")) { 37 | const color = e.target.value; 38 | $theme.setAttribute("value", color); 39 | } 40 | } 41 | }); 42 | 43 | const $formFidelity = document.querySelector("form#js-fidelity"); 44 | $formFidelity.querySelector("button").style.display = "none"; 45 | $formFidelity.addEventListener("change", () => { 46 | $formFidelity.submit(); 47 | }); 48 | -------------------------------------------------------------------------------- /src/server/styles/basic.css: -------------------------------------------------------------------------------- 1 | /* 2 | Inspired by: 3 | 4 | “What’s the smallest amount of CSS that you can write to make HTML look halfway decent?” 5 | https://www.robinrendle.com/notes/the-smallest-css/ 6 | 7 | “You can design a blog that’s superior to most with a couple lines of CSS.” 8 | https://web.archive.org/web/20200807101742/https://frankchimero.com/blog/2020/redesign-this-design/ 9 | */ 10 | html { 11 | color-scheme: light dark; 12 | } 13 | 14 | body { 15 | font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", 16 | Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", 17 | "Segoe UI Symbol"; 18 | padding: 0 15px; 19 | max-width: 40rem; 20 | font-size: 1.125rem; /* 18px */ 21 | line-height: 1.5; 22 | margin-left: auto; 23 | margin-right: auto; 24 | } 25 | 26 | svg, 27 | img { 28 | max-width: 100%; 29 | height: auto; 30 | } 31 | 32 | pre code { 33 | white-space: pre-wrap; 34 | } 35 | -------------------------------------------------------------------------------- /src/server/svgs/check-mark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/server/svgs/feed-html.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/server/svgs/feed-json.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/server/svgs/feed-rss.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/server/svgs/heroicon-close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/server/svgs/heroicon-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/server/svgs/heroicon-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/server/svgs/heroicon-menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/server/svgs/heroicon-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/server/svgs/heroicon-system.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/server/svgs/heroicon-x-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/server/svgs/preferences.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/server/theme-picker.js: -------------------------------------------------------------------------------- 1 | class ThemePicker extends HTMLElement { 2 | constructor() { 3 | super(); 4 | 5 | let initialAppearance = window.theme.appearance.get(); 6 | document 7 | .querySelector(`input[name=appearance][value=${initialAppearance}]`) 8 | ?.setAttribute("checked", ""); 9 | 10 | let initialColor = window.theme.color.get(); 11 | document 12 | .querySelector(`input[name=color][value=${initialColor}]`) 13 | ?.setAttribute("checked", ""); 14 | } 15 | 16 | connectedCallback() { 17 | // Handle expanding/collapsing the color picker through the

18 | this.addEventListener("click", (e) => { 19 | e.stopPropagation(); 20 | 21 | if (e.target.name === "color") { 22 | const value = e.target.value; 23 | if (value !== window.theme.color.get()) { 24 | window.theme.color.set(value); 25 | } 26 | } 27 | 28 | if (e.target.name === "appearance") { 29 | const value = e.target.value; 30 | if (value !== window.theme.appearance.get()) { 31 | window.theme.appearance.set(value); 32 | } 33 | } 34 | }); 35 | } 36 | } 37 | 38 | customElements.define("theme-picker", ThemePicker); 39 | -------------------------------------------------------------------------------- /src/server/utils.js: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import { fileURLToPath } from "url"; 3 | 4 | export function html(strings, ...values) { 5 | let out = ""; 6 | strings.forEach((string, i) => { 7 | const value = values[i]; 8 | 9 | // Array 10 | if (Array.isArray(value)) { 11 | out += string + value.join(""); 12 | // String 13 | } else if (typeof value === "string") { 14 | out += string + value; 15 | // Number 16 | } else if (typeof value === "number") { 17 | out += string + String(value); 18 | // object 19 | } else if (typeof value === "object") { 20 | out += string + value; 21 | console.warn( 22 | "Templating warning: failed to coerce an object in your template." 23 | ); 24 | // undefined, null, boolean 25 | } else { 26 | out += string; 27 | } 28 | }); 29 | return out; 30 | } 31 | 32 | /** 33 | * Takes a date and returns how we format dates in the UI 34 | * @param {string} - ISO8601 date 35 | * @returns {string} - 2012-10-20 36 | */ 37 | export function toDateUI(date) { 38 | return date.slice(0, 10); 39 | } 40 | 41 | /** 42 | * 43 | * @param {string} relativeFilePath 44 | * @returns {string} 45 | */ 46 | export function readFile(relativeFilePath) { 47 | const fileUrl = import.meta.resolve(relativeFilePath); 48 | const filePath = fileURLToPath(fileUrl); 49 | return fs.readFileSync(filePath).toString(); 50 | } 51 | -------------------------------------------------------------------------------- /src/site.ori: -------------------------------------------------------------------------------- 1 | { 2 | // =========================================================================== 3 | // Gather all the data 4 | // =========================================================================== 5 | 6 | // Get the cache of site data generated prebuild 7 | (data): .cache/site.json/ 8 | 9 | // Generate a tree of posts 10 | // Post paths by year, e.g. `/2024/slug/index.html` 11 | (postsTree): tree:group(data/posts, (post) => new:Date(post/date)/getFullYear()) 12 | // Process the years 13 | -> (years) => tree:map(years, (year) => 14 | // Process the posts in each year 15 | tree:map(year, { 16 | // Use the slug as the key for a folder 17 | key: (post) => post/slug 18 | // Generate the HTML for each post as the index page in that folder 19 | value: (post) => { 20 | index.html: server/Post.js({ site: data, post: tree:plain(post) }) 21 | } 22 | }) 23 | ) 24 | 25 | // =========================================================================== 26 | // Create the site 27 | // =========================================================================== 28 | 29 | // Merge static assets 30 | ...static/ 31 | 32 | // Merge all our posts 33 | ...postsTree 34 | 35 | // Routes 36 | // TODO: use origami's feed generator rather than `feed.*` routes 37 | ...deepMap(./routes, { 38 | extension: ".js->", 39 | value: (route) => route/(data) 40 | }) 41 | 42 | // These path to `/well-known/...` in the build output and then we do a 43 | // rewrite because netlify is apparently weird about hidden files 44 | // https://answers.netlify.com/t/hidden-files-removed-in-zip-deploy/8997 45 | well-known = { 46 | links = { 47 | index.json = js:JSON/stringify(tree:plain(data/externalLinks)) 48 | 404.json = js:JSON/stringify({ error: "Domain not found" }) 49 | ...tree:map(data/externalLinks, { 50 | key: (item) => `${item/domain}.json`, 51 | value: (item) => js:JSON/stringify(tree:plain(item)) 52 | }) 53 | } 54 | } 55 | 56 | // Generate everything for the search experience 57 | pagefind/ = once(=package:@weborigami/pagefind(postsTree)) 58 | } 59 | -------------------------------------------------------------------------------- /src/static/404-pie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimniels/blog/028381a5721e60746c432e5b5684b3933ef7f030/src/static/404-pie.jpg -------------------------------------------------------------------------------- /src/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimniels/blog/028381a5721e60746c432e5b5684b3933ef7f030/src/static/apple-touch-icon.png -------------------------------------------------------------------------------- /src/static/assets/img/fidelity-high.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/static/assets/img/fidelity-low.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/static/assets/img/fidelity-med.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/static/assets/img/jimniels.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimniels/blog/028381a5721e60746c432e5b5684b3933ef7f030/src/static/assets/img/jimniels.jpg -------------------------------------------------------------------------------- /src/static/assets/img/logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimniels/blog/028381a5721e60746c432e5b5684b3933ef7f030/src/static/assets/img/logo-black.png -------------------------------------------------------------------------------- /src/static/assets/img/logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimniels/blog/028381a5721e60746c432e5b5684b3933ef7f030/src/static/assets/img/logo-white.png -------------------------------------------------------------------------------- /src/static/assets/img/preferences.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/static/assets/img/twitter-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimniels/blog/028381a5721e60746c432e5b5684b3933ef7f030/src/static/assets/img/twitter-card.png -------------------------------------------------------------------------------- /src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimniels/blog/028381a5721e60746c432e5b5684b3933ef7f030/src/static/favicon.ico -------------------------------------------------------------------------------- /src/static/pagefind.js: -------------------------------------------------------------------------------- 1 | // @ts-expect-error 2 | const result = new PagefindUI({ 3 | element: "#js-search-root", 4 | pageSize: 10, 5 | showImages: false, 6 | showSubResults: false, 7 | }); 8 | 9 | const $form = document.querySelector("#js-search-form"); 10 | if (!$form) { 11 | throw new Error("Form not found"); 12 | } 13 | const $myInput = $form.querySelector("input"); 14 | if (!$myInput) { 15 | throw new Error("Input not found"); 16 | } 17 | 18 | // Handle form clear 19 | $form.addEventListener("reset", (event) => { 20 | updatePagefindInput(""); 21 | $myInput.focus(); 22 | }); 23 | 24 | // Prevent default no-JS submission 25 | $form.addEventListener("submit", (event) => { 26 | event.preventDefault(); 27 | }); 28 | 29 | // Sync our custom input with the pagefind component 30 | /** @type {HTMLInputElement} */ 31 | $myInput.addEventListener("input", async (event) => { 32 | // @ts-expect-error 33 | const value = event.target.value; 34 | if (typeof value === "string") { 35 | updatePagefindInput(value); 36 | } 37 | }); 38 | 39 | /** 40 | * 41 | * @param {string} value 42 | */ 43 | function updatePagefindInput(value) { 44 | /** @type {HTMLInputElement | null} */ 45 | const $pagefindInput = document.querySelector(".pagefind-ui__search-input"); 46 | if (!$pagefindInput) { 47 | throw new Error("Pagefind input not found"); 48 | } 49 | $pagefindInput.value = value; 50 | const inputEvent = new Event("input", { bubbles: true }); 51 | $pagefindInput.dispatchEvent(inputEvent); 52 | const changeEvent = new Event("change", { bubbles: true }); 53 | $pagefindInput.dispatchEvent(changeEvent); 54 | } 55 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, // Allows TypeScript to process JavaScript files 4 | "checkJs": true, // Enables type-checking for all .js files 5 | "strict": true, // Optional, for strict type checking 6 | "lib": ["ES2016", "DOM"], 7 | "target": "ES2015", 8 | "module": "NodeNext", 9 | "moduleResolution": "NodeNext", 10 | "types": ["node"], 11 | "baseUrl": ".", // Makes imports relative to the tsconfig.json location 12 | "noEmit": true, // Only check types, don't generate files 13 | "paths": { 14 | "types": ["types.ts"] 15 | } 16 | }, 17 | "include": [ 18 | "./src/**/*.js", 19 | "types.ts" // Add the types file 20 | ] 21 | } 22 | --------------------------------------------------------------------------------