


























The opinions stated here are my own, not necessarily those of my employer.
Over the past few weeks I’ve been thinking about how we can make a framework easier for AI. In particular I’ve been only focused on building user interface. When we add a backend, database, and communication protocol across the backend and the frontend, we get another set of problems that could be a good fit for another post and exploration.
Looking at the current landscape of platforms for “vibe coding” I see two main problems:
You can find the code from this experiment on GitHub.
There are a variety of solutions to these problems. For example:
I decided to solve these problems by building a framework!
The LLM-first framework I created has the following design:
I based this LLM-first framework on Revolt with one major change - the framework gets all text node and attribute values by invoking a getter function. This way, the framework accesses reactive and static values in the same way.
For example instead of specifying the value of the text node and the style attribute as text values, I’d use functions.
const HelloWorld = () => {
return {
name: "div",
children: () => "Hello, World!",
attributes: {
style: () => "color: red;"
}
};
};
This makes it easier for the LLM to produce working code. It doesn’t have to “understand” the difference between a static and reactive value.
I had a few spare hours and built a “vibe coding” platform that generates Revolt apps.
You can find the source code on GitHub.
Here’s a quick demo video:
The first (and only) draft of the system prompt I came up with:
You are a senior web developer who is expert in using signals in JavaScript. Create an application
based on a user prompt. For the purpose, use the framework and the examples of apps implemented in
this framework below:
// Framework implementation
// A couple of basic component examples
// Todo example, intentionally skipped
// Tetris example, intentionally skipped
Output the application as syntactically correct and executable JavaScript and will render the app on the screen.
All the styles of the application should be inlined under the style attribute of each element.
Use a dark theme for all the applications you generate.
Give your output in the format:
<revolt-response>
<revolt-explanation>
Explanation in up to 3 sentences and without any newlines
</revolt-explanation>
<revolt-code>
The code
</revolt-code>
</revolt-response>
For example:
<revolt-response>
<revolt-explanation>
Here is a simple hello world app
</revolt-explanation>
<revolt-code>
const HelloWorld = () => {
return {
name: "div",
children: () => "Hello, World!",
attributes: {
style: () => "color: red;"
}
};
};
render(HelloWorld(), document.body);
</revolt-code>
</revolt-response>
All future prompts will be from the user in the format:
User prompt: <prompt>
In Revolt LLM, I decided to keep chat history for the past two prompts and responses to provide a little extra context to the LLM. This works well for flows such as:
> User: Create a todo app
> LLM: [output]
> User: Change the color of the delete button to red
> LLM: [output]
In the example above, in addition to the “Change the color…” prompt, the LLM will also receive the previous prompt and output it produced.
Another potential path forward is to use Revolt as an intermediate representation to generate code that uses a general purpose framework such as Angular or React. Technologies like mitosis use a similar technique for other use cases.
Revolt as an IR
This way we get the benefit of avoiding version skew since we pass Revolt in the context window. At the same time, the final output is code that uses a general purpose framework. In the compiler that transforms Revolt to Angular/React, we can hardcode rules that ensure the output uses the latest general purpose framework APIs.
Generating code that uses a general purpose framework allows developers to debug a technology they are familiar with and get a better interop with the corresponding framework ecosystem.
The three different approaches we discussed are:
All the three approaches have their trade-offs. I can definitely see a future in which an entire product will be based on a LLM-first framework and will provide a component model, together with integrations with other platforms.
In the short-term, I see how tools will primarily use the first approach and fallback to the third one in case of highly personalized user interface.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。