diff --git a/.dockerignore b/.dockerignore index bffc125..2fc9b2e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -42,5 +42,8 @@ source-* # Tests don't need to ship inside the runtime image tests/ +# Standalone static marketing site, deployed separately (marketing-site/README.md) +marketing-site/ + # This file .dockerignore diff --git a/docs/brand/PHOTOGEN-MARKETING-BRIEF.md b/docs/brand/PHOTOGEN-MARKETING-BRIEF.md new file mode 100644 index 0000000..49769f5 --- /dev/null +++ b/docs/brand/PHOTOGEN-MARKETING-BRIEF.md @@ -0,0 +1,164 @@ +# PhotoGen: design and marketing brief + +Version 1, 2026-10-04. Repo: camster91/creative-studio (public, Flask). App: photogen.ashbi.ca. Scope: **the marketing site and assets only.** Another job owns credit metering and pricing logic in PR #152 (`fix/photogen-credit-metering`, which also edits `templates/landing.html`, `templates/terms.html` and the billing code). Don't touch those files. Build the marketing site as a separate static site in `marketing-site/` so the two PRs can't conflict. + +## 1. Positioning + +- **One-liner:** Studio-quality product photos for every channel, built from your real product and brand rules. Press Go. +- **Category shelf:** AI product photography for CPG/DTC brands (Pebblely, Photoroom, Claid, Shopify Magic). +- **Why PhotoGen wins:** + - It starts from your brand and product truth, not a blank prompt. A **Brand Passport** holds colours, fonts, tone and must-never-show rules. **Product Truth** holds the exact SKU, verified facts and approved claims. + - **One button.** Fill in a short work order (goal, audience, channels, style, number of variations). A readiness check shows anything missing, then you press **Go**. + - **Every channel in one run:** square marketplace shots, 4:5 social, 2:3 Pinterest, 16:9 email and web banners. + - **You review before you publish.** No automatic posting. + - **Prompt Studio** gives direct control to anyone who wants to write prompts. + - Your own Gemini key works free. Without one, you use credits. +- **Audience:** + - Founders and e-commerce or marketing leads at lean CPG/DTC brands, typically 1–20 people, selling on Shopify, Amazon and Instagram. They need fresh listing, ad and social images every week and can't book a studio each time. + - Secondary: small agencies and freelancers producing content for several brands (Ashbi's own clients). +- **Anti-persona:** brands that need regulated pack-compliance sign-off without human review; fashion on-model catalog work at scale. +- **Objections to answer:** + - Will it change my packaging or label? It's built from your product photo. Always check the label before you publish; the app says this too. + - Is this just a background remover? No. It's campaign sets with brand rules. + - What does it cost per image? See the credits table. + - Who owns the images? You do, subject to the provider terms. Check `templates/privacy.html` and the terms; don't over-claim. + - Where does my data go? The owner-scoped database plus the image provider, per the Privacy page. + +## 2. Voice + +Confident, practical, a little playful, like a good studio producer. Short sentences, concrete outputs ("12 images, four sizes, one click"). No hype words ("revolutionary", "stunning", "AI-powered magic"). + +## 3. Visual direction (Brand Lock) + +The concept is "the studio in a button". Colour-blocked seamless paper backdrops, the way a photo studio rolls out paper, and one big round cobalt **Go** button as the signature element. Everything else stays white and quiet so the product photos carry the page. + +| Token | Hex | Role | +|---|---|---| +| Graphite | `#16181D` | Text, wordmark | +| White | `#FFFFFF` | Page background | +| Cobalt | `#2340FF` | The Go button, primary CTAs, links. White on Cobalt is 6.5:1 | +| Butter | `#FFE07A` | Backdrop panel (hero, OG) | +| Coral | `#FF8A6B` | Backdrop panel; never for text on white | +| Mint | `#8EE0C1` | Backdrop panel; never for text on white | +| Mist | `#F3F4F6` | Quiet section background, borders `#E4E6EA` | + +- **Type:** **Archivo** (Google Fonts, variable, with a width axis). Headlines use Archivo at width 112–125, weight 800, tracking -0.02em. Body and UI use Archivo at width 100, weight 400/500. One family with a deliberate width contrast. +- **Shape:** + - Photos sit in rounded 20px frames on colour panels. + - The Go button is a true circle, 120px or more on desktop. Pressing it plays a subtle "shutter" scale effect (0.96, then 1). + - Buttons are pill-shaped, with a 48px minimum height. +- **Motion:** one moment. In the hero, the Go button gives one gentle pulse after load. Clicking it scrolls to the "How it works" demo, or goes to signup. Respect `prefers-reduced-motion`. +- **Don'ts:** + - Dark mode with neon accents. + - Gradient blobs. + - All-caps eyebrows on every section. + - Fake logos or testimonials. + - Numbered "01/02/03" markers, except for the real three-step sequence. + +## 4. Site architecture (`marketing-site/`, static HTML/CSS, no build step) + +``` +/ index.html: home (single long page with anchors) +/pricing/ pricing/index.html: plans, credits per image, FAQ +/compare/photoroom/ compare/photoroom/index.html (adapted from content/blog/photoroom-vs-photogen.md; keep claims factual) +/404.html +robots.txt, sitemap.xml, site.webmanifest, favicon set +``` + +- **Header:** logo, then How it works, Examples, Pricing, then Sign in (`https://photogen.ashbi.ca/login`). The primary CTA "Try it free" goes to `https://photogen.ashbi.ca/signup`. +- **Put the app base URL in one place:** a `data-app-url` attribute on ``, with a tiny JS rewrite, or just a clear constant at the top of each page plus a README note. That way Cameron can change the domain once. +- **Footer:** Product (How it works, Pricing, Prompt Studio → `/app`), Compare, Company (Ashbi Design, Contact), Legal (Privacy → app `/privacy`, Terms → app `/terms`). + +## 5. Home page copy + +**Hero** (butter backdrop image right, text left; on mobile, text then image) +- H1: **Your product, shot for every channel. Press Go.** +- Sub: Upload one product photo, set your brand rules once, and PhotoGen produces studio, lifestyle and ad-ready images in every size you sell in. You review before anything goes live. +- Primary: the big round **Go** button, labelled "Try it free" for screen readers and visually "Go". Next to it, the text CTA "Try it free: 5 images on us". Both go to `/signup`. +- Secondary link: "See an example run", which goes to `#example`. +- Image: `hero-studio-set.webp`. + +**Alternative headlines:** +- "A product photoshoot in one click." +- "Studio product photos without the studio." + +**Before and after** (`#example`) +- H2: "One phone photo in. A whole campaign out." +- Left: `before-phone-snapshot.webp`, captioned "What you upload". +- Right: a 2×2 grid of `channel-marketplace-1x1`, `channel-instagram-4x5`, `channel-pinterest-2x3` and `channel-email-16x9`, each tagged with its size and use: "Marketplace 1:1", "Instagram 4:5", "Pinterest 2:3", "Email banner 16:9". +- Small print: "Example images created with PhotoGen's workflow for a sample product. Not a customer." + +**How it works.** A real sequence, so numbers are allowed. Icons: brand-passport, product-truth, go. +1. **Set your brand once.** Colours, fonts, tone, and anything that must never appear. +2. **Add the product and what's true about it.** Exact SKU, verified facts and approved claims, so images never invent a benefit. +3. **Pick channels and press Go.** PhotoGen checks that nothing is missing, then makes the full set. + +**Benefits.** Three, with icons channels, review and work-order: +- **Every size, one run.** Square, portrait, Pinterest and banner formats from a single brief. +- **On-brand by default.** Your rules ride along with every generation. +- **You stay in charge.** Review and refine before anything ships. Prefer prompts? Prompt Studio gives direct control. + +**Range strip.** Three category images on their colour panels: `yuzu-can-studio` (drinks), `serum-mint` (beauty), `coffee-bag` (pantry). Caption: "Drinks, beauty, pantry, supplements: if it has a pack, PhotoGen can shoot it." + +**Pricing teaser.** +- Starter $19/mo (100 credits). +- **Pro $49/mo (500 credits), recommended.** +- Studio $99/mo (1,500 credits). +- "5 free credits when you sign up. Bring your own Gemini key and generate without credits." +- Link to `/pricing/`. + +**FAQ** (with FAQPage JSON-LD): +- Will PhotoGen change my label or packaging? It works from your product photo and your product facts, but AI can still get small details wrong. Check every image against the real pack before you publish. +- How is this different from a background remover? It makes complete campaign sets (studio, lifestyle and ad formats) from your brand rules and approved claims, not a single cut-out. +- What does an image cost? Simple images cost 1 credit, high-quality images 2, and Ultra images 5. A Pro plan covers about 500 everyday images a month. +- Can I use my own API key? Yes. Add your Gemini key in the app and generation doesn't use credits. +- Where does my data go? Your brand and product records stay in your PhotoGen account. Images and prompts are sent to the image provider to generate results. See the Privacy page. + +**Final CTA.** Coral backdrop. +- H2: "Your next product shoot is one click away." +- The Go button. +- "5 free images. No card required." (Verify against the signup flow: a magic link plus 5 trial credits. Don't promise "no card" if signup asks for one.) + +## 6. Pricing page + +- Plans: Starter $19 (100 credits), Pro $49 (500, recommended), Studio $99 (1,500). Monthly, cancel anytime through the Stripe customer portal. Mention the portal only because it exists in code. +- Credits-per-image table, taken from PR #152's `CREDIT_WEIGHT_BY_TIER`: + + | Tier | Credits per image | + |---|---| + | Fast | 1 | + | Balanced | 1 | + | Quality | 2 | + | Ultra | 5 | + +- Add an HTML comment noting that it must match `billing.py` once #152 merges. +- Show "≈ images per month" for each plan at Balanced and at Ultra. +- Include the BYO-key note, the FAQ, and `Product` + `Offer` JSON-LD. +- No annual toggle (none exists in code). + +## 7. SEO + +- **Home title:** "PhotoGen: AI Product Photography for DTC & CPG Brands" (≤60 characters). +- **Meta description:** "Turn one product photo into studio, lifestyle and ad-ready images for Amazon, Shopify, Instagram and email. Set your brand rules once and press Go." +- **Keywords:** AI product photography, product photos for Shopify, Amazon product images, AI product photoshoot, CPG product photography. +- **Canonical:** use a placeholder origin from one config (`https://photogen.ashbi.ca` for now), noted in the README. +- **OG:** `og.jpg`. Also set `twitter:card` to `summary_large_image`. +- **JSON-LD:** `SoftwareApplication` with offers, plus `FAQPage`. +- **Images:** WebP with width/height set, lazy-loaded below the fold. Preload the hero. +- **Performance:** keep the whole page under ~1.5 MB on first load. No JS framework. + +## 8. Asset list (`/workspace/brand-assets/photogen/`) + +All made with Higgsfield. The sample product "Yuzu Tonic" is fictional. + +| File (web/) | Use | +|---|---| +| `logo-a-aperture-go.svg` | **Recommended mark:** aperture iris with a Go triangle. Pair it with the wordmark "PhotoGen" set in Archivo Expanded 800 (needs Cameron's approval) | +| `logo-b-sweep-tile.svg`, `logo-c-shutter-p.svg` | Alternatives | +| `icon-512.png`, `icon-192.png`, `apple-touch-icon.png`, `favicon-32.png` | Favicons from logo A | +| `hero-studio-set.webp` | Hero | +| `before-phone-snapshot.webp` | "What you upload" | +| `channel-marketplace-1x1.webp`, `channel-instagram-4x5.webp`, `channel-pinterest-2x3.webp`, `channel-email-16x9.webp` | Channel set | +| `yuzu-can-studio.webp`, `serum-mint.webp`, `coffee-bag.webp` | Range strip | +| `brand-passport.svg`, `product-truth.svg`, `work-order.svg`, `go.svg`, `channels.svg`, `review.svg` | Icons (Graphite + Cobalt) | +| `og.jpg` | 1200×630 share card | diff --git a/marketing-site/404.html b/marketing-site/404.html new file mode 100644 index 0000000..c5d4a95 --- /dev/null +++ b/marketing-site/404.html @@ -0,0 +1,48 @@ + + + + + + Page not found | PhotoGen + + + + + + + + + + + + + + + + +
+
+

