<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: 고광웅</title>
    <description>The latest articles on Forem by 고광웅 (@ernham).</description>
    <link>https://forem.com/ernham</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3886873%2F8197dd3d-2edb-4b7e-8532-d8c6f2156632.jpg</url>
      <title>Forem: 고광웅</title>
      <link>https://forem.com/ernham</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ernham"/>
    <language>en</language>
    <item>
      <title>Your AI's Persona Is a String. A New Paper Argues It Should Be a Steering Vector.</title>
      <dc:creator>고광웅</dc:creator>
      <pubDate>Sun, 19 Apr 2026 14:08:10 +0000</pubDate>
      <link>https://forem.com/ernham/your-ais-persona-is-a-string-a-new-paper-argues-it-should-be-a-steering-vector-4bha</link>
      <guid>https://forem.com/ernham/your-ais-persona-is-a-string-a-new-paper-argues-it-should-be-a-steering-vector-4bha</guid>
      <description>&lt;h2&gt;
  
  
  The Mismatch Most Persona Products Live With
&lt;/h2&gt;

&lt;p&gt;If you've built any kind of AI agent product in the last two years, you've probably shipped a "persona" feature. Usually it looks like this: a text field where the user (or the product) writes "You are a witty, slightly sarcastic assistant who loves climbing," and that string gets stitched into a system prompt. Done. Persona complete.&lt;/p&gt;

&lt;p&gt;The thing is, nobody who has ever worked with real people thinks of personality that way. Actual humans don't have a single mode. The friendly coworker is different at 2am on a deadline. The patient teacher is different when a student is being deliberately obtuse. Situation changes behavior, and most of the time it changes it a lot.&lt;/p&gt;

&lt;p&gt;A paper that went up on arXiv this week formalizes that mismatch and proposes something interesting about how to fix it. It's not the kind of paper that'll get quoted in keynote slides — there are no dramatic benchmarks in the abstract — but the conceptual move is, I think, more important than the specific method.&lt;/p&gt;

&lt;p&gt;The paper is &lt;a href="https://arxiv.org/abs/2604.13846" rel="noopener noreferrer"&gt;Beyond Static Personas: Situational Personality Steering for Large Language Models&lt;/a&gt; (Wei, Li, Wang, Deng, April 15). Short version: instead of treating personality as a string you define once, treat it as a runtime steering signal over the model's neurons — one that shifts with the situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Paper Actually Argues
&lt;/h2&gt;

&lt;p&gt;The technical contribution is a framework the authors call &lt;strong&gt;IRIS&lt;/strong&gt; — &lt;em&gt;Identify, Retrieve, Steer&lt;/em&gt;. It's training-free and operates at the neuron level. Three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Situational persona neuron identification&lt;/strong&gt; — find the specific neurons whose activation patterns correspond to personality traits in context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Situation-aware neuron retrieval&lt;/strong&gt; — given a new situation, retrieve the relevant neuron set for the desired persona expression under that situation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Similarity-weighted steering&lt;/strong&gt; — apply a steering vector to those neurons at inference time, weighted by how similar the current situation is to the retrieved references.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What I find more interesting than the method is the empirical claim underneath it: the authors argue (and their analysis attempts to demonstrate) that situation-dependency and situation-behavior patterns already exist inside LLM personalities, at the neuron level. Personality isn't just an artifact of the system prompt — it's something the model has internalized structurally, and that structure is responsive to context.&lt;/p&gt;

&lt;p&gt;If that holds up under replication, the implication is bigger than IRIS itself. It means the right abstraction for "persona" in an LLM might not be &lt;em&gt;a description you write&lt;/em&gt; but &lt;em&gt;a manifold you steer&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I'm hedging because the abstract doesn't give specific win margins and I haven't dug into the full paper. The method could under-perform cleaner approaches in practice. But the framing is worth thinking about regardless of whether IRIS turns out to be the method that wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is a Design Problem, Not Just a Method Problem
&lt;/h2&gt;

