Antigravity as web developer on ancient and obscure technology (AI in an IDE)

A collaboration between John Morgan and Philip Greenspun.

This is a follow-up to LLMs to replace dead programmers who worked in dead languages (ChatGPT updates AOLserver Tcl API code).

We set Antigravity loose on a directory of AOLserver code behind philip.greenspun.com. The code base includes ArsDigita Community System, AOLserver configuration, and an installation of WordPress that was bolted on later. Antigravity was configured to use Gemini 3 Pro as the LLM.

Question 1

This is a directory for a web site called philip.greenspun.com. The page root is the www directory. If the / file is requested what is served is philip-home.html . What causes this file to be served instead of index.html and what functions process philip-home.html before it goes out to the browser?

Answer 1 (after 6 seconds)

Identified that
index.tcl
handles the root request, reads SpecialIndexPage parameter from
parameters/philip.tcl
(set to
philip-home.html
), and serves it using ns_returnfile without content processing.

Here is what I found regarding the serving of 

philip-home.html

:

1. Why 

philip-home.html

 is served instead of 

index.html

: The file 

www/index.tcl

 is the default directory index file (prioritized by the server configuration 

DirectoryFile

 in 

config/philip.tcl

). When 

index.tcl

 executes, it checks for a parameter named 

SpecialIndexPage

. This parameter is defined in 

parameters/philip.tcl

 (line 269) as: 

ns_param SpecialIndexPage /philip-home.html

 Because this parameter is set, 

index.tcl

 serves this file immediately.

2. What functions process 

philip-home.html

: The file itself is not processed by any template functions (like ADP parsing) because:

  • It is served via the  ns_returnfile  command in  index.tcl , which bypasses the ADP parser.
  • The  .html  extension is not mapped to the ADP parser in  config/philip.tcl  (only  .adp  is).

The functions in 

index.tcl

 that lead to the file being served are:

  • ad_parameter  (to retrieve the  SpecialIndexPage  value)
  • empty_string_p  (to check if the parameter is set)
  • ns_info pageroot  (to construct the full path for the existence check)
  • file exists  (to verify the file is there)
  • ns_url2file  (to get the absolute path for  ns_returnfile )
  • ns_returnfile  (to send the file content to the browser)

Question 2

What HTTP server is this code written for and that is likely being used for the live site?

Answer 2 (immediate)

Based on the codebase analysis, the site is written for AOLserver. … [extension explanation] … It is likely running AOLserver 4.5 (or potentially a compatible version of NaviServer) given the explicit path references in the configuration.

Question about ADP tags (a niche technology copied from Microsoft ASP)

[After browsing to /photography/learn/interior.adp] Where is the photonetheader ADP tag used in this file defined?

Answer re: ADP

Question about where to tweak

I want to modify either this function or the ad_header function that it calls to add a viewport META tag to the HEAD of every ADP page that is served. Which function should be modified and what would the modification look like?

Answer about where to tweak

I recommend modifying ad_header in d:\Backups\philip.greenspun.com\philip\tcl\2-hooks.tcl because this file already acts as a “hook” to inject content (currently a CSS file) into the header of all pages. This ensures the viewport tag is applied globally, including all ADP pages.

I have created an implementation plan to make this change.

Error: below is a fragment of the current file.

append extra_stuff_for_document_head "<LINK REL=STYLESHEET HREF=\"/margins-and-ads.css\" TYPE=\"text/css\">\n"

Unless wrapped in {}, the quotes within the META tag to be added need to be escaped with backslashes. Antigravity doesn’t mention this.

Question about home page rendering

I modified this file on my dev server to include a viewport META tag, but it still doesn’t render well on mobile because the image on the left is much too large. What can I do with CSS to make this look good on mobile?

Answer

Conclusion

Antigravity can be a significant time-saver when you’re groping around a code base that you don’t understand, either because you never understood it or haven’t touched it for 20 years. Much of a programmer’s time on legacy code is figuring out what files are relevant and where a reasonable place might be to insert a required modification. Antigravity is a great shortcut.

Full post, including comments

LLMs to replace dead programmers who worked in dead languages (ChatGPT updates AOLserver Tcl API code)

More from John Morgan and Philip Greenspun on using AI when doing web development…

Intro from Philip

In 1994, when I built my first web services backed by relational database management (RDBMS) systems, every request to an HTTP (Web) server resulted in an expensive fork, i.e., the spawning of a new process within the Unix operating system. If the request was for a small computer program to run, rather than a static file from the file system, that resulted in a second fork for a CGI script. If there was a need to refer to information in an RDBMS, such as Oracle, the CGI script would initiate the login process to the RDBMS, which would check username and password and… initiate another fork for a new process to handle what would ordinarily be 8 hours of SQL requests from a human user at a desktop in the 1980s client/server world. So that would be three new processes created on the server in order to handle a request for a web page. All would be torn down once the page had been delivered to the user. Consider how much longer it takes to start up Microsoft Word on your desktop computer than it does for Word to respond to a command. That’s the difference between starting up a program as a new process and interacting with an already-running program. Here’s an illustration of the four processes ultimately involved. The top one is the user’s browser. The three below that were spawned to handle a single request.

