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
43 changes: 35 additions & 8 deletions components/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ const DEFAULT_MOMENT_CREATE_HREF = `${MOMENT_CREATE_HREF}&source=moment-shell`;
const PRIMARY_NAV_CREATE_HREF = `${MOMENT_CREATE_HREF}&source=primary-nav`;
/** Home sticky shell: one primary Generate→360 (AIT-413 friction cut). */
const HOME_SHELL_GENERATE_HREF = createGenerate360Href("app-shell-home");
/**
* Mobile home Moment secondary door (AIT-607 residual dual doors).
* Generate stays the solid primary; Moment is outline/text only so sticky
* still offers both product paths after the hero dual-door fold scrolls away.
*/
const HOME_SHELL_MOMENT_HREF = `${MOMENT_CREATE_HREF}&source=app-shell-home-moment` as const;

function active(path: string, href: string) {
const route = href.split("?")[0];
Expand Down Expand Up @@ -259,15 +265,36 @@ function AppShellInner({ children }: { children: React.ReactNode }) {
)}
/>
</Link>
<div className="flex items-center gap-2">
<div className="flex min-w-0 items-center gap-1.5">
{momentSurface ? (
<Link
href={home ? HOME_SHELL_GENERATE_HREF : DEFAULT_MOMENT_CREATE_HREF}
data-app-shell-home-generate={home ? "360" : undefined}
className="inline-flex min-h-9 items-center rounded-full bg-[var(--grad-cta)] px-4 text-[10px] font-black text-[var(--primary-foreground)]"
>
{home ? "Generate 360°" : "Use this motion"}
</Link>
home ? (
// AIT-607: sticky dual doors after hero scrolls — Generate solid
// primary + Moment text secondary (not dual solid / Moment-first).
<>
<Link
href={HOME_SHELL_GENERATE_HREF}
data-app-shell-home-generate="360"
data-shell-mobile-360-cta
className="inline-flex min-h-9 shrink-0 items-center rounded-full bg-[var(--grad-cta)] px-3.5 text-[10px] font-black text-[var(--primary-foreground)] shadow-[0_0_18px_rgba(196,165,116,0.28)]"
>
Generate 360°
</Link>
<Link
href={HOME_SHELL_MOMENT_HREF}
data-shell-mobile-moment-cta
className="inline-flex min-h-9 shrink-0 items-center rounded-full border border-white/20 bg-white/[0.06] px-3 text-[10px] font-black text-[var(--cream)]/85 transition hover:border-[var(--brand)]/45 hover:text-[var(--cream)]"
>
Create with my toy
</Link>
</>
) : (
<Link
href={DEFAULT_MOMENT_CREATE_HREF}
className="inline-flex min-h-9 items-center rounded-full bg-[var(--grad-cta)] px-4 text-[10px] font-black text-[var(--primary-foreground)]"
>
Use this motion
</Link>
)
) : resultShell ? (
<>
<Link
Expand Down
7 changes: 5 additions & 2 deletions components/HomeCinemaHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,11 @@ export function HomeCinemaHero() {
</div>
<figcaption className="flex items-start justify-between gap-3 border-t border-[var(--border)] px-4 py-3">
<div>
<p className="text-[10px] font-semibold uppercase tracking-[0.16em] text-[var(--brand)]">
Style study · try 360°
<p
className="text-[10px] font-semibold uppercase tracking-[0.16em] text-[var(--brand)]"
data-home-hero-lab-label
>
PIKBO Lab · Style study · try 360°
</p>
<p className="mt-0.5 text-sm font-semibold text-[var(--fg)]">
{HERO_STILL.title}
Expand Down
6 changes: 3 additions & 3 deletions components/HomeDesignerGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export function HomeDesignerGallery() {
Collectible subjects — not cartoon fillers
</h2>
<p className="mt-3 text-sm leading-6 text-[var(--fg-muted)]">
Style studies and lab lighting references for vinyl, blind box,
mecha kits, and plush. Labeled studies — not customer uploads, not
fake UGC. Tap any still to open listing 360°.
PIKBO Lab style studies and lighting references for vinyl, blind
box, mecha kits, and plush. Labeled Lab stills — not customer
uploads, not fake UGC. Tap any still to open listing 360°.
</p>
</div>
<div className="flex flex-col items-start gap-2 sm:items-end">
Expand Down
16 changes: 16 additions & 0 deletions lib/createRouteContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ export function isGenerate360Effect(effect: string | undefined): boolean {
*
* AIT-521 gallery residual: every designer-toy still is a one-tap 360 door
* (home-gallery-*) so home never routes stills through /toys or Moment first.
*
* AIT-607 residual continuity: dormant / off-home rails that still tag home-*
* (browse, feature, proof wall, tool shelf) must stay entry tags — never
* invent dead `/projects/home-*` remix links or skip Lab/Live honesty.
*/
export const HOME_GENERATE_ENTRY_SOURCES = [
"home-hero",
Expand All @@ -132,6 +136,10 @@ export const HOME_GENERATE_ENTRY_SOURCES = [
"home-gallery-capsule",
"home-gallery-section",
"home-explore-rail",
"home-browse",
"home-feature",
"home-proof-wall",
"home-tool-shelf",
] as const;

export type HomeGenerateEntrySource =
Expand Down Expand Up @@ -177,6 +185,14 @@ export function homeGenerateEntryLabel(
return "From Home · gallery Generate";
case "home-explore-rail":
return "From Home · Lab explore rail";
case "home-browse":
return "From Home · browse Generate 360°";
case "home-feature":
return "From Home · feature Generate 360°";
case "home-proof-wall":
return "From Home · Lab proof wall";
case "home-tool-shelf":
return "From Home · tool shelf Generate";
default:
return "From Home · Generate 360°";
}
Expand Down
16 changes: 8 additions & 8 deletions lib/designerToyGallery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const DESIGNER_TOY_GALLERY: DesignerToyGalleryItem[] = [
toyKind: "art-toys",
src: "/style-studies/art-vinyl-guardian-v1.jpg",
href: createGenerate360Href("home-gallery-vinyl-guardian"),
badge: "Style study · try 360°",
badge: "PIKBO Lab · Style study · try 360°",
aspect: "3/4",
},
{
Expand All @@ -63,7 +63,7 @@ export const DESIGNER_TOY_GALLERY: DesignerToyGalleryItem[] = [
toyKind: "blind-box-figures",
src: "/style-studies/art-vinyl-blind-box-direction-v1.jpg",
href: createGenerate360Href("home-gallery-blind-box"),
badge: "Style study · try 360°",
badge: "PIKBO Lab · Style study · try 360°",
aspect: "3/4",
},
{
Expand All @@ -73,7 +73,7 @@ export const DESIGNER_TOY_GALLERY: DesignerToyGalleryItem[] = [
toyKind: "vinyl-figures",
src: "/style-studies/art-vinyl-social-flash-direction-v1.jpg",
href: createGenerate360Href("home-gallery-social-flash"),
badge: "Style study · try 360°",
badge: "PIKBO Lab · Style study · try 360°",
aspect: "3/4",
},
{
Expand All @@ -83,7 +83,7 @@ export const DESIGNER_TOY_GALLERY: DesignerToyGalleryItem[] = [
toyKind: "model-kits",
src: "/style-studies/precision-mecha-v1.jpg",
href: createGenerate360Href("home-gallery-mecha"),
badge: "Style study · try 360°",
badge: "PIKBO Lab · Style study · try 360°",
aspect: "3/4",
},
{
Expand All @@ -93,7 +93,7 @@ export const DESIGNER_TOY_GALLERY: DesignerToyGalleryItem[] = [
toyKind: "plush-toys",
src: "/style-studies/plush-hybrid-v1.jpg",
href: createGenerate360Href("home-gallery-plush"),
badge: "Style study · try 360°",
badge: "PIKBO Lab · Style study · try 360°",
aspect: "3/4",
},
{
Expand All @@ -103,7 +103,7 @@ export const DESIGNER_TOY_GALLERY: DesignerToyGalleryItem[] = [
toyKind: "art-toys",
src: "/moments/gallery-spotlight.jpg",
href: createGenerate360Href("home-gallery-spotlight"),
badge: "Lab still · try 360°",
badge: "PIKBO Lab · still · try 360°",
aspect: "16/9",
},
{
Expand All @@ -113,7 +113,7 @@ export const DESIGNER_TOY_GALLERY: DesignerToyGalleryItem[] = [
toyKind: "blind-box-figures",
src: "/moments/capsule-reveal.jpg",
href: createGenerate360Href("home-gallery-capsule"),
badge: "Lab still · try 360°",
badge: "PIKBO Lab · still · try 360°",
aspect: "16/9",
},
{
Expand All @@ -124,7 +124,7 @@ export const DESIGNER_TOY_GALLERY: DesignerToyGalleryItem[] = [
src: "/moments/colorblock-pedestal.jpg",
// AIT-462 / AIT-521: skip /effects hop — one tap into listing 360 workbench
href: createGenerate360Href("home-gallery-pedestal"),
badge: "Lab still · 360 listing",
badge: "PIKBO Lab · still · 360 listing",
aspect: "16/9",
},
];
Expand Down
58 changes: 58 additions & 0 deletions scripts/generate-360-cta-smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,64 @@ assert.doesNotMatch(
/home \? ["']Try Street Power-Up["']|home \? ["']Create my drop clip["']/,
"AppShell home sticky must not remain Moment-only copy"
);
// AIT-607 residual: mobile Home dual doors — Generate solid primary + Moment secondary
assert.match(
appShellSrc,
/data-shell-mobile-360-cta/,
"AppShell mobile home must mark Generate 360 dual-door primary"
);
assert.match(
appShellSrc,
/data-shell-mobile-moment-cta/,
"AppShell mobile home must mark Moment dual-door secondary"
);
assert.match(
appShellSrc,
/data-shell-mobile-360-cta[\s\S]*data-shell-mobile-moment-cta/,
"mobile dual doors must order Generate primary then Moment secondary"
);
assert.match(
appShellSrc,
/source=app-shell-home-moment/,
"mobile Moment secondary must tag app-shell-home-moment (not bare Moment)"
);
assert.doesNotMatch(
appShellSrc,
/data-shell-mobile-moment-cta[\s\S]{0,200}bg-\[var\(--grad-cta\)\]/,
"mobile Moment secondary must not use solid primary CTA fill"
);
// Honest Lab labels on gallery-calm stills (never bare style study without Lab)
const designerGallery = read("lib/designerToyGallery.ts");
assert.match(
designerGallery,
/PIKBO Lab · Style study · try 360°/,
"gallery style-study badges must prefix PIKBO Lab"
);
assert.match(
designerGallery,
/PIKBO Lab · still · try 360°/,
"gallery Lab still badges must prefix PIKBO Lab"
);
assert.match(
designerGallery,
/PIKBO Lab · still · 360 listing/,
"gallery pedestal badge must prefix PIKBO Lab"
);
assert.doesNotMatch(
designerGallery,
/badge:\s*["']Style study · try 360°["']/,
"gallery must not ship bare Style study badges without Lab"
);
assert.match(
homeHero,
/data-home-hero-lab-label/,
"home hero still must mark honest Lab label"
);
assert.match(
homeHero,
/PIKBO Lab · Style study · try 360°/,
"home hero still caption must prefix PIKBO Lab"
);
// Browse surfaces that keep AppShell tab nav must be in showBar
for (const route of [
"/explore",
Expand Down
18 changes: 18 additions & 0 deletions scripts/generate-workbench-lab-honesty-smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ assert.match(
"createRouteContract must export HOME_GENERATE_ENTRY_SOURCES"
);
// AIT-462 money doors + AIT-521 gallery residual + explore rail
// AIT-607 residual: dormant home-* rails stay entry tags (not project remix ids)
for (const tag of [
"home-hero",
"app-shell-home",
Expand All @@ -330,13 +331,30 @@ for (const tag of [
"home-gallery-capsule",
"home-gallery-section",
"home-explore-rail",
"home-browse",
"home-feature",
"home-proof-wall",
"home-tool-shelf",
]) {
assert.match(
contractLib,
new RegExp(`["']${tag}["']`),
`HOME_GENERATE_ENTRY_SOURCES must include ${tag}`
);
}
// Honest entry eyebrows for residual home rails
for (const [tag, label] of [
["home-browse", "browse Generate 360"],
["home-feature", "feature Generate 360"],
["home-proof-wall", "Lab proof wall"],
["home-tool-shelf", "tool shelf Generate"],
]) {
assert.match(
contractLib,
new RegExp(`case\\s+["']${tag}["'][\\s\\S]*?return\\s+["'][^"']*${label}`),
`homeGenerateEntryLabel must cover ${tag}`
);
}
assert.match(
contractLib,
/export function isHomeGenerateEntrySource/,
Expand Down
Loading