This shot didn't make the set.

+

The page you asked for isn't here. It may have moved, or the link has a typo.

+

Back to the home page

+

Looking for your work? Open your campaigns in the app.

+
+
+ + diff --git a/marketing-site/README.md b/marketing-site/README.md new file mode 100644 index 0000000..ab1f126 --- /dev/null +++ b/marketing-site/README.md @@ -0,0 +1,62 @@ +# PhotoGen marketing site + +A standalone static site for PhotoGen: plain HTML, one CSS file and a few lines of JS. No framework, no build step, no npm dependencies. It's separate from the Flask app so it can be deployed and changed on its own. + +Brief and Brand Lock: [`docs/brand/PHOTOGEN-MARKETING-BRIEF.md`](../docs/brand/PHOTOGEN-MARKETING-BRIEF.md). + +``` +marketing-site/ + index.html Home + pricing/index.html Plans, credits per image, FAQ + compare/photoroom/index.html + 404.html + robots.txt sitemap.xml site.webmanifest + assets/site.css All styles + assets/site.js App URL (the one place to change it) + assets/img/ assets/icons/ Higgsfield-generated images and icons +``` + +## Preview + +Pages use root paths (`/assets/...`), so serve the folder as the web root. Either: + +```sh +npx serve marketing-site +# or +python3 -m http.server 8080 --directory marketing-site +``` + +Then open the printed URL. Opening the HTML files straight from disk won't load styles. + +## Deploy + +Any static host works. Publish the `marketing-site/` folder as the site root and serve `404.html` for missing pages. + +- **Cloudflare Pages:** build command none, output directory `marketing-site`. `404.html` is picked up automatically. +- **Coolify:** create a new application from this repo using the Static build pack, base directory `/marketing-site`, no build command. If auto-deploy is on, every push to `main` redeploys it. +- **Plain Nginx/Caddy on the VPS:** copy the folder and set `try_files $uri $uri/ =404; error_page 404 /404.html;`. + +It's excluded from the app Docker image via `.dockerignore`. + +## Change the app URL + +All sign-up, sign-in and app links point at the PhotoGen app, `https://photogen.ashbi.ca` by default. + +- **App URL:** edit `APP_URL` at the top of `assets/site.js`. Every link marked `data-app="/path"` is rewritten to `APP_URL + path` on load. The `href`s in the HTML hold the default so links still work without JS; if the app moves permanently, also run the find-and-replace below so crawlers see the new URL. +- **Canonical domain** (canonical tags, Open Graph URLs, JSON-LD, `robots.txt`, `sitemap.xml`): these must be in the HTML, so change them with one find-and-replace: + + ```sh + grep -rl 'https://photogen.ashbi.ca' marketing-site | xargs sed -i 's#https://photogen.ashbi.ca#https://NEW-DOMAIN#g' + ``` + + If the marketing site takes the root domain and the app moves to `app.`, run that for the canonical domain, then set `APP_URL` and replace the `data-app` link `href`s with the app subdomain. + +## Keep pricing in sync + +- Plans and monthly credits must match `_BILLING_PLANS` in `scripts/creative-studio-web.py`. +- The credits-per-image table on `pricing/index.html` (and the "≈ images" figures and FAQ answers on the home and pricing pages) must match `CREDIT_WEIGHT_BY_TIER` in `billing.py` once PR #152 merges. Today that's Fast 1, Balanced 1, Quality 2, Ultra 5. +- Prices in the JSON-LD assume USD. Change `priceCurrency` if Stripe bills in another currency. + +## Checks + +No test suite. Before publishing, serve the folder and click through each page on mobile and desktop, and make sure every local `src`/`href` resolves. diff --git a/marketing-site/assets/apple-touch-icon.png b/marketing-site/assets/apple-touch-icon.png new file mode 100644 index 0000000..b74c8d3 Binary files /dev/null and b/marketing-site/assets/apple-touch-icon.png differ diff --git a/marketing-site/assets/favicon-32.png b/marketing-site/assets/favicon-32.png new file mode 100644 index 0000000..108dc4f Binary files /dev/null and b/marketing-site/assets/favicon-32.png differ diff --git a/marketing-site/assets/icon-192.png b/marketing-site/assets/icon-192.png new file mode 100644 index 0000000..dadbdc4 Binary files /dev/null and b/marketing-site/assets/icon-192.png differ diff --git a/marketing-site/assets/icon-512.png b/marketing-site/assets/icon-512.png new file mode 100644 index 0000000..edd0548 Binary files /dev/null and b/marketing-site/assets/icon-512.png differ diff --git a/marketing-site/assets/icons/brand-passport.svg b/marketing-site/assets/icons/brand-passport.svg new file mode 100644 index 0000000..0d7010e --- /dev/null +++ b/marketing-site/assets/icons/brand-passport.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/marketing-site/assets/icons/channels.svg b/marketing-site/assets/icons/channels.svg new file mode 100644 index 0000000..98105fc --- /dev/null +++ b/marketing-site/assets/icons/channels.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/marketing-site/assets/icons/go.svg b/marketing-site/assets/icons/go.svg new file mode 100644 index 0000000..a06f2e8 --- /dev/null +++ b/marketing-site/assets/icons/go.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/marketing-site/assets/icons/product-truth.svg b/marketing-site/assets/icons/product-truth.svg new file mode 100644 index 0000000..2e802f2 --- /dev/null +++ b/marketing-site/assets/icons/product-truth.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/marketing-site/assets/icons/review.svg b/marketing-site/assets/icons/review.svg new file mode 100644 index 0000000..4df2a02 --- /dev/null +++ b/marketing-site/assets/icons/review.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/marketing-site/assets/icons/work-order.svg b/marketing-site/assets/icons/work-order.svg new file mode 100644 index 0000000..670d0d1 --- /dev/null +++ b/marketing-site/assets/icons/work-order.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/marketing-site/assets/img/before-phone-snapshot.webp b/marketing-site/assets/img/before-phone-snapshot.webp new file mode 100644 index 0000000..c9a9cbf Binary files /dev/null and b/marketing-site/assets/img/before-phone-snapshot.webp differ diff --git a/marketing-site/assets/img/channel-email-16x9.webp b/marketing-site/assets/img/channel-email-16x9.webp new file mode 100644 index 0000000..e1e5f45 Binary files /dev/null and b/marketing-site/assets/img/channel-email-16x9.webp differ diff --git a/marketing-site/assets/img/channel-instagram-4x5.webp b/marketing-site/assets/img/channel-instagram-4x5.webp new file mode 100644 index 0000000..947e8b0 Binary files /dev/null and b/marketing-site/assets/img/channel-instagram-4x5.webp differ diff --git a/marketing-site/assets/img/channel-marketplace-1x1.webp b/marketing-site/assets/img/channel-marketplace-1x1.webp new file mode 100644 index 0000000..e787933 Binary files /dev/null and b/marketing-site/assets/img/channel-marketplace-1x1.webp differ diff --git a/marketing-site/assets/img/channel-pinterest-2x3.webp b/marketing-site/assets/img/channel-pinterest-2x3.webp new file mode 100644 index 0000000..ff1120b Binary files /dev/null and b/marketing-site/assets/img/channel-pinterest-2x3.webp differ diff --git a/marketing-site/assets/img/coffee-bag.webp b/marketing-site/assets/img/coffee-bag.webp new file mode 100644 index 0000000..36c1ce9 Binary files /dev/null and b/marketing-site/assets/img/coffee-bag.webp differ diff --git a/marketing-site/assets/img/hero-studio-set.webp b/marketing-site/assets/img/hero-studio-set.webp new file mode 100644 index 0000000..46f7ced Binary files /dev/null and b/marketing-site/assets/img/hero-studio-set.webp differ diff --git a/marketing-site/assets/img/serum-mint.webp b/marketing-site/assets/img/serum-mint.webp new file mode 100644 index 0000000..0c9f426 Binary files /dev/null and b/marketing-site/assets/img/serum-mint.webp differ diff --git a/marketing-site/assets/img/yuzu-can-studio.webp b/marketing-site/assets/img/yuzu-can-studio.webp new file mode 100644 index 0000000..3f924f0 Binary files /dev/null and b/marketing-site/assets/img/yuzu-can-studio.webp differ diff --git a/marketing-site/assets/logo.svg b/marketing-site/assets/logo.svg new file mode 100644 index 0000000..f2d7800 --- /dev/null +++ b/marketing-site/assets/logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/marketing-site/assets/og.jpg b/marketing-site/assets/og.jpg new file mode 100644 index 0000000..5b49e6c Binary files /dev/null and b/marketing-site/assets/og.jpg differ diff --git a/marketing-site/assets/site.css b/marketing-site/assets/site.css new file mode 100644 index 0000000..a10d418 --- /dev/null +++ b/marketing-site/assets/site.css @@ -0,0 +1,529 @@ +/* PhotoGen marketing site. Brand Lock: docs/brand/PHOTOGEN-MARKETING-BRIEF.md §3 */ + +:root { + --graphite: #16181D; + --white: #FFFFFF; + --cobalt: #2340FF; + --cobalt-deep: #1A30CC; + --butter: #FFE07A; + --coral: #FF8A6B; + --mint: #8EE0C1; + --mist: #F3F4F6; + --line: #E4E6EA; + --muted: #4A4F59; + + --wide: 125; + --page: min(1200px, 100% - 2.5rem); + --frame: 20px; + --panel: 32px; + --space: clamp(4rem, 9vw, 7.5rem); +} + +*, *::before, *::after { box-sizing: border-box; } + +html { + -webkit-text-size-adjust: 100%; + scroll-behavior: smooth; + scroll-padding-top: 5.5rem; +} + +body { + margin: 0; + background: var(--white); + color: var(--graphite); + font-family: "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif; + font-size: 1.0625rem; + line-height: 1.6; + font-variation-settings: "wdth" 100; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; +} + +img { display: block; max-width: 100%; height: auto; } + +a { color: var(--cobalt); text-underline-offset: 0.18em; text-decoration-thickness: 1px; } +a:hover { text-decoration-thickness: 2px; } + +:focus-visible { + outline: 3px solid var(--cobalt); + outline-offset: 3px; + border-radius: 6px; +} + +h1, h2, h3 { + margin: 0; + font-weight: 800; + font-variation-settings: "wdth" var(--wide); + font-stretch: 125%; + letter-spacing: -0.02em; + line-height: 1.04; + text-wrap: balance; +} +h1 { font-size: clamp(2.5rem, 6.4vw, 4.75rem); } +h2 { font-size: clamp(2rem, 4.4vw, 3.25rem); } +h3 { font-size: 1.3125rem; line-height: 1.2; --wide: 112; font-stretch: 112%; } + +p { margin: 0; text-wrap: pretty; } + +.wrap { width: var(--page); margin-inline: auto; } +.section { padding-block: var(--space); } +.section--mist { background: var(--mist); } +.lede { font-size: clamp(1.125rem, 1.6vw, 1.3125rem); color: var(--muted); max-width: 38em; } +.section-head { max-width: 46rem; margin-bottom: clamp(2.5rem, 5vw, 3.5rem); } +.section-head p { margin-top: 1rem; } +.fine { font-size: 0.875rem; color: var(--muted); } + +.skip-link { + position: absolute; + left: 1rem; + top: -4rem; + z-index: 100; + padding: 0.75rem 1.25rem; + background: var(--graphite); + color: var(--white); + border-radius: 999px; + font-weight: 600; +} +.skip-link:focus { top: 1rem; } + +.visually-hidden { + position: absolute !important; + width: 1px; height: 1px; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; +} + +/* Header */ + +.site-header { + position: sticky; + top: 0; + z-index: 50; + background: rgb(255 255 255 / 0.94); + backdrop-filter: saturate(1.4) blur(10px); + border-bottom: 1px solid var(--line); +} +.site-header .wrap { + display: flex; + align-items: center; + gap: 1rem; + min-height: 4.5rem; +} + +.brand { + display: inline-flex; + align-items: center; + gap: 0.55rem; + min-height: 44px; + color: var(--graphite); + text-decoration: none; + font-weight: 800; + font-size: 1.3125rem; + font-variation-settings: "wdth" 125; + font-stretch: 125%; + letter-spacing: -0.02em; +} +.brand img { width: 34px; height: 34px; } + +.nav { display: none; margin-left: 1.5rem; gap: 0.25rem; } +.nav a, .header-signin { + display: inline-flex; + align-items: center; + min-height: 44px; + padding-inline: 0.75rem; + color: var(--graphite); + text-decoration: none; + font-weight: 500; + border-radius: 999px; +} +.nav a:hover, .header-signin:hover { background: var(--mist); } +.nav a[aria-current="page"] { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 0.35em; } + +.header-actions { margin-left: auto; display: flex; align-items: center; gap: 0.25rem; } + +@media (min-width: 820px) { + .nav { display: flex; } +} + +/* Buttons */ + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 48px; + padding: 0.75rem 1.5rem; + border-radius: 999px; + border: 2px solid transparent; + font: inherit; + font-weight: 600; + line-height: 1.2; + text-align: center; + text-decoration: none; + cursor: pointer; + transition: background-color 0.15s ease, transform 0.12s ease; +} +.btn--primary { background: var(--cobalt); color: var(--white); } +.btn--primary:hover { background: var(--cobalt-deep); } +.btn--ghost { border-color: var(--graphite); color: var(--graphite); background: transparent; } +.btn--ghost:hover { background: var(--graphite); color: var(--white); } +.btn:active { transform: scale(0.97); } +.btn--primary:focus-visible { outline-color: var(--graphite); } +.header-actions .btn { min-height: 44px; padding-inline: 1.1rem; } + +/* The Go button: the one signature element. */ + +.go { + --size: 104px; + position: relative; + display: inline-grid; + place-items: center; + flex: none; + width: var(--size); + height: var(--size); + border-radius: 50%; + background: var(--cobalt); + color: var(--white); + text-decoration: none; + font-weight: 800; + font-size: calc(var(--size) * 0.3); + font-variation-settings: "wdth" 125; + font-stretch: 125%; + letter-spacing: -0.02em; + box-shadow: 0 0 0 6px var(--white), 0 18px 30px -14px rgb(35 64 255 / 0.65); + transition: transform 0.14s cubic-bezier(.3,.7,.4,1), background-color 0.15s ease; +} +.go:hover { background: var(--cobalt-deep); } +.go:active { transform: scale(0.96); } +.go:focus-visible { outline: 3px solid var(--graphite); outline-offset: 9px; border-radius: 50%; } +.go--pulse { animation: go-pulse 1.4s ease-out 0.9s 1 both; } +.go--on-panel { box-shadow: 0 18px 30px -14px rgb(22 24 29 / 0.45); } + +@keyframes go-pulse { + 0% { box-shadow: 0 0 0 6px var(--white), 0 0 0 6px rgb(35 64 255 / 0.45), 0 18px 30px -14px rgb(35 64 255 / 0.65); } + 60% { box-shadow: 0 0 0 6px var(--white), 0 0 0 30px rgb(35 64 255 / 0), 0 18px 30px -14px rgb(35 64 255 / 0.65); } + 100% { box-shadow: 0 0 0 6px var(--white), 0 0 0 30px rgb(35 64 255 / 0), 0 18px 30px -14px rgb(35 64 255 / 0.65); } +} + +@media (min-width: 960px) { + .go { --size: 132px; } +} + +/* Panels: colour-blocked seamless paper. */ + +.panel { + border-radius: var(--panel); + padding: clamp(0.875rem, 2.4vw, 1.75rem); +} +.panel--butter { background: var(--butter); } +.panel--coral { background: var(--coral); } +.panel--mint { background: var(--mint); } +.panel--mist { background: var(--mist); } + +.frame { border-radius: var(--frame); overflow: hidden; background: var(--mist); } +.frame img { width: 100%; } + +/* Hero */ + +.hero { padding-block: clamp(2.5rem, 6vw, 5rem) var(--space); } +.hero .wrap { + display: grid; + gap: clamp(2.5rem, 5vw, 4rem); + align-items: center; +} +.hero h1 { max-width: 11em; } +.hero .lede { margin-top: 1.5rem; } + +.hero-cta { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 1.25rem 1.75rem; + margin-top: 2.25rem; +} +.hero-cta__text { display: grid; gap: 0.25rem; justify-items: start; } +.cta-link { + display: inline-flex; + align-items: center; + min-height: 44px; + font-weight: 700; + font-size: 1.125rem; + color: var(--graphite); + text-decoration-color: var(--cobalt); + text-decoration-thickness: 2px; +} +.cta-link:hover { color: var(--cobalt); } +.text-link { display: inline-flex; align-items: center; min-height: 44px; font-weight: 500; } + +.hero-media .frame { aspect-ratio: 2000 / 1116; } +.hero-media img { height: 100%; object-fit: cover; } + +@media (min-width: 960px) { + .hero .wrap { grid-template-columns: 5fr 6fr; } +} + +/* Before / after */ + +.run { + display: grid; + gap: 1.5rem; + align-items: center; +} +.run figure { margin: 0; } +.run figcaption, .tile figcaption { + margin-top: 0.75rem; + font-weight: 600; +} +.run__arrow { + display: grid; + place-items: center; + justify-self: center; + width: 64px; + height: 64px; + border-radius: 50%; + background: var(--cobalt); + color: var(--white); + font-weight: 800; + font-variation-settings: "wdth" 125; + font-stretch: 125%; +} +.tiles { + display: grid; + grid-template-columns: 1fr 1fr; + gap: clamp(0.75rem, 2vw, 1.25rem); +} +.tile { margin: 0; } +.tile__stage { + display: grid; + place-items: center; + aspect-ratio: 1; + padding: clamp(0.75rem, 2vw, 1.25rem); + background: var(--mist); + border-radius: var(--frame); +} +.tile__stage img { + max-height: 100%; + width: auto; + border-radius: 10px; + object-fit: contain; +} +.tile figcaption { font-size: 0.9375rem; } +.tile figcaption span { display: block; font-weight: 400; color: var(--muted); } +.run__note { margin-top: 2rem; } + +@media (min-width: 900px) { + .run { grid-template-columns: 5fr auto 7fr; gap: 2rem; } +} + +/* Steps: a real three-step sequence, so numbers are allowed. */ + +.steps { + display: grid; + gap: 2.5rem; + padding: 0; + margin: 0; + list-style: none; + counter-reset: step; +} +.step { counter-increment: step; display: grid; gap: 0.75rem; align-content: start; } +.step__top { display: flex; align-items: center; justify-content: space-between; } +.step__top::before { + content: counter(step); + font-weight: 800; + font-size: 4rem; + line-height: 1; + font-variation-settings: "wdth" 125; + font-stretch: 125%; + color: var(--graphite); +} +.step img { width: 56px; height: 56px; } +.step h3 { margin-top: 0.5rem; } +.step p { color: var(--muted); } + +@media (min-width: 820px) { + .steps { grid-template-columns: repeat(3, 1fr); gap: 3rem; } + .step + .step { border-left: 1px solid var(--line); padding-left: 3rem; } +} + +/* Benefits */ + +.benefits { display: grid; gap: 2.5rem; } +.benefit { display: grid; grid-template-columns: 56px 1fr; gap: 1.25rem; align-items: start; } +.benefit img { width: 56px; height: 56px; } +.benefit p { margin-top: 0.5rem; color: var(--muted); } + +@media (min-width: 820px) { + .benefits { grid-template-columns: repeat(3, 1fr); gap: 3rem; } + .benefit { grid-template-columns: 1fr; } +} + +/* Range strip */ + +.range { display: grid; gap: 1rem; margin: 0; padding: 0; list-style: none; } +.range figure { margin: 0; } +.range .frame { aspect-ratio: 4 / 5; } +.range img { height: 100%; object-fit: cover; } +.range figcaption { margin-top: 0.75rem; font-weight: 600; padding-left: 0.25rem; } +.range-caption { margin-top: 2rem; font-size: 1.125rem; max-width: 40em; } + +@media (min-width: 700px) { + .range { grid-template-columns: repeat(3, 1fr); } + .range li:nth-child(2) { transform: translateY(2rem); } +} + +/* Plans */ + +.plans { display: grid; gap: 1.25rem; } +.plan { + position: relative; + display: flex; + flex-direction: column; + gap: 1rem; + padding: 2rem; + border: 1px solid var(--line); + border-radius: var(--frame); + background: var(--white); +} +.plan--pick { border: 2px solid var(--cobalt); box-shadow: 0 24px 40px -28px rgb(35 64 255 / 0.55); } +.plan__flag { + align-self: flex-start; + padding: 0.25rem 0.75rem; + border-radius: 999px; + background: var(--cobalt); + color: var(--white); + font-size: 0.875rem; + font-weight: 600; +} +.plan h3 { font-size: 1.5rem; } +.plan__price { + font-weight: 800; + font-size: 3rem; + line-height: 1; + font-variation-settings: "wdth" 112; + font-stretch: 112%; + letter-spacing: -0.02em; +} +.plan__price span { font-size: 1rem; font-weight: 500; letter-spacing: 0; color: var(--muted); } +.plan__credits { font-weight: 600; } +.plan ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.5rem; color: var(--muted); } +.plan ul li { padding-left: 1.4rem; position: relative; } +.plan ul li::before { + content: ""; + position: absolute; + left: 0; top: 0.6em; + width: 0.55rem; height: 0.55rem; + border-radius: 50%; + background: var(--cobalt); +} +.plan .btn { margin-top: auto; } +.plans-note { margin-top: 2rem; display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; align-items: center; } + +@media (min-width: 900px) { + .plans { grid-template-columns: repeat(3, 1fr); align-items: stretch; } +} + +/* Credit table */ + +.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--frame); } +table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; } +caption { text-align: left; padding: 1.25rem 1.5rem 0; font-weight: 700; } +th, td { padding: 1rem 1.5rem; text-align: left; border-bottom: 1px solid var(--line); vertical-align: top; } +thead th { font-weight: 600; color: var(--muted); font-size: 0.9375rem; } +tbody tr:last-child th, tbody tr:last-child td { border-bottom: 0; } +tbody th { font-weight: 600; } +td.num, th.num { text-align: right; } + +/* FAQ */ + +.faq { max-width: 52rem; } +.faq details { border-bottom: 1px solid var(--line); } +.faq details:first-of-type { border-top: 1px solid var(--line); } +.faq summary { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + min-height: 64px; + padding-block: 1rem; + font-weight: 600; + font-size: 1.125rem; + cursor: pointer; + list-style: none; +} +.faq summary::-webkit-details-marker { display: none; } +.faq summary::after { + content: ""; + flex: none; + width: 14px; height: 14px; + border-right: 2.5px solid var(--graphite); + border-bottom: 2.5px solid var(--graphite); + transform: translateY(-3px) rotate(45deg); + transition: transform 0.2s ease; +} +.faq details[open] summary::after { transform: translateY(3px) rotate(-135deg); } +.faq details p { padding-bottom: 1.5rem; max-width: 44em; color: var(--muted); } + +/* Final CTA */ + +.closer { padding-block: var(--space); } +.closer .panel { + display: grid; + gap: 2rem; + justify-items: start; + padding: clamp(2.5rem, 7vw, 5rem); +} +.closer h2 { max-width: 12em; } +.closer__row { display: flex; flex-wrap: wrap; align-items: center; gap: 1.25rem 2rem; } +.closer__row p { font-weight: 600; font-size: 1.125rem; max-width: 20em; } + +@media (min-width: 900px) { + .closer .panel { grid-template-columns: 1fr auto; align-items: center; } +} + +/* Compare */ + +.verdicts { display: grid; gap: 1.25rem; } +.verdict { padding: 2rem; border-radius: var(--frame); } +.verdict h2 { font-size: 1.5rem; --wide: 112; font-stretch: 112%; } +.verdict ul { margin: 1rem 0 0; padding-left: 1.2rem; display: grid; gap: 0.5rem; } +@media (min-width: 820px) { .verdicts { grid-template-columns: 1fr 1fr; } } + +.prose { max-width: 44rem; } +.prose > * + * { margin-top: 1rem; } +.prose h2 { font-size: clamp(1.625rem, 3vw, 2.25rem); margin-top: 3rem; } +.prose ul { padding-left: 1.2rem; display: grid; gap: 0.5rem; } + +.page-head { padding-block: clamp(3rem, 7vw, 5.5rem) clamp(2rem, 4vw, 3rem); } +.page-head .lede { margin-top: 1.25rem; } + +/* Footer */ + +.site-footer { border-top: 1px solid var(--line); padding-block: 4rem 3rem; font-size: 0.9375rem; } +.footer-grid { display: grid; gap: 2rem; grid-template-columns: repeat(2, 1fr); } +.footer-grid h2 { font-size: 0.9375rem; font-weight: 700; letter-spacing: 0; font-variation-settings: "wdth" 100; font-stretch: 100%; } +.footer-grid ul { list-style: none; margin: 0.5rem 0 0; padding: 0; } +.footer-grid a { display: inline-flex; align-items: center; min-height: 44px; color: var(--graphite); text-decoration: none; } +.footer-grid a:hover { color: var(--cobalt); text-decoration: underline; } +.footer-brand { grid-column: 1 / -1; display: grid; gap: 0.75rem; max-width: 22rem; } +.footer-brand p { color: var(--muted); } +.footer-base { margin-top: 3rem; color: var(--muted); } + +@media (min-width: 820px) { + .footer-grid { grid-template-columns: 2fr repeat(4, 1fr); } + .footer-brand { grid-column: auto; } +} + +/* 404 */ + +.lost { min-height: 60vh; display: grid; align-content: center; gap: 1.5rem; padding-block: var(--space); } + +@media (prefers-reduced-motion: reduce) { + html { scroll-behavior: auto; } + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + .go--pulse { animation: none; } +} diff --git a/marketing-site/assets/site.js b/marketing-site/assets/site.js new file mode 100644 index 0000000..176cb28 --- /dev/null +++ b/marketing-site/assets/site.js @@ -0,0 +1,8 @@ +// Where the PhotoGen app lives. This is the one place to change it. +// Every app link is marked up as , +// so links work without JS and are rewritten here if APP_URL changes. +const APP_URL = 'https://photogen.ashbi.ca'; + +document.querySelectorAll('a[data-app]').forEach((link) => { + link.href = APP_URL + link.dataset.app; +}); diff --git a/marketing-site/compare/photoroom/index.html b/marketing-site/compare/photoroom/index.html new file mode 100644 index 0000000..d93bff7 --- /dev/null +++ b/marketing-site/compare/photoroom/index.html @@ -0,0 +1,182 @@ + + + + + + Photoroom vs PhotoGen: Which Fits Your CPG Brand? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Photoroom vs PhotoGen

