Twenty-four pages, one owner for the New York query, prices from one file, and 141 Vitest tests holding both in place.
2026 · Web
Web Development

Food Truck Rentals

Scroll to explore

A New York brand-activation company wraps, staffs, and permits food trucks for fashion houses, department stores, and restaurants. They were selling all of it without a website of their own.

Next.js 16 and React 19 in TypeScript, Tailwind CSS 4, and Motion for the hero, the roster and the nav, with Archivo, Public Sans and Overpass Mono loaded through next/font. Vitest 4 with Testing Library and axe runs 141 tests across 24 files. Twenty-four routes plus seven case studies from one template, deployed on Vercel, with Resend delivering every inquiry to the client's inbox.

Search

One query, one owner.

Nine phrasings of the New York rental query, from food truck rental nyc to rent a food truck new york, are treated as one keyword, so exactly one page may claim any of them in its title, description or heading: the NYC rental page. A test lists the nine, scans every route file for a second claimant, and fails the run if it finds one. It scans the root layout too, because the homepage title lives there, read Food Truck Rentals NYC from launch, and sat outside the guard for twelve days.

The guard stayed green while Google split two pages on their body copy anyway. Measured on 16 August 2026, the NYC hub sat at position 45 for food truck rentals while the money page it was built to feed was nowhere in the top 94, and food truck rentals nyc returned four of the site's own URLs at 57, 69, 83 and 92. So the hub was merged into the owner. Its five-borough ledger, its parking, permit and power notes and its case spreads moved across, and the old address became a permanent redirect, with a test that no redirect on the site chains through another.

The NYC rental page, the one route allowed to own the New York query: the breadcrumb Food truck rental NYC, the headline Food truck rental in New York City, priced up front, a lead that publishes $1,500 a day unbranded and $10,000 custom-wrapped, and the top of the facts ledger.
Pricing

Every price comes from one file.

Three tiers, four add-ons and a $1,500 floor live in one module, and the files that machines read are generated from it on request: the price sheet at pricing.md and both llms files are route handlers, and nobody edits them by hand. Their route list comes from the sitemap, so a redirected URL cannot appear in them. Seven pages build their structured-data offers from the same tiers, the hero's day rate is the module's floor, and the rental page's service-area row prints the module's label word for word.

The module does not reach every page. Four pages still hard-code a minimum price in their schema, and most prose prints its figures as literals, so the control there is a test. It scans every page and component for the two floors that were corrected in July 2026, unbranded $4,500 down to $1,500 and branded $15,000 down to $10,000, expands the $15K shorthand first so both spellings are covered, and fails the run if either reappears as the site's own price.

The rental page: the headline Food truck rental, handled end to end, a lead whose $1,500 a day is the pricing module's floor, and a facts ledger whose service-area row reads NYC + Long Island, New Jersey & Connecticut, the module's label verbatim.
Guards

Tests for the rules a comment could not hold.

The sitemap dates every route by hand rather than stamping the build time on all of them, and the file's own comment says to bump a date when its page changes. That rule broke twice in two days: eight stale dates on 15 August 2026, sixteen of twenty-three the next morning. So a test now reads one git log for the whole history, finds each route's last commit, and fails when the sitemap claims a page is older than its own file. It also fails if it cannot read git at all, so a broken harness cannot pass by checking nothing.

The Google Business Profile is wired into the structured data by stable ids, with the listing's spelling of the name carried as an alternate name so the listing and the site resolve to one company, and its hours as read off the profile on 16 August 2026. The listing's telephone number is in the JSON-LD and nowhere a person can read it; a test fails if it leaks into a page or a component. There is no street address on purpose, because the profile hides one, and tests assert that neither company node, nor the contact and NYC pages' own schema, carries one.

When the brief asked for truck specifications lifted from competitors, the published numbers refused to agree: throughput ran from 40 to 150 guests an hour and generator draw from 3,000 to 25,000 watts, because the menu and the equipment on board set both. The site publishes those as category ranges under a standing caveat, keeps its own fleet's specs marked unverified until the owner supplies them, and a test fails if a range ever turns into a claim about these trucks.

The same suite holds the contact page's reply promise to one wording, within 48 hours, reads the built HTML for a word fused onto a closing tag, and types the seven case studies' slugs as a union so a page cannot link to a study nobody wrote. All seven render from one template and one data file, with the client's own activation facts as their metrics.

The contact page: the headline Start an activation, a lead asking for the brand, the market and the dates, and a facts ledger led by Quote turnaround, within 48 hours, with no telephone number anywhere on the page.
The work index: every activation, with the client, the borough, and the year, opening on the Louis Vuitton spread and its two metrics.
The work index. Seven activations from one template, each with the client, the borough, and the year.
Front door

Three trucks at once.

The hero was a pinned section two screens tall that scrubbed three photographs past the viewport one at a time, so a visitor scrolled through two screens before reaching any content and only ever saw one truck. Since 16 August 2026 it is one screen: a three-by-two collage with Louis Vuitton in the large panel because its near-square frame crops best there, and the other two stacked beside it. Only the large panel is preloaded. A generated video that once backed the hero was removed in July. The frame at the top of this page is that hero.

Below it, seventeen clients from one data file. The active name widens on the typeface's width axis, from 100 to 112, and the names cannot wrap, because measured widening on wrapping text moved the wrap point and shoved the roster down 24 pixels mid-scroll. The card that shows each client's photographs exists from 1,280 pixels wide; below that, tapping a row opens its strip inline. The client's twenty-two phone photographs were converted by a script that bakes each rotation into the pixels before it strips the metadata, because doing it the other way round shipped three of them sideways.

Project details

In the client's words

“He took my ideas and turned them into a clean, modern, fast-loading site that looks great on every device. Communication was clear, deadlines were met, and the final result exceeded my expectations.”

Brian Murphy, Google review, August 2026

Do two of your pages compete for the same search?