&lt;p&gt;Here's the thing I keep coming back to. Most of the persona code I've written — and most of what I see shipped in agent products — treats persona as a &lt;strong&gt;compile-time primitive&lt;/strong&gt;. You write it once, it goes into the system prompt, and from that point forward the agent's "character" is whatever that text produces in combination with whatever comes after.&lt;/p&gt;

&lt;p&gt;What this paper is pointing at is that persona is arguably a &lt;strong&gt;runtime primitive&lt;/strong&gt;. It's not a fixed definition. It's a behavior modulation that should respond to context — and the model already has the internal machinery to do that if you know where to apply the signal.&lt;/p&gt;

&lt;p&gt;Those are two different things, and I don't think the industry has fully reckoned with the difference. We're selling "custom AI personas" while implementing static strings. The user-facing story is "you can make this agent sarcastic" but the implementation is a shim that barely survives contact with an adversarial user.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Game Designers Have Been Saying For Decades
&lt;/h2&gt;

&lt;p&gt;I spent a decade designing games before I started building AI agents. The paper's framing feels very familiar to me — it's arriving, through a different path, at something the game AI community has treated as common knowledge for a long time.&lt;/p&gt;

&lt;p&gt;Static NPC personalities get old in a session. A guard who always says the same thing in the same tone at the same time regardless of what the player has been doing is immediately legible as a set piece, not a character. The guards players remember are the ones that modulated — the ones whose threat level shifted with how many times you'd returned to the same area, the ones whose dialogue tree branched based on tension state.&lt;/p&gt;

&lt;p&gt;The vocabulary was different. We didn't say "steering vectors." We said mood systems, faction relationships, dynamic difficulty, dialog branching by tension. But the underlying insight is the same: behavior is a function of state × situation × character, not just character.&lt;/p&gt;

&lt;p&gt;The novelty of a paper like IRIS, from a game designer's lens, isn't the idea. It's the discovery that the scaffolding for this kind of behavior is already latent in LLM weights and can be activated without retraining. That part is genuinely new.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Questions to Ask About Your Own Persona Implementation
&lt;/h2&gt;

&lt;p&gt;If you ship a product where users can define or tune an AI's personality, it's worth auditing what you actually built against what you probably told users you built. Some specific questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. What happens to your persona when the user asks something hostile?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Static-string personas tend to collapse under adversarial pressure. The "patient teacher" prompt starts talking like a base model the moment someone pushes hard. If your persona is a product promise, you need a mechanism beyond a string — otherwise the promise is broken the first time someone tests it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Does your persona change register with conversation length?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Real teachers get firmer as a session drags on. Real assistants get more efficient as trust is established. If your agent sounds the same in message 1 and message 40, you've got a behavior rigidity that will eventually feel wrong to users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What does your persona do when the topic shifts to something the "character" wouldn't know about?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the case where static personas fail most visibly. A persona designed around "warm emotional support" doesn't gracefully handle a user suddenly asking for tax advice. A situational model would know to shift register without dropping character. A string-based model can only either stay in character and refuse, or break character and help. Neither is right.&lt;/p&gt;

&lt;p&gt;These aren't theoretical. They're the three places where persona products routinely fail in ways that erode user trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Part That Matters for Builders
&lt;/h2&gt;

&lt;p&gt;I don't think the takeaway from this paper is that everyone should rewrite their agents to do neuron-level steering next week. The infrastructure to do that at production scale doesn't really exist outside research labs yet.&lt;/p&gt;

&lt;p&gt;The takeaway is more structural. The "persona" primitive most of us are using is probably a UI convenience over a more correct runtime mechanism. The more correct mechanism isn't accessible yet, but the mismatch is worth being honest about in how we design around persona features today.&lt;/p&gt;

&lt;p&gt;Some implications I'm thinking through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Treat persona as a layered system rather than a single string.&lt;/strong&gt; Core traits at one level, situational modifiers at another, tone adjustments at a third. This is messier in the UX but closer to what's actually happening.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build instrumentation for persona drift.&lt;/strong&gt; How does your agent's tone change across a long conversation? Across different user emotional states? You probably don't measure this and should.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be wary of "custom persona" as a feature promise.&lt;/strong&gt; If your implementation is a text field and the model is doing the rest, you're selling something the mechanism can't reliably deliver. Setting user expectations honestly is better than overselling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What This Paper Doesn't Settle
&lt;/h2&gt;