+

Both make product photos. They're built for different jobs. Photoroom is a fast editor for cut-outs and clean backgrounds. PhotoGen makes whole campaign sets from your brand rules and product facts. Here's how to pick.

+
+
+ +
+
+
+
+

Pick Photoroom if you mostly need

+
    +
  • Background removal for product-page PNGs
  • +
  • Quick edits to a photo you already have, like swapping the background
  • +
  • A mature editor with lots of ready-made templates
  • +
+
+
+

Pick PhotoGen if you need

+
    +
  • Lifestyle and ad scenes, not just a cut-out
  • +
  • One brief that returns every channel size you sell in
  • +
  • Brand rules and approved claims applied to every image
  • +
  • A review step before anything goes live
  • +
+
+
+
+
+ +
+
+
+

Job by job

+
+
+ + + + + + + + + + + + + +
Which tool fits each product photo job
JobPhotoroomPhotoGen
Cut out a background for a product pageStrong fitWorks, but it's more than you need
Hero shot on a clean studio backgroundStrong fitStrong fit
Five lifestyle scenes from one product photoNot its focusBuilt for it: in-hand, studio, action, lifestyle and with-props in one run
Marketplace 1:1, Instagram 4:5, Pinterest 2:3 and email 16:9 from one briefTemplates and resizing per formatOne work order, every size
Keep brand rules and approved claims on every imageBrand kit for logos, fonts and coloursBrand Passport plus Product Truth, checked before generation
Small change to an existing photoStrong fitWeaker: PhotoGen generates new images
+
+