NaviServer (later “AOLserver” after NaviSoft’s acquisition by AOL) was the first web server to combine the following:

  • multi-threading, enabling a request for a static file to be served without a fork
  • internal API, enabling small programs that generated web pages to run within the web server’s process, thus eliminating the CGI fork
  • pooling of database connections, e.g., four persistent connections to an RDBMS that could be used to handle queries from thousands of requests, thus eliminating the fork of an RDBMS server process to handle a “new” client on every request

The available languages for page scripts that could run inside the AOLserver were C (macho, compiled, slow for development, potential to destroy the entire web server, not just break a single page, with one mistake; see the API) and Tcl (embarrassing to admit using, simple, interpreted, safe; see the API).

As the architect of the information systems that would be available to all of Hearst Corporation‘s newspapers, magazines, radio stations, TV stations, cable networks, etc., I selected the then-new NaviServer in late 1994 in order to achieve (1) high performance with minimal server hardware investment, and (2) high developer productivity. The result was that I developed a lot of code in Tcl, a language that I hadn’t used before. It didn’t seem to matter because the Tcl was generally just glue between an HTML template and a SQL query. The real programming and design effort went into the SQL (are we asking for and presenting the correct information? Will comments, orders, and other updates from hundreds of simultaneous readers be recorded correctly and with transactional integrity in the event of a server failure?) and the HTML (will the reader be able to understand and use the information? Will comments, orders, and other updates from the reader be easy to make?).

Just a few years later, of course, other companies caught up to AOLserver’s threaded+scripts inside the server+database connection pools architecture, most notably Microsoft’s Internet Information Server (IIS). Eventually the open source folks caught up to AOLserver as well, with a variety of Apache plug-ins. And then I persuaded America Online to open-source AOLserver.

Here we are 32 years later and I’m still running code that we wrote at Hearst. The company was interested in publishing, not software products, so they graciously allowed me to use whatever I wrote at Hearst on my own photo.net web site and, ultimately, to release the code as part of the free open-source ArsDigita Community System (adopted by about 10,000 sites worldwide, including some at Oracle, Siemens, the World Bank, Zipcar, and a bunch of universities).

[One fun interaction: in 2012, I was at a social gathering with a developer from the Berklee School of Music (Boston). He talked about some legacy software in a horrible computer language that nobody knew that they had been using for 10 years to track and organize all of their courses, students, teachers, assignments, grades, etc. They’d had multiple expensive failed projects to try to transition to newer fancier commercial tools and finally, at enormous cost in dollars and time, had succeeded getting away from the hated legacy system. It turned out that he was talking about the .LRN module that we’d developed for the MIT Sloan School in the 1990s and that was then rolled into the open-source toolkit. I kept quiet about my role in what had turned into a pain point for Berklee’s IT folks…]

Our Project

As part of our experimentation with AI and web design, we asked LLMs to do some redesign work on philip.greenspun.com. They all came back and said that it would be necessary to modify the HTML flying out of the server and not merely an already-referenced CSS file. It would be technically feasible, of course, to write a script to run on the server to open up every HTML file and add

<meta name="viewport" content="width=device-width, initial-scale=1">

to the HEAD of every document before writing it back into the file system. This would, however, have the side effect of updating all of the last-modified dates on files that, in fact, hadn’t been touched for decades (fixable with a little more scripting) and also creating a blizzard of updates to the git version control system.

The server was already set up with a standard ArsDigita Community System feature in which a Tcl procedure would be run for every HTML file request. This obviously reduces performance, but it enables legacy static HTML pages to be augmented with navigation bars, comment links, comments pulled from the RDBMS, advertising JavaScript, extra footers or headers, etc. Instead of modifying every HTML file under the page root, in other words, we could simply modify this function to add whatever tags we wanted in the head.

The questions:

  • Would an LLM be able to understand a Tcl program that had grown over the decades into a confusing hairball?
  • Would an LLM be able to do a minimalist modification of the program to insert the one line that was needed?
  • Would an LLM be able to reorganize the software for improved legibility, modularity, and maintainability?

The original

The original file is about 500 lines long and contains 18 procedures. The LLM will have to figure out which procedure to modify and then pick the best place within the procedure.

If a human programmer were to do an insertion with minimum risk of breaking everything, it would probably be around line 185. The file has been read and is sitting in a variable called “whole_page”. Even if there is a “do not disturb” tag within the page (i.e., don’t try to add comments or ads) it would still make sense to add this modern META tag in the output at line 189.

The prompt

Can you add one small feature to this AOLserver Tcl program, making as few changes as possible? It implements a procedure that runs every time a .html page is requested from the server and may add comment links, Google ads, navigation bars, and other items to legacy static pages. I want it to add “<meta name=”viewport” content=”width=device-width, initial-scale=1″>” to the HEAD of every outgoing page. Please tell me the line numbers of the file where you’ve changed, inserted, or deleted anything.

Grok can’t count

Grok finds the same location that a human programmer would, but either can’t count or numbers the lines differently from how Notepad++ and Emacs count/number. What’s at line 185 in Notepad++ and perhaps 187 in Emacs is 105-110 for Grok:

Grok helpfully offers to enhance this a bit:

Grok is capable of explaining its regsub command. Here’s part of the explanation:

Grade: A! (would have been A+ if the line counting corresponded to how text editors count lines)

ChatGPT gets an A++

It took 3.5 minutes for ChatGPT to wrap its Hopper architecture brain (assuming H200 chips) around Tcl, but the results were spectacular. Unlike Grok, it counts the lines correctly. Also unlike Grok, it puts the new META tag in a variable so that changing the META tag doesn’t risk breaking the regexp. ChatGPT also prepares an updated file for download.