&lt;p&gt;I want to name a few things the paper, as I understand it from the abstract, does not resolve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The specific benchmarks (PersonalityBench and the authors' new SPBench) aren't standard in the field yet.&lt;/strong&gt; Situational personality benchmarks are hard to construct well, and it's possible a different benchmark would tell a different story.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Training-free methods are appealing for deployment but sometimes undersell what you'd get from even a small amount of targeted fine-tuning.&lt;/strong&gt; IRIS may be the right research contribution but not the right engineering choice for a given product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neuron-level steering is interpretability-adjacent territory, and that field has been notably humble about what its findings mean.&lt;/strong&gt; Identifying "persona neurons" is a strong claim that deserves scrutiny before anyone builds on it as foundational.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm flagging these not to pick fights with the paper but because conceptual takeaways are more portable than methodological ones, and conflating them is how builders end up chasing implementations that don't actually help their products.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Close
&lt;/h2&gt;

&lt;p&gt;What I'm sitting with, after reading this paper alongside the last few days of working on agent products, is that a lot of the primitives we use are shaped by what was easy to build rather than what is actually the right model of the thing we're building.&lt;/p&gt;

&lt;p&gt;Persona-as-string is easy. Persona-as-neural-steering-signal is hard. So we shipped the easy one. That's fair — you ship what works today. But it's worth occasionally asking whether the abstraction you shipped is actually the right abstraction, or just the one that was available.&lt;/p&gt;

&lt;p&gt;For persona specifically, my current guess is that the right abstraction is situational and runtime, not descriptive and static. The paper arrives at that conclusion through empirical analysis of neuron activations. Game designers arrived there through twenty years of making NPCs that didn't suck. Different paths, convergent answer.&lt;/p&gt;

&lt;p&gt;Whether IRIS is the specific mechanism that ends up winning is almost beside the point. What matters is the reframe: &lt;strong&gt;behavior is a function of situation, and persona is a steering problem, not a description problem.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building in this space, it's worth checking which one your product actually implements.&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>llm</category>
      <category>persona</category>
      <category>iris</category>
    </item>
    <item>
      <title>Claude Design Looks Like AI Magic. Reading the Source, It's Four Engineering Patterns.</title>
      <dc:creator>고광웅</dc:creator>
      <pubDate>Sun, 19 Apr 2026 04:34:45 +0000</pubDate>
      <link>https://forem.com/ernham/claude-design-looks-like-ai-magic-reading-the-source-its-four-engineering-patterns-3p9m</link>
      <guid>https://forem.com/ernham/claude-design-looks-like-ai-magic-reading-the-source-its-four-engineering-patterns-3p9m</guid>
      <description>&lt;h2&gt;
  
  
  Before the Hype Settles
&lt;/h2&gt;

&lt;p&gt;Anthropic shipped Claude Design on April 17, and most of the discussion has framed it as a Figma-challenging AI design tool. I used it differently. Instead of treating it as a design tool, I treated it as a specimen — generated a handful of skill bundles, exported the output, then spent more time reading the source than tweaking the design. I was more interested in &lt;em&gt;how the product works&lt;/em&gt; than in &lt;em&gt;what it can design&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What I found is more interesting than "AI can design now." The product appears to be mostly four discrete engineering patterns that happen to have a model at the entry point. The model doesn't feel like the magic — it's writing into a carefully structured runtime that almost any team could build.&lt;/p&gt;

&lt;p&gt;This post walks through those four patterns, what they actually do, and what I'm taking into my own stack. Caveat up front: these are observations from a source read of a small number of bundles, not a rigorous evaluation of the product's full behavior. I'll flag assumptions as I go.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Inspected
&lt;/h2&gt;

&lt;p&gt;A Claude Design skill bundle we looked at contained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Wireframes.html&lt;/code&gt; — a 72KB single-file wireframe document with five navigation variations across three screens each, plus a live Tweaks engine.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IR Deck - Hi-fi.html&lt;/code&gt; and &lt;code&gt;IR Deck - Wireframes.html&lt;/code&gt; — 1920×1080 slide decks wrapped in a custom Web Component.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;deck-stage.js&lt;/code&gt; — a 621-line Web Component that provides the slide runtime.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;colors_and_type.css&lt;/code&gt; — a 160-line design token sheet organized into seven categories.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SKILL.md&lt;/code&gt; — a 20-line skill manifest with frontmatter.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;README.md&lt;/code&gt; — a 223-line brand and voice guide.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;preview/&lt;/code&gt; — twelve single-file "at-a-glance" cards, one per token category.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ui_kits/web/&lt;/code&gt; — a React 19 UMD clickable prototype.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The total footprint is small. What's striking is how the pieces fit together — and how few moving parts there actually are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 1 — Tweaks: &lt;code&gt;data-*&lt;/code&gt; Attributes with CSS Variables
&lt;/h2&gt;

&lt;p&gt;The Tweaks panel is what makes the output feel interactive: click "dusk" and the whole design shifts to a warm dark palette. Click "compact" and the layout tightens. No regeneration. No API round-trip.&lt;/p&gt;

&lt;p&gt;The mechanism is mundane. Every theme, accent, layout, and density option is a &lt;code&gt;:root&lt;/code&gt; CSS variable override keyed to a &lt;code&gt;data-*&lt;/code&gt; attribute on the root element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"paper"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--ink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#1a1a1a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="py"&gt;--paper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#f4efe6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#c53b1e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"dusk"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;         &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--ink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#eae3d2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="py"&gt;--paper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#2a2620&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#e77c5f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"midnight"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--ink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#f0ebde&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="py"&gt;--paper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#14110d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#ff8a6a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-accent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"gold"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;#d4a017&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"stack"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-density&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"compact"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A click handler sets &lt;code&gt;document.documentElement.dataset.theme = "dusk"&lt;/code&gt;, persists to &lt;code&gt;localStorage&lt;/code&gt;, and &lt;code&gt;postMessage&lt;/code&gt;s the host window so it can save the selection against the artifact. That's the entire switching layer.&lt;/p&gt;

&lt;p&gt;Four axes, three-to-four options each, roughly 144 combinations available without regenerating anything. The design-system work is done at token definition time, not at runtime.&lt;/p&gt;

&lt;p&gt;The takeaway I'm sitting with: what feels like "AI variant generation" in interactive design tools may be mostly static CSS token switching. The AI wrote the tokens once. The switching is attribute swapping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 2 — &lt;code&gt;deck-stage.js&lt;/code&gt;: A 621-Line Web Component That Replaces a Slide Tool
&lt;/h2&gt;

&lt;p&gt;The decks in the output aren't Reveal.js or a bespoke React app. They're a custom Web Component, &lt;code&gt;&amp;lt;deck-stage&amp;gt;&lt;/code&gt;, containing plain &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; children as slides.&lt;/p&gt;

&lt;p&gt;What the component does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fits a design-size canvas (default 1920×1080) to whatever viewport it's rendered in, using &lt;code&gt;transform: scale()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Handles keyboard navigation (arrows, PgUp/PgDn, Space, Home, End, 0–9, R).&lt;/li&gt;
&lt;li&gt;Adds mobile tap zones (left third / right third).&lt;/li&gt;
&lt;li&gt;Persists the current slide to &lt;code&gt;localStorage&lt;/code&gt;, keyed by document path, so a refresh restores position.&lt;/li&gt;
&lt;li&gt;Renders a floating overlay with previous/next/reset controls and a slide counter.&lt;/li&gt;
&lt;li&gt;Injects a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag into &lt;code&gt;document.head&lt;/code&gt; with &lt;code&gt;@page { size: 1920px 1080px; margin: 0; }&lt;/code&gt; so the browser's native "Print to PDF" produces one page per slide.&lt;/li&gt;
&lt;li&gt;Emits a &lt;code&gt;slidechange&lt;/code&gt; CustomEvent with &lt;code&gt;bubbles: true, composed: true&lt;/code&gt; and a &lt;code&gt;reason&lt;/code&gt; field (&lt;code&gt;init/keyboard/click/tap/api&lt;/code&gt;) — listenable cleanly from outside the shadow DOM.&lt;/li&gt;
&lt;li&gt;Reads a &lt;code&gt;&amp;lt;script type="application/json"&amp;gt;&lt;/code&gt; block of speaker notes and posts them to the host window.&lt;/li&gt;
&lt;li&gt;Honors a &lt;code&gt;noscale&lt;/code&gt; attribute for PPTX export cases where the CSS transform is undesirable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two implementation details stood out:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@page&lt;/code&gt; rule has to be injected into the outer document because shadow DOM ignores &lt;code&gt;@page&lt;/code&gt;. So the component walks up and writes into &lt;code&gt;document.head&lt;/code&gt; during &lt;code&gt;connectedCallback&lt;/code&gt;. This is the kind of detail that gets no documentation credit but separates "works in print" from "falls apart at export time."&lt;/p&gt;

&lt;p&gt;Slides are hidden, not unmounted, with &lt;code&gt;visibility: hidden; opacity: 0&lt;/code&gt;. That preserves the state of videos, iframes, form inputs, and React subtrees across navigation. If you're building a slide system in React with conditional rendering, you're quietly discarding state every time the user hits the arrow key. A cheap fix with meaningful UX consequences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 3 — &lt;code&gt;SKILL.md&lt;/code&gt;: A Manifest Format, Not a System Prompt
&lt;/h2&gt;

&lt;p&gt;The skill manifest is smaller than I expected. Three frontmatter fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;skill-kebab-case&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;this&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;skill&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;generate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;well-branded&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;interfaces&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;assets&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;domain&amp;gt;.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Contains&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;key&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;files&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;style&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;context&amp;gt;."&lt;/span&gt;
&lt;span class="na"&gt;user-invocable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The body reads like a protocol, not a persona:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Read &lt;code&gt;README.md&lt;/code&gt; within this skill first."&lt;/li&gt;
&lt;li&gt;"Then look at &lt;code&gt;colors_and_type.css&lt;/code&gt;."&lt;/li&gt;
&lt;li&gt;"If creating visual artifacts (slides, mocks): copy assets out, produce static HTML."&lt;/li&gt;
&lt;li&gt;"If working on production code: treat &lt;code&gt;&amp;lt;path&amp;gt;/frontend/app/&lt;/code&gt; as canonical."&lt;/li&gt;
&lt;li&gt;"If invoked with no other guidance: ask 3–5 questions about scope and audience, then act as an expert designer."&lt;/li&gt;
&lt;li&gt;"Always flag: font substitutions, chart color choices, and any deviation from the documented color contract."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three things about this format stood out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Description is the routing signal.&lt;/strong&gt; The orchestrator decides &lt;em&gt;when&lt;/em&gt; to invoke the skill by reading the description alone. So the description has to encode domain, output type, and stylistic signal in one paragraph — different from how most agent frameworks define a role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The body is a branched protocol.&lt;/strong&gt; "If A, do X. If B, do Y." Not a soft persona, not a goal statement. Concrete execution paths keyed to invocation context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Always flag" is mandatory self-reporting at the manifest level.&lt;/strong&gt; Fonts were substituted? Flag it. Deviated from the color contract? Flag it. It's an anti-hallucination pattern written into the skill definition rather than left to the model to remember.&lt;/p&gt;

&lt;p&gt;I don't think the manifest format itself is novel — it's structurally close to how Claude Code's existing SKILL.md works. But its use as an agent interface for a consumer-facing design product is a concrete shape I haven't seen written down this cleanly before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 4 — Output = Self-Contained HTML Bundle
&lt;/h2&gt;

&lt;p&gt;The artifact isn't stored in a proprietary database. It's a folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IR/
├── assets/
│   └── colors_and_type.css
├── IR Deck - Hi-fi.html
└── deck-stage.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The HTML references the CSS by relative path and the JS by relative path. Everything is physically co-located.&lt;/p&gt;

&lt;p&gt;Zip it, upload to any static host, it works. No build step. No framework runtime. No server-side rendering required.&lt;/p&gt;

&lt;p&gt;There's a small interesting trick: the same &lt;code&gt;colors_and_type.css&lt;/code&gt; file appears as copies in multiple subfolders — one for the deck, one for the UI kit, one for the preview cards. The bundle is optimized for survival, not deduplication. If a user downloads just the deck folder, they don't lose styling.&lt;/p&gt;

&lt;p&gt;More bytes, no broken links. For a consumer product where users will definitely cut-and-paste the wrong subset of files, that tradeoff probably earns itself back quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Shape Is Interesting
&lt;/h2&gt;

&lt;p&gt;Going in, my mental model was roughly: "Claude Design is a big AI system that generates design output."&lt;/p&gt;

&lt;p&gt;What I came away with is closer to: "It looks like a thin AI orchestration layer over a carefully engineered runtime and manifest format, and the interesting work is in the runtime."&lt;/p&gt;

&lt;p&gt;The model writes HTML, CSS, and SKILL.md files into this system. The system is what makes the output interactive, exportable, and robust across environments. If Anthropic swapped the model tomorrow for a comparable one, my guess is the user experience would barely change — because the experience is mostly the runtime.&lt;/p&gt;

&lt;p&gt;That reframes the build-vs-buy question for anyone working in this space. You may not need a design-specialized model to get most of the user-facing value. What seems to matter more is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A token CSS file with tight, opinionated choices.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;data-*&lt;/code&gt; attribute theming layer.&lt;/li&gt;
&lt;li&gt;A Web Component (or equivalent) that handles presentation concerns: scale, navigation, print.&lt;/li&gt;
&lt;li&gt;A manifest format for the skills that generate into the runtime.&lt;/li&gt;
&lt;li&gt;A bundle format that survives being zipped and sent around.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build that scaffold, then any capable LLM plausibly becomes your design engine. If this read is right, the hard work isn't the AI — it's the runtime the AI writes into. I'm hedging because one bundle inspection isn't enough to generalize.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Taking
&lt;/h2&gt;

&lt;p&gt;Four patterns I'm adapting into our own stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Four-axis Tweaks (theme / accent / layout / density).&lt;/strong&gt; Roughly fifty lines of CSS and JavaScript for a meaningful UX upgrade. Low risk, high visibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@page&lt;/code&gt; dynamic injection for PDF export.&lt;/strong&gt; Potentially removes the need for a separate PDF library in slide-style outputs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SKILL.md manifest format for our agents.&lt;/strong&gt; Three-field frontmatter, branched body, mandatory "Always flag" section. Structural improvement on how we currently define agent behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-contained HTML bundles as the default artifact.&lt;/strong&gt; No server dependency, zippable, survives cut-and-paste. Lowers the support surface dramatically for client-facing deliverables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm leaving aside porting the slide Web Component for now, because we already have a working runtime and the license review cost isn't obviously worth the marginal gain. The patterns above are portable with a day or two of work each.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Open Question
&lt;/h2&gt;

&lt;p&gt;The specific shape I'm describing — four patterns around a model — isn't obviously unique to design. It's roughly the shape of a lot of AI-labeled products right now. The product does something useful and the model is the visible new thing, but most of what makes it work seems to be conventional engineering inside a well-thought-out structure.&lt;/p&gt;

&lt;p&gt;If that holds, a lot of "AI products" are really platform products where the AI is the entry point rather than the engine. The scarce skill in that world isn't prompting. It's designing the runtime the prompts write into.&lt;/p&gt;

&lt;p&gt;I'm not sure whether that's a durable observation or a snapshot of where we are in this early phase of AI product maturity. But it's the one I came away from this source read with, and it's shifted how I'm thinking about our own architecture.&lt;/p&gt;

&lt;p&gt;If you're building in this space, reading the bundles your tools produce might teach you more than reading the marketing. That's the part I'd put the most confidence on.&lt;/p&gt;

</description>
      <category>claudedesign</category>
      <category>anthropic</category>
      <category>engineering</category>
      <category>webcomponents</category>
    </item>
  </channel>
</rss>