Photoroom details reflect our understanding as of October 2026. Check photoroom.com for its current features and pricing.

+
+
+ +
+
+

What neither tool does for you

+
    +
  • Pack-level sign-off. AI can get small label details wrong. Check every image against the real pack before you publish, whichever tool made it.
  • +
  • Fine colour control. "This exact colour, slightly warmer" is still easier in a photo editor. Both tools trade some control for speed.
  • +
  • Tricky materials. Hair, fur and translucent packaging are hard edge cases for generative tools.
  • +
+

Many brands use both

+

Photoroom for the product page cut-outs, PhotoGen for the launch campaign. If your week is mostly ads, social and email, start with PhotoGen. If it's mostly product-page PNGs, start with Photoroom.

+

How PhotoGen is priced

+

Monthly plans from $19 for 100 credits, with 1 credit per everyday image. Or bring your own Gemini key and generate without credits. See pricing.

+
+
+ +
+
+
+

See what one brief makes.

+
+ Go +

5 free credits. No card required. Sign in with an email link.

+
+
+
+
+
+ + + + diff --git a/marketing-site/index.html b/marketing-site/index.html new file mode 100644 index 0000000..8ed1619 --- /dev/null +++ b/marketing-site/index.html @@ -0,0 +1,352 @@ + + + + + + PhotoGen: AI Product Photography for DTC & CPG Brands + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Your product, shot for every channel. Press Go.