ChatGPT is kind of like Air Traffic Control in dealing with humans who are making mistakes. Instead of pointing out “You’re going in the wrong direction,” ATC will generally ask the pilot to “Say heading” or just say “Turn left heading 180” (if 180 was the correct heading to fly). ChatGPT recognizes that only a stupid human would want to insert the viewport META tag into an HTML page that already has one and it just includes the regexp check in an IF statement before the regsub operation: A++!

Claude gets a B-

Unlike ChatGPT, Claude runs its regsub without first checking to see if there is already a viewport META tag. Unlike Grok, it doesn’t offer an improved version that does perform a check. Unlike both ChatGPT and Grok, Claude puts this important code after the DND pages have been served and also after some random Amazon ad tags has been searched for. Like Grok, Claude puts the new meta tag right in the regsub statement, thus making maintenance riskier.

Claude has a convenient side-by-side layout for working with code.

Credit: Claude takes the interesting approach of looking for the closing HEAD tag rather than the opening one. This avoids having to have a more complex matching pattern. That lifts Claude from a C to a B-.

Gemini Pro (C isn’t just for memory leaks)

Gemini Pro combines all of the worst features of the other LLMs. It counts lines idiosyncratically, like Grok. It fails to use the /HEAD tag and also fails to do a matching pattern that will match HEAD tags with attributes. It chooses the wrong part of the file and, unlike Claude, either lacks awareness that this means a lot of DND pages will be served without the viewport tag or chooses not to explain the implication of the placement after the DND pages are served.

Antigravity

Antigravity backed by Gemini takes a slightly different approach than we saw from Gemini in the previous test. It puts the regsub after the DND pages, but before the Amazon ads. It matches a HEAD tag with additional attributes. Grade: B

Interestingly the Antigravity chat interface gives us insight into the reasoning that led to this result. In this case we see that Gemini chose this placement location not because it failed to understand the relevance of the DND option but rather because it interpreted the “do not disturb” concept that it found in the code to be a more important than the prompt’s instruction to apply the <meta> tag to all pages. As it came up with its plan it changed its mind back and forth before ultimately deciding that the best compromise was to place the code after the DND check:

  • I’m now grappling with the implications of “Do Not Disturb” pages. Lines 189 and beyond are relevant. The existing logic immediately returns $whole_page if the tag is present, implying an “unmolested” state. The user requested adding to “every outgoing page.” However, “unmolested” suggests no modifications, contradicting the user’s intent if the request is taken literally. I’m leaning toward not inserting the viewport tag if the DND tag exists, as that aligns with the script’s and the variable names’, intended functionality.
  • I’m now carefully considering the implications of inserting the viewport meta tag in the context of “Do Not Disturb” (DND) pages, aiming to
Full post, including comments

Antigravity as web developer (AI in an IDE)

As noted in previous posts, the web chat interface can be a cumbersome method of interacting with an LLM for the purpose of web development tasks such as adding a CSS file to an HTML page to make it render nicely on smartphones.

What if we try artificial intelligence as a companion to a programmer’s integrated development environment (IDE)? Google’s $2.4 billion baby, Antigravity, is the contender for this post, a collaboration between John Morgan and Philip Greenspun.

Installing Antigravity immediately presents the new user with a challenging question: Review-driven development vs. Agent-driven development. There is no explanation on the setup screen as to what the difference between these two might be:

Antigravity’s default user interface presents the developer with three panes: a file explorer on the left, a code editor in the middle, and an LLM chat interface on the right. We start this experiment by opening a folder we’ve created named bh-antigravity-gemini that contains the HTML for the decidedly archaic Berkshire Hathaway homepage and proceeding to write a prompt asking to generate CSS and edit the page’s HTML to make it responsive:

Antigravity offers a variety of models to choose from but for the purposes of this experiment we’ll use the default which is Gemini 3 Pro (High) in Planning mode. Planning mode causes Gemini to come up with plans before implementing them. After submitting the prompt Gemini begins to think through a plan:

As Gemini works to develop a plan Antigravity presents a Task document showing the steps to be taken:

Once Gemini has come up with its plan Antigravity presents us with an Implementation Plan document outlining the proposed changes as well as a verification plan:

Since the plan sounds sensible we instruct Gemini to implement it:

Once Gemini completes the task Antigravity presents us with a Walkthrough document with an overview of the results of completing the task:

Below the message announcing the completion of the task Antigravity presents us with a list of files that have been changed including counts for lines added and removed. Just below the list is a button to “Accept all” changes. We want to inspect the changes for ourselves first so we select the berkshire-hathaway.htm file to see what was added. Sure enough, Gemini has kept the changes to a minimum as requested and simply inserted a viewport <meta> tag and a <link> to incorporate the newly created stylesheet:

We accept the changes in the HTML and move on to examine the newly created style.css file. The CSS includes comments indicating that Gemini has tailored it to match the styling present in the original HTML while implementing the proposed changes to make the page responsive:

Satisfied with its suggestions we accept the changes and proceed to view the results. The images below are the original page as viewed on desktop followed by the new page as viewed on desktop. As promised Gemini has kept the desktop styling largely the same with the primary difference being greater spacing between links:

