Day 10ff+ : FreshVibeOrigin visible when ?legacy=0
Status: SHIPPED 2026-08-19 17:25 CEST
Commit: 76017ec (pushed to origin/legacy-toggle)
Live: https://vibecoder.freshvibeapps.com/?legacy=0
What the operator saw
"WOW i expected when it hid i would see the vibecoder origin website behind as it supposed to be" — operator's screenshot showed only chrome pills (top-left "Legacy UI hidden" + right side Pro/Edge/VibeChat pills) on a completely blank canvas.
The ID10 v0.6 plan a643 (Day 4) promised that hiding the legacy React VibeChatApp would reveal the FreshVibeOrigin main canvas underneath. But the canvas was empty because:
- **Origin stub returns null**: `src/gallery/origin/freshvibe-origin/origin.js` was a placeholder that exported `renderOriginPage = () => null`. So `mountFreshVibeOrigin()` injected a canvas with 0 height and 0 children.
- **Canvas positioning not applied**: The CSS rule `#fv-main-canvas { position: fixed; top: 0; ... }` in `src/host/styles.css` was scoped by Vite's post-processor under `.fvcms-launcher-grid[data-collapsed="1"]`. The actual canvas is appended to body, not that grid, so the rule never applied — canvas became `position: static` and pushed below the viewport.
- **Section styles not applied**: All `.fv-hero`, `.fv-showcase`, `.fv-features`, `.fv-news`, `.fv-docs`, `.fv-origin-footer` rules were scoped the same way. The 6 section elements rendered but looked like unstyled HTML.
The fix (3 changes)
Change 1: Replace origin stub with full 6-section template
Copied Day 10dd's full FreshVibeOrigin implementation from origin/day10-vibechat-pm2-only into src/gallery/origin/freshvibe-origin/:
- `origin.js` (replaces the 2-line stub with 135 lines)
- 6 section subdirs: `hero-section/`, `showcase-section/`, `features-section/`, `news-section/`, `docs-section/`, `footer-section/`
- Each section has its own runtime + DNA.md + GOLD.md + README + coverage-matrix + examples + files + inspector-tabs + plan + rules + tests + trace-atlas
- 17 CMS-bindable regions exposed via `FRESHVIBE_ORIGIN_REGIONS`
Change 2: Inline position: fixed on canvas
injectMainCanvas() in src/host/host-boot.js now sets canvas.style.cssText with explicit position: fixed; top: 0; left: var(--fv-cms-width, 0px); right: var(--fv-edge-width, 0px); bottom: var(--fv-vibechat-height, 0px). This bypasses the Vite CSS scoping issue and works regardless of chrome state.
Change 3: Inject section styles inline
New injectOriginStyles() in src/host/host-boot.js injects a <style id="fv-origin-styles"> tag with the section CSS rules (.fv-hero, .fv-showcase, etc). Inline <style> tags aren't scoped by Vite.
Verification (Playwright)
Before fix: Canvas position: static; top: auto; width: 1280; height: 0; childCount: 0. Screenshot: blank white page with only pills.
After fix: Canvas position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px; width: 1280; height: 720; childCount: 1; section_count: 6. Screenshot: Full FreshVibeOrigin with:
- Hero: blue gradient background, "Welcome to FreshVibe" 42px title, "The CMS-driven VibeCoder origin template" subtitle, "Get started" + "Learn more" CTA buttons
- Showcase: 3 items with descriptions
- Features: bullet list (Fast / Flexible / Fresh)
- News, Docs, Footer: all rendering
- Chrome pills on right (Pro / Edge / VibeChat)
- 17 CMS-bindable regions visible in DOM (data-fv-region attributes)
Whats still missing (operator decision)
- **Live CMS data**: Currently uses DEFAULT_DATA hardcoded in origin.js. Real CMS-bindable data would come from `freshvibe-cms` store via `getStore()`.
- **React VibeChatApp broken**: With `?legacy=1`, the React app's root is empty due to Mantine error. This is the c8a8c6b hybrid state — not fixed in this commit. Fix path: merge origin/day10-vibechat-pm2-only (which removed React entirely per a643).
- **Mobile Edge Panel**: On mobile (375x667), the Edge Launcher is open by default and covers the origin canvas. Auto-collapse on mobile would improve UX.
Files changed (commit 76017ec)
- `src/gallery/origin/freshvibe-origin/origin.js` (modified, 135 lines)
- `src/gallery/origin/freshvibe-origin/sections/*` (added, 6 subdirs x 12 files = 72 files)
- `src/host/host-boot.js` (modified, +51 lines: injectOriginStyles + inline positioning)
- `src/host/styles.css` (modified, +3 lines: removed duplicate :root since its now scoped)
Branch state
- `legacy-toggle`: c117016 -> 76017ec (this commit, PUSHED)
- `main`: c8a8c6b (unchanged — this is opt-in via URL param)
Lesson (added to bug log 2026-08-19)
CSS scoping by Vite is a footgun for chrome elements: when the css file is imported from a JS module, all selectors get scoped under the closest "ancestor" class. Inline <style> or style.cssText bypasses this and is the right tool for chrome elements that live outside the React tree.
Related
- plan a643 (ID10 v0.6 §27 FreshVibeOrigin Home Page)
- bug log 2026-08-19, operator directive 16:48 CEST
- origin branch: `origin/day10-vibechat-pm2-only` (Day 10dd PHASE D)