+

Upload one product photo, set your brand rules once, and PhotoGen produces studio, lifestyle and ad-ready images in every size you sell in. You review before anything goes live.

+ +
+
+
+ A Yuzu Tonic can on a white plinth against a yellow paper backdrop, with a softbox and studio lights either side. +
+
+
+
+ +
+
+
+

One phone photo in. A whole campaign out.

+

One run, four channel sizes, the same can every time.

+
+
+
+
+ A phone snapshot of a Yuzu Tonic can on a cluttered kitchen counter, next to a dish rack, a sponge and a fruit bowl. +
+
What you upload
+
+ +
+
+
The can on a clean white background.
+
Marketplace 1:1Amazon and Shopify listings
+
+
+
A hand lifting the can from a rooftop table with sliced yuzu and an iced drink at golden hour.
+
Instagram 4:5Feed posts and ads
+
+
+
Overhead flat lay of the can on yellow with yuzu slices, mint, crushed ice and petals.
+
Pinterest 2:3Pins
+
+
+
The can mid-splash with yuzu halves on a coral background, with open space on the left for a headline.
+
Email banner 16:9Email and web headers
+
+
+
+

Example images created with PhotoGen's workflow for a sample product. Not a customer.

+
+
+ +
+
+
+

How it works

+

Three steps. The first two you do once per brand and product.