The images below are the original page as viewed on mobile followed by the new page as viewed on mobile. The new CSS has transformed the page such that it is no longer rendered as it would be on desktop but instead presents the links as a single column with text that is readable and easy to select without needing to zoom.

The quality of Gemini’s code generation in this experiment appears comparable to what we saw from it in our previous comparison of ChatGPT, Claude, Gemini, and Grok. This is not surprising as Antigravity is merely another interface for a developer to interact with an LLM such as Gemini.

Our conclusion is that having AI integrated tightly into the IDE where the chat log is presented and persisted alongside the code and the model can be quickly directed to analyze files within the codebase without the need to paste them into a chat window or manually upload them via a web interface saves time and leads to a more organized and less fragmented experience. We also find that the IDE’s ability to highlight proposed changes and allow us to accept or reject them and edit our files in place achieves a level of integration into the development workflow that a web chat interface cannot match.

Full post, including comments

AI competition for the redesign of a site that already has CSS

In our last post, John Morgan and Philip Greenspun compared four LLMs to see how they would do on redesigning the Berkshire Hathaway home page, an HTML relic of the 1990s untainted by CSS. Today we’ll give AI a tougher challenge: redesign the philip.greenspun.com site from four sample HTML files and the CSS that is referenced by them. The contenders are ChatGPT, Grok, Gemini, and Claude.

The Prompt

I want to update the CSS on a web site so that it renders nicely on mobile and, ideally, has an improved look on desktop as well. I’d like to not make too many changes to the HTML, though I could add a viewport meta tag in the head of every HTML file, for example. I’m going to upload four sample HTML files from this site and two CSS files that are referenced (margins-and-ads.css is the one that nearly all pages on the site reference). Please send me back new CSS and any changes that you think would be worth doing on all of the HTML pages on the site.

Sample Pages on Desktop Before (Chrome)

Sample Pages on Mobile Before (iPhone 17 Pro Max, Chrome)

Comment from Philip: I’m grateful to John for not looking at these and asking, “Did you think that mobile web browsing was a fad and would go away?” (on the actual device they all are absurdly small and hard to read)

from ChatGPT 5.2

Below is a “drop-in” modernization that keeps your existing HTML working, but makes it responsive on phones and nicer on desktop—without needing structural HTML changes.

It’s designed around what I see in your samples:

  • Most pages pull in margins-and-ads.css and currently just set big left/right margins plus floats for images/ads/notes. margins-and-ads
  • Some pages also include philg.css for paragraph spacing/indents and note backgrounds. philg
  • Layout is often “classic HTML”: <body bgcolor=...> , <center> , <table> for header layout, images with align/hspace/vspace , etc. Philip Greenspun on Photography Travels with Samantha Home
  • Photo pages use <div class="minigallery">…</div> with <br><br> breaks. How to Photograph Architecture …
  • Some pages include custom elements like <photonetpage> / <photonetpagenav> and <product…> tags. How to Photograph Architecture … How to Photograph Architecture …
  • p.marginnote exists and is sometimes floated right at 25% width (bad on mobile). margins-and-ads

One small HTML change I recommend on every page

Add this inside <head> :

<meta name="viewport" content="width=device-width, initial-scale=1">

That alone fixes a lot of “tiny text / zoomed-out” mobile behavior.

(Your pages currently don’t have this viewport meta in the sample heads. Philip Greenspun on Photography Travels with Samantha Home)

Optional but nice (safe even with older markup):

<meta name=”color-scheme” content=”light”>

Why these changes help (mapped to your existing markup)

  • Big fixed margins become mobile-friendly padding: your current body {margin-left/right: 3em} can still be too wide or awkward on phones. margins-and-ads
  • Floats collapse on mobile: images with align="right" and your .illustration floats (plus margin notes/ads) are the #1 cause of “narrow column” mobile misery. Philip Greenspun on Photography margins-and-ads
  • minigallery becomes usable: instead of relying on <br><br> breaks, it wraps naturally and centers on small screens. How to Photograph Architecture …
  • Layout tables stack: your header table (image + title) won’t force sideways scrolling. Philip Greenspun on Photography
  • Custom tags display correctly: <photonetpage> / <photonetpagenav> should behave like block containers. How to Photograph Architecture …

If you’re willing to do one more (still small) HTML improvement later

Not required, but high value over time:

  1. Remove bgcolor / text attributes from <body> and let CSS control it. (Right now you set it in HTML on many pages. Philip Greenspun on Photography)
  2. Replace <center> blocks with CSS classes (centering via CSS is more controllable). Travels with Samantha Home

But again: the CSS above works even if you do none of that.


If you want, I can also generate a tiny “smoke test” checklist (pages to open + what to verify) based on these exact sample files (header table, minigallery , marginnote , and a long chapter page).

[after asking for the checklist]

After ChatGPT

A huge amount of screen space is wasted when the browser is opened at my usual width:

Maybe ChatGPT is right that this is about as wide as a column of text should be, but on a site without ads it doesn’t look right and denies the user the choice to get more content on his or her screen. My previous style sheets didn’t set a font, which enabled the browser to default to whatever the browser authors thought was best or whatever the user had chosen via customization (of course, it would be a rare user who’d take the trouble). ChatGPT has hard-coded in a sans-serif font. Asked why, ChatGPT explains:

But then it backpedals and says that maybe serif could play a role:

Why serif may actually be the right choice for your site

