Instrument x Seth Akkerman
Projects AI Brand Layout Generator

AI Brand Layout Generator

A web tool that generates on-brand marketing layouts with built-in contrast analysis and AI-powered brand compliance checking — built specifically for Nordstrom's creative workflow.

Brand consistency at scale is one of those problems that sounds simple until you’re managing dozens of layout variations across a retail creative team. This tool tackles it head-on — a full-stack layout generator that lets users compose marketing banners, export production-ready HTML and CSS, and get real-time feedback on whether the output actually meets brand standards.

How it works

The frontend is a React app that presents a form-driven layout composer. You pick a layout type (horizontal banner, and others), drop in your main text, upload an image, and select color palettes. A live preview renders at scale in real time using layout definitions that output both preview styles and export-ready HTML/CSS simultaneously. An Express backend handles image processing and export generation, deployed on DigitalOcean, while the frontend lives on Netlify.

What makes it more than a template tool is the AI layer. A Flask microservice wraps OpenAI’s GPT-4o Vision API to analyze uploaded imagery against Nordstrom’s brand guidelines — evaluating subjects, lighting, color palette, composition, and mood, then returning a 0–1 brand alignment score with a detailed breakdown. An earlier iteration used AWS Rekognition to generate image labels before passing them to GPT-4 for evaluation, which is a useful fallback for teams without Vision API access.

The contrast analysis layer

Below the preview, a contrast analysis panel breaks down text legibility against the background — a small but meaningful addition that catches accessibility issues before anything goes to production. It’s the kind of check that usually gets skipped when a designer is moving fast, so baking it into the export flow makes it impossible to miss.

Why it matters

This is a pattern worth paying attention to: brand guardrails embedded directly into the creation tool, not bolted on afterward as a review step. The same architecture could power: creative ops workflows — where junior designers get instant feedback without needing a senior review; multi-brand platforms — swap the guidelines object and the AI evaluates against an entirely different brand identity; content moderation pipelines — where visual brand compliance needs to scale beyond what a human team can review. The real insight is that AI-assisted brand checking works best when it’s friction-free and in-context, not a separate audit tool someone has to remember to use.

Applying this to your project

  1. Clone the right layer. The real app lives in netlify-digitalocean-version/layout-generator/ (a frontend/ React app + backend/ Express app + a shared/ layouts folder). Discard the root-level app.py, brand_checker.py, test_aws_credentials.py, test_openai_credentials.py, and run_on_different_port.py — these are one-off Python prototypes for an early “gut check” experiment (using AWS Rekognition and Flask) that were superseded by the Node backend. Also discard generative-layout-engine/ (a single-file HTML prototype) and the unused root package.json/package-lock.json.

  2. Set up environment variables. Copy frontend/.env and backend/.env templates and fill in: OPENAI_API_KEY (from platform.openai.com) in backend/.env, and REACT_APP_REMOVE_BG_API_KEY (from remove.bg) plus REACT_APP_API_URL (pointing at your backend) in frontend/.env. For local development you can skip real auth entirely — frontend/src/auth/AuthContext.js automatically switches to devAuth.js when NODE_ENV=development, which lets you set your own access role via a browser prompt instead of wiring up Netlify Identity.

  3. Swap out the brand-specific content. The AI prompts in backend/src/routes/generate-ai-text.js and generate-ai-layout.js are hardcoded to a specific retail brand’s voice (“Nordstrom”) — rewrite those prompt strings for your own brand voice and tone. The color palettes in frontend/src/utils/colorUtils.js (warmGrey, beauty, gold, anniversary, etc.) and the logo/wordmark SVG embedded in shared/layouts/LayoutDefinitions.js are also brand-specific and need replacing, as do the fonts referenced in frontend/src/fonts.css.

  4. Know where your content plugs in. shared/layouts/LayoutDefinitions.js is the actual template engine — each entry (style, beauty, ai, instagramPost, etc.) defines dimensions, text constraints, and a generator() function that returns preview styles plus exportable HTML/CSS. frontend/src/components/LayoutGeneratorInput.js is the form that collects a user’s text/images and feeds them into whichever template is selected. On export, backend/src/routes/generate-image.js calls that same generator() function and hands the resulting HTML/CSS to backend/src/services/puppeteer.js, which renders it headlessly into the final PNG. To add a new template, you edit LayoutDefinitions.js first, then wire new fields into LayoutGeneratorInput.js.

  5. Gotchas found while reading the code:

    • shared/layouts/LayoutDefinitions.js and backend/src/layouts/LayoutDefinitions.js are two separate copies that have already drifted apart — until this is unified, template changes need to be made in both places.
    • backend/src/routes/share-preview.js stores shareable preview links in an in-memory Map with a 24-hour expiry — restarting the backend wipes every outstanding preview link, so it’s not durable as-is; swap in Redis or a database if you need persistence.
    • Background removal (frontend/src/components/ImageProcessor.js) calls the remove.bg API directly from the browser, meaning the API key is exposed client-side — acceptable for an internal tool, not for a public-facing one.
    • backend/Dockerfile installs system Chromium and sets PUPPETEER_EXECUTABLE_PATH so Puppeteer can run in DigitalOcean’s container — if you deploy the backend anywhere else, you’ll need to replicate that Chromium install or PNG export will fail silently.
    • Don’t carry forward brand_checker.py — it contains a hardcoded AWS key and secret rather than reading them from environment variables.

