Migrating Adobe product pages (e.g., Photoshop, Illustrator, Premiere Pro) from https://www.adobe.com/products/ to Adobe Edge Delivery Services. This guide captures content structure decisions learned from the Photoshop migration to ensure consistent, correct results across all product pages.
- https://www.adobe.com/products/illustrator.html
- https://www.adobe.com/products/premiere.html
- https://www.adobe.com/products/photoshop.html
- Screenshots to
/tmp/only. Never save screenshots to project root or workspace folders. - Read files before editing. Never modify code without reading it first.
- Keep PROJECT.md current. Update this file when creating/modifying/deleting blocks, variants, patterns, or learning new gotchas.
- Video posters: scrape at desktop resolution (>=1200px). Tablet/mobile viewports serve different aspect ratios. Reload after resizing; posters load on page init.
- Art-directed image sets: Some sections serve multiple versions of the same image for responsive breakpoints (desktop, tablet, mobile). Keep only one image — typically the first/desktop version.
- Videos → poster images. The source pages use autoplaying
<video>elements for visual sections. Do NOT import videos. Instead, extract theposterattribute URL from the<video>tag and import that as a static image. Example: given<video poster="https://www.adobe.com/cc-shared/fragments/products/illustrator/media_16c2b...png?width=2000&format=webply&optimize=medium" ...>, import the poster URL as the image for that section.
This file is the project's source of truth. Update it when:
| Event | Action |
|---|---|
| Block created/deleted | Update Block Reference |
| Variant added/removed | Update the block's variant table |
| New section style | Add to Section Styles table |
| New design token | Add to Design Tokens table |
| New icon/asset added | Add to Local Assets section |
| Bug fix with learnings | Add to Gotchas section |
### block-name
**Location**: `/blocks/block-name/`
| Variant | Class | Purpose |
|---------|-------|---------|
| Default | `.block-name` | Description |
**Authoring / Features / Responsive behavior**[List project-specific key files here]
Adobe product pages follow a consistent section pattern. Each --- below represents a section separator.
Section 1: HERO (Columns block - text left, image right)
---
Section 2: FEATURE HIGHLIGHT (Columns block - image left, text right)
---
Section 3: FEATURE HIGHLIGHT (Columns block - text left, image right)
---
Section 4: FEATURE HIGHLIGHT (Columns block - image left, text right)
---
Section 5: FEATURE CAROUSEL (default content heading + Carousel block + CTA link)
---
Section 6: PRICING (default content intro + Tabs block + CTA link)
---
Section 7: PLATFORM SHOWCASE (default content - heading, text, single image)
---
Section 8: COMPANION APP (default content intro + 3-column Columns block for tool links)
---
Section 9: FAQ (default content heading + Accordion block)
---
Section 10: BOTTOM CTA (default content + Section Metadata dark)
---
Section 11: PAGE METADATA (Metadata block - title, description, image)
Not every product page will have all sections, and some may have additional ones. Use this as a guide, not a rigid template.
Adobe product pages show the hero as a side-by-side layout: text content on the left, product image on the right. This is a Columns block, not a full-bleed Hero block.
Structure:
- Column 1 (text): eyebrow (bold), h1, description, CTA buttons, secondary links
- Column 2 (image): single product hero image
+---+---+
| **Columns** | |
+---+---+
| **Product Name** |  |
| | |
| # Main heading text. | |
| | |
| Description paragraph. | |
| | |
| [Buy now](url) [Free trial](url) | |
| | |
| Browse plans for [businesses](url) or [students](url). | |
+---+---+
Each feature gets its own section with its own Columns block. Alternate image placement:
- Feature 1: image LEFT, text right
- Feature 2: text left, image RIGHT
- Feature 3: image LEFT, text right
Each feature column contains:
- Bold eyebrow text
- h2 heading
- Description paragraph
+---+---+
| **Columns** | |
+---+---+
|  | **Eyebrow** |
| | |
| | ## Feature heading. |
| | |
| | Description text. |
+---+---+
The "Explore [Product] features" section has:
- A heading as default content (h2)
- A Carousel block with multiple slides (each slide = image + h3 + description)
- A CTA link as default content after the block
## Explore [Product] features.
+---+---+
| **Carousel** | |
+---+---+
|  | ### Slide 1 heading. |
| | |
| | Slide 1 description. |
+---+---+
|  | ### Slide 2 heading. |
| | |
| | Slide 2 description. |
+---+---+
[View all features](url)
The pricing section has:
- Default content intro: small eyebrow text, h2 heading, description
- A Tabs block (typically: Individuals, Students and teachers, Teams)
- A CTA link after the block
Tab 1 (Individuals) typically contains the most detail: icon, product name, price, billing period, description, CTA buttons, feature checklist. Tabs 2 and 3 are shorter with a single paragraph and link.
Membership plans
## Get [Product].
Description text.
+---+---+
| **Tabs** | |
+---+---+
| Individuals |  |
| | |
| | **Product Name** |
| | |
| | US$XX.XX/mo |
| | |
| | Annual, billed monthly |
| | |
| | Short description. |
| | |
| | [Free trial](url) [Buy now](url) |
| | |
| | See what's included: |
| | |
| | - Feature 1 |
| | - Feature 2 |
+---+---+
| Students and teachers | Summary text with [link](url). |
+---+---+
| Teams | Summary text with [link](url). |
+---+---+
[Compare plans](url)
This section is pure default content: heading, paragraph, and a single image. If the original page shows multiple art-directed versions of the same image, keep only one.
## [Product] goes everywhere you go.
Description text.