Now the counter-argument—and this matters for your content.

Your site is:

  • long-form
  • essay-like
  • book-structured
  • historically text-forward
  • intentionally “print-ish” (paragraph indents, chapter structure)

That is exactly where serif shines, especially on desktop and tablets.

You’re not running a SaaS dashboard or news feed—you’re publishing durable prose.


My recommended compromise (best of both worlds)

Use serif for body text, sans-serif for UI and headings, with mobile-aware tuning.

Option A: Classic, conservative (very “Philip Greenspun-appropriate”)

body{
font-family: Georgia, "Times New Roman", Times, serif;
}

Then add (already supported by the rest of the CSS):

h1, h2, h3, h4,
photonetpagenav{
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
}

This:

  • preserves the essay/book feel
  • keeps navigation and headings crisp
  • avoids over-modernizing the site

Option B: Modern serif optimized for screens (my favorite)

body{
font-family: Georgia, "New York", "Times New Roman", Times, serif;
font-size: 17px;
line-height: 1.6;
}

Plus mobile tweak:

@media (max-width: 720px){
body{
font-size: 16px;
}
}

This gives you:

  • excellent long-form readability
  • no “tiny Times on iPhone” problem
  • minimal aesthetic change from the original site

Option C: Keep sans-serif everywhere (only if you want a stylistic reset)

This is what I initially gave you, but I would not recommend it unless you’re intentionally rebranding the site visually.


Why I didn’t ask first (and what I’d do now)

I defaulted to sans-serif because:

  • the stated priority was mobile correctness
  • you wanted minimal HTML changes
  • CSS-only fixes favor safe defaults

But given:

  • your paragraph indents
  • chapter structures
  • archival nature of the content

I would switch the body back to serif and tune size/line-height instead.


TL;DR

  • I chose sans-serif for mobile safety and cross-platform predictability.
  • For your site, serif is not only appropriate—it’s arguably better.
  • Best solution: serif body, sans-serif headings, with slightly larger text and generous line-height.

If you want, I can:

  • give you a one-line diff to revert the font choice cleanly, or
  • mock up before/after screenshots (conceptually) for desktop vs mobile so you can decide instantly.

That last offer is interesting. Maybe ChatGPT actually does have a browser in its back pocket, contrary to what we’ve seen in earlier interactions. Asked for the screenshots, it responds that the first rule of Screenshot Club is that there are no screenshots.

Great—since I can’t literally render screenshots of your pages here, the most useful thing I can do is give you faithful visual mock-ups of what you’d see, tied directly to your actual content and layout patterns. Think of this as a guided “mental screenshot” you can compare against your browser in 30 seconds. Another page:

Things actually look pretty good on mobile. These are iPhone 14 Pro Max mockups from Desktop Chrome’s developer tools:

From Grok Expert

Analysis and Key Changes

  • Mobile Responsiveness:
    • Added media queries for screens under 768px (common breakpoint for tablets/mobile). On small screens, I remove floats (e.g., stack margin notes and ads vertically), ensure images scale down, reduce body margins for more content space, and increase relative font sizes where needed (e.g., small notes).
    • Images now have max-width: 100% and height: auto to prevent overflow and maintain aspect ratios.
    • Flexible layouts: Used relative units (em, %) more consistently. No fixed pixel widths were added; existing ones (like 25% for margin notes) are adjusted or overridden on mobile.
  • Desktop Improvements:
    • Modernized typography slightly: Set a base font size (16px for readability), used a sans-serif font stack (system fonts for performance), and added subtle line-height and padding for better readability.
    • Improved spacing: Increased paragraph margins slightly for breathing room, without altering the vintage feel.
    • Kept the look simple and consistent with the original— no major redesigns like grids or flexbox (to minimize potential breakage on old HTML).
  • Minimal HTML Impact:
    • No structural changes needed (e.g., no new wrappers or classes). The existing classes (e.g., .illustration, .marginnote) are leveraged.
    • The only global HTML change I recommend is adding a viewport meta tag to every <head> (this enables proper scaling on mobile).
    • Tested mentally against the provided HTML samples: They should render well without edits beyond the meta tag. For example:
      • “Travels with Samantha Home.htm”: Centered content and image galleries stack nicely on mobile.
      • “Chapter X_ Overcharged in Katmai.htm”: Narrative text with inline images flows better; philg.css styles (e.g., indented paragraphs) are preserved but made responsive.
      • “How to Photograph Architecture (Interior).htm”: Minigalleries (floated images) stack vertically on mobile.
      • “Philip Greenspun on Photography.htm”: Lists and blockquotes remain readable.
  • Other Notes:
    • Combined some redundant styles from philg.css into margins-and-ads.css (e.g., body margins, paragraph indents). If philg.css is only used on specific pages (like “Chapter X”), you can keep it but update it similarly.
    • Assumed no JavaScript or modern frameworks—just plain CSS.
    • Performance: Kept CSS lightweight; no bloat.
    • Browser Compatibility: Should work on modern browsers (IE11+ might need tweaks, but the site is old anyway).
    • Testing: I recommend testing on real devices (e.g., via BrowserStack or your phone). If you provide a live URL, I could refine further.

Recommended HTML Changes

Add this to the <head> of every HTML file (right after the <title> or existing meta tags):

HTML

<meta name="viewport" content="width=device-width, initial-scale=1.0">

