Simulation

Beyond the Benchmarks: Why Multi-Agent Coding Requires a Holistic Approach to AI

Ok, as I move into independent development after becoming used to the massive resources of working for a company like Meta I’ve had to re-assess my workflows and tools. Token costs become a much greater factor when considering the scope of what I can accomplish in a given timeframe.

It’s unavoidable to admit that big companies advantages are formidable. Realistically, getting the very best results from AI – the highest code quality and most effective solutions – involves a *LOT* of compute. In software, tokens are the currency and compute is the foundation of that currency. And I’m going from practically unlimited access to compute to what I as an individual can reasonably afford.

I can still do the same things, for the most part. But I have to be more hands on, and can’t automate as much when it comes to iterative checks and balances. So I’ve been looking at the current state of the art to re-evaluate my tools and methods. Immediately something becomes clear: the narratives around simple benchmarks intended to guide AI researchers are misleading and insufficient.

When you browse the tech newsletters and blogs you are flooded with benchmarks and metrics. Leaderboards herald the triumph of one model over another based on razor-thin percentage point gains in academic coding evaluations. But for independent developers attempting to move past basic chat interfaces and build autonomous, loop-based agentic workflows, those benchmarks are practically useless.

Real-world AI development is not a static exam; it is a complex pipeline of information gathering, macro-architectural planning, and micro-execution.

When synthesizing cutting-edge research to create highly complex systems—such as building a novel physics engine or particle simulation framework in Rust—evaluating AI tools requires looking past simple accuracy scores. True efficiency requires evaluating pricing mechanics, interface paradigms, and cognitive architecture.

Let’s look at a comparison between Anthropic’s Claude and Google’s Gemini. Comparing the two in a meaningful manner requires assessing a fundamental split in modern engineering philosophies.


1. The Economics of the Loop: Subscriptions vs. Context Windows

Autonomous agentic development introduces a brutal reality to API billing: the loop tax.

Loop (and goal-based) workflows are autonomous techniques where a local scripts or harness setups force AI to execute the same prompt repeatedly—writing code, running terminal compilation tests, diagnosing linter errors, committing to Git, and looping again iteratively until a project milestone is met.

Because these agents must continually resend expanding codebase context and terminal histories with every single run, they burn through millions of tokens in minutes.

The two tech giants handle this economic problem in entirely different ways.

The Anthropic Bottleneck

Anthropic’s answer for developers is Claude Code, a terminal-first CLI tool powered by high-tier subscriptions ($100–$200/month). Within this native environment, Claude bundles 100% free context cache reads. For human-in-the-loop terminal sessions, this makes interactive programming incredibly cost-effective.

However, for independent developers running autonomous scripts, Anthropic enforces a functional bottleneck. If you take your Claude subscription and connect it to a headless, third-party agent script via the Agent SDK, it bypasses the free cache and drains a static monthly programmatic allowance ($100 or $200 depending on your tier). Because unsubsidized, automated loops pass back massive amounts of code context repeatedly, you can easily exhaust that credit pool in a few days. Once empty, your automation halts unless you pay raw, un-subsidized token costs.

The Google Surplus

Google approaches the independent developer through sheer infrastructure scale. Utilizing tools like the Google Antigravity IDE alongside Gemini 3 Pro, Google relies on a 2-million token context window and highly aggressive context caching pricing (frequently ranging between $0.15 and $1.00 per million tokens per hour).

Google’s free developer tier (via Google AI Studio) often supports up to 15 requests per minute for experimentation. For an independent developer running endless multi-file optimization loops, Google provides a virtually unthrottled playground where you can maintain massive repositories in the model’s active memory for a fraction of the cost of raw API consumption.

Simply put, Anthropic is smaller and doesn’t have the compute to spare. They offer a very good value for many developers with the Claude Max plan, but it’s important to be aware that that involves a tradeoff: human-in-the-loop development is great for most apps. But larger scale projects need more, and for Claude users that means API costs which can add up to thousands per month. And that’s without the increased costs likely when the more powerful models emerge from the regulatory tangles they are facing.

Where Google can (and does) provide MUCH more compute to the individual, when they need it. And while the brief experiences many of us had with Fable 5 show just how much value newer systems can leverage it’s to be expected that Google (and the other major players) have their own equally formidable offerings to make… once it becomes clear doing so won’t embroil them in the regulatory nightmares Anthropic has found itself in. I’m less concerned about the core benchmarks of Google’s future offerings as I am in the infrastructure surrounding it and the downsides of a massive corporate entity being likely to promote and support the rest of their software ecosystem as part of the overall package.


