Enhancing CSS Editing with LLMs: Using Puppeteer for Visual Context
In this presentation, Ryan explores a practical approach to editing CSS with Large Language Models (LLMs), focusing on creating a virtuous cycle of design improvements. He highlights the challenges of working with CSS, particularly for developers familiar with older versions who may struggle with modern CSS syntax and styles. Ryan points out that CSS can be complex, with styles defined in multiple locations, making it difficult to track changes and understand their impact across large codebases that may contain thousands of lines of code spread across numerous files. Ryan demonstrates an innovative solution using Puppeteer through an MCP (Model Control Protocol) server to take screenshots of local websites. This approach allows the LLM to see the visual representation of the site, providing crucial context for making informed CSS recommendations. Throughout the demonstration, Ryan shows how to set up and configure the MCP server, start a local PHP server to host the test site, and use Gemini 2.5 Pro to suggest and implement CSS changes. Despite some workflow challenges such as needing to approve screenshot captures manually, Ryan emphasizes the speed advantages of this approach, noting that the quick feedback cycle creates an efficient workflow that almost mimics real-time browser editing but with AI assistance. The demonstration concludes with a successful modification to the header styling, illustrating the potential of this visual-context approach to AI-assisted CSS editing.
Jump To
- 🕒 Introduction to editing CSS with LLMs
- 🕒 Challenges with CSS complexity and versioning
- 🕒 Examining the AI tools lab website and its extensive CSS
- 🕒 Introduction to using Puppeteer for visual context
- 🕒 Setting up PHP to serve the static website locally
- 🕒 First attempt at querying without Puppeteer enabled
- 🕒 Enabling Puppeteer in the MCP server settings
- 🕒 Dealing with screenshot approval requirements
- 🕒 Getting CSS suggestions based on the screenshot
- 🕒 Testing CSS changes in a safe test branch
- 🕒 Handling stalled screenshots and retrying
- 🕒 Reviewing the implemented header style changes
Resources
- Puppeteer - Headless browser automation library for taking screenshots of websites
- Model Control Protocol (MCP) - Protocol for connecting AI models to external tools like Puppeteer
- Gemini 2.5 Pro - Google's LLM used in the demonstration for CSS suggestions
- PHP local server - Used to serve static website files locally for testing
- CSS documentation - Mozilla's comprehensive guide to CSS properties and syntax
Key Takeaways
- Using visual context through screenshots helps LLMs make better CSS editing decisions than relying on text alone
- Puppeteer integration with LLMs creates a virtuous feedback cycle for quickly iterating on design changes
- The MCP (Model Control Protocol) server is essential for allowing LLMs to interact with local development environments
- Working in a test branch provides a safe environment for experimenting with AI-suggested CSS changes
- Despite requiring manual approval for screenshots, the workflow with Gemini 2.5 Pro is fast enough to create an efficient development experience
Full Transcript
[00:00:00] Ryan: Today I figured we'd talk about editing CSS with LLMs and in particular, I'm going to talk about a way of going back and forth, like a virtuous cycle when you're dealing with design and how you can deal with LLMs. Traditionally when dealing with LLMs, you'd probably be using text basically.
You grab this, you chat, you ask, Hey, what it look like, that kind of thing. The problem that I found with CSS is that it can be defined in a number of different places. it can be quite complicated, and the version of CSS that I know I feel is CSS one as opposed to CSS two or CSS three, which I think is current and as a result, I'm just not familiar with how things are defined, the syntax, the styles all that type of stuff. Going into this, we've got our AI tool site, which I'll show off here. So if we go to AI tools lab so we can see that it's got success, everything's set up here. It's got like a different way of marking out different things, got different fonts, there's quite a few different styles at play here. In fact, if you look at this document, you can see there's actually quite a bit of context. So if we scroll down here, I feel like it's got. Maybe 2000 lines. Maybe 3000 lines. Okay. 3000. And then on top of that, each of these pages may actually have styles in them as well.
[00:01:00] And sometimes they can be up to a hundred lines. So it can be a lot to figure out what's going on. In the past what I've done is use things like synthetics as like a post test kind of thing. But in this case, what I'm going to do is use puppeteer. In order to pull up our website, take a screenshot, and have the LLM use that screenshot when making decisions.
In fact, I'd like you to check that everything's fine prior to making changes Now. MCP servers can be problematic to run depending on how they're set up. In this case, what I'm going to do is use NPX, that's NPX, what you see here, and it's pretty straightforward, but I wanna say if you're using a few MCP servers already, you'll probably want to grab just this portion.
Okay, so we've got the MCP block and then the full block itself, but just the inside. So what you want to add, now, that being said, if you're brand new to using MCP series, you're probably going to grab this whole thing. So let's show you where that is in cursor. So if we click on settings up here to the right, and then click on MCP, you can see that I've got it set up already as well as the non-working one below it in Docker.
[00:02:00] So if you go through here, you can actually see that this is set up.
We can see that it's enabled. I'm going to turn it off first to show you what the experience looks like when you don't have an MCP service. Basically what happens is when you're asking things about a local website, it's not going to run. A couple things here. We wanna start this website now. I've been using PHP for a long time, so I happen to know that you can run PHP into any folder and it will just serve the static case ML for you.
Not a problem whatsoever. What I want to do, on the other hand, is make sure that it's installed. 'cause I don't think it's installed by default in most new max server builds. But I think I, I actually brew installed this earlier, so it should work. Okay. Looks like it started, which is great. We have puppeteer turned off right now.
The MCP server is not turned on, but what we're going to do is try to query that site to see what's going on. So let's see. Let's pop all the way to the top and let's see what the effect of this is on the code. For example, we'll ask it to open local Host 80 80, which we just started.
[00:03:00] And we wanna see what this does on that page. If this is affecting the page or something else somewhere is 'cause casing skull sheets, it's in the name, but they can cascade down and your styles could be defined at the root or in the ht ML, it could be all over the place kind of thing. Now in this case, it looks like, oh, excellent.
It's given me some stuff in here, but it actually can't. Access that logo. What we're going to do is go back into here and we'll turn on Puppeteer. I'm refreshing just because sometimes it doesn't seem to pick it up, but we're going to do that query again if we go up here. Okay. Sorry.
We've used this a couple times. So let's scroll up right to the top and right here. We'll try again. So we're gonna do the same thing. Try again. The model we're using today is Gemini 2.5 Pro, but what we're going to do is see if it can actually open up that host and do things. I happen to be running this before, we'll see if it pulls up here, but it doesn't seem to, so it tells me that something's actually wrong, which is fine ... this does happen, but I feel like it's not actually doing anything.
[00:04:00] Use MCP puppeteer, oops. See if that works. I found that sometimes the first query that you use requires specifying this though. After that it doesn't seem to be required. So let's see if this will actually work.
There we go. This is what I was getting at is I know I'm using it because it'll ask for approval, which is kind of a pain. I'm looking for a way to turn this off at the moment. But basically it's the only thing standing between me and this virtuous cycle is making sure that when I click this, that it runs and I don't have to click it every time.
You can see that it popped up a headless Google Chrome browser and that it's waiting for approval here. We'll accept that. It's taking the screenshot so we should be okay. Alright, quick demo, but you can see what it's done is actually looked at our screenshot running the MCP server and it's getting us suggestions based on the screenshot.
[00:05:00] What we can do is... we can actually have it change the file, but what we wanna do is make sure that everything is proper before you go ahead.
Okay, so it seems like everything should be good.
Let's see if it works. Now again, we should see those popups here letting us know that's actually hitting the site. And in fact, in here we can see the logs as well. Styles...
and so it actually knows that some of these need to be modified. I think because I'm in the same chat from before I just happen to know that some of these styles are defined both in the index as well, as in the style. So I guess we're cheating with the context here, and we'll see if that goes through.
[00:06:00] Okay. Excellent. And again, Gemini 2.5 Pro is pretty fast.
What I really like about it is that it comes back really quickly. So that virtuous cycle that I was talking about is really short. It's fast for me to change things , almost as if I was adding code in the browser and then saving it out, which is actually pretty handy.
Okay, it's gonna go through this in a moment and it's gonna go through we're on a test branch here, so we should be. Okay. Let's just confirm yes, we are in fact on test, which is good. Alright. It looks like you're going through. Now. One thing that might be handy in this kind of mode is to use yolo -essentially have it auto approve everything. Let's say I'm opting for caution, but we are in the test branch, so it's not that risky. But generally I'm a little bit more hesitant to use that mode. Okay, so it didn't actually test using the MCP server. And is asking me to look but I'd rather it do the work for me, I'm saying test here, but I'm hoping that it knows that "test" is to take a screenshot.
[00:07:00] Sometimes it does not. There we go. It does in fact, and again, this depends on your context as you're going along but I have found the second or third time that you go through it will in fact pick up what you're trying to actually get it to do.
I think it's made some changes. Now it should be running the site and then opening it up, pulling a screenshot. Sometimes I found that it can stall here on the screenshot and it may not work. What I found is that just restarting this can help and then you're gonna see that I'm just kinda run the same thing again and this should work.
If not, we may have to. Okay, that seems to be good. Let's see if I can pull up the page again. We should see the browser window pop up, excellent, and then we save the screenshot. It should be quite fast. Okay. It seems to have... excellent. And let's have a look at it. So did it change anything? Yes. In fact, this header has changed. And it looks like none of the other changes that we wanted to change. Good. But we did at least change the header. I would say it probably changed it for the worse, but at least something has changed. So all this to say what I'm talking about today is MCP tools in particular Puppeteer.
[00:08:00] The ways of actually taking screenshots with Mac is a bit of a pain. That being said, having to approve things to take screenshots, isn't that great? I'd like to get rid of that in terms of a virtuous cycle, like being able to go really fast when I'm doing my code, but I think this is a good, quick demo of how things can work.