Other ways to repurpose this

Product Design

Web Design

Marketing

Branding

Dependencies

react 18.3.1 Core UI framework powering the whole frontend — the layout builder, brand assistant, gut-checker, and logo/trim tools all run as routed React pages.
react-router-dom 7.1.3 Client-side routing between the tool pages (layout tool, brand book, brand assistant, logo generator, trim tool, gut checker, preview links).
@mui/material 6.4.11 Provides the form controls, buttons, and layout chrome for the input panels used to configure each generated layout.
@mui/icons-material 6.4.11 Icon set used throughout the tool UI (upload, zoom, color, export actions).
@emotion/react 11.14.0 Styling engine required by MUI's component theming.
@emotion/styled 11.14.0 Styled-component API used alongside MUI's theme for custom-styled elements.
axios 1.7.7 Frontend HTTP client used to call the Express backend's export, AI, and gut-check endpoints.
html2canvas 1.4.1 Client-side DOM-to-image rendering, used for exports that don't go through the Puppeteer backend (e.g. the logo generator).
react-color 2.19.3 Color picker UI for choosing accent/brand colors when configuring a layout.
react-p5 1.4.1 p5.js wrapper powering the generative/animated canvas in the Loopy and Motion tool pages.
netlify-identity-widget 1.9.2 Production authentication — gates access and supplies the role (admin/some/minimal) used to restrict which fields a user can edit.
lucide-react 0.263.1 Icon set used in custom (non-MUI) components like the image processor/trim tool.
express 4.21.1 Backend API server (DigitalOcean-hosted) exposing the export, AI generation, gut-check, and share-preview routes.
puppeteer 21.11.0 Headless Chromium that renders each layout template's generated HTML/CSS into the final export PNG.
sharp 0.33.5 Server-side image processing/resizing for uploaded and exported images.
fluent-ffmpeg 2.1.3 Encodes exported animation frames into MP4/WebM/GIF for the animation export route.
multer 1.4.5-lts.2 Handles multipart image uploads on the backend (e.g. the gut-check image submission).
cors 2.8.5 Allows the Netlify-hosted frontend to call the separately-hosted DigitalOcean API.
dotenv 16.4.5 Loads OpenAI key and other backend config from `.env` at runtime.
adm-zip 0.5.16 Bundles multi-file exports (e.g. multiple layout assets) into a downloadable zip.
uuid 11.1.0 Generates session/temp-directory IDs for animation export jobs.
axios 1.8.4 Backend HTTP client used to call OpenAI's REST API directly (chat completions + vision) instead of the official SDK.
react-scripts 5.0.1 Create React App build toolchain used to build and serve the frontend.
tailwindcss 3.4.17 Utility classes for the Trim Tool's crop/background-removal UI, layered on top of MUI elsewhere in the app.
@netlify/functions 2.8.2 Wraps a few debug/proxy endpoints (e.g. gut-check) as Netlify Functions alongside the static frontend deploy.
nodemon 3.1.7 Backend auto-restart during local development.
Role
Design Engineer
Tools
React Express Flask OpenAI GPT-4o AWS Rekognition Netlify DigitalOcean TailwindCSS
Video thumbnail for AI Brand Layout Generator