2. Research vs. Execution: The Architectural Split

Beyond the billing mechanisms, the underlying models think differently. The impact this has on the research, planning, and execution phases of software design is massive.

Google Gemini: An Associative Researcher

Gemini excels at broad-horizon synthesis. Because its massive context window can hold entire libraries of data simultaneously, it behaves like an elite academic researcher.

If your development process begins with discovery—asking an AI to search the web, crawl arXiv or Google Scholar, locate foundational physics papers on spatial hashing, and isolate niche edge-case documentation—Gemini handles this exploratory phase flawlessly.

Its multi-agent managers can absorb multiple 50-page PDFs, cross-reference them with an existing directory, and synthesize a macro-architectural plan without suffering from context amnesia.

The downside? Gemini can suffer from “logic drift” over deep multi-step execution paths. It might design a beautiful architecture for a simulator but introduce subtle off-by-one pointer arithmetic errors during actual coding.

Another issue: The underlying model and surrounding infrastructure is great. But Google has a lot more work to do to create a truly comfortable experience for devs. Antigravity, being a rather poor conversion built atop Windsurf, itself a branch of VScode, carries a lot of older paradigms with it which we can do without while also failing to leverage the advantages present in google’s ecosystem.

Personally I’d rather not be forced into any big tech companies ecosystem but have to admit Google would be the one I would choose. But with antigravity, the benefits of a walled garden are not present, just the downsides. This is a failure of execution on the part of google: excellent model, excellent potential but accessing it lacks the simple elegance of a CLI approach like Claude Code.

Claude Code: A Logical Surgical Knife

Anthropic models operate like precise, deterministic compilers. Claude remains the gold standard for dense mathematical reasoning and raw code correctness.

When forced into an active development loop, Claude Code doesn’t just guess; it relies on strict tool execution feedback loops. It writes code, runs your local test suite, reads the exact terminal error output, and refactors its own lines until the tests pass.

The drawback is its localized view. Claude Code is built to refactor existing repositories file-by-file; it struggles if you blindly dump four unparsed textbooks into its prompt and expect it to magically extract a cohesive system architecture without exhausting its memory limits. This can be mitigated, and there are known and proven means to do so. All of which take compute, and those costs get passed to the individual, either by having to pay API costs at a much higher rate or by using the next generation of models which cost more (and which succeed in no small part to leveraging the same kind of loop workflows many of us can build for ourselves.)


3. The Hybrid Approach: Building a Particle Simulator in Rust

To understand why benchmarks fail to capture this reality, consider the task of building a high-performance particle simulation application in Rust.

Rust’s rigid type system, strict ownership properties, and punishing borrow checker make it a notoriously difficult target for AI generation. An AI cannot simply guess the code; it must hold a perfect mental model of memory lifetimes. Furthermore, a novel simulation framework requires extracting complex math from academic theory—like Smoothed Particle Hydrodynamics (SPH)—before writing code.

If you rely solely on one AI offering, your workflow breaks down:

    • Using only Gemini/Antigravity: You will effortlessly gather foundational papers and build an excellent architectural blueprint. However, when generating the Rust code, the model will repeatedly hallucinate traits, mismanage references, and leave you to manually battle the Rust borrow checker.

    • Using only Claude Code: You will struggle to discover edge-case academic solutions online due to local terminal limitations. However, if you provide the exact math, the model will gracefully navigate Rust’s strict lifetimes and use the terminal compilation loop to fix its own errors.

Example

This collaborative approach rejects the single-model paradigm and treats AI offerings as specialized members of an engineering team:

The Research Phase (Google Antigravity): Task Gemini’s broad context and web-browsing agents with scouring academic repositories. Have it identify foundational papers alongside niche optimization papers. Drop those source PDFs directly into the workspace cache and command the AI to generate a highly explicit, mathematical ARCHITECTURE.md file mapping out the simulation parameters.

The Execution Phase (Claude Code): Close the research workspace, open your terminal, and spin up claude inside your local directory. Point Claude Code directly to the generated ARCHITECTURE.md. Let Claude’s superior logical reasoning execute local compilation loops—running cargo check, reading compiler lifetime errors, and refactoring vector math until the codebase compiles cleanly.


The Lesson for Developers

The modern AI landscape has evolved past the point where a single “Best Model” leaderboard matters. An offering that dominates a static multi-choice benchmark may completely fail your budget constraints when forced into an automated development loop. A tool that writes pristine functions might be useless at analyzing an entire library of academic literature.