+
+
    +
  1. +
    +

    Set your brand once.

    +

    Colours, fonts, tone, and anything that must never appear. It's saved as your Brand Passport.

    +
  2. +
  3. +
    +

    Add the product and what's true about it.

    +

    Exact SKU, verified facts and approved claims, so images never invent a benefit.

    +
  4. +
  5. +
    +

    Pick channels and press Go.

    +

    Fill in a short work order: goal, audience, channels, style and how many variations. PhotoGen checks that nothing is missing, then makes the full set.

    +
  6. +
+
+
+ +
+
+
+

Built like a shoot, not a prompt box.

+
+
+
+ +
+

Every size, one run.

+

Square, portrait, Pinterest and banner formats from a single brief.

+
+
+
+ +
+

On-brand by default.

+

Your rules ride along with every generation.

+
+
+
+ +
+

You stay in charge.

+

Review and refine before anything ships. Nothing posts automatically. Prefer prompts? Prompt Studio gives direct control.

+
+
+
+
+
+ +
+
+
+

Made for things in packs.

+
+
    +
  • +
    +
    A drinks can on a white plinth against a yellow backdrop.
    +
    Drinks
    +
    +
  • +
  • +
    +
    A dropper bottle of daily serum on stacked stones, with palm-leaf shadows on a mint backdrop.
    +
    Beauty
    +
    +
  • +
  • +
    +
    A kraft coffee bag with a coral House Blend band on a wooden board, with a scoop of beans in window light.
    +
    Pantry
    +
    +
  • +
