# James Long

A bunch of little things and sketches

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Designing a Website with Experimental DOM Effects and AI-Created Tools

DevFeed: [Designing a Website with Experimental DOM Effects and AI-Created Tools](<https://devfeed.tech/articles/i-got-caught-up-in-design-again-28088.md>)

Original publisher: [Read original article](<https://jlongster.com/caught-up-in-design>)

Author: James Long

Published: 2025-12-03T12:00:00Z

Content type: opinion

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [Document Object Model (DOM)](<https://devfeed.tech/topics/dom.md>), [Artificial Intelligence](<https://devfeed.tech/topics/ai.md>), [Website](<https://devfeed.tech/topics/website.md>), [procedural flowers](<https://devfeed.tech/topics/procedural-flowers.md>)

Tags: [ai](<https://devfeed.tech/tags/ai.md>), [animation](<https://devfeed.tech/tags/animation.md>), [design](<https://devfeed.tech/tags/design.md>), [editor](<https://devfeed.tech/tags/editor.md>), [tools](<https://devfeed.tech/tags/tools.md>), [website](<https://devfeed.tech/tags/website.md>)

### AI overview

The author reflects on an experimental website redesign built around warped DOM elements, explaining that the visual concept became too distracting from the site's purpose of presenting readable content. They describe simplifying the design and using AI to create animation and drawing tools during the process.

### Source excerpt

Over a week ago, I had a thought: "I'm gonna make my website cool." I really love visual exploration. But there's a problem: given no constraints, it's so easy to get wrapped up into a one idea and go too far down that path. Here's what happened: I found a cool trick to "warp" real DOM elements. I took this approach to the extreme and tried to build my whole site around it. Here was one early version: I still really like this. It feels like my personal messy desk that that world can see. But that's also a problem: it's too messy. The hardest part about design is executing it in a way that doesn't detract from the original need. It still needs to fulfill the original requirement. In this case, the requirement is I should be able to quickly write content for you to read. I spent almost a week working on this before realizing this approach just fundamentally detracted from the experience too much. Maybe a better designer could have figured out how to execute this better. For now, I ripped it out and implemented what you see in ONE HOUR. It's time to focus on content again. I left my in-progress work up so you can see it on this page. (I also wrote this up as a thread which has a few more details & videos) This is my favorite part of the design by far. I made the demo videos into little polaroid pictures. These are real videos that are playing! They animate in like a paper would, and there's a nice paper-like interaction on hover, and you can drag them around: (I wrote some notes when implementing this: https://jlongster.com/slicing-up-a-video) I learned a ton throughout this process. The biggest thing was I used AI to create design tools on the fly. For example, I create a full animation keyframe editor that let me create keyframes of the warped DOM nodes, and then a runtime player plays these keyframes to make the animation: I installed the perfect-freehand library and created a live animation drawing tool. You can press record, draw stuff on the screen, and stop reco

## Warp any DOM element with this bookmarklet

DevFeed: [Warp any DOM element with this bookmarklet](<https://devfeed.tech/articles/warp-any-dom-element-with-this-bookmarklet-28096.md>)

Original publisher: [Read original article](<https://jlongster.com/warp-any-dom-element-with-this-bookmarklet>)

Author: James Long

Published: 2025-11-19T12:00:00Z

Content type: tutorial

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [Warp](<https://devfeed.tech/topics/warp.md>), [Document Object Model (DOM)](<https://devfeed.tech/topics/dom.md>), [Snippet](<https://devfeed.tech/topics/snippet.md>)

Tags: [js](<https://devfeed.tech/tags/js.md>), [snippet](<https://devfeed.tech/tags/snippet.md>), [warp](<https://devfeed.tech/tags/warp.md>)

### AI overview

This article presents a JavaScript bookmarklet for interactively selecting a DOM element and applying a visual warp effect to it. The code includes element highlighting, selection, draggable control points, and cleanup behavior.

### Source excerpt

I've been working on a design and found a cool effect that would make a great bookmarklet. A bookmarklet is a JS snippet that you can drag to your bookmarks bar and run on any page. Press ESC to cancel`;const closeBtn=document.createElement('button');closeBtn.textContent='✕ Close';closeBtn.style.cssText=`padding: 6px 12px;background: #ef4444;color: white;border: none;border-radius: 4px;cursor: pointer;font-weight: 500;font-size: 12px;margin-left: auto;`;closeBtn.onclick=cleanup;instructions.appendChild(instructionText);instructions.appendChild(closeBtn);document.body.appendChild(instructions);document.addEventListener('mousemove',onSelectorMove);document.addEventListener('click',onSelectorClick);document.addEventListener('keydown',(e)=>{if(e.key==='Escape')cleanup();});window.__bezierCleanup=()=>{instructions.remove();cleanup();};}function onSelectorMove(e){if(!selectorActive)return;const target=document.elementFromPoint(e.clientX,e.clientY);if(!target||target===highlightBox)return;const rect=target.getBoundingClientRect();highlightBox.style.display='block';highlightBox.style.left=rect.left+'px';highlightBox.style.top=rect.top+'px';highlightBox.style.width=rect.width+'px';highlightBox.style.height=rect.height+'px';}function onSelectorClick(e){if(!selectorActive)return;e.preventDefault();e.stopPropagation();const target=document.elementFromPoint(e.clientX,e.clientY);if(!target)return;selectorActive=false;highlightBox.style.display='none';document.removeEventListener('mousemove',onSelectorMove);document.removeEventListener('click',onSelectorClick);selectElement(target);}function selectElement(element){selectedElement=element;const rect=element.getBoundingClientRect();const scrollX=window.pageXOffset||document.documentElement.scrollLeft;const scrollY=window.pageYOffset||document.documentElement.scrollTop;transformedContainer=document.createElement('div');transformedContainer.style.cssText=`position: absolute;left: ${rect.left+scrollX}px;top: ${rect.top+scrollY}px;width

## Building an AI REPL with QuickJS

DevFeed: [Building an AI REPL with QuickJS](<https://devfeed.tech/articles/building-an-ai-repl-with-quickjs-28087.md>)

Original publisher: [Read original article](<https://jlongster.com/building-an-ai-repl-with-quickjs>)

Author: James Long

Published: 2025-11-18T12:00:00Z

Content type: opinion

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [Artificial Intelligence](<https://devfeed.tech/topics/ai.md>), [wasm](<https://devfeed.tech/topics/wasm.md>), [WebAssembly](<https://devfeed.tech/topics/web-assembly.md>), [anthropic](<https://devfeed.tech/topics/anthropic.md>), [Claude Code](<https://devfeed.tech/topics/claude-code.md>), [User experience (UX)](<https://devfeed.tech/topics/ux.md>), [C](<https://devfeed.tech/topics/c.md>), [debug](<https://devfeed.tech/topics/debug.md>), [Error Handling](<https://devfeed.tech/topics/error-handling.md>)

Tags: [ai](<https://devfeed.tech/tags/ai.md>), [anthropic](<https://devfeed.tech/tags/anthropic.md>), [bytecode](<https://devfeed.tech/tags/bytecode.md>), [c](<https://devfeed.tech/tags/c.md>), [claude-code](<https://devfeed.tech/tags/claude-code.md>), [debugger](<https://devfeed.tech/tags/debugger.md>), [error-handling](<https://devfeed.tech/tags/error-handling.md>), [github](<https://devfeed.tech/tags/github.md>), [ux](<https://devfeed.tech/tags/ux.md>), [webassembly](<https://devfeed.tech/tags/webassembly.md>)

### AI overview

The article describes a three-hour experiment building an AI-integrated REPL with a custom WebAssembly build of QuickJS. The system evaluated JavaScript locally, exposed function bytecode and execution controls, and sent failed evaluations to Anthropic's Sonnet 4.5. The author concludes that the approach was not very useful for simple scripts but sees potential in sharing an executing environment with AI and debugger hooks.

### Source excerpt

Yesterday I did a livestream where I built a usable REPL with AI integration. Mostly from scratch, all in 3 hours. It uses a custom WASM build of QuickJS for evaluation. If the evaluation fails, it sends the text to Anthropic to speak to Sonnet 4.5. The idea was to meld a live evaluation environment together with AI. By using QuickJS as an evaluator, we get more than just a sandbox: we are able to inspect bytecode of functions, we could pause execution as needed, etc. I thought we might discover use cases that would be difficult to do by sending JS to eval off to a remote sandbox (or a separate node instance). It's also a UX experiment: you can either write code or talk to AI. In the end, it didn't prove to be super useful. The cases where I want to provide deep introspection at runtime to AI are where I'm already working with a very complex codebase, not writing simple scripts. For the UX, I generally want to write code in a dedicated editor and send it off to be evaluated. I still think there's merit in the idea of sharing an executing environment with AI with the debugger hooks enabled; I'm researching companies working on this. Let me know if you know of any. Still, it was fun to give AI the ability to get the bytecode for a function and describe what the function does at a very low-level. I asked to write a function that sums the numbers in an array, and then asked it to get the bytecode and describe it: Some notable things that happened during this: QuickJS doesn't come with a WASM build by default. I told Claude Code to compile it to WebAssembly, and it got Emscripten all setup and successfully built it to WASM Sonnet 4.5 was able to very easily write a bunch of C code to provide new APIs in QuickJS Changing how error handling works, another example of how nice it was to get AI to work with the C code I intended to eventually dig into QuickJS and change some fundamental features but decided to pause this experiment Adding tools is really fun. Here I added a t

## Wrangling my email with Claude Code

DevFeed: [Wrangling my email with Claude Code](<https://devfeed.tech/articles/wrangling-my-email-with-claude-code-28099.md>)

Original publisher: [Read original article](<https://jlongster.com/wrangling-email-claude-code>)

Author: James Long

Published: 2025-11-14T12:00:00Z

Content type: opinion

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [Claude Code](<https://devfeed.tech/topics/claude-code.md>), [email](<https://devfeed.tech/topics/email.md>), [Artificial Intelligence](<https://devfeed.tech/topics/ai.md>), [MCP](<https://devfeed.tech/topics/mcp.md>), [n8n](<https://devfeed.tech/topics/n8n.md>)

Tags: [ai](<https://devfeed.tech/tags/ai.md>), [api](<https://devfeed.tech/tags/api.md>), [claude-code](<https://devfeed.tech/tags/claude-code.md>), [email](<https://devfeed.tech/tags/email.md>), [mcp](<https://devfeed.tech/tags/mcp.md>), [n8n](<https://devfeed.tech/tags/n8n.md>)

### AI overview

The author describes exploring AI-assisted workflows for managing an email backlog. After trying self-hosted n8n automation, they turn to Claude Code and investigate using MCP to give it access to Gmail for identifying follow-ups and organizing information about companies.

### Source excerpt

I'm terrible at managing emails/DMs/etc. A lot of times it feels like trying to keep up is a full-time job in and of itself. Now that I don't have a job I finally have time to figure out a better workflow to manage life. I have a good workflow for writing notes and managing tasks in Bear, but my biggest weakness is staying on top of communication. What happens frequently is I'll have a backlog so big that I end up ignoring it, which is really bad as I miss out on opportunities or important emails. We now have AI as an incredible tool. I was always too busy to sit down and learn how to leverage AI to transform my life; it's so early and this space is super chaotic. However, I finally have time to figure out new workflows that use AI. My first attempt was to run my own instance of n8n on fly and setup some workflows for processing email. I got it working (and accidentally spammed my wife with multiple emails every hour, which she is still annoyed by), but I realized right now I don't need automations. I just need new tools to help manage my life. Next, I turned to Claude Code. I use it all the time while writing code, and I knew there was a way to extend it. So I thought of a specific use case: after announcing I left my job, I received a lot of emails from interested companies. Since I'm still dealing with some burnout, it's been difficult to stay on top of. How can AI help us here? I thought of a few questions: Which email threads should I follow-up on? Are there any important ones that I forgot to reply to? How can I more clearly see all these companies to help decide what my next step should be? I want to be able to clearly see a list of companies and info about them The first step is to give Claude Code access to my gmail. Writing a Gmail Skill to access email I've used tool calling before only when interacting with an LLM via an API. How do I give Claude Code, a product, the ability to read my email? It looked like MCP was the way to do it. Claude Code has an /m

## Verlet cloth

DevFeed: [Verlet cloth](<https://devfeed.tech/articles/verlet-cloth-28095.md>)

Original publisher: [Read original article](<https://jlongster.com/verlet-cloth>)

Author: James Long

Published: 2025-04-11T12:00:00Z

Content type: article

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [Demo](<https://devfeed.tech/topics/demo.md>), [Code](<https://devfeed.tech/topics/code.md>), [Canvas](<https://devfeed.tech/topics/canvas.md>)

Tags: [canvas](<https://devfeed.tech/tags/canvas.md>), [code](<https://devfeed.tech/tags/code.md>), [demo](<https://devfeed.tech/tags/demo.md>), [experiment](<https://devfeed.tech/tags/experiment.md>), [script](<https://devfeed.tech/tags/script.md>)

### AI overview

An interactive Verlet cloth demo lets users drag the cloth with the left mouse button, tear it with the right button, and adjust its size. The demo was written with a fork of LLJS that compiles to asm.js, and its code is available.

### Source excerpt

body { background-color: black; } #demo-mount { margin-top: 50px; } .sizer { position: absolute; bottom: 60px; width: 500px; left: calc(50% - 250px); text-align: center; color: white; background-color: #303040; padding: 20px; border-radius: 6px; } .sizer input { width: 100%; margin-bottom: 20px; } .sizer .output { font-size: 3em; line-height: 1em; } .info { position: fixed; bottom: 0; right: 0; display: block; margin: 1.5em; } .info.closed { display: none; } .info span { display: block; text-align: right; font-size: .75em; } div.info { color: white; width: 250px; background-color: rgba(255, 255, 255, .2); padding: 1em; } a.info { color: #004854; background-color: white; border-radius: 50%; width: 25px; height: 25px; text-align: center; padding-top: 12px; line-height: 0; opacity: .4; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } a.info:hover { opacity: 1; cursor: pointer; } ^96c620 <div id="demo-mount"></div> ^f31aec <div class="sizer"> <input name="size" type="range" min="100" max="350" value="100" /> <div class="output">32 x 33</div> </div> <a class="info">?</a> <div class="info closed"> <p> Drag the cloth around with the left mouse button, and tear it with the right button. </p> <p> This was written with <a href="https://github.com/jlongster/LLJS">my fork</a> of <a href="http://lljs.org/">LLJS</a> that compiles to <a href="http://asmjs.org/">asm.js</a>. Get <a href="https://github.com/jlongster/lljs-cloth">the code</a>, and see more demos at <a href="https://jlongster.com">my site</a>. <span>- James Long</span> </p> </div> <script src="https://archive.jlongster.com/lljs-cloth/stats.min.js"></script> <script src="https://archive.jlongster.com/lljs-cloth/gl-matrix.js"></script> <script src="https://archive.jlongster.com/lljs-cloth/gl-renderer.js"></script> <script src="https://archive.jlongster.com/lljs-cloth/canvas-renderer.js"></script> <script src="https://archive.jlongster.com/lljs-cloth/verlet-run.js"></script> <script s

## Subverting control with weak references

DevFeed: [Subverting control with weak references](<https://devfeed.tech/articles/subverting-control-with-weak-references-28094.md>)

Original publisher: [Read original article](<https://jlongster.com/subverting-control-weak-refs>)

Author: James Long

Published: 2025-02-24T12:00:00Z

Content type: tutorial

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [JavaScript](<https://devfeed.tech/topics/javascript.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>), [Memory Leaks](<https://devfeed.tech/topics/memory-leaks.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [data-structure](<https://devfeed.tech/tags/data-structure.md>), [javascript](<https://devfeed.tech/tags/javascript.md>), [memory](<https://devfeed.tech/tags/memory.md>), [memory-leaks](<https://devfeed.tech/tags/memory-leaks.md>), [reference](<https://devfeed.tech/tags/reference.md>)

### AI overview

This JavaScript article explains weak references, WeakRef, and WeakMap. It describes how weak references interact with garbage collection and how WeakMap can avoid retaining objects and causing memory leaks.

### Source excerpt

Weak references are neat. The best language features unlock different kinds of abstractions, and weak references do exactly that. Let me show you why. In JavaScript we have two APIs to work with weak references: WeakMap and WeakRef. (Before I wrote this article I thought WeakRef was only a proposal, but it turns out most browsers have already implemented it) One of the more common use cases uses WeakMap. This data structure keeps a weak reference to the keys in the map, and a strong reference between the keys and values. I guess I should explain what a "weak reference" is: usually if you have a reference to an object in a variable, it stops the garbage collector from deleting it (which makes sense). It'd be weird if suddenly your variable pointed to nothing right? A "weak reference" doesn't stop the object from being garbage collected. Usually languages' semantics don't allow a variable to change in the middle of execution however: // this doesn't exist, but what if we could create a weak reference like this? let weak trans = new Transaction(); // do a bunch of things... // error! trans is... nothing? it got garbage collected trans.transfer(); ^3d7637 Wouldn't it be weird if trans changed in the middle of execution? If that was possible all bets would be off for everything in the entire program because these weak references could be passed anywhere. Instead, APIs for weak references force you to call a function to get the value. The WeakRef class has a deref method to get the object. const ref = new WeakRef(obj) // get the object ref.deref() // do a bunch of things... ref.deref() ^ae238d In the above example, if nothing has a reference to obj, it'll eventually get garbage collected. That means deref might return obj the first time, but the second time it might return undefined. Let's get back to WeakMap which is the more common usage of weak references. (Direct weak references have a lot of weird behaviors and they should be considered very low-level.) A WeakMap has

## Quick synthesizer with harmonics

DevFeed: [Quick synthesizer with harmonics](<https://devfeed.tech/articles/quick-synthesizer-with-harmonics-28093.md>)

Original publisher: [Read original article](<https://jlongster.com/quick-synthesizer-with-harmonics>)

Author: James Long

Published: 2024-09-29T12:00:00Z

Content type: opinion

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [cursor](<https://devfeed.tech/topics/cursor.md>)

Tags: [cursor](<https://devfeed.tech/tags/cursor.md>)

### AI overview

The author describes using Cursor to create a quick synthesizer from scratch, play with harmonics, and visualize frequencies in the spectrum.

### Source excerpt

I've been studying synths and recently this guy's tutorial really make things click for me. The way he shows the sound in the frequency spectrum really shows what makes the sound, and explaining harmonics was really interesting. Tonight I thought I'd give Cursor a chance to create a quick synth from scratch to play with harmonics. I also wanted to visualize the frequencies. Here's the Cursor came up with really quickly while the kids brush their teeth: (note: skipping interactive content block) ^d66d99 (note: skipping interactive content block) ^7b915a

## Notes on The Little Learner: Parameters, Tensors, and Mathematical Operations

DevFeed: [Notes on The Little Learner: Parameters, Tensors, and Mathematical Operations](<https://devfeed.tech/articles/little-learnings-28092.md>)

Original publisher: [Read original article](<https://jlongster.com/little-learnings>)

Author: James Long

Published: 2024-09-02T12:00:00Z

Content type: tutorial

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [dataset](<https://devfeed.tech/topics/dataset.md>), [math](<https://devfeed.tech/topics/math.md>), [implementation](<https://devfeed.tech/topics/implementation.md>), [render](<https://devfeed.tech/topics/render.md>)

Tags: [dataset](<https://devfeed.tech/tags/dataset.md>), [graph](<https://devfeed.tech/tags/graph.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [learnings](<https://devfeed.tech/tags/learnings.md>), [math](<https://devfeed.tech/tags/math.md>), [render](<https://devfeed.tech/tags/render.md>)

### AI overview

Notes working through The Little Learner explain function parameters, datasets, scalars, tensors and tensor rank, then implement extended mathematical operators such as addition and sum.

### Source excerpt

(note: skipping interactive content block) ^f3bf01 ^aeae51 A collection of notes as I work through The Little Learner. (note: skipping interactive content block) ^0c0c15 Chapter 1 1.5: graph a line with $w$ and $b$ parameters const f = (w, b) => x => w * x + b; render(graph(f(100, 10))); render(graph(f(10, 0))); ^2b4784 1.14: reverse the order to make $x$ an argument and $w$ and $p$ parameters // A version where w and b become parameters _after_ `x` const f = x => (w, b) => w * x + b; return graph(x => f(x)(2, 20)); ^14f8ec x is the argument of the line, while w and b which come after are parameters 1.19 plot the xs, ys dataset const xs = [2, 1, 4, 3]; const ys = [1.8, 1.2, 4.2, 3.3]; return graph({ marks: Plot.dot(zip(xs, ys), { x: n => n[0], y: n => n[1], fill: "black" }), domainX: [0, 5], domainY: [0, 5] }); ^dc0f98 Rule of parameters: every parameter is a number Given x and y, or arguments to a function, we can walk backwards and figure out the parameters and then use that to predict other y values for a given x θ is the parameter set (lowercase theta) Given θ, there parameters if it referred to as θ$_1$, θ$_2$, etc const f = θ => (θ_1, θ_2) => θ_1 * x + θ_2 ^7052b4 Chapter 2 "Scalars" are real numbers A "tensor" is a vector of scalars: [2.0, 1.0, 4.3, 4.2] The book uses tensor$^1$ with a superscript Tensors can be nested, and the superscript indicates the level of "nested" "elements" are the individual values in the tensor I think tensor$^1$ (with the 1 superscript) specifically means a vector of scalars, and higher tensors have tensors as elements All tensors$^m$ must have the same number of elements A scalar is atensor$^0$ 9 is tensor$^0$ [9, 9, 9] is tensor$^1$ [[9, 9, 9] [9, 9, 9]] is tensor$^2$ 2.25: define a function that finds the rank of a tensor window.scalarp = v => typeof v === "number"; window.rank = t => (scalarp(t) ? 0 : 1 + rank(t[0])); return log(output => { output(rank(4), 0); output(rank([4, 1]), 1); output(rank([[4, 1], [3, 6]]), 2); output(r

## Intro to the new site

DevFeed: [Intro to the new site](<https://devfeed.tech/articles/intro-to-the-new-site-28091.md>)

Original publisher: [Read original article](<https://jlongster.com/intro-new-site>)

Author: James Long

Published: 2024-07-09T12:00:00Z

Content type: article

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [Back end](<https://devfeed.tech/topics/backend.md>), [Obsidian](<https://devfeed.tech/topics/obsidian-md.md>), [User experience (UX)](<https://devfeed.tech/topics/ux.md>), [Syntax Highlighting](<https://devfeed.tech/topics/syntax-highlighting.md>), [render](<https://devfeed.tech/topics/render.md>), [math](<https://devfeed.tech/topics/math.md>)

Tags: [backend](<https://devfeed.tech/tags/backend.md>), [math](<https://devfeed.tech/tags/math.md>), [obsidian](<https://devfeed.tech/tags/obsidian.md>), [render](<https://devfeed.tech/tags/render.md>), [syntax-highlighting](<https://devfeed.tech/tags/syntax-highlighting.md>), [ux](<https://devfeed.tech/tags/ux.md>), [workflow](<https://devfeed.tech/tags/workflow.md>), [writing](<https://devfeed.tech/tags/writing.md>)

### AI overview

The author introduces a new site backend and a workflow centered on Obsidian for fast writing and publishing. The site supports interactive JavaScript code blocks, syntax highlighting, DOM output, rendering functions, and KaTeX mathematics, motivated partly by the author's AI studies.

### Source excerpt

I just pushed a new backend for this site. I love having a quick direct connection to my site: being able to write content and publish it with a quick press of a key. Previously, I was using logseq for this but while writing my latest post I got frustrated with how slow it is. I use this site not just for writing content, but also quick sketches of interactive code. I can easily make a code block interactive by tagging it to run inline in the page, making it easy to develop quick ideas. For this to work, publishing needs to be instant and the editing experience is vital. In logseq, it took 3-4 seconds to publish content (some of this is due to how I wired up the process) but worse is the editing experience in large posts with lots of code was very slow and frustrating. My new setup uses obsidian to write content which I've found extremely polished and fast. A big difference is logseq is an "outliner" and obsidian treats content as a simple file of text. I'll miss certain features of outliners but overall the UX improvement is very much worth it. New site allows code with syntax highlighting (just as before): function calc(x) { return x + 6 * 10000; } ^659b71 I can make code blocks easily run by adding the run tag to a codeblock. It looks like this: ```js run function calc(x) { return x + 5 * 10; } return calc(10); ``` ^4536cf If I want to show something from the code I can just return the value and it appears in the DOM: (note: skipping interactive content block) ^ef4d56 Alternatively I could use a render function within the code block to do the same thing: render(calc(10)). It's a little more verbose, but the benefit with this is I can render multiple things and at different places in the call stack. I also took the time to support math which is rendered with katex. For example $g(\\sqrt{a^2 + b^2})$ renders as this: $g(\sqrt{a^2 + b^2})$. This new workflow will be instrumental in my AI studies, which was the primary motivation for this rehaul. Watch this space: I

## Why does the chromaticity diagram look like that?

DevFeed: [Why does the chromaticity diagram look like that?](<https://devfeed.tech/articles/why-does-the-chromaticity-diagram-look-like-that-28097.md>)

Original publisher: [Read original article](<https://jlongster.com/why-chromaticity-shape>)

Author: James Long

Published: 2024-01-08T12:00:00Z

Content type: article

Language: en

Sources: [James Long](<https://devfeed.tech/sources/james-long.md>)

Topics: [math](<https://devfeed.tech/topics/math.md>), [pixel](<https://devfeed.tech/topics/pixel.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [color](<https://devfeed.tech/tags/color.md>), [image](<https://devfeed.tech/tags/image.md>), [pixel](<https://devfeed.tech/tags/pixel.md>), [rgb](<https://devfeed.tech/tags/rgb.md>), [theory](<https://devfeed.tech/tags/theory.md>)

### AI overview

This article explains why the CIE 1931 chromaticity diagram has its characteristic shape and how its colors are computed. It introduces color-matching functions for red, green, and blue, then describes calculating color mixtures and rendering sampled points into a two-dimensional image.

### Source excerpt

(note: skipping interactive content block) ^30b920 I've always wanted to understand color theory, so I started reading about the XYZ color space which looked like it was the mother of all color spaces. I had no idea what that meant, but it was created in 1931 so studying 93-year old research seemed like a good place to start. When reading about the XYZ color space, this cursed image keeps popping up: By BenRG - Own work based on: CIExy1931.svg, Public Domain, https://commons.wikimedia.org/w/index.php?curid=7889658 I say "cursed" because I have no idea what that means. What the heck is that shape?? I couldn't find any reasonably clear answer to my question. It's obviously not a formula like x = func(y). Why is it that shape, and where did the colors come from? Obviously the edges are wavelengths which have a specific color, but how did the image above compute every pixel? I became obsessed with this question. Below is the path I took to try to answer it. I'll spoil the answer but it might not make sense until you read this article: the shape comes from how our eyes perceive red, green, and blue relative to each other. Skip to the last section if you want to see some direct examples. The fill colors inside the shape are another story, but a simple explanation is there is some math to calculate the mixture of colors and we can draw the above by sampling millions of points in the space and rendering them onto the 2d image. Let's dig in more. (note: skipping interactive content block) ^f0af28 (note: skipping interactive content block) ^82e29b Color matching functions The first place to start is color matching functions. These functions determine the strength of specific wavelengths (color) to contribute so that our eyes perceive a target wavelength (color). We have 3 color matching functions for red, green, and blue (at wavelengths 700, 546, and 435 respectively), and these functions specify how to mix RGB to so that we visually see a spectral color. More simply put: ima