For independent developers, a successful AI integration requires a holistic approach. Stop looking for the one model to rule your entire workflow. Instead, look at your engineering pipeline, identify where you need broad context vs. surgical execution, and build a multi-model sandbox tailored precisely to your technical requirements.

Vorticle Fluids implemented in PopcornFX

This is a really crude first approximation of a homebrew realtime fluid simulation using vorticles. The general idea is a sparse layer of particles are queried for position and orientation and used as centers of rotation to simulate turbulent fluids. Even this very simple first experiment is very promising.

No noises, fields or turbulence forces are used, the motion is all directly a result of particles interacting with a layer of vorticles, which I reveal in the latter portion of this video.

Simulation is entirely on the CPU and takes 18ms per frame for 21,000 particles. One nice thing about vorticle simulations is the motion does not change with the number of particles, meaning a simulation can be tuned while running very fast and then the simulation turned up for millions of particles to be rendered in After Effects etc. I look forward to seeing how fast this will run when entirely on the GPU.

Apologies for the tiny video… this is just a screen capture.

Newtonian Universe Simulation

I’ve been using PopcornFX a lot lately and have been using it as a playground to explore some simple physics simulation. For example Hooke’s law and compressible springs:

And it was pretty fun exploring Newton’s law of universal gravitation with a classic “orbit” simulation:

But then it occurred to me… PopcornFX is pretty efficient, why not scale up my basic simulation to handle not only a few orbiting bodies, but hundreds of thousands? While not correct to the universe we live in the result should look a bit like elliptical galaxies, right?

Let’s try it.

Ok then, here’s a screenshot of a sim of around 900k particles, running 30-50ms per frame. Too slow for game work but pretty fast for cinematics, and PKFX is integrated into After Effects so I really should try rendering out a movie.

In motion the effect is mesmerizing, with “galaxies” merging, splitting, devouring each other and for some reason periodically seeming to explode into rope-like strands. Nowhere near physically correct of course, but evocative of space imagery and very beautiful. 

Why no spiral galaxies? In the real world a lot more is going on, with gasses compressing and angular momentum preserved. This little simulation doesn’t account for more than the most basic, crude motion so, alas, the “galaxies” which form are elliptical only and rarely stable for very long.

CG Supervisor for 3 Nike Spots

Two of 3 spots. “Evolution” was a small team, 3 weeks, lighting and effects with Softimage and Arnold.

I love small but intense projects like this.

“Run” was primarily Maya/Vray with a touch of ICE. The studio (Royale) is only 6 years old but advancing fast, and it’s been a real pleasure working with them. For their first exploration of ICE, Royale invited in some familiar SI friends – Ciaran Moloney, Steven Caron, Leonard Kotch, Billy Morrison and yours truly doing a first gig start to finish as a CG sup (which with guys like this mostly involved saying “go for it.”)

Like the Psyop “Telstra” spot, this commercial essentially required us to create a system for knitting cloth from massive numbers of strands. Leonard Kotch wrote a system which performs many of the same tasks as the Psyop “Entwiner” tool, but he took a slightly different direction, it was fascinating to compare how the two diverged. The progressive animation required for these two shots resulted in a pretty flexible and broad system, which we are currently using for the last of the three spots, which will wrap in production soon.

strandlayoutb_s40_062613 NikeEvo_shoe_comp_v001 NIKE_evolution_shot40

Royale has been an enthusiastic and fun group to work with and it’s been great getting to show a studio as strong as they are in design some of the possibilities ICE can bring to jobs like this. Expect to see some version of Leonard’s “LKFabric” system gifted to the community before long – very cool Royale, thanks! (They also throw good parties, their 6’th birthday celebration was impressive and… unusual.)

 

 

Example – Particle Clumping

example_particleClumps

The simulation is “meh”, but it was a test. This scene wasn’t originally about particle clumping, either: that was just put in as a way for me to play with the idea but not really my original focus. I was using it as a testbed for a homebrew collision/bounce node, which functions, but in the end that part wasn’t anything particularly special or even sophisticated. The clumping part is more interesting in the long run.

Someone recently asked about clumping particles online, and I recalled that I had this scene on hand. So here it is, as built by yours truly while never intending it to be anything other than personal experimentation… with some comments put in after the fact.

The file (softimage2013 ~8mb): example_createParticleClusters

Example – PostSim Needles

During the making of the film “Barnyard,” which happened to be around the time ICE was being first conceptualized and built, a number of effects were identified which were a challenge at the time. Some of those effects became some of the first demonstration compounds later, presumably Helge and others still had those challenges in mind… making footprints in mud, falling leaves, rain/snow interacting on characters etc.

