VERATechnologies
Role
Positioning, brand, site, content system and ad campaigns — full engagement
Span
September 2026
Status
Live at ocdesign949.com
Stack
Hand-written HTML · One stylesheet · Python standard library · S3 · CloudFront

OC Design 949

A construction consultancy needed a position, a face and a publishing pipeline. It got all three in a month, and the pipeline is one photo in, three channels out.

We own OC Design 949, so no invoice changed hands. Everything else about this was a client engagement: a real business with real customers, a positioning problem, a launch deadline, a budget, and an ad campaign built to reach homeowners across Orange County. It is the complete service, start to finish — which is why we can scope and quote the same thing for you.

The situation

Every contractor in the market says the same three words: good, fast, cheap — pick two. The audience has heard it so often that claiming all three reads as a lie before the sentence finishes. So the business had a positioning problem before it had a marketing problem.

It also had a distribution problem. A consultancy that works from photographs needs those photographs on a website, on Instagram and on Facebook, sized correctly for each, without three separate manual workflows that nobody keeps up.

The brief

Written down before anything was built, because a scope nobody has written down is a scope nobody can be held to. The requirements were the business’s, and they were specific:

  • Reach homeowners in Orange County who are about to spend six figures — not contractors, not other consultants, and not the whole of California.
  • Generate conversations, not clicks. A form fill from someone who wanted a brochure is worth nothing here; a direct message from someone with a kitchen and a budget is the entire point.
  • Sound like a grown-up. The audience is nervous about being sold to by the trades. No hype, no emoji, no “🔥 GAME CHANGER” — authority from knowing things they do not.
  • Never claim what cannot be defended on a jobsite. Every number hedged, every figure traceable to a real project.
  • Keep the ongoing effort to minutes. A marketing routine that takes four browser tabs and twenty minutes stops happening by about week three.
  • Do not spend a cent without a human saying so.

Everything below is a response to one of those six lines.

What we built

The positioning first: Plan first. Build once. The iron triangle has a centre, and planning is the free variable that reaches it — quality, time and cost move together, and the centre is earned rather than claimed. That reframe is the whole business.

Then the identity: a speed square as the mark, because the silhouette reads as trades in a fraction of a second rather than as consulting. Full logo set, profile images, a cover banner.

Then a five-page live site — hand-written HTML and one 227-line stylesheet, no build step and no JavaScript dependencies — deployed to a private S3 bucket behind CloudFront.

Then the content: twelve 1080×1350 feed posts and a thirty-second reel, published to @ocdesign949 on Instagram and to the Facebook page.

The publishing pipeline

This is the part most worth stealing, and it is the thing we now build for other businesses.

One photograph goes in. A script derives the web sizes at two widths with correct srcset, generates an Instagram-legal derivative — padded onto brand navy rather than cropped, because cropping to a square decapitates a portrait shot of a stairwell — regenerates the gallery block on the website, and posts to Instagram and Facebook. Three surfaces, one command, no copy-pasting between four tabs.

Underneath it are two separate Meta APIs, which is the detail that catches people out. Organic posts go through the Content Publishing API. Advertising is the Marketing API — a different permission, a different account, and a payment method. An ad is not a post: it appears in other people’s feeds marked Sponsored, it never lands on your profile grid, and it stops the moment the budget does.

The ad campaigns

This is the part the brief cared most about, and the part with the most decisions in it.

The campaign is click-to-message: the ad appears in a homeowner’s feed with a Send Message button, and a tap opens a conversation rather than a landing page. That choice follows directly from “generate conversations, not clicks”, and it drove the technical shape — OUTCOME_ENGAGEMENT with the optimisation goal set to CONVERSATIONS, which is the documented pairing for ads that click through to Messenger.

The obvious-looking alternative was rejected deliberately. OUTCOME_LEADS sounds like the right objective for a consultancy chasing leads, but on Meta it means a Messenger lead form — a form to fill in rather than a conversation to start. More friction, worse fit for a “DM me the word PLAN” call to action, and a worse lead at the end of it.

The structure is campaign → ad set → one ad per creative. The campaign carries what counts as success and cannot be changed after creation, so getting that right first time matters more than anything else in the build. The ad set carries the budget, the schedule, the audience and where the click goes. Each of the twelve rendered graphics can become its own ad, which is what makes testing creative cheap.

Everything is created paused. The campaign, the ad set and every ad are built with delivery off. build never activates anything; only a person switching it on in Ads Manager starts delivery and starts spending. That was a hard requirement, and it is the right default for anyone — a script that can begin spending your money on its own is a script nobody should run.

To be exact about status: the campaign tooling is built and the campaign builds. Nothing in this case study claims a campaign has delivered impressions or produced a cost-per-conversation figure, because switching it live is a decision with a budget attached and it belongs to the business, not to the script.

How it was built: AI-assisted, end to end

The same way kudo.kids is built, applied to a very different shape of work — brand and copy and tooling rather than an app.

52 of the 53 commits on this project are AI co-authored. That covers the Python that talks to the Graph API, the image pipeline, the hand-written HTML and stylesheet, and the rendering scripts that produce the feed graphics and the reel. The positioning and the judgment — what the business should claim, and what it must not — are ours. The execution was collaborative, and the commit log says so rather than hiding it.

The automation goes one step further than development here. Publishing a job is packaged as a single command that a non-engineer can run: point it at a photograph, and it derives the web sizes, builds the Instagram-legal derivative, regenerates the gallery, and posts to both networks. The point of automating that is not speed. It is that a marketing routine which takes four tabs and twenty minutes stops happening by about week three, and one that takes a single command does not.

Where the line is: every numeric claim in the copy was checked by hand against real jobs, and every one is hedged — “typically”, “on the projects I’ve run”. A tool that writes confident marketing copy about a trade it has never worked is exactly how a business ends up making a claim it cannot defend on site.

The work, as photographed

A commercial suite stripped back to bare concrete and framing at the demolition stage

Demolition. Nothing about this stage is persuasive on its own — it matters because of what follows it.

The same space with new flooring laid and partitions closed up

Flooring and partitions. The sequence argument made visually: floor goes down after the dust-making trades are finished, not before.

The finished reception desk and corridor of the completed commercial fit-out

Reception, finished. Three frames from one job, in order, do more selling than any adjective — which is the entire thesis of the content system.

A feed graphic reading: good, fast, cheap — the triangle has a centre

One of the twelve feed graphics. The positioning and the content system are the same argument in two formats.

Judgment calls

No build step

Five pages and one stylesheet. A bundler would have added a toolchain to maintain and would have bought nothing the site actually needs. The deploy is a file sync. Two years from now it will still build, because there is nothing to build.

Standard library only

The publisher talks to the Graph API through urllib. No requirements file, no virtual environment to drift, no supply chain to audit. It will still run in five years on whatever Python is installed.

Changing the message rather than the spend

The first version of the advert claimed all three corners of the triangle and did not convert, because the audience is trained to disbelieve exactly that claim. Reframing planning as the variable that earns the centre fixed it. The lesson worth keeping is that the budget was not the problem.

What we would do differently

The gallery is generated from a marker-delimited block by a Python script, which is the right shape — but the captions live in the HTML rather than beside the photographs. Moving them into a sidecar file next to the images would make adding a job a single-directory operation instead of two edits in two places.

The numbers

~145Files
53Commits
52 of 53AI co-authored commits
5Live pages
227 linesStylesheet
0Build steps
0JavaScript dependencies
74Web-derivative images
12Feed posts rendered
30s, 1080×1920Reel

All figures measured September 2026.

Live

ocdesign949.com · Instagram — @ocdesign949 · Facebook