This is the only change needed site-wide. It tells mobile browsers to use the device’s width for layout and start at 1:1 scale (no forced zooming out).

If you want to automate this (e.g., via a script or find/replace), search for </head> and insert it just before.

No other HTML changes are required—the CSS updates handle everything via existing selectors.

Updated CSS Files

Updated margins-and-ads.css

This is the primary CSS file (referenced by nearly all pages). I’ve incorporated relevant styles from philg.css (e.g., paragraph margins and indents) to make it self-contained. If a page references both, this won’t conflict, but you could remove redundant philg.css includes if desired.

after Grok

Not nearly the epic waste of horizontal screen space:

Based on the desktop samples: Advantage, Grok. How about mobile?

These seem fairly similar to what ChatGPT’s CSS produced.

from Gemini Pro

Here is a modern, mobile-responsive solution for your website.

1. The HTML Change (Crucial)

You must add the “viewport” meta tag to the <head> of every HTML file. Without this, mobile phones will zoom out to show the desktop view, making the text tiny and unreadable regardless of what CSS we write.

Insert this line inside the <head> section of all HTML files:

HTML

<meta name="viewport" content="width=device-width, initial-scale=1">

2. The CSS Updates

Since margins-and-ads.css is your primary stylesheet, we will transform it into a “Master” stylesheet that modernizes the look and handles mobile layouts.

Replace the entire content of margins-and-ads.css with this:

For philg.css : The old text-indent (indenting the first line of every paragraph) makes mobile text look messy and is generally outdated for web design. I recommend replacing the content of philg.css with the following, which aligns with the new modern style:

3. Summary of Changes

  1. Fixed Widths Removed: The old CSS set specific margins (3em) that squeezed phone screens. The new CSS uses max-width: 900px for desktop (comfortable reading width) and small padding for mobile.
  2. Images Tamed: Old HTML uses width="230" attributes and align="right" . The new CSS overrides this on mobile, forcing images to scale
Full post, including comments

Can LLMs bring the Berkshire Hathaway web site into the 21st century? (AI and CSS/HTML)

Another collaborative post from Philip Greenspun and John Morgan…

Let’s see what the Giants of Coding can do in the world of HTML and CSS design. Web page design should be much easier than generating C, Java, Python, etc. because people with no programming experience are often capable of writing HTML/CSS. On the other hand, HTML/CSS also entails the challenge of taste. There is no technical obstacle to making every word on a page bold and bright red, but should every word be bold/red?

This article will compare the performance of ChatGPT, Grok, Gemini, and Claude on the challenge of redesigning a legacy web site to render tastefully and legibly on both mobile and desktop. (Inspiration: Peter Norvig’s comparison of LLM performance on small programming puzzles.)

Let’s start with Berkshire Hathaway, market cap $1 trillion. “Berkshire has failed to outperform the S&P 500 since 2008—not because Buffett lost his touch, but because deploying an unwieldy $1 trillion in capital effectively is exponentially harder than investing millions” says Morningstar. The underperformance relative to the S&P can’t be attributed to diverting effort into web page design. The home page is a hideous example of misleading user interface. The text that isn’t hyperlinked is in blue, the standard color for hyperlinks, and unvisited links are in purple, the standard color for already-visited hyperlinks. This isn’t a site that was competently built in the mid-1990s and then didn’t evolve with the rest of the Web; it would have been an example of substandard web design taste even in the mid-1990s.

How does it perform on mobile (iPhone 17 Pro Max; Chrome)? It’s a literal waste of (screen) space:

Tiny barely legible fonts and half the screen left blank.

The Prompt

Here’s an HTML file [upload] with no style sheet reference that doesn’t render well on mobile. Please create a .css file that it can reference and also tell me what changes will be needed in the .html (please keep this to a minimum) to make the site responsive and also look as good as it can on both desktop and mobile.

from Grok

Here’s a practical approach to make the Berkshire Hathaway homepage look decent on both desktop and mobile with minimal HTML changes and one new CSS file.

Minimal HTML changes required

Add these two lines inside the <head> (right after the <title> is fine):

HTML

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="berkshire.css">

That’s it for HTML edits. (If the file is named something else, adjust the href accordingly.)

Suggested berkshire.css file

CSS

/* ============================================================================
   Berkshire Hathaway Homepage - Responsive CSS
   Minimal modern cleanup + mobile-friendly layout
   ============================================================================ */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Georgia, "Times New Roman", Times, serif;
color: #000080;
background-color: #ffffff;
line-height: 1.45;
}
...
  font[size="1"] {
font-size: 0.78rem;
}
}

What this CSS does

  • Keeps the classic Berkshire color scheme and serif font feel
  • Makes the two-column table become a single-column stacked layout on phones/tablets
  • Improves spacing, readability and touch targets
  • Slightly modernizes typography without destroying the retro aesthetic
  • Handles very small screens reasonably well

Optional nice-to-have HTML improvements (not required)

If you are willing to make a few more small changes later:

HTML

<!-- Replace the big first <p align="center"><b>...</b></p> with: -->
<h1 style="text-align:center; margin:1.5rem 0; font-size:clamp(2rem, 8vw, 3.4rem);">
B<span style="font-size:0.65em;">ERKSHIRE </span>
H<span style="font-size:0.65em;">ATHAWAY </span>
INC.
</h1>
<p style="text-align:center; color:#333; font-size:1.1rem; margin-bottom:1.5rem;">
3555 Farnam Street<br>Omaha, NE 68131<br>
<strong>Official Home Page</strong>
</p>

