<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Vue Lynx Blog</title>
        <link>https://vue.lynxjs.org/</link>
        <description>Vue 3 framework for building Lynx apps</description>
        <lastBuildDate>Mon, 17 Aug 2026 20:14:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>© 2026 Xuan Huang (huxpro). All Rights Reserved.</copyright>
        <item>
            <title><![CDATA[How I Built Vue Lynx with AI in Two Weeks]]></title>
            <link>https://vue.lynxjs.org/blog/announcing-vue-lynx</link>
            <guid isPermaLink="false">/blog/announcing-vue-lynx</guid>
            <pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Vue Lynx went from a weekend architecture experiment to a production-shaped, dual-thread Vue framework in two weeks. Here is the architecture, testing harness, agentic verification loop, and the bill.]]></description>
            <content:encoded><![CDATA[<h1 class="rp-toc-include" id="how-i-built-vue-lynx-with-ai-in-two-weeks"><span>How I Built Vue Lynx with AI in Two Weeks</span><a href="#how-i-built-vue-lynx-with-ai-in-two-weeks" class="rp-header-anchor rp-link" aria-hidden="true">#</a> </h1><div class="rp-not-doc rp-llms-container"><button class="rp-not-doc rp-llms-button rp-llms-copy-button"><div class="rp-llms-copy-button__icon-wrapper"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-llms-copy-button__icon-success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-llms-copy-button__icon-copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg></div><span>Copy Markdown</span></button><button class="rp-llms-button rp-llms-view-options__trigger "><svg width="1em" height="1em" viewBox="0 0 32 32" class="rp-llms-view-options__arrow "><path fill="currentColor" d="M16 22 6 12l1.4-1.4 8.6 8.6 8.6-8.6L26 12z"></path></svg></button></div><!--$--><a href="/blog/" class="backLink-OiU6me">← <!-- -->All Posts</a><div class="blogHeader-TGxjXC"><span class="date-GC1HAk">March 26, 2026</span><div class="blog-avatar-frame-tezKVf avatars-TetuDG"><span class="avatar-item-Mdx49S"><img class="avatar-img-WIennJ" src="https://github.com/huxpro.png" alt="Xuan Huang"/><div class="avatar-text-KkTNZx"><span class="avatar-name-row-qlDUJL"><span class="avatar-name-QRE8vq">Xuan Huang</span><span class="avatar-socials-kVoJOe"><span class="avatar-social-link-Kh0lPm" role="link"><svg class="icon-x-laLkVm" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.727-8.835L1.254 2.25H8.08l4.253 5.622L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117L17.083 19.77z"></path></svg></span><span class="avatar-social-link-Kh0lPm" role="link"><span role="img" aria-label="github_logo" class="semi-icon semi-icon-default semi-icon-github_logo"><svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" focusable="false" aria-hidden="true"><path d="M12.01 1a11 11 0 0 0-3.48 21.45c.55.11.75-.23.75-.52l-.02-2.05c-3.06.66-3.7-1.3-3.7-1.3-.5-1.28-1.22-1.61-1.22-1.61-1-.68.07-.68.07-.68 1.11.08 1.7 1.13 1.7 1.13.98 1.68 2.56 1.2 3.2.92.1-.72.39-1.2.7-1.48-2.45-.26-5.02-1.2-5.02-5.43 0-1.2.44-2.2 1.13-2.96-.1-.27-.49-1.4.11-2.91 0 0 .93-.3 3.03 1.13a10.66 10.66 0 0 1 5.5 0c2.1-1.42 3.03-1.13 3.03-1.13.6 1.51.22 2.64.1 2.91a4.21 4.21 0 0 1 1.14 2.96c0 4.23-2.57 5.16-5.03 5.43.4.35.74 1 .74 2.04l-.01 3.03c0 .29.2.63.74.52A11 11 0 0 0 12.01 1Z" fill="currentColor"></path><path d="M5.17 16.8c-.01.06-.1.08-.18.04-.07-.04-.13-.1-.09-.16.02-.06.11-.08.18-.04.08.04.11.11.1.16Zm.44.5c-.05.05-.16.01-.22-.06-.07-.07-.09-.18-.03-.24.05-.05.14-.01.22.06.07.1.09.2.03.24Zm.44.63c-.07.06-.18 0-.24-.09-.07-.09-.07-.22 0-.25.08-.06.18 0 .24.09.07.09.07.2 0 .25Zm.6.62c-.05.08-.18.06-.3-.03-.08-.1-.12-.22-.05-.28.06-.07.19-.05.3.04.09.07.1.2.05.27Zm.82.35c-.02.1-.14.13-.27.1-.13-.04-.2-.15-.18-.23.01-.09.14-.12.27-.09.13.04.2.13.18.22Zm.9.07c0 .1-.12.17-.24.17-.13 0-.24-.08-.24-.17 0-.09.11-.16.24-.16.12 0 .23.07.23.16Zm.83-.14c.02.09-.07.18-.2.2-.13.02-.23-.04-.25-.13-.02-.1.07-.18.2-.2.13-.02.23.04.25.13Z" fill="currentColor"></path></svg></span></span></span></span><span class="avatar-role-iGDJdR">Creator of Vue Lynx</span></div></span></div><div class="rp-not-doc rp-llms-container"><button class="rp-not-doc rp-llms-button rp-llms-copy-button"><div class="rp-llms-copy-button__icon-wrapper"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-llms-copy-button__icon-success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-llms-copy-button__icon-copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg></div><span>Copy Markdown</span></button><button class="rp-llms-button rp-llms-view-options__trigger "><svg width="1em" height="1em" viewBox="0 0 32 32" class="rp-llms-view-options__arrow "><path fill="currentColor" d="M16 22 6 12l1.4-1.4 8.6 8.6 8.6-8.6L26 12z"></path></svg></button></div></div>
<p>Vue developers have wanted native for years. The <a href="https://x.com/danielkelly_io/status/1899746975588737407" target="_blank" rel="noopener noreferrer" class="rp-link">&quot;Vue + Lynx = Vue Native&quot;</a> tweet pulled 1.7k likes. The <a href="https://github.com/lynx-family/lynx/issues/193" target="_blank" rel="noopener noreferrer" class="rp-link">Vue integration issue</a> on our repo hit 1,600 upvotes — our biggest feature request ever. The demand was clear; the question was bandwidth.</p>
<p>When <a href="https://lynxjs.org/" target="_blank" rel="noopener noreferrer" class="rp-link">Lynx</a> open-sourced a year ago, <a href="https://x.com/youyuxi/status/1898663514581168173" target="_blank" rel="noopener noreferrer" class="rp-link">Evan You</a> and <a href="https://x.com/Huxpro/status/1927276405328429259" target="_blank" rel="noopener noreferrer" class="rp-link">Rich Harris</a> both shouted it out, but production-quality framework integration has always demanded serious engineering bandwidth. Then projects like <a href="https://vercel.com/blog/we-ralph-wiggumed-webstreams-to-make-them-10x-faster" target="_blank" rel="noopener noreferrer" class="rp-link">Vercel&#x27;s web streams rewrite</a> and <a href="https://blog.cloudflare.com/vinext/" target="_blank" rel="noopener noreferrer" class="rp-link">Cloudflare&#x27;s ViNext</a> showed how solo engineers, armed with AI, can ship what used to take a team. That changed the math for me.</p>
<p>Vue already has the foundation: a mature Custom Renderer API. I spent a weekend on it. One ~$1,400, 37-hour hackathon. It started with a design exploration: “Can Vue&#x27;s Custom Renderer even work with dual-thread code splitting, and how?” By 3am Sunday I was debugging “Tap to increment doesn&#x27;t work” with Claude. By Monday morning, I had <a href="https://x.com/Huxpro/status/2028672358912086524" target="_blank" rel="noopener noreferrer" class="rp-link">a working TodoMVC</a>. I couldn&#x27;t resist dropping a subtle subtweet, and it immediately took off on X.</p>
<h2 class="rp-toc-include" id="introducing-vue-lynx"><a href="#introducing-vue-lynx" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Introducing Vue Lynx</h2>
<p>The next two weeks of evenings and weekends went into making it real: 160+ commits across ~180 sessions.</p>
<div class="rp-codeblock language-text"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="text"><code><span class="line"><span>▎ Week 1   ████████████░░░░░░░░  Runtime + Toolchain</span></span>
<span class="line"><span>▎ Week 2   ░░░░░░░░████████████  Docs + Examples + i18n</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="#22a041" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg></button></div></div></div>
<p>I could have shipped after week one. But if you know me, you know my principle:</p>
<blockquote>
<p>When things actually work, you let the demos do the talking.</p>
</blockquote>
<p>Check <a href="https://vue.lynxjs.org/" target="_blank" rel="noopener noreferrer" class="rp-link">vue.lynxjs.org</a> for 20+ example apps running natively and on the web — you can try them without leaving your browser.</p>
<p>We cover the full Composition API, <code>&lt;Transition&gt;</code>, <code>&lt;Suspense&gt;</code>, and ecosystem integrations including Vue Router, Pinia, Tailwind CSS, and TanStack Query. We also ported Lynx&#x27;s official tutorial (Waterfall Gallery and Swiper) to showcase native components and Main Thread Script for zero-latency gestures. A HackerNews clone brings them all together.</p>
<h3 class="rp-toc-include" id="try-it-today"><a href="#try-it-today" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Try It Today</h3>
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">npm</span><span style="color:var(--shiki-token-string)"> create</span><span style="color:var(--shiki-token-string)"> vue-lynx@latest</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="#22a041" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg></button></div></div></div>
<p>It&#x27;s <a href="https://github.com/huxpro/vue-lynx" target="_blank" rel="noopener noreferrer" class="rp-link">open source</a>, of course. If it sparked something, give it a Star! And give some love to the <a href="https://github.com/lynx-family/lynx" target="_blank" rel="noopener noreferrer" class="rp-link">Lynx Engine</a> and <a href="https://github.com/lynx-family/lynx-stack" target="_blank" rel="noopener noreferrer" class="rp-link">Lynx Frontend Stack</a> too. They are the shoulders we&#x27;re standing on.</p>
<p>I&#x27;d love for the Vue and Lynx communities to build on it together. Issues, PRs, and feedback are all welcome.</p>
<h2 class="rp-toc-include" id="harness-engineering"><a href="#harness-engineering" class="rp-header-anchor rp-link" aria-hidden="true">#</a>“Harness” Engineering</h2>
<blockquote>
<p>You gotta use the hottest word after “AI”, “vibe”, and “agentic” — <em>harness</em>.</p>
</blockquote>
<p>No humans were harmed to write code in the making of this project.</p>
<h3 class="rp-toc-include" id="setting-up-the-architecture-for-ai"><a href="#setting-up-the-architecture-for-ai" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Setting Up the Architecture for AI</h3>
<p>There were two prior community efforts. The second, from the Vue Vine maintainer <a href="https://x.com/Shenqingchuan" target="_blank" rel="noopener noreferrer" class="rp-link">@Shenqingchuan</a>, went impressively far, <a href="https://x.com/Shenqingchuan/status/1996862232593129815" target="_blank" rel="noopener noreferrer" class="rp-link">even getting Main Thread Script demos running</a>. But both kept Vue on the main thread just like the Web. This works on Lynx, but it&#x27;s not taking advantage of the <a href="https://lynxjs.org/blog/lynx-unlock-native-for-more#use-the-main-thread-responsibly-for-interactivity" target="_blank" rel="noopener noreferrer" class="rp-link">dual-thread architecture</a> Lynx is known for: offload the heavy framework re-rendering on background and ensure the native UI thread stays non-blocking and is only tapped when needed (with Main Thread Scripts).</p>
<p>This was the core architectural decision I validated on Day 1. In Vue Lynx, the entire Vue runtime runs on the Background Thread. A lightweight <code>ShadowElement</code> linked-list tree mirrors the native element tree in memory, and every DOM mutation gets serialized into a flat ops buffer shipped to the Main Thread in one batch per tick:</p>
<div class="rp-codeblock language-text"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="text"><code><span class="line"><span>┌──────────────────────────────────────────────────────┐</span></span>
<span class="line"><span>│                  Background Thread                   │</span></span>
<span class="line"><span>│  Vue 3 runtime · reactivity · lifecycle · your code  │</span></span>
<span class="line"><span>└──────────────┬──────────────────────▲────────────────┘</span></span>
<span class="line"><span>          ops  │                      │  events</span></span>
<span class="line"><span>               ▼                      │</span></span>
<span class="line"><span>┌──────────────────────────────────────┴───────────────┐</span></span>
<span class="line"><span>│                    Main Thread                       │</span></span>
<span class="line"><span>│  Native elements · layout · rendering · MTS handlers│</span></span>
<span class="line"><span>└──────────────────────────────────────────────────────┘</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="#22a041" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg></button></div></div></div>
<p>To keep the agent aligned with this dual-threaded architecture and stop it drifting toward the single-threaded Web model it defaults to, I embedded all <a href="https://github.com/Huxpro/vue-lynx/tree/main/plans" target="_blank" rel="noopener noreferrer" class="rp-link">critical plans directly in the source tree</a>: design discussion notes, decision logs, and post-implementation learning as cross-session context. Each new session picks up where the last left off, inheriting our architectural constraints and the reasoning that shaped the code.</p>
<h3 class="rp-toc-include" id="bridging-the-vue-upstream-tests"><a href="#bridging-the-vue-upstream-tests" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Bridging the Vue Upstream Tests</h3>
<p>The most critical investment in any AI-driven development is feedback. Ideally, to ensure conformance with official Vue, we&#x27;d reuse Vue&#x27;s upstream test suite directly. But Vue&#x27;s test suite assumes a single-thread DOM. How do you run it to test a dual-thread renderer?</p>
<p>Fortunately, Lynx already has the infrastructure for <a href="https://lynxjs.org/next/api/lynx-testing-environment/index.html#lynx-jstesting-environment" target="_blank" rel="noopener noreferrer" class="rp-link">dual-threaded testing environments</a>. So we can rewire the suite to run through our dual-thread pipeline — BG <code>ShadowElement</code> → ops buffer → <code>syncFlush()</code> → MT <code>applyOps</code> → PAPI → jsdom — then let the agent grind until no remaining failures are fixable (effectively a <a href="https://ghuntley.com/loop/" target="_blank" rel="noopener noreferrer" class="rp-link">Ralph Loop</a>).</p>
<p>The result: 852 passed out of 949 upstream tests. Every failure is accounted for in a <a href="https://github.com/Huxpro/vue-lynx/blob/main/packages/upstream-tests/skiplist.json" target="_blank" rel="noopener noreferrer" class="rp-link">skiplist</a> with documented reasons, and all turned out to be negligible. See the <a href="https://github.com/Huxpro/vue-lynx/blob/main/packages/upstream-tests/README.md" target="_blank" rel="noopener noreferrer" class="rp-link">full report and skip analysis</a>.</p>
<p>We also added our own tests for Lynx-specific surface area such as <code>&lt;list&gt;</code> elements, <code>bindtap</code> events, and Main Thread Scripting APIs. With the pipeline proven, I pushed further and forked the <a href="https://vue.lynxjs.org/guide/7guis" target="_blank" rel="noopener noreferrer" class="rp-link">7GUIs benchmark</a> from the official Vue docs as a stress test.</p>
<div class="rp-codeblock language-text"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="text"><code><span class="line"><span>                BG Thread  ┃  Main Thread</span></span>
<span class="line"><span>                           ┃</span></span>
<span class="line"><span>Vue → ShadowElement → Ops  ┃  PAPI → Lynx Engine → UI</span></span>
<span class="line"><span>                           ┃</span></span>
<span class="line"><span>├─ vue runtime-core ─┤     ┃</span></span>
<span class="line"><span>├─── vue runtime-dom ──────╂──┤</span></span>
<span class="line"><span>        ├── E2E Pipeline ──╂─────────────┤</span></span>
<span class="line"><span>                           ┃         ├── Agentic ───┤</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="#22a041" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg></button></div></div></div>
<h3 class="rp-toc-include" id="agentic-e2e-verification-loop"><a href="#agentic-e2e-verification-loop" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Agentic E2E Verification Loop</h3>
<p>But those classic machinery tests can&#x27;t catch real UI bugs that used to require human evaluation: a misaligned CSS layout, an interaction broken on a real device. For advanced Vue features like <code>&lt;Transition&gt;</code> and <code>&lt;Suspense&gt;</code>, you need to see them run and interact to verify the behavior.</p>
<p>With the right harnessing, writing examples isn&#x27;t just demoing — they double as workloads that the agent can evaluate automatically. I wired up two execution environments: iOS Simulator via <a href="https://lynxjs.org/next/ai/lynx-devtool-mcp.html" target="_blank" rel="noopener noreferrer" class="rp-link">Lynx DevTool MCP</a>/CLI/Skill, and an agent-controlled browser via <a href="https://lynxjs.org/next/guide/start/integrate-with-existing-apps?platform=web" target="_blank" rel="noopener noreferrer" class="rp-link">Lynx for Web</a>. The loop is simple: run an example in both, observe and verify the output, and let any regression trigger a fix. No human in the loop.</p>
<div class="rp-codeblock language-text"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="text"><code><span class="line"><span>┌──── Fix ◀─────────────────────────────────┐</span></span>
<span class="line"><span>│                                           │</span></span>
<span class="line"><span>▼                                           │</span></span>
<span class="line"><span>Example ──┬──▶ iOS Simulator ───┬──▶ Evaluate</span></span>
<span class="line"><span>          │    (DevTool MCP)     │</span></span>
<span class="line"><span>          │                      │</span></span>
<span class="line"><span>          └──▶ Lynx for Web ─────┘</span></span>
<span class="line"><span>               (agent-browser)</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="#22a041" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg></button></div></div></div>
<p>I started with Vue core features, where correctness is well-defined: the agent reads the official docs, writes an example, and checks whether the output conforms. Then I expanded the scope to ecosystem integrations: Vue Router, Pinia, TanStack Query, and Tailwind CSS.</p>
<p>For the final exams, I tried a different approach — one I&#x27;d later learn has a name: <em>differential evaluation</em>. I let the agent port existing applications and verify the output against the originals. The first used the canonical Vue HackerNews implementation as ground truth, running both the Web version and the Vue Lynx port with Lynx for Web side-by-side in the browser; the second used existing ReactLynx demos as reference, porting them to Vue Lynx and verifying parity on the iOS Simulator via Lynx DevTool MCP. The harness doesn&#x27;t need to know what “correct” looks like in the abstract. It just needs the two outputs to agree.</p>
<div class="rp-table-scroll-container rp-scrollbar"><table><thead><tr><th>Ground Truth</th><th>Candidate</th><th>Environment</th></tr></thead><tbody><tr><td>Vue HackerNews (Web)</td><td>Vue Lynx port</td><td>Lynx Web (browser)</td></tr><tr><td>ReactLynx demos</td><td>Vue Lynx port</td><td>Lynx Native (Simulator)</td></tr></tbody></table></div>
<div class="rp-codeblock language-text"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="text"><code><span class="line"><span>                    ┌─────────────────────────────┐</span></span>
<span class="line"><span>       ┌────────────▶  ground truth ──▶       A   │</span></span>
<span class="line"><span>       │            │                         │   │</span></span>
<span class="line"><span>Input ─┤            │                      Compare ──▶ Divergence</span></span>
<span class="line"><span>       │            │                         │   │        │</span></span>
<span class="line"><span>       └────────────▶  Lynx (candidate) ──▶    B   │        ▼</span></span>
<span class="line"><span>                    └─────────────────────────────┘     Fix Loop</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="#22a041" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg></button></div></div></div>
<h3 class="rp-toc-include" id="the-bill"><a href="#the-bill" class="rp-header-anchor rp-link" aria-hidden="true">#</a>The Bill</h3>
<div class="rp-codeblock language-text"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="text"><code><span class="line"><span>┌──────────────────────────────────────────┐</span></span>
<span class="line"><span>│ The Bill (at Opus rate)                  │</span></span>
<span class="line"><span>├──────────────────────────────┬───────────┤</span></span>
<span class="line"><span>│ Input (3.8M tokens)          │ $      57 │</span></span>
<span class="line"><span>│ Output (6.8M tokens)         │ $     510 │</span></span>
<span class="line"><span>│ Cache Write (117.9M tokens)  │ $   2,211 │</span></span>
<span class="line"><span>│ Cache Read (2.5B tokens)     │ $   3,769 │</span></span>
<span class="line"><span>├──────────────────────────────┼───────────┤</span></span>
<span class="line"><span>│ TOTAL                        │ $   6,547 │</span></span>
<span class="line"><span>└──────────────────────────────┴───────────┘</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="#22a041" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" d="M20 8v12H8V8zm0-2H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2"></path><path fill="currentColor" d="M4 16H2V4a2 2 0 0 1 2-2h12v2H4Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="#49cd37" d="m9.55 18-5.7-5.7 1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"></path></svg></button></div></div></div>
<p>The numbers tell a story. Output tokens — the code and text Claude actually <em>wrote</em> — account for just 8% of the cost. The other 92% is comprehension: re-reading the codebase, ingesting tool outputs, and re-processing conversation history across 31,700 API turns. That&#x27;s 2.5 billion tokens of reading to produce 6.8 million tokens of writing — a 370:1 ratio. This is what “agentic” actually looks like at the billing level.</p>
<p>Was the “$6,500” API rate worth it? Claude <a href="https://x.com/Huxpro/status/2031973188440052119" target="_blank" rel="noopener noreferrer" class="rp-link">gifted me</a> the $200 Claude Max through <a href="https://x.com/Huxpro/status/2031973188440052119" target="_blank" rel="noopener noreferrer" class="rp-link">its Open Source program</a>, thankfully.</p>
<h2 class="rp-toc-include" id="whats-next"><a href="#whats-next" class="rp-header-anchor rp-link" aria-hidden="true">#</a>What&#x27;s Next?</h2>
<p>This project started as one person&#x27;s nights-and-weekends effort. I&#x27;d love to explore with the Vue core team how we can shape the future of Vue on native together. Personally, and on behalf of the Lynx team, we&#x27;re committed to supporting its growth.</p>
<p>Vue Lynx is pre-alpha. The architecture is solid, but Vue&#x27;s API surface is large, and we haven&#x27;t verified every corner of it.</p>
<ul>
<li>Features like <code>KeepAlive</code> and <code>Teleport</code> likely need runtime adaptations.</li>
<li><code>&lt;style scoped&gt;</code> and <code>v-model</code> on native inputs are solvable but not yet implemented.</li>
<li>The Main Thread Script API currently reuses ReactLynx&#x27;s directive-based design. A more Vue-idiomatic approach (like <code>&lt;script main-thread setup&gt;</code>) is worth exploring.</li>
<li>Vue DevTools integration with the Lynx DevTool app.</li>
</ul>
<p>And beyond Vue core, there&#x27;s a massive Vue ecosystem waiting for us to adapt and grow on native.</p>
<p>The vision is simple: Vue developers should be able to ship native apps as naturally as they ship for the web today. We&#x27;re not there yet, but the foundation is in place, and the path is clear.</p>
<p>If you&#x27;ve read this far: <a href="https://vue.lynxjs.org/" target="_blank" rel="noopener noreferrer" class="rp-link">try it</a>. Build something. Tell us what&#x27;s missing.</p>
<p>Oh, and by the way: <a href="https://x.com/Huxpro/status/2032279225479176229" target="_blank" rel="noopener noreferrer" class="rp-link">Lynx was initially created with Vue 2</a>.</p>
<hr/>
<p>Originally published as an <a href="https://x.com/Huxpro/status/2036993665965416601" target="_blank" rel="noopener noreferrer" class="rp-link">X Article</a> on March 26, 2026.</p><!--/$-->]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vue Lynx Blog]]></title>
            <link>https://vue.lynxjs.org/blog/</link>
            <guid isPermaLink="false">/blog/</guid>
            <content:encoded><![CDATA[<BlogList />
]]></content:encoded>
        </item>
    </channel>
</rss>