One effect involved a bunch of hay getting dumped on a character. At the time Hans Payer completed the effect via some nice scripting and syflex tricks. Now in ICE it is pretty easy, so when a thread about a similar effect was mentioned on the softimage list, and so soon after I had done the post-sim tutorial, I gave it a quick go. They basically asked for a way to use strands with the “falling leaves” compound. Here’s the result… while the collisions are not accurate the way RBDs would be I hope it’s food for thought at least. :D

[vimeo]http://www.vimeo.com/56985570[/vimeo]

Caveat: like similar tricks using the post simulation tree, motion blur is a concern… this is the kind of “quickie” effect that can often get you by, but hero shots would take a lot more effort, for instance if you had to see clearly the fibers bend and react to collisions, collide with each other, accurate mb etc. That kind of difference in the details is why feature film effects can get so hairy – often you can’t get away with simple cheats like this one.

File: softimage 2013 .scn, 237 kb

example_postSimNeedles

 

Post-simulation and softimage ICE (part 3 – vectors and modulo)

So, we’ve made a strand circle which rings our original point positions from the simulation, now let’s make those circles align with the rotation of the simulated particle. In practice this is very, very simple. Just insert a “rotate vector” node after you calculate the coordinates on a circle for the strand points, and then use the particle orientation as the input rotation.

Ok, that was nice, but why did it work?

Point positions are vectors. Vectors are displacements:

This is one of the simple but critical concepts that is the real purpose for me writing this series of posts, because it’s a foundational way of thinking which lets you come up with solutions to problems every day.

What is a point? It’s a place, within a space. A particle can have all kinds of attributes, like color size and orientation. But a point is just a position, it only has a single value, a vector (x,y,z). In a manner of thinking, a point is a vector. The vector which describes a point is a direction and distance from the origin. It’s a displacement from that point of reference. When you talk about “global” and “local” space you are talking about different frames of reference, different points of origin from which to draw a vector describing points.

So, what we really did when we calculated an array of strand positions on a circle was make an array of vectors. Hence, rotating those vectors is really the same thing as rotating the strand point positions to match the orientation of our original particle. Points are vectors, they are offsets (or displacements) from an origin. And ICE is very, very good at doing stuff with points vectors. You can call these manipulations vector math if you want, but that in itself doesn’t make it beyond your average artist, who like ICE are also very, very good at manipulating points. If you are an artist you already have an intuitive grasp of vectors! You just need to define some terms, so that saying stuff like “rotate a vector” translates to the visual adjustments you do in your head day in and day out.

Seeing stars… and why modulo is so handy:

Ok, cool. We have a bunch of strand rings centered and oriented where our simulated particles were. Let’s make the rings star shapes, as a way of talking about another useful technique in ICE (it’s useful all over in fact), making patterns via the modulo function.

Ok, a digression first – some housekeeping. By now you’ve realized this isn’t one of those step-by-step makes-a-scene tutorial, I’m discussing more and glossing over a lot of the details you may need to actually plug all this together. I really should have provided a sample scene earlier, I don’t want you focusing on plugging nodes together, the whole point of this is the underlying ideas. So here you go. A sample scene with nifty comments and stuff. If all you want is a scene that will make circles and stars, there you go. And it was made with an educational license, even. But if you want the ideas used so you can make all kinds of other stuff, well then dear reader, read on.