But again — the two <head> lines + the CSS file above should already give you a surprisingly usable mobile experience with almost zero HTML surgery.

Let me know if you’d like a darker mode variant or more aggressive modernization while still preserving the spirit of the page.

after Grok

Desktop:

Mobile:

from Gemini

It is a classic “rite of passage” for developers to look at the Berkshire Hathaway website—it’s famously minimalist (some might say “frozen in 1996”).

To modernize this without stripping its soul, we need to move away from fixed-width tables and use a CSS Grid layout.

1. The CSS File ( style.css )

Create a new file named style.css in the same folder as your HTML. This code handles the responsiveness, typography, and spacing.

/* Basic Reset & Typography */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #000080;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
background-color: #ffffff;
}
... 
/* The Magic: Convert the Table to a Responsive Grid */
tbody {
display: grid;
grid-template-columns: repeat(2, 1fr); /* 2 columns on desktop */
gap: 20px;
}
...
.geico-box {
text-align: center;
padding: 20px;
background: #fff;
}

2. Changes to the HTML

You only need to add two lines to your <head> section. Everything else will be handled by the CSS targeting the existing tags.

  1. The Viewport Meta Tag: This tells mobile browsers to match the screen width.
  2. The Link Tag: This connects your new CSS file.

Add these inside the <head> tags:

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">

What these changes achieve:

  • Mobile First: On a phone, those two columns of links will now stack vertically so you don’t have to “pinch and zoom” to read them.
  • Readability: It replaces the default Times New Roman with modern system fonts that are much easier on the eyes.
  • Touch Friendly: By adding padding and a light background color to the table cells ( td ), we turn the links into “cards” that are much easier to tap with a thumb.
  • Minimal Intrusion: We didn’t have to rewrite the table structure or delete any of the original content, which honors the “no-nonsense” spirit of the original site.

Would you like me to help you refactor the HTML further to remove the legacy <font> and <center> tags entirely for better SEO?

after Gemini

Desktop:

Mobile (less compact than Grok’s layout, but arguably more attractive and consistent):

from Claude (slick two-window presentation! Multi-minute analysis)

after Claude

Desktop:

Mobile (failure to notice that the text will overlap; perhaps the AI doesn’t have its own headless browser where it can test and see whether HTML/CSS renders properly?):

from ChatGPT

Below is a drop-in stylesheet + the smallest HTML tweaks needed to make your page render cleanly on phones while still looking good on desktop (your file is very “classic” HTML with <font> tags + a two-column <table> layout berkshire-hathaway).


1) Create styles.css

Save this as styles.css in the same folder as your .htm file:

/* styles.css - responsive polish for legacy table/layout HTML */
/* --- sensible defaults --- */
:root {
--page-max: 980px;
--pad: 16px;
--text: #0a2a6a;          /* close to the original text color */
--bg: #ffffff;
--link: #5a1a7a;          /* close to the original link color */
--visited: #b00000;       /* close to the original vlink */
--rule: rgba(0,0,0,0.18);
}
...
/* Lists look cramped by default in many browsers */
ul {
margin: 0.4rem 0 0.8rem 0;
padding-left: 1.25rem;
}
li { margin: 0.35rem 0; }
...
/* --- mobile: convert the 2-col table into stacked sections --- */
@media (max-width: 640px) {
:root { --pad: 14px; }
/* Turn table rows/cells into blocks so each "column" stacks */
table, tbody, tr, td { display: block; width: 100% !important; }
td {
padding: 6px var(--pad);
}
/* Reduce overly-large headline spacing on small screens */
p[align="center"] {
margin: 12px auto;
}
/* Better tap targets for links inside list items */
li a {
display: inline-block;
padding: 6px 0;
}
}

What this accomplishes:

  • Keeps the old-school Berkshire look (colors, centered header, simple typography), but
  • Prevents horizontal squish/overflow, and
  • Stacks the two columns into a single column on phones (because your core layout is a 2-column table with width="50%" tds berkshire-hathaway).

2) Minimal HTML changes needed

A) Add viewport + CSS link (recommended)

In your <head>...</head> add these two lines (anywhere before </head> ):

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">

Why: without a viewport meta tag, mobile browsers often render “desktop width” then shrink it, making everything tiny.

B) (Optional but nice) add a language attribute

Change:

<html>

to:

<html lang="en">

That’s it—no restructuring required. The stylesheet is designed to “wrap” and modernize the existing markup (including the <table width="90%"> layout berkshire-hathaway) without you having to rewrite the HTML.


If you want, I can also provide a second CSS variant that’s more “modern” (card-like sections, a little more whitespace, subtle background tint) while still preserving the minimalist vibe—still with minimal/no HTML changes.

after ChatGPT

Desktop:

Mobile (another failure via overlap):

after ChatGPT again (accepted the offer of a more modern CSS)

Desktop:

Mobile (still overlapping):

Summary

Despite the apparent simplicity of the challenge, Gemini was the only LLM that was able to create a web site that rendered well on mobile. Grok came in second with a mobile rendering that featured odd spacing and horizontal lines placed seemingly randomly but at least kept the text legible. Both ChatGPT and Claude’s styling resulted in mobile rendering that can only be described as broken with multiple instances of overlapping text.