This section promotes Adobe Express tools. The intro (icon, heading, description) is default content. The tool links (Resize Image, Crop Image, Logo Maker, etc.) go in a separate 3-column Columns block.
Do NOT wrap everything in one 2-column Columns block.

## Need a quick edit? Your [Product] plan includes Adobe Express.
Description text.
+---+---+---+
| **Columns** | | |
+---+---+---+
| [ Tool 1](link-url) | [ Tool 2](link-url) | [ Tool 3](link-url) |
+---+---+---+
## Questions? We have answers.
+---+---+
| **Accordion** | |
+---+---+
| Question text? | Answer text with [links](url). |
+---+---+
| Question text? | Answer text. |
+---+---+
The final CTA section uses default content in a dark-styled section:

### Tagline heading.
Description text.
US$XX.XX/mo. for the annual billed monthly plan.
[Free trial](url) [Buy now](url)
+---+---+
| **Section Metadata** | |
+---+---+
| style | dark |
+---+---+
Always end with the Metadata block. Hide the metadata section in global styles so it does not render on the page. When a template metadata entry is set, ensure the JS applies its value as a class name on the <body> element.
+---+---+
| **Metadata** | |
+---+---+
| title | Page title |
+---+---+
| description | Page description |
+---+---+
| image | OG image URL |
+---+---+
[Document CSS custom properties defined in /styles/styles.css]
Always verify variables exist in styles.css before using them. Non-existent variables silently resolve to nothing.
| Style name | Applied via | Purpose |
|---|---|---|
dark |
Section Metadata → style: dark |
Dark background with light text for CTA sections |
[Complete reference of all blocks and their variants]
Hard-won lessons that the skills don't cover.
- Fragment files (nav.html, footer.html) must NOT have
<header>or<footer>tags. These cause recursive loading of header/footer blocks. - Template meta tag goes in
<head>.decorateTemplateAndTheme()reads<meta name="template" content="...">from the head, not from the metadata block in the body. - Links vs buttons: A link alone in its own paragraph (
<p><a>...</a></p>) becomes a button styled by global styles. Block CSS that needs different button styling must override with block-scoped selectors. - Art-directed image sets: Source pages may serve different image URLs per viewport. During migration, keep only the desktop image to avoid duplicates in authored content.
- Metadata section must be hidden. The Metadata block at the end of the page is for page-level meta tags, not visible content. Add
display: noneto the metadata section in global styles. - Template class on
<body>. When atemplateentry exists in the Metadata block, its value must be applied as a class on the<body>element bydecorateTemplateAndTheme()inscripts.js.
- Page-specific styles stay page-specific. Never modify shared block CSS in ways that affect other pages. Use template-specific selectors like
body.template-name .blockor create a new variant. - Block CSS must not set
color: var(--link-color)ona.button. This overrides global button styling and makes buttons appear as plain links.
- Lazy loading breaks after DOM restructuring. When block JS moves images to new containers, the browser's Intersection Observer loses track. Fix: set
img.loading = 'eager'on allimg[loading="lazy"]elements after restructuring.
.dropdown::before {
content: '';
position: absolute;
top: -8px;
left: 50%;
transform: translateX(-50%);
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid #fff;
filter: drop-shadow(0 -2px 2px rgb(0 0 0 / 8%));
}