+

Drinks, beauty, pantry, supplements: if it has a pack, PhotoGen can shoot it.

+
+
+ +
+
+
+

Plans that fit a weekly content calendar.

+

Monthly plans. Cancel anytime.

+
+
+
+

Starter

+

$19 /month

+

100 credits a month

+
+
+

Recommended

+

Pro

+

$49 /month

+

500 credits a month

+
+
+

Studio

+

$99 /month

+

1,500 credits a month

+
+
+
+

5 free credits when you sign up. Bring your own Gemini key and generate without credits.

+ See pricing and credits per image +
+
+
+ +
+
+
+

Questions brands ask first

+
+
+
+ Will PhotoGen change my label or packaging? +

It works from your product photo and your product facts, but AI can still get small details wrong. Check every image against the real pack before you publish.

+
+
+ How is this different from a background remover? +

It makes complete campaign sets (studio, lifestyle and ad formats) from your brand rules and approved claims, not a single cut-out. See how it compares with Photoroom.

+
+
+ What does an image cost? +

Simple images cost 1 credit, high-quality images 2, and Ultra images 5. A Pro plan covers about 500 everyday images a month. Full credit table.

+
+
+ Can I use my own API key? +

Yes. Add your Gemini key in the app and generation doesn't use credits.

+
+
+ Where does my data go? +