The modulo function is just an instruction to divide two numbers and pick out the decimal remainder of that division. If you feed a linear sequence of numbers (like the index of an array: 0,1,2,3… call any of these numbers “n”) into the modulo function, you get a value counting up between 0 and 1. You can use this to identify every “n’th” item in your list. In fact if you crack open ICE’s “every n’th particle compound etc you will basically see exactly this.) If you can do things every “n’th” time, you can make patterns. Think about it. Braiding hair, knitting, drawing a dotted line – making almost any pattern involves counting and every “n’th” count doing something differently. Modulo is how you do that kind of thing in ICE (and elsewhere. Hey, realflow has an ICE like system now. And it works in scripting too. This math stuff pops up everywhere. The big secret is this – it’s just a way of looking at things you probably already do really well.

I’m a visual thinker so when I was first learning about modulo I had to scribble on a napkin, with results something like this:

All a star shape is, is a pattern where we take every other point on our circle and change it’s radius. Now we know how to find every other point from our list (the array) of strand positions, so we just change the radius of the formula we used to make the circle for those points. And you get a star.

Cooooool.

Ok, so just one last part to this tutorial, and a brief one – how to take the single circles we made and, using the earth-shaking power of ICE and the post-simulation region, turn that result into a lot of circles: all different and making little atom things like we see in the example video. And in fact, the example scene here already shows you how, so we’re not even going to do much besides discuss it and crack bad jokes. Cheers. – AM

The file (softimage 2013 educational, 1.2 mb)

strandPostSimOffset_tutorialPart4

Post-simulation and softimage ICE (part 1)

“What happens in the post simulation tree stays in the post simulation tree”

A quick review: ICE operators are evaluated differently depending on where they reside in the construction history (also known as the operator stack or modifier stack.) When an ICE tree is under the modeling region it is evaluated every frame unless a simulation region exists – if it does, it is evaluated once. An ice operator under simulation is evaluated every frame, and all data is updated every frame. In other words, changes persist and appear in the next frame – if you move a point, in the next frame that change is reflected. And when an ice operator is in a post-simulation region, it is evaluated every frame but changes are discarded. The “lower” regions evaluated first, then each region “above” it in the explorer, like so:

This is very, very useful. You can have an entire simulation going in the simulation region, and then do stuff to it prior to display. For instance, you could cull out all particles which aren’t visible to the camera to reduce cache size and speed evaluation. You can calculate per-particle lighting prior to rendering it, to control lighting entirely within ICE. Or, in the example below, you can move points around without altering the original simulation.

Example: Strand shapes

Here’s an interesting “look” done entirely with strands in ICE. A typical particle simulation has been used as input for an ICE operator in a post-simulation region, which uses the simulation as a basis to draw many circular strands.

First, I made a very basic particle simulation:

Then, in a post-simulation tree, I drew the strands.

… So you can see that for this effect the bulk of the work was done in the post-sim ICE tree. I use the point positions and orientation from the simulation as a center point around which I add new particles with strands. In my next post I’ll show exactly what I did, but the point I’m getting at here is that things don’t have to end with merely a simulation. You can get into some very cool stuff by considering each frame of a simulation (or a cached result) as a starting point. You can deform your entire simulation, rig it to a character, light it, or perform housekeeping tasks like camera frustrum culling. You can even treat the entire simulation as a single unit and scatter it – they sky’s the limit.

A quick note about motion blur:

When I wax rhapsodic about the post simulation tree the most frequent argument I run into is that moving particles around in a post-simulation operator invalidates motion blur calculations. This is true. Motion blur is based on the velocity of a particle, which can be considered a vector from the previous point position to the current. In the post simulation operators, the previous location is unavailable… it’s like a dog’s sense of time, only what exists “now” has any meaning. So, you have to do some extra work if you need motion blur. Basically, you store the previous point position into a user variable which can be read by your post simulation ICE  tree and use that information to calculate not only how you wish to move a particle, but how you moved it in the prior frame as well. From this you can calculate a valid velocity to pass to the renderer for motion blurring. That sounds awful, but it’s not really that bad. (Still, it would be handy if the devs gave us an easier workflow than this, for instance could they store and give us access to post-sim point positions and velocity or something?)

Next:

We will look at creating the offset strand shapes – circles, stars etc. Stay tuned!

Example ICE scene – Rain on the Bunny

Pretty basic. Shows how you can use a user attribute to effectively create “states” of a simulation without relying on the state machine. Also contains a compound which is part of my regular toolkit, which forces particles and strands onto the closest surface. Like I said, basic stuff, but thats what these examples are… here it is in case anyone could use it for learning or whatever.

Scene (Softimage 2013, .zip) – example_RainOnBunny

The stanford bunny has a hard life.

Points from strands example for Arnold instancing etc.

This isn’t an earth-shattering ground-breaking post, just a simple example of a workaround which came up on the SItoA mailing list…

In Mental Ray rendering out a copy of a Softimage ICE particle’s shape per strand point is easy, just disable the “stranddeform” attribute (when using “generate strand trails” it’s the “loft shape along strand” checkbox.) Now instead of rendering a continuous, lofted result the strand is depicted as a series of particle shapes or instances. Easy enough, and is described as a basic workflow in the softimage documentation.

But when using Arnold as a renderer, particle shapes are lofted no matter what. So how do you get a result where shapes are repeated along a strand? This is the question which came up on the mailing list, and Stefano Jannuzzo and Mathieu Leclaire posted a simple and direct solution: clone (or add manually) a point for each strandPosition on a new cloud. When using add points instead of cloning, you also need to carry over relevant information such as orientation and velocity.

This is a pretty common kind of technique for this sort of thing and is worth putting on the record where people can search for it, so I’ve implemented their suggestion in a compound and example scene here. Enjoy.

PointsFromStrands