Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/self-host-lookaside-images.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@astryxdesign/cli': patch
---

[chore] Self-host template demo imagery in the repo instead of streaming it
from the internal `lookaside.facebook.com` CDN.

- Template demo images are now committed under
`apps/docsite/public/template-assets/` and referenced by root-relative
`/template-assets/*` paths (previously Meta-internal CDN URLs invisible to
external contributors).
- `stripTemplateAssetRefs` still swaps these paths for the inline `data:` URI
placeholder on scaffold, so generated projects render with zero setup and no
network dependency β€” no image is ever copied into a scaffolded project.

@imdreamrunner
17 changes: 12 additions & 5 deletions .github/instructions/templates.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,18 @@ layout change β†’ full structure pass`.
missing fields, a wrong `aspectRatio`, `componentsUsed` drift, and missing
`scale` for tiny components (Badge/StatusDot/single Icon/Spinner β†’ `2` or
`3`).
6. **Image handling (5)** β€” images only from the astryx CDN via the permanent
lookaside URL (`https://lookaside.facebook.com/assets/astryx/<asset>.png`)
with an asset-name comment. Flag external URLs (unsplash/placehold/picsum),
checked-in image files, data URIs, and expiring signed `scontent…fbcdn.net`
URLs.
6. **Image handling (5)** β€” demo imagery is referenced by a root-relative path
under `/template-assets/<asset>.png`, self-hosted in the repo under
`apps/docsite/public/template-assets/` (mirrored into the sandbox preview at
generate time). To use an existing image, browse that directory and reference
it by name with an asset-name comment; to add a new one, drop the file into
that same directory and reference it the same way. On scaffold,
`stripTemplateAssetRefs` swaps these paths for an inline placeholder so a
generated project renders with zero setup. Flag external URLs
(unsplash/placehold/picsum), expiring signed `scontent…fbcdn.net` URLs, and
inline data URIs. Image-backed Thumbnail examples are the one exception: they
inline a same-origin, samplable `data:` URI (required by `useImageMode` β€” see
`scripts/check-demo-media.mjs`).
7. **Code quality (10)** β€” `'use client';` first line; `export default`;
self-contained imports (`@astryxdesign/core/*`, `@heroicons/react/*`, or
local only); realistic mock data (real names/values, never
Expand Down
Binary file added apps/docsite/public/images/Astryx-Banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/docsite/public/images/theme-y2k-picker.png
Binary file not shown.
2 changes: 1 addition & 1 deletion apps/docsite/src/__tests__/data-extraction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ describe('componentRegistry', () => {
expect(lightbox!.playground?.defaults).toMatchObject({
isOpen: false,
media: {
src: expect.stringContaining('https://'),
src: expect.stringContaining('/template-assets/'),
alt: expect.any(String),
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ import type {HeroThemeContent} from './heroThemeContent';

// One recurring member across every theme slide (the per-theme `member` copy is
// intentionally not used here).
const CDN = 'https://lookaside.facebook.com/assets/astryx';
const REWARD_MEMBER_NAME = 'Ami Pena';
const REWARD_MEMBER_AVATAR = `${CDN}/DATA-Ami-Pena.png`;
const REWARD_MEMBER_AVATAR = '/images/avatars/DATA-Ami-Pena.png';

const styles = stylex.create({
// Desktop overlap stage: fixed, viewport-centered 1200px box (shared with the
Expand Down
29 changes: 12 additions & 17 deletions apps/docsite/src/app/(site)/_landing/hero/heroThemeContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ import {BRAND_BLUE} from '@/constants';
// Sentinel for the docsite's local brand theme (not an @astryxdesign/theme-* package).
const ASTRYX = 'astryx';

// Shared Astryx asset CDN. The per-theme reel cards pull the same product photos
// the /themes showcase uses (see themeShowcaseContent.ts) so the hero and the
// gallery stay in sync.
const IMAGE_CDN = 'https://lookaside.facebook.com/assets/astryx';

export interface HeroThemeContent {
/** Product card (image + title/description + price). */
product: {
Expand Down Expand Up @@ -158,18 +153,18 @@ const CONTENT_BY_THEME: Record<string, HeroThemeContent> = {
},
'@astryxdesign/theme-butter': {
product: {
image: `${IMAGE_CDN}/Butter-Croissant.png`,
image: '/images/butter/preview-watch.png',
title: 'Butter croissant',
description: 'Flaky, laminated layers baked golden each morning.',
price: '$6',
},
feature: {
image: `${IMAGE_CDN}/Butter-Waffle.png`,
image: '/images/butter/preview-backpack.png',
title: 'Belgian waffle',
price: '$8',
},
mini: {
image: `${IMAGE_CDN}/Butter-Pancake.png`,
image: '/images/butter/preview-headphones.png',
title: 'Pancakes',
description: 'Stacked tall with melting butter.',
},
Expand All @@ -179,18 +174,18 @@ const CONTENT_BY_THEME: Record<string, HeroThemeContent> = {
},
'@astryxdesign/theme-matcha': {
product: {
image: `${IMAGE_CDN}/matcha-product-1.png`,
image: '/images/matcha/preview-watch.png',
title: 'Matcha',
description: 'Stone-ground ceremonial matcha over cold milk.',
price: '$6',
},
feature: {
image: `${IMAGE_CDN}/matcha-product-2.png`,
image: '/images/matcha/preview-headphones.png',
title: 'Strawberry matcha',
price: '$7',
},
mini: {
image: `${IMAGE_CDN}/matcha-product-4.png`,
image: '/images/matcha/preview-tumbler.png',
title: 'Ube matcha',
description: 'Ube and cream matcha.',
},
Expand All @@ -205,18 +200,18 @@ const CONTENT_BY_THEME: Record<string, HeroThemeContent> = {
},
'@astryxdesign/theme-gothic': {
product: {
image: `${IMAGE_CDN}/Gothic-1.png`,
image: '/images/gothic/preview-watch.png',
title: 'Sea holly',
description: 'A single preserved thistle stem with a steely bloom.',
price: '$24',
},
feature: {
image: `${IMAGE_CDN}/Gothic-2.png`,
image: '/images/gothic/preview-headphones.png',
title: 'Garden rose',
price: '$18',
},
mini: {
image: `${IMAGE_CDN}/Gothic-3.png`,
image: '/images/gothic/preview-backpack.png',
title: 'Ranunculus',
description: 'Layered petals in a soft mauve.',
},
Expand All @@ -226,18 +221,18 @@ const CONTENT_BY_THEME: Record<string, HeroThemeContent> = {
},
'@astryxdesign/theme-y2k': {
product: {
image: `${IMAGE_CDN}/Y2K-Phone.png`,
image: '/images/y2k/preview-watch.png',
title: 'Phone',
description: 'Iridescent clamshell with a rainbow screen.',
price: '$18',
},
feature: {
image: `${IMAGE_CDN}/Y2K-Star.png`,
image: '/images/y2k/preview-headphones.png',
title: 'Glow star set',
price: '$12',
},
mini: {
image: `${IMAGE_CDN}/Y2K-Butterfly.png`,
image: '/images/y2k/preview-backpack.png',
title: 'Butterfly',
description: 'Sparkly stick-on in pastel chrome.',
},
Expand Down
2 changes: 1 addition & 1 deletion apps/docsite/src/app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export async function generateMetadata({
// (images are not inherited), so the fallback must be explicit here.
const ogImage =
post.coverImage ??
'https://lookaside.facebook.com/assets/astryx/Astryx-Banner.png';
'/images/Astryx-Banner.png';
const ogAlt = post.coverImage ? (post.coverAlt ?? post.title) : post.title;

return {
Expand Down
4 changes: 2 additions & 2 deletions apps/docsite/src/app/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ export const metadata: Metadata = {
title: `${BLOG_TITLE} Β· Astryx`,
description: BLOG_DESCRIPTION,
url: '/blog',
images: ['https://lookaside.facebook.com/assets/astryx/Astryx-Banner.png'],
images: ['/images/Astryx-Banner.png'],
},
twitter: {
card: 'summary_large_image',
title: `${BLOG_TITLE} Β· Astryx`,
description: BLOG_DESCRIPTION,
images: ['https://lookaside.facebook.com/assets/astryx/Astryx-Banner.png'],
images: ['/images/Astryx-Banner.png'],
},
};

Expand Down
2 changes: 1 addition & 1 deletion apps/docsite/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
// uses for its cover. Reusing the same branded banner keeps the shared-link
// preview consistent with the launch creative across the site and the post.
const OG_IMAGE =
'https://lookaside.facebook.com/assets/astryx/Astryx-Banner.png';
'/images/Astryx-Banner.png';

export const metadata: Metadata = {
metadataBase: new URL(SITE_URL),
Expand Down
25 changes: 12 additions & 13 deletions apps/docsite/src/components/ThemePackagePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ import commandBlockStyles from './ThemeCommandBlock.module.css';
const THEME_SHOWCASE_SOURCE =
templates.find(t => t.slug === 'theme-showcase')?.source ?? '';

// CDN host for the per-theme picker banners (same host as the showcase
// product photos), so the artwork can be updated without a code change.
const PICKER_CDN = 'https://lookaside.facebook.com/assets/astryx';
// Per-theme picker banners are self-hosted under the docsite's /public/images
// dir (same location as the showcase product photos).

// Gallery order β€” themes are listed in the same canonical visual-
// closeness order used elsewhere (most restrained β†’ most expressive).
Expand Down Expand Up @@ -296,51 +295,51 @@ const styles = stylex.create({
// Per-theme bespoke picker artwork β€” one rule per theme that
// has a custom photo (vs. the multi-radial-gradient default).
// Each rule sets the picker card's background to a dedicated
// theme-<slug>-picker.png banner hosted on the Astryx asset CDN
// (see PICKER_CDN). These are SEPARATE files from the
// theme-<slug>-picker.png banner self-hosted under /public/images.
// These are SEPARATE files from the
// theme-<slug>-preview.png images used on the /themes overview +
// detail page hero β€” these picker assets are sized and
// art-directed for the small 120px-tall picker card.
// background-size:cover so each image always fills the card
// regardless of the source's intrinsic dimensions.
surfaceButter: {
backgroundColor: 'transparent',
backgroundImage: `url(${PICKER_CDN}/theme-butter-picker.png)`,
backgroundImage: `url(/images/theme-butter-picker.png)`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
},
surfaceGothic: {
backgroundColor: 'transparent',
backgroundImage: `url(${PICKER_CDN}/theme-gothic-picker.png)`,
backgroundImage: `url(/images/theme-gothic-picker.png)`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
},
surfaceY2k: {
backgroundColor: 'transparent',
backgroundImage: `url(${PICKER_CDN}/theme-y2k-picker.png)`,
backgroundImage: `url(/images/theme-y2k-picker.png)`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
},
surfaceStone: {
backgroundColor: 'transparent',
backgroundImage: `url(${PICKER_CDN}/theme-stone-picker.png)`,
backgroundImage: `url(/images/theme-stone-picker.png)`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
},
surfaceNeutral: {
backgroundColor: 'transparent',
backgroundImage: `url(${PICKER_CDN}/theme-neutral-picker.png)`,
backgroundImage: `url(/images/theme-neutral-picker.png)`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
},
surfaceMatcha: {
backgroundColor: 'transparent',
backgroundImage: `url(${PICKER_CDN}/theme-matcha-picker.png)`,
backgroundImage: `url(/images/theme-matcha-picker.png)`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
Expand Down Expand Up @@ -500,8 +499,8 @@ const styles = stylex.create({
// can swap the card's `surface` (background image) and the `label`
// color (most use labelAccent so the wordmark reads as a brand
// signature on top of the photo). Adding artwork for a new theme
// is a two-step addition: upload a theme-<slug>-picker.png banner to
// the asset CDN (PICKER_CDN) + add a `surface<Name>` rule into the
// is a two-step addition: add a theme-<slug>-picker.png banner under
// /public/images + add a `surface<Name>` rule into the
// styles block above, then reference both here.
const PICKER_OVERRIDES: Record<
string,
Expand Down
61 changes: 30 additions & 31 deletions apps/docsite/src/components/themeShowcaseContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,15 @@ export interface ThemeShowcaseContent {
inventory: InventoryRow[];
}

const IMAGE_CDN = 'https://lookaside.facebook.com/assets/astryx';

// Matcha cafΓ© β€” matcha-drink photos.
const MATCHA_IMAGES: Record<string, string> = {
watch: `${IMAGE_CDN}/matcha-product-1.png`,
headphones: `${IMAGE_CDN}/matcha-product-2.png`,
backpack: `${IMAGE_CDN}/matcha-product-3.png`,
wallet: `${IMAGE_CDN}/matcha-product-5.png`,
tumbler: `${IMAGE_CDN}/matcha-product-4.png`,
throw_: `${IMAGE_CDN}/matcha-product-6.png`,
watch: '/images/matcha/preview-watch.png',
headphones: '/images/matcha/preview-headphones.png',
backpack: '/images/matcha/preview-backpack.png',
wallet: '/images/matcha/preview-wallet.png',
tumbler: '/images/matcha/preview-tumbler.png',
throw_: '/images/matcha/preview-throw.png',
};

const MATCHA_CONTENT: ThemeShowcaseContent = {
Expand Down Expand Up @@ -131,12 +130,12 @@ const MATCHA_CONTENT: ThemeShowcaseContent = {
// Butter bakery β€” butter/breakfast photos. Only five Butter assets exist, so
// the croissant is reused for the sixth slot.
const BUTTER_IMAGES: Record<string, string> = {
watch: `${IMAGE_CDN}/Butter-Croissant.png`,
headphones: `${IMAGE_CDN}/Butter-Pancake.png`,
backpack: `${IMAGE_CDN}/Butter-Waffle.png`,
wallet: `${IMAGE_CDN}/Butter-Toast.png`,
tumbler: `${IMAGE_CDN}/Butter-Stick.png`,
throw_: `${IMAGE_CDN}/Butter-Croissant.png`,
watch: '/images/butter/preview-watch.png',
headphones: '/images/butter/preview-headphones.png',
backpack: '/images/butter/preview-backpack.png',
wallet: '/images/butter/preview-wallet.png',
tumbler: '/images/butter/preview-tumbler.png',
throw_: '/images/butter/preview-throw.png',
};

const BUTTER_CONTENT: ThemeShowcaseContent = {
Expand Down Expand Up @@ -233,12 +232,12 @@ const BUTTER_CONTENT: ThemeShowcaseContent = {

// Stone homeware β€” stoneware photos on stone plinths.
const STONE_IMAGES: Record<string, string> = {
watch: `${IMAGE_CDN}/Stone-bowl.png`,
headphones: `${IMAGE_CDN}/Stone-cup.png`,
backpack: `${IMAGE_CDN}/Stone-plate.png`,
wallet: `${IMAGE_CDN}/Stone-servingbowl.png`,
tumbler: `${IMAGE_CDN}/Stone-teapot.png`,
throw_: `${IMAGE_CDN}/Stone-vase.png`,
watch: '/images/stone/preview-watch.png',
headphones: '/images/stone/preview-headphones.png',
backpack: '/images/stone/preview-backpack.png',
wallet: '/images/stone/preview-wallet.png',
tumbler: '/images/stone/preview-tumbler.png',
throw_: '/images/stone/preview-throw.png',
};

const STONE_CONTENT: ThemeShowcaseContent = {
Expand Down Expand Up @@ -335,12 +334,12 @@ const STONE_CONTENT: ThemeShowcaseContent = {

// Y2K trinkets β€” iridescent/holo objects.
const Y2K_IMAGES: Record<string, string> = {
watch: `${IMAGE_CDN}/Y2K-Phone.png`,
headphones: `${IMAGE_CDN}/Y2K-Star.png`,
backpack: `${IMAGE_CDN}/Y2K-Butterfly.png`,
wallet: `${IMAGE_CDN}/Y2K-Heart.png`,
tumbler: `${IMAGE_CDN}/Y2K-Flower.png`,
throw_: `${IMAGE_CDN}/Y2K-Couch.png`,
watch: '/images/y2k/preview-watch.png',
headphones: '/images/y2k/preview-headphones.png',
backpack: '/images/y2k/preview-backpack.png',
wallet: '/images/y2k/preview-wallet.png',
tumbler: '/images/y2k/preview-tumbler.png',
throw_: '/images/y2k/preview-throw.png',
};

const Y2K_CONTENT: ThemeShowcaseContent = {
Expand Down Expand Up @@ -437,12 +436,12 @@ const Y2K_CONTENT: ThemeShowcaseContent = {

// Gothic botanicals β€” moody single-stem floral photos.
const GOTHIC_IMAGES: Record<string, string> = {
watch: `${IMAGE_CDN}/Gothic-1.png`,
headphones: `${IMAGE_CDN}/Gothic-2.png`,
backpack: `${IMAGE_CDN}/Gothic-3.png`,
wallet: `${IMAGE_CDN}/Gothic-4.png`,
tumbler: `${IMAGE_CDN}/Gothic-5.png`,
throw_: `${IMAGE_CDN}/Gothic-6.png`,
watch: '/images/gothic/preview-watch.png',
headphones: '/images/gothic/preview-headphones.png',
backpack: '/images/gothic/preview-backpack.png',
wallet: '/images/gothic/preview-wallet.png',
tumbler: '/images/gothic/preview-tumbler.png',
throw_: '/images/gothic/preview-throw.png',
};

const GOTHIC_CONTENT: ThemeShowcaseContent = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ tags:
- 'Release'
- 'AI'
- 'Design systems'
coverImage: 'https://lookaside.facebook.com/assets/astryx/Astryx-Banner.png'
coverImage: '/images/Astryx-Banner.png'
coverAlt: 'Introducing Astryx by Meta'
relatedDocs:
- title: 'Getting started'
Expand Down
2 changes: 1 addition & 1 deletion apps/docsite/src/lib/pageMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {SITE_NAME} from './siteConfig';

/** Branded launch banner that matches the root layout + blog fallback card. */
const DEFAULT_OG_IMAGE =
'https://lookaside.facebook.com/assets/astryx/Astryx-Banner.png';
'/images/Astryx-Banner.png';

export interface PageMetadataInput {
/** Plain page title; rendered as "<title> Β· Astryx" via the root template. */
Expand Down
Loading
Loading