Your brand and product records stay in your PhotoGen account. Images and prompts are sent to the image provider (Google Gemini) to generate results. See the Privacy page.

+
+
+
+
+ +
+
+
+

Your next product shoot is one click away.

+
+ Go +

5 free credits. No card required. Sign in with an email link.

+
+
+
+
+
+ + + + diff --git a/marketing-site/pricing/index.html b/marketing-site/pricing/index.html new file mode 100644 index 0000000..b743e35 --- /dev/null +++ b/marketing-site/pricing/index.html @@ -0,0 +1,264 @@ + + + + + + PhotoGen Pricing: Plans and Credits per Image + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Pay for the images you make.

+

Every plan is monthly and includes a set number of credits. Simple images cost 1 credit, so a Pro plan covers about 500 everyday images a month. Start with 5 free credits; no card needed.

+
+
+ +
+
+

Plans

+ +
+
+

Starter

+

$19 /month

+

100 credits a month

+
    +
  • ≈ 100 Balanced images
  • +
  • ≈ 20 Ultra images
  • +
  • For a brand testing one product line
  • +
+ Start free, then pick Starter +
+
+

Recommended

+

Pro

+

$49 /month

+

500 credits a month

+
    +
  • ≈ 500 Balanced images
  • +
  • ≈ 100 Ultra images
  • +
  • Fresh listing, ad and social sets every week
  • +
+ Start free, then pick Pro +
+
+

Studio

+

$99 /month

+

1,500 credits a month

+
    +
  • ≈ 1,500 Balanced images
  • +
  • ≈ 300 Ultra images
  • +
  • For several brands, or an agency running clients
  • +
+ Start free, then pick Studio +
+
+

Monthly billing through Stripe. Cancel anytime from the Stripe customer portal in your billing settings. Credits reset each billing cycle and don't roll over.

+
+
+ +
+
+
+

Credits per image

+

You choose the quality tier for each run. Higher tiers cost more to make, so they use more credits per image.

+
+ +
+ + + + + + + + + + + + + + + + + +
Credits per image by quality tier, and images per plan
Quality tierCredits per imageStarterProStudio
Fast1≈ 100≈ 500≈ 1,500
Balanced1≈ 100≈ 500≈ 1,500
Quality2≈ 50≈ 250≈ 750
Ultra5≈ 20≈ 100≈ 300
+
+

Plan columns show images per month at that tier. Mixed runs land in between.

+
+
+ +
+
+
+

Bring your own Gemini key

+

Add your own Google Gemini API key in the app and generation doesn't use credits. Google bills your key directly at its own rates. Your key is stored in your browser, not in PhotoGen's database.

+
+
+
+ +
+
+
+

Pricing questions

+
+
+
+ What is a credit? +

Credits pay for generated images. Fast and Balanced images cost 1 credit each, Quality images 2 and Ultra images 5.

+
+
+ Do unused credits roll over? +

No. Your balance resets to your plan's monthly credits at the start of each billing cycle.

+
+
+ Can I generate without credits? +

Yes. Add your own Gemini API key in the app and generation doesn't use credits. Google bills your key directly.

+
+
+ How do I cancel? +

Plans are monthly. Cancel anytime from the billing settings in the app, which open the Stripe customer portal.

+
+
+ Do I need a card to try it? +

No. Sign up with an email link and you get 5 free credits.

+
+
+
+
+ +
+
+
+

Try it on your own product.

+
+ Go +

5 free credits. No card required. Sign in with an email link.

+
+
+
+
+
+ + + + diff --git a/marketing-site/robots.txt b/marketing-site/robots.txt new file mode 100644 index 0000000..f217993 --- /dev/null +++ b/marketing-site/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://photogen.ashbi.ca/sitemap.xml diff --git a/marketing-site/site.webmanifest b/marketing-site/site.webmanifest new file mode 100644 index 0000000..5ac0a5b --- /dev/null +++ b/marketing-site/site.webmanifest @@ -0,0 +1,13 @@ +{ + "name": "PhotoGen", + "short_name": "PhotoGen", + "description": "Studio-quality product photos for every channel. Press Go.", + "start_url": "/", + "display": "browser", + "background_color": "#FFFFFF", + "theme_color": "#2340FF", + "icons": [ + { "src": "/assets/icon-192.png", "sizes": "192x192", "type": "image/png" }, + { "src": "/assets/icon-512.png", "sizes": "512x512", "type": "image/png" } + ] +} diff --git a/marketing-site/sitemap.xml b/marketing-site/sitemap.xml new file mode 100644 index 0000000..a4a4222 --- /dev/null +++ b/marketing-site/sitemap.xml @@ -0,0 +1,6 @@ + + + https://photogen.ashbi.ca/2026-10-04 + https://photogen.ashbi.ca/pricing/2026-10-04 + https://photogen.ashbi.ca/compare/photoroom/2026-10-04 +