These LLMs probably could do much better if they ran an open-source web browser, such as Firefox, internally and used the browser to render whatever they’d designed and then used their image understanding capabilities to spot obvious problems, e.g., overlapping blocks of text.

Stay turned for more comparisons among LLMs in the web development domain, including a look at the Brave New World of artificial intelligence in integrated development environments (AI in IDEs).

Full post, including comments

Why Johnny LLM can’t read web page source code

First of a series of posts by John Morgan and Philip Greenspun on using AI models to perform HTML and CSS design.

The plan: Compare ChatGPT, Gemini, Claude, and Grok to see which LLMs do the best job on CSS and, if necessary, HTML redesign of existing web pages.

All of these models failed at the simplest imaginable HTML/CSS question (not hyperlinks in the queries, but included here for convenience):

Do all four of these HTML pages reference the same .css file? https://philip.greenspun.com/samantha/ https://philip.greenspun.com/samantha/samantha-X https://philip.greenspun.com/photography/ https://philip.greenspun.com/photography/learn/interior

All four pages actually do reference the same .css file, /margins-and-ads.css, and one file also references /philg.css

Sample actual page content:

<head>
<meta name="keywords" content="interior photography">
<LINK REL=STYLESHEET HREF="/margins-and-ads.css" TYPE="text/css">

<title>How to Photograph Architecture (Interior)
</title>
</head>
<head>
<link rel=stylesheet href="/margins-and-ads.css" type="text/css">
<LINK REL=STYLESHEET HREF="/philg.css" TYPE="text/css">
<title>Chapter X:  Overcharged in Katmai</title>
<meta name=processor content=adp>
</head>

from ChatGPT

I checked the content of the four pages you listed, but from the snippets returned there is no visible <link rel=”stylesheet” …> line in the parts shown — that’s because the portions we could fetch start at the body text and don’t include the <head> section where CSS is normally referenced. … If you want precise verification, I can fetch and show the full <head> source (including the exact <link …> line) for each of the four URLs — just let me know.

[after “Yes please fetch the full HEAD source for each one and verify.”]

I tried to fetch the full HTML <head> source of each of the four pages you listed — specifically to look for the <link rel=”stylesheet” …> tag that shows which CSS file (if any) each page references. However, the tool returns only the rendered body content and not the complete <head> section, so I couldn’t directly inspect the <link> tags for CSS in the fetched results.

from Claude

I should note that the web_fetch tool extracts text content and may not always show the complete HTML <head> section where CSS references typically appear. The pages I did fetch appear to be very minimalist in design, consistent with early-to-mid 1990s web design when these pages were originally created.

Without being able to see the complete HTML source including the <head> sections of all four pages, I cannot definitively confirm whether they all reference the same CSS file.

[prompted further]

Now I have all four pages. Let me examine them for CSS file references. Looking at the extracted HTML content from all four pages, I notice that none of them contain explicit <link> tags to external CSS files in the content that was extracted.

from Gemini

[Us: Google’s smartest child has trouble counting and trouble understanding HTML, but it is great at presentation. It says that three pages reference no external CSS and then shows a table featuring two files that reference CSS. It is dead wrong about the interior page, which references margins-and-ads.css. It either cross-contaminated its own thinking by looking at the samantha-X file, which does reference philg.css or found a reference to the file in the BODY of https://philip.greenspun.com/panda/html.]

No, they do not all reference the same CSS file. In fact, three of the pages appear to use no external CSS at all, while one of them uses a specific stylesheet for that section of the site.

Based on the source code for each page:

  1. https://philip.greenspun.com/samantha/
    • CSS: None.
    • Details: This page uses old-school HTML attributes (like bgcolor=white and text=black in the <body> tag) for styling rather than an external CSS file.
  2. https://philip.greenspun.com/samantha/samantha-X
    • CSS: None.
    • Details: Like the index page for this book, individual chapters are formatted using plain HTML and inline attributes.
  3. https://philip.greenspun.com/photography/
    • CSS: References /philg.css
    • Details: This page contains a <link rel="stylesheet" href="/philg.css" type="text/css"> tag in the <head> .
  4. https://philip.greenspun.com/photography/learn/interior
    • CSS: References /philg.css
    • Details: As part of the photography tutorial section, it shares the same stylesheet as the photography index.

Limitation Rationale

Why are these LLMs so hobbled? Apparently, it is intentional for the LLM to see only what a user might see. This ensures that dynamic sites are properly understood and also may prevent some security risks.

When prompted, ChatGPT replied that this limitation is due to its web content fetching tool not returning the full payload and instead querying “search indexes, reader-mode extracts, preprocessed HTML snapshots, [and] content extraction pipelines” that are “optimized for reading and summarizing, not inspection.” It explained that “in those pipelines, the <head> is usually stripped entirely or reduced to a title and a few meta fields [because] CSS links, JS, analytics, preload hints, etc. are irrelevant to text extraction [and] keeping them increases size and complexity with no benefit for search/reading.” If true, this suggests that the tool was not built with full HTML analysis in mind but rather optimized for the admittedly more common text extraction use case.

Next Steps

Since our future AI overlords won’t download a web page from the Internet and click “view source”, the next step was to see what these LLMs could do if we downloaded HTML and CSS files to our desktop computers and then uploaded the files back up to the LLMs along with our questions.

Full post, including comments