chati-dev 4.2.1 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -53
- package/bin/chati.js +150 -5
- package/framework/agents/build/dev.md +509 -76
- package/framework/agents/deploy/devops.md +40 -25
- package/framework/agents/discover/brief.md +156 -22
- package/framework/agents/discover/brownfield-wu.md +24 -14
- package/framework/agents/discover/greenfield-wu.md +100 -14
- package/framework/agents/plan/architect-data-engineer.md +6 -6
- package/framework/agents/plan/architect-system.md +46 -12
- package/framework/agents/plan/architect.md +40 -20
- package/framework/agents/plan/detail.md +36 -24
- package/framework/agents/plan/phases.md +36 -26
- package/framework/agents/plan/tasks.md +114 -33
- package/framework/agents/plan/ux-brand-architect.md +240 -8
- package/framework/agents/plan/ux-component-engineer.md +28 -13
- package/framework/agents/plan/ux-researcher.md +7 -6
- package/framework/agents/plan/ux.md +55 -22
- package/framework/agents/quality/qa-implementation.md +143 -74
- package/framework/agents/quality/qa-planning.md +115 -42
- package/framework/agents/quality/qa-visual.md +439 -0
- package/framework/agents/shared/visualizer.md +128 -0
- package/framework/config.yaml +8 -7
- package/framework/constitution.md +127 -43
- package/framework/context/governance.md +12 -7
- package/framework/context/quality.md +6 -5
- package/framework/context/root.md +6 -6
- package/framework/data/entity-registry.yaml +377 -4
- package/framework/data/model-limits.json +19 -0
- package/framework/domains/agents/qa-visual.yaml +74 -0
- package/framework/domains/constitution.yaml +46 -2
- package/framework/domains/workflows/greenfield-fullstack.yaml +2 -2
- package/framework/hooks/advance-trigger.js +131 -0
- package/framework/hooks/brief-validator.js +83 -0
- package/framework/hooks/constitution-guard.js +91 -36
- package/framework/hooks/license-guard.js +129 -190
- package/framework/hooks/mode-governance.js +68 -16
- package/framework/hooks/model-governance.js +19 -8
- package/framework/hooks/package.json +3 -0
- package/framework/hooks/post-dev.js +207 -0
- package/framework/hooks/prism-engine.js +288 -105
- package/framework/hooks/read-protection.js +37 -9
- package/framework/hooks/reasoning-escalator.js +371 -0
- package/framework/hooks/reference-trigger.js +117 -0
- package/framework/hooks/session-digest.js +94 -20
- package/framework/hooks/settings.json +32 -1
- package/framework/hooks/style-guard.js +52 -13
- package/framework/hooks/team-quality-gate.js +58 -25
- package/framework/hooks/undercover-guard.js +34 -13
- package/framework/i18n/en.yaml +3 -3
- package/framework/i18n/es.yaml +3 -3
- package/framework/i18n/fr.yaml +3 -3
- package/framework/i18n/pt.yaml +3 -3
- package/framework/intelligence/context-engine.md +4 -5
- package/framework/intelligence/decision-engine.md +1 -1
- package/framework/intelligence/hooks-performance.md +3 -3
- package/framework/migrations/v1.0-to-v1.1.yaml +1 -1
- package/framework/migrations/v1.4-to-v2.0.yaml +11 -11
- package/framework/migrations/v4.0-to-v4.1.yaml +2 -2
- package/framework/migrations/v4.2-to-v4.3.yaml +29 -0
- package/framework/orchestrator/chati-router.js +387 -0
- package/framework/orchestrator/chati-update.md +40 -40
- package/framework/orchestrator/chati.md +318 -115
- package/framework/scaffold/motion-premium/README.md +89 -0
- package/framework/scaffold/motion-premium/app/globals.css.template +400 -0
- package/framework/scaffold/motion-premium/app/layout.tsx.template +110 -0
- package/framework/scaffold/motion-premium/components/animation/BackgroundCrossfadeProvider.tsx.template +170 -0
- package/framework/scaffold/motion-premium/components/animation/LenisProvider.tsx.template +49 -0
- package/framework/scaffold/motion-premium/components/animation/PageTransitionWrapper.tsx.template +83 -0
- package/framework/scaffold/motion-premium/components/animation/Preloader.tsx.template +171 -0
- package/framework/scaffold/motion-premium/components/ui/Container.tsx.template +69 -0
- package/framework/scaffold/motion-premium/components/ui/PageSection.tsx.template +74 -0
- package/framework/scaffold/motion-premium/lib/animations/gsap.ts.template +112 -0
- package/framework/scaffold/motion-premium/lib/animations/refreshCoordinator.ts.template +75 -0
- package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +119 -0
- package/framework/scaffold/motion-premium/lib/animations/useGsapContext.ts.template +92 -0
- package/framework/scaffold/motion-premium/lib/animations/useScrollSnapStepper.ts.template +265 -0
- package/framework/scaffold/motion-premium/lib/animations/useSmoothScroll.ts.template +67 -0
- package/framework/scaffold/motion-premium/lib/brand.ts.template +43 -0
- package/framework/scaffold/motion-premium/scaffold.yaml +174 -0
- package/framework/scaffold/motion-premium-3d/README.md +80 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoCanvas.tsx.template +81 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/ScrollDemoClient.tsx.template +75 -0
- package/framework/scaffold/motion-premium-3d/app/(3d)/scroll-demo/page.tsx.template +26 -0
- package/framework/scaffold/motion-premium-3d/components/3d/CameraRig.tsx.template +100 -0
- package/framework/scaffold/motion-premium-3d/components/3d/CanvasProvider.tsx.template +85 -0
- package/framework/scaffold/motion-premium-3d/components/3d/InvalidateOnScroll.tsx.template +51 -0
- package/framework/scaffold/motion-premium-3d/components/3d/MeshCrossfade.tsx.template +79 -0
- package/framework/scaffold/motion-premium-3d/components/3d/ScrollCrossfade.tsx.template +88 -0
- package/framework/scaffold/motion-premium-3d/components/3d/ScrollScene.tsx.template +121 -0
- package/framework/scaffold/motion-premium-3d/components/webgl/SceneFallback.tsx.template +65 -0
- package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +68 -0
- package/framework/scaffold/motion-premium-3d/lib/webgl/detect.ts.template +69 -0
- package/framework/scaffold/motion-premium-3d/scaffold.yaml +133 -0
- package/framework/schemas/session.schema.json +109 -21
- package/framework/scripts/reference-capture.js +430 -0
- package/framework/scripts/visual-qa.js +674 -0
- package/framework/tasks/orchestrator-handoff.md +1 -1
- package/framework/tasks/orchestrator-resume.md +1 -1
- package/framework/tasks/orchestrator-route.md +1 -1
- package/framework/tasks/orchestrator-status.md +3 -3
- package/framework/tasks/qa-planning-gate-define.md +1 -1
- package/framework/templates/brandbook-html-tmpl.md +1 -1
- package/framework/templates/brandbook-tmpl.yaml +1 -1
- package/framework/templates/component-spec-tmpl.yaml +1 -1
- package/framework/templates/design-token-tmpl.yaml +1 -1
- package/framework/templates/icon-system-tmpl.yaml +1 -1
- package/framework/templates/team-planning-tasks.yaml +6 -5
- package/framework/workflows/brownfield-discovery.yaml +2 -2
- package/framework/workflows/brownfield-fullstack.yaml +15 -11
- package/framework/workflows/brownfield-service.yaml +14 -10
- package/framework/workflows/brownfield-ui.yaml +15 -11
- package/framework/workflows/greenfield-fullstack.yaml +16 -13
- package/framework/workflows/quick-flow.yaml +3 -3
- package/framework/workflows/standard-flow.yaml +12 -9
- package/package.json +10 -5
- package/src/autonomy/autonomous-gate.js +1 -0
- package/src/autonomy/build-state.js +1 -2
- package/src/autonomy/progress-reporter.js +1 -1
- package/src/config/agent-customizer.js +11 -3
- package/src/config/claude-settings-generator.js +226 -0
- package/src/config/context-file-generator.js +41 -21
- package/src/config/framework-adapter.js +1 -0
- package/src/config/gemini-hooks-generator.js +76 -6
- package/src/config/mcp-configs.js +1 -0
- package/src/context/layers/l1-global.js +2 -1
- package/src/dashboard/data-reader.js +4 -3
- package/src/dashboard/layout.js +2 -1
- package/src/decision/analyzer.js +6 -30
- package/src/decision/engine.js +4 -28
- package/src/decision/registry-healer.js +3 -2
- package/src/decision/registry-updater.js +23 -14
- package/src/extensions/loader.js +2 -8
- package/src/gates/g1-planning-complete.js +2 -1
- package/src/gates/g2-qa-planning.js +2 -1
- package/src/gates/g3-implementation.js +2 -1
- package/src/gates/g4-qa-implementation.js +3 -2
- package/src/gates/g5-deploy-ready.js +2 -1
- package/src/health/engine.js +4 -3
- package/src/installer/core.js +557 -81
- package/src/installer/preflight.js +131 -0
- package/src/installer/provider-overlay.js +3 -3
- package/src/installer/scaffold-applier.js +358 -0
- package/src/installer/templates.js +52 -31
- package/src/installer/validator.js +17 -12
- package/src/intelligence/registry-manager.js +22 -29
- package/src/intelligence/timeline.js +11 -6
- package/src/license/commands.js +1 -1
- package/src/license/wait.js +102 -0
- package/src/memory/agent-memory.js +81 -0
- package/src/memory/dream.js +32 -1
- package/src/merger/replace-merger.js +28 -15
- package/src/orchestrator/agent-selector.js +2 -1
- package/src/orchestrator/cli.js +1908 -80
- package/src/orchestrator/doctor.js +270 -0
- package/src/orchestrator/handoff-engine.js +4 -3
- package/src/orchestrator/index.js +2 -0
- package/src/orchestrator/pipeline-manager.js +306 -15
- package/src/orchestrator/session-manager.js +331 -6
- package/src/tasks/handoff.js +3 -2
- package/src/telemetry/config.js +4 -3
- package/src/telemetry/schema.js +1 -0
- package/src/terminal/collector.js +3 -2
- package/src/terminal/index.js +1 -2
- package/src/terminal/isolation.js +52 -18
- package/src/terminal/prompt-builder.js +42 -25
- package/src/terminal/run-parallel.js +1 -1
- package/src/terminal/run-team.js +3 -3
- package/src/terminal/team-task-list.js +43 -4
- package/src/upgrade/backup.js +3 -2
- package/src/upgrade/checker.js +3 -2
- package/src/upgrade/migrator.js +65 -7
- package/src/upgrade/tracked-files-detector.js +86 -0
- package/src/upgrade/user-messages.js +94 -0
- package/src/utils/config-parser.js +2 -1
- package/src/utils/feature-flags.js +2 -1
- package/src/utils/flatten-entities.js +69 -0
- package/src/utils/framework-dir.js +16 -0
- package/src/utils/model-id.js +85 -0
- package/src/utils/provider-limits.js +84 -23
- package/src/utils/schema-validator.js +1 -1
- package/src/wizard/i18n.js +5 -4
- package/src/wizard/index.js +14 -0
- package/assets/logo - c/303/263pia.png +0 -0
- package/assets/logo.svg +0 -42
- package/assets/logo2.png +0 -0
- package/assets/social-preview.png +0 -0
- package/scripts/bundle-framework.js +0 -69
- package/scripts/changelog-generator.js +0 -222
- package/scripts/codebase-mapper.js +0 -728
- package/scripts/commit-message-generator.js +0 -167
- package/scripts/coverage-analyzer.js +0 -260
- package/scripts/dependency-analyzer.js +0 -280
- package/scripts/doctor/checks/agents.js +0 -77
- package/scripts/doctor/checks/constitution.js +0 -41
- package/scripts/doctor/checks/domain-alignment.js +0 -58
- package/scripts/doctor/checks/prism-layers.js +0 -84
- package/scripts/doctor/checks/registry.js +0 -55
- package/scripts/doctor/checks/schemas.js +0 -61
- package/scripts/doctor/fixes/reference-fix.js +0 -100
- package/scripts/doctor/fixes/registry-fix.js +0 -56
- package/scripts/doctor/index.js +0 -212
- package/scripts/framework-analyzer.js +0 -308
- package/scripts/generate-constitution-domain.js +0 -253
- package/scripts/generate-signing-key.js +0 -33
- package/scripts/health-check.js +0 -481
- package/scripts/ide-sync.js +0 -326
- package/scripts/performance-analyzer.js +0 -325
- package/scripts/plan-tracker.js +0 -278
- package/scripts/populate-entity-registry.js +0 -481
- package/scripts/pr-review.js +0 -317
- package/scripts/rollback-manager.js +0 -310
- package/scripts/semantic-lint.js +0 -328
- package/scripts/sign-manifest.js +0 -53
- package/scripts/stuck-detector.js +0 -343
- package/scripts/test-quality-assessment.js +0 -257
- package/scripts/validate-agents.js +0 -368
- package/scripts/validate-package.js +0 -367
- package/scripts/validate-tasks.js +0 -465
- package/src/autonomy/worktree-manager.js +0 -250
- package/src/intelligence/decision-engine.js +0 -256
- package/src/intelligence/document-sharder.js +0 -221
- package/src/intelligence/elicitation.js +0 -265
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Motion Premium Scaffold — v1.0.0
|
|
2
|
+
|
|
3
|
+
Opinionated premium animation infrastructure for Next.js / React 18+ / Tailwind v4 projects. Ships the 13 non-negotiable sauce patterns + 12 responsive principles proven on reference implementations (focus-ai-website).
|
|
4
|
+
|
|
5
|
+
## What this scaffold gives you
|
|
6
|
+
|
|
7
|
+
**Phase 1 (foundation) — shipped in v1.0.0:**
|
|
8
|
+
- `app/globals.css` — fluid type scale (Utopia-based), 4px-base spacing, radius/shadow tokens, `--breakpoint-xl: 75rem` override, reduced-motion safety net, brand placeholders.
|
|
9
|
+
- `lib/brand.ts` — typed brand token source of truth. Single place to edit project colors.
|
|
10
|
+
|
|
11
|
+
**Phase 2–4 (coming in v1.0.0 full ship):**
|
|
12
|
+
- `lib/animations/*` — gsap glue, tokens, scoped hooks (Phase 2)
|
|
13
|
+
- `components/animation/*` — Lenis, crossfade, transition, preloader providers (Phase 3)
|
|
14
|
+
- `components/ui/Container.tsx`, `PageSection.tsx` — UI contract (Phase 4)
|
|
15
|
+
|
|
16
|
+
## When NOT to use this scaffold
|
|
17
|
+
|
|
18
|
+
- Static landing pages without scroll-driven animation — overkill.
|
|
19
|
+
- Non-Tailwind projects — this scaffold is tightly coupled to Tailwind v4 syntax.
|
|
20
|
+
- Projects already using Framer Motion exclusively (no GSAP/Lenis) — import conflicts.
|
|
21
|
+
|
|
22
|
+
## How customization works (Decision 3)
|
|
23
|
+
|
|
24
|
+
Brand tokens flow one-way at install time: `brand.ts` → placeholder resolution → `globals.css` (concrete hex values).
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
lib/brand.ts (single source of truth, user-owned)
|
|
28
|
+
↓
|
|
29
|
+
scaffold-applier resolves {{PRIMARY_HEX}}, {{PRIMARY_RGB}}, ...
|
|
30
|
+
↓
|
|
31
|
+
app/globals.css (concrete --color-* vars, editable but expected to stay in sync)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**If you edit `brand.ts` after install**, globals.css is NOT auto-updated. Run:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx chati-dev scaffold motion-premium --sync-brand
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This re-resolves placeholders and rewrites the brand var block in globals.css without touching your spacing/radius/shadow customizations.
|
|
41
|
+
|
|
42
|
+
## Override classification
|
|
43
|
+
|
|
44
|
+
| File | Class | Behavior on upgrade |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `lib/brand.ts` | full | Never overwritten. Your edits are protected via hash diff. |
|
|
47
|
+
| `app/globals.css` | partial | Brand vars re-synced on `--sync-brand`; rest of file preserved if user-modified. |
|
|
48
|
+
| `lib/animations/gsap.ts` | none | Scaffold-owned. Upgrades replace, warning if user-modified. |
|
|
49
|
+
| `lib/animations/tokens.ts` | partial | Adjust values (durations, easings, staggers); keep the exported shape. |
|
|
50
|
+
| `lib/animations/useGsapContext.ts` | none | Scaffold-owned. Core pattern (reduced-motion safeguards) — do not modify. |
|
|
51
|
+
| `lib/animations/useSmoothScroll.ts` | none | Scaffold-owned. Race-guarded async Lenis init consumed by `LenisProvider`. |
|
|
52
|
+
| `lib/animations/useScrollSnapStepper.ts` | none | Scaffold-owned. Wheel + touch accumulator for panel-snap pins. |
|
|
53
|
+
| `lib/animations/refreshCoordinator.ts` | none | Scaffold-owned. Debounced `ScrollTrigger.refresh()` singleton. |
|
|
54
|
+
| `components/animation/LenisProvider.tsx` | none | Scaffold-owned. |
|
|
55
|
+
| `components/animation/BackgroundCrossfadeProvider.tsx` | partial | Customize color stops array; keep ScrollTrigger logic. |
|
|
56
|
+
| `components/animation/PageTransitionWrapper.tsx` | none | Scaffold-owned. Framer Motion opacity fade on pathname change. |
|
|
57
|
+
| `components/animation/Preloader.tsx` | partial | Swap video for logo if desired; keep readyState gate. |
|
|
58
|
+
| `app/layout.tsx` | partial | Provider nesting + pre-hydration scroll/motion scripts are scaffold-owned. Fill metadata / fonts / chrome / analytics. |
|
|
59
|
+
| `components/ui/Container.tsx` | none | THE contract. Never edit — subclass via composition if needed. |
|
|
60
|
+
| `components/ui/PageSection.tsx` | none | Scaffold-owned. Use `noPadding` / `noContainer` props for exceptions. |
|
|
61
|
+
|
|
62
|
+
All 15 files listed above match `scaffold.yaml` `files[]` exactly.
|
|
63
|
+
|
|
64
|
+
## Anti-patterns (will break the premium guarantees)
|
|
65
|
+
|
|
66
|
+
1. **Adding max-width or horizontal padding anywhere except Container.tsx** — breaks the "one authority" contract (Principle 1). Visual QA will fail.
|
|
67
|
+
2. **Creating your own Lenis instance** — conflicts with the scaffold's single-RAF loop. Use `useSmoothScroll()` (Phase 2).
|
|
68
|
+
3. **Calling `gsap.registerPlugin` in components** — already registered module-level in `gsap.ts`. Re-registration causes silent failures.
|
|
69
|
+
4. **Inline `text-[var(--text-xl)]` without the `length:` type hint** — Tailwind v4 silently omits untyped arbitrary CSS vars. Use `text-xl` (fluid utility) or `text-[length:var(--text-xl)]`.
|
|
70
|
+
5. **Animating without `data-gsap-target`** — loses the reduced-motion safety net. Every pinned/revealed element must carry this attribute.
|
|
71
|
+
|
|
72
|
+
## Version info
|
|
73
|
+
|
|
74
|
+
- **Scaffold**: `motion-premium@1.0.0`
|
|
75
|
+
- **Requires framework**: chati.dev >= 4.3.0
|
|
76
|
+
- **Requires stack**: Next.js OR React Vite, Tailwind v4+, TypeScript 5+, React 18+, Node 18+
|
|
77
|
+
- **Reference implementation**: `focus-ai-website` (all 13 sauce patterns verified in production)
|
|
78
|
+
|
|
79
|
+
## Upgrading
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Check for scaffold updates
|
|
83
|
+
npx chati-dev scaffold motion-premium --check
|
|
84
|
+
|
|
85
|
+
# Apply latest (preserves your customizations via hash diff)
|
|
86
|
+
npx chati-dev scaffold motion-premium --upgrade
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Scaffold versioning is independent of the framework version. Scaffold 1.0.x → 1.1.x is additive-only; 1.x → 2.x may require migrations (provided via `framework/migrations/scaffold-*.yaml`).
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
/* Exclude non-source directories from Tailwind v4 scanning */
|
|
4
|
+
@source not "../artifacts";
|
|
5
|
+
@source not "../.chati";
|
|
6
|
+
@source not "../.chati.dev";
|
|
7
|
+
@source not "../docs";
|
|
8
|
+
|
|
9
|
+
/* =========================================================
|
|
10
|
+
DESIGN TOKENS
|
|
11
|
+
Brand hex values are placeholders, resolved at scaffold
|
|
12
|
+
apply time from lib/brand.ts (Decision 3).
|
|
13
|
+
To re-sync after editing brand.ts:
|
|
14
|
+
npx chati-dev scaffold motion-premium --sync-brand
|
|
15
|
+
========================================================= */
|
|
16
|
+
|
|
17
|
+
:root {
|
|
18
|
+
color-scheme: dark;
|
|
19
|
+
|
|
20
|
+
/* --- Neutral Scale (dark-theme defaults; user-editable) --- */
|
|
21
|
+
--color-neutral-0: #F5F5FA;
|
|
22
|
+
--color-neutral-50: #E8E8EE;
|
|
23
|
+
--color-neutral-100: #D0D0DD;
|
|
24
|
+
--color-neutral-200: #8A8A9A;
|
|
25
|
+
--color-neutral-300: #8888A0;
|
|
26
|
+
--color-neutral-400: #5C5C7A;
|
|
27
|
+
--color-neutral-500: #3A3A55;
|
|
28
|
+
--color-neutral-600: #2A2A42;
|
|
29
|
+
--color-neutral-700: #1F1F35;
|
|
30
|
+
--color-neutral-800: #1A1A2E;
|
|
31
|
+
--color-neutral-900: #0F0F1A;
|
|
32
|
+
|
|
33
|
+
/* --- Brand Colors (placeholders → resolved from brand.ts) --- */
|
|
34
|
+
--color-primary: {{PRIMARY_HEX}};
|
|
35
|
+
--color-primary-rgb: {{PRIMARY_RGB}};
|
|
36
|
+
--color-primary-hover: {{PRIMARY_HOVER_HEX}};
|
|
37
|
+
--color-primary-muted: rgba(var(--color-primary-rgb), 0.15);
|
|
38
|
+
|
|
39
|
+
/* --- Background Levels --- */
|
|
40
|
+
--color-secondary: var(--color-neutral-800);
|
|
41
|
+
--color-bg-deeper: #0A0A12;
|
|
42
|
+
--color-bg-deep: {{BG_DEEP_HEX}};
|
|
43
|
+
--color-bg-primary: {{BG_PRIMARY_HEX}};
|
|
44
|
+
--color-bg-surface: var(--color-bg-deep);
|
|
45
|
+
--color-bg-elevated: {{BG_ELEVATED_HEX}};
|
|
46
|
+
|
|
47
|
+
/* --- Text Levels --- */
|
|
48
|
+
--color-text-primary: {{TEXT_PRIMARY_HEX}};
|
|
49
|
+
--color-text-secondary: {{TEXT_SECONDARY_HEX}};
|
|
50
|
+
--color-text-tertiary: var(--color-neutral-400);
|
|
51
|
+
--color-text-inverse: {{TEXT_INVERSE_HEX}};
|
|
52
|
+
|
|
53
|
+
/* --- Semantic Colors --- */
|
|
54
|
+
--color-semantic-success: #22C55E;
|
|
55
|
+
--color-semantic-warning: #F59E0B;
|
|
56
|
+
--color-semantic-error: #EF4444;
|
|
57
|
+
--color-semantic-info: #60A5FA;
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* Fluid Typography Scale (Utopia-based)
|
|
61
|
+
* Linear interpolation from 320vw (min) to 2560vw (max, 27" reference).
|
|
62
|
+
* Formula: slope = (max - min) / 22.4, base = min - slope * 3.2
|
|
63
|
+
* Expression: clamp(min_rem, base_rem + slope_vw, max_rem)
|
|
64
|
+
* Every token is mathematically consistent. Same growth curve across the scale.
|
|
65
|
+
*/
|
|
66
|
+
--text-xs: clamp(0.75rem, 0.732rem + 0.089vw, 0.875rem); /* 12 -> 14 */
|
|
67
|
+
--text-sm: clamp(0.875rem, 0.857rem + 0.089vw, 1rem); /* 14 -> 16 */
|
|
68
|
+
--text-base: clamp(1rem, 0.982rem + 0.089vw, 1.125rem); /* 16 -> 18 */
|
|
69
|
+
--text-lg: clamp(1.125rem, 1.089rem + 0.179vw, 1.375rem); /* 18 -> 22 */
|
|
70
|
+
--text-xl: clamp(1.25rem, 1.196rem + 0.268vw, 1.625rem); /* 20 -> 26 */
|
|
71
|
+
--text-2xl: clamp(1.5rem, 1.429rem + 0.357vw, 2.125rem); /* 24 -> 34 */
|
|
72
|
+
--text-3xl: clamp(1.75rem, 1.625rem + 0.625vw, 2.625rem); /* 28 -> 42 */
|
|
73
|
+
--text-4xl: clamp(2.125rem, 1.929rem + 0.982vw, 3.5rem); /* 34 -> 56 */
|
|
74
|
+
--text-5xl: clamp(2.5rem, 2.214rem + 1.429vw, 4.5rem); /* 40 -> 72 */
|
|
75
|
+
--text-6xl: clamp(3rem, 2.571rem + 2.143vw, 6rem); /* 48 -> 96 */
|
|
76
|
+
--text-7xl: clamp(3.5rem, 2.929rem + 2.857vw, 7.5rem); /* 56 -> 120 */
|
|
77
|
+
--text-8xl: clamp(4rem, 3.286rem + 3.571vw, 9rem); /* 64 -> 144 */
|
|
78
|
+
--text-display: clamp(4.5rem, 3.714rem + 3.929vw, 10rem); /* 72 -> 160 */
|
|
79
|
+
--text-hero: clamp(5rem, 4.143rem + 4.286vw, 11rem); /* 80 -> 176 */
|
|
80
|
+
|
|
81
|
+
/* Line-heights paired with fluid sizes */
|
|
82
|
+
--leading-tight: 1.05;
|
|
83
|
+
--leading-snug: 1.2;
|
|
84
|
+
--leading-normal: 1.5;
|
|
85
|
+
--leading-relaxed: 1.65;
|
|
86
|
+
|
|
87
|
+
/* --- Spacing (4px base unit) --- */
|
|
88
|
+
--space-1: 4px;
|
|
89
|
+
--space-2: 8px;
|
|
90
|
+
--space-3: 12px;
|
|
91
|
+
--space-4: 16px;
|
|
92
|
+
--space-5: 20px;
|
|
93
|
+
--space-6: 24px;
|
|
94
|
+
--space-7: 28px;
|
|
95
|
+
--space-8: 32px;
|
|
96
|
+
--space-9: 36px;
|
|
97
|
+
--space-10: 40px;
|
|
98
|
+
--space-11: 44px;
|
|
99
|
+
--space-12: 48px;
|
|
100
|
+
--space-16: 64px;
|
|
101
|
+
--space-20: 80px;
|
|
102
|
+
--space-24: 96px;
|
|
103
|
+
--space-32: 128px;
|
|
104
|
+
--space-48: 192px;
|
|
105
|
+
|
|
106
|
+
/* --- Layout --- */
|
|
107
|
+
--container-max-width: 1200px;
|
|
108
|
+
--nav-height: 72px;
|
|
109
|
+
|
|
110
|
+
/* --- Border Radius --- */
|
|
111
|
+
--radius-none: 0px;
|
|
112
|
+
--radius-sm: 4px;
|
|
113
|
+
--radius-md: 8px;
|
|
114
|
+
--radius-lg: 12px;
|
|
115
|
+
--radius-xl: 16px;
|
|
116
|
+
--radius-2xl: 24px;
|
|
117
|
+
--radius-full: 9999px;
|
|
118
|
+
|
|
119
|
+
/* --- Shadows --- */
|
|
120
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
121
|
+
--shadow-md: 0 4px 8px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
122
|
+
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.6), 0 2px 4px rgba(0, 0, 0, 0.3);
|
|
123
|
+
--shadow-xl: 0 20px 48px rgba(0, 0, 0, 0.7), 0 4px 8px rgba(0, 0, 0, 0.4);
|
|
124
|
+
--shadow-glow-primary: 0 0 24px rgba(var(--color-primary-rgb), 0.2), 0 0 8px rgba(var(--color-primary-rgb), 0.1);
|
|
125
|
+
--shadow-glow-sm: 0 0 8px rgba(var(--color-primary-rgb), 0.15);
|
|
126
|
+
|
|
127
|
+
/* --- Icon Sizes --- */
|
|
128
|
+
--icon-xs: 12px;
|
|
129
|
+
--icon-sm: 16px;
|
|
130
|
+
--icon-md: 20px;
|
|
131
|
+
--icon-lg: 24px;
|
|
132
|
+
--icon-xl: 32px;
|
|
133
|
+
--icon-2xl: 48px;
|
|
134
|
+
|
|
135
|
+
/* --- Duration --- */
|
|
136
|
+
--duration-instant: 0ms;
|
|
137
|
+
--duration-fast: 150ms;
|
|
138
|
+
--duration-normal: 300ms;
|
|
139
|
+
--duration-slow: 500ms;
|
|
140
|
+
--duration-dramatic: 900ms;
|
|
141
|
+
--duration-cinematic: 1400ms;
|
|
142
|
+
|
|
143
|
+
/* --- Easing --- */
|
|
144
|
+
--ease-default: cubic-bezier(0.25, 0.1, 0.25, 1);
|
|
145
|
+
--ease-in: cubic-bezier(0.42, 0, 1, 1);
|
|
146
|
+
--ease-out: cubic-bezier(0, 0, 0.58, 1);
|
|
147
|
+
--ease-in-out: cubic-bezier(0.42, 0, 0.58, 1);
|
|
148
|
+
--ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
149
|
+
--ease-cinematic: cubic-bezier(0.16, 1, 0.3, 1);
|
|
150
|
+
--ease-gentle: cubic-bezier(0.4, 0, 0.2, 1);
|
|
151
|
+
|
|
152
|
+
/* --- Scroll-Driven Scene Background (Phase 3: BackgroundCrossfadeProvider) --- */
|
|
153
|
+
--scene-bg: var(--color-bg-deep);
|
|
154
|
+
|
|
155
|
+
/* --- Button Tokens --- */
|
|
156
|
+
--btn-padding-x-sm: var(--space-3);
|
|
157
|
+
--btn-padding-x-md: var(--space-5);
|
|
158
|
+
--btn-padding-x-lg: var(--space-8);
|
|
159
|
+
--btn-height-sm: 36px;
|
|
160
|
+
--btn-height-md: 44px;
|
|
161
|
+
--btn-height-lg: 52px;
|
|
162
|
+
--btn-radius: var(--radius-md);
|
|
163
|
+
--btn-primary-bg: var(--color-primary);
|
|
164
|
+
--btn-primary-text: var(--color-text-inverse);
|
|
165
|
+
--btn-primary-hover-bg: var(--color-primary-hover);
|
|
166
|
+
--btn-secondary-bg: transparent;
|
|
167
|
+
--btn-secondary-border: 1px solid var(--color-neutral-500);
|
|
168
|
+
--btn-secondary-text: var(--color-text-primary);
|
|
169
|
+
--btn-ghost-text: var(--color-text-secondary);
|
|
170
|
+
|
|
171
|
+
/* --- Card Tokens --- */
|
|
172
|
+
--card-bg: var(--color-bg-surface);
|
|
173
|
+
--card-border: 1px solid var(--color-neutral-600);
|
|
174
|
+
--card-radius: var(--radius-lg);
|
|
175
|
+
--card-padding: var(--space-8);
|
|
176
|
+
--card-hover-shadow: var(--shadow-lg);
|
|
177
|
+
--card-hover-border: 1px solid var(--color-neutral-500);
|
|
178
|
+
|
|
179
|
+
/* --- Input Tokens --- */
|
|
180
|
+
--input-bg: var(--color-bg-surface);
|
|
181
|
+
--input-border: 1px solid var(--color-neutral-500);
|
|
182
|
+
--input-border-focus: 1px solid var(--color-primary);
|
|
183
|
+
--input-border-error: 1px solid var(--color-semantic-error);
|
|
184
|
+
--input-radius: var(--radius-md);
|
|
185
|
+
--input-padding-x: var(--space-4);
|
|
186
|
+
--input-height: 44px;
|
|
187
|
+
--input-text: var(--color-text-primary);
|
|
188
|
+
--input-placeholder: var(--color-text-tertiary);
|
|
189
|
+
|
|
190
|
+
/* --- Nav Tokens --- */
|
|
191
|
+
--nav-bg: rgba(8, 10, 9, 0.85);
|
|
192
|
+
--nav-backdrop-blur: blur(20px);
|
|
193
|
+
--nav-border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
194
|
+
--nav-link-text: var(--color-text-secondary);
|
|
195
|
+
--nav-link-hover: var(--color-text-primary);
|
|
196
|
+
--nav-link-active: var(--color-primary);
|
|
197
|
+
|
|
198
|
+
/* --- Breakpoints (reference only, use Tailwind breakpoints in classes) --- */
|
|
199
|
+
--bp-sm: 640px;
|
|
200
|
+
--bp-md: 768px;
|
|
201
|
+
--bp-lg: 1024px;
|
|
202
|
+
--bp-xl: 1280px;
|
|
203
|
+
--bp-2xl: 1536px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* =========================================================
|
|
207
|
+
TAILWIND v4 @theme BLOCK
|
|
208
|
+
Registers tokens as Tailwind utilities to avoid
|
|
209
|
+
arbitrary value syntax where possible.
|
|
210
|
+
========================================================= */
|
|
211
|
+
|
|
212
|
+
@theme {
|
|
213
|
+
/*
|
|
214
|
+
* Custom breakpoint override: xl lowered from 80rem (1280px) to 75rem (1200px).
|
|
215
|
+
* This aligns laptop viewports in the 1200 to 1279 range (MacBook Air M4 13.8"
|
|
216
|
+
* scaled default) with desktop xl: utilities, eliminating the dead zone where
|
|
217
|
+
* lg: applied but xl: did not, which produced layout gaps and mismatched padding
|
|
218
|
+
* between laptop and external desktop monitors.
|
|
219
|
+
*/
|
|
220
|
+
--breakpoint-xl: 75rem;
|
|
221
|
+
|
|
222
|
+
/*
|
|
223
|
+
* Font sizes: all alias the fluid --text-* tokens defined in :root.
|
|
224
|
+
* Utopia-based linear fluid scale, 320vw (min) to 2560vw (max).
|
|
225
|
+
* Registered here so Tailwind utilities text-xs..text-hero render correctly.
|
|
226
|
+
*/
|
|
227
|
+
--font-size-xs: var(--text-xs);
|
|
228
|
+
--font-size-sm: var(--text-sm);
|
|
229
|
+
--font-size-base: var(--text-base);
|
|
230
|
+
--font-size-lg: var(--text-lg);
|
|
231
|
+
--font-size-xl: var(--text-xl);
|
|
232
|
+
--font-size-2xl: var(--text-2xl);
|
|
233
|
+
--font-size-3xl: var(--text-3xl);
|
|
234
|
+
--font-size-4xl: var(--text-4xl);
|
|
235
|
+
--font-size-5xl: var(--text-5xl);
|
|
236
|
+
--font-size-6xl: var(--text-6xl);
|
|
237
|
+
--font-size-7xl: var(--text-7xl);
|
|
238
|
+
--font-size-8xl: var(--text-8xl);
|
|
239
|
+
--font-size-display: var(--text-display);
|
|
240
|
+
--font-size-hero: var(--text-hero);
|
|
241
|
+
|
|
242
|
+
/* Colors registered in @theme for Tailwind color utilities */
|
|
243
|
+
--color-primary: {{PRIMARY_HEX}};
|
|
244
|
+
--color-primary-hover: {{PRIMARY_HOVER_HEX}};
|
|
245
|
+
|
|
246
|
+
--color-bg-deeper: #0A0A12;
|
|
247
|
+
--color-bg-deep: {{BG_DEEP_HEX}};
|
|
248
|
+
--color-bg-primary: {{BG_PRIMARY_HEX}};
|
|
249
|
+
--color-bg-surface: var(--color-bg-deep);
|
|
250
|
+
--color-bg-elevated: {{BG_ELEVATED_HEX}};
|
|
251
|
+
--color-secondary: var(--color-neutral-800);
|
|
252
|
+
|
|
253
|
+
--color-text-primary: {{TEXT_PRIMARY_HEX}};
|
|
254
|
+
--color-text-secondary: {{TEXT_SECONDARY_HEX}};
|
|
255
|
+
--color-text-tertiary: var(--color-neutral-400);
|
|
256
|
+
--color-text-inverse: {{TEXT_INVERSE_HEX}};
|
|
257
|
+
|
|
258
|
+
--color-neutral-0: #F5F5FA;
|
|
259
|
+
--color-neutral-50: #E8E8EE;
|
|
260
|
+
--color-neutral-100: #D0D0DD;
|
|
261
|
+
--color-neutral-200: #8A8A9A;
|
|
262
|
+
--color-neutral-300: #8888A0;
|
|
263
|
+
--color-neutral-400: #5C5C7A;
|
|
264
|
+
--color-neutral-500: #3A3A55;
|
|
265
|
+
--color-neutral-600: #2A2A42;
|
|
266
|
+
--color-neutral-700: #1F1F35;
|
|
267
|
+
--color-neutral-800: #1A1A2E;
|
|
268
|
+
--color-neutral-900: #0F0F1A;
|
|
269
|
+
|
|
270
|
+
--color-semantic-success: #22C55E;
|
|
271
|
+
--color-semantic-warning: #F59E0B;
|
|
272
|
+
--color-semantic-error: #EF4444;
|
|
273
|
+
--color-semantic-info: #60A5FA;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* =========================================================
|
|
277
|
+
GLOBAL BASE STYLES
|
|
278
|
+
Must live inside @layer base so Tailwind utilities
|
|
279
|
+
(mx-auto, px-*, etc.) declared in @layer utilities
|
|
280
|
+
can override these defaults via normal cascade order.
|
|
281
|
+
========================================================= */
|
|
282
|
+
|
|
283
|
+
@layer base {
|
|
284
|
+
html {
|
|
285
|
+
scroll-behavior: auto; /* Lenis handles smooth scroll — see Phase 3 LenisProvider */
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
body {
|
|
289
|
+
background-color: var(--scene-bg, var(--color-bg-primary));
|
|
290
|
+
color: var(--color-text-primary);
|
|
291
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
292
|
+
font-size: var(--text-base);
|
|
293
|
+
line-height: 1.65;
|
|
294
|
+
-webkit-font-smoothing: antialiased;
|
|
295
|
+
-moz-osx-font-smoothing: grayscale;
|
|
296
|
+
transition: background-color var(--duration-normal) var(--ease-gentle);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
h1, h2, h3, h4, h5, h6 {
|
|
300
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
301
|
+
color: var(--color-text-primary);
|
|
302
|
+
}
|
|
303
|
+
h1 {
|
|
304
|
+
font-weight: 700;
|
|
305
|
+
letter-spacing: -0.02em;
|
|
306
|
+
line-height: 1.1;
|
|
307
|
+
}
|
|
308
|
+
h2 {
|
|
309
|
+
font-weight: 700;
|
|
310
|
+
letter-spacing: -0.02em;
|
|
311
|
+
line-height: 1.15;
|
|
312
|
+
}
|
|
313
|
+
h3 {
|
|
314
|
+
font-weight: 600;
|
|
315
|
+
letter-spacing: -0.01em;
|
|
316
|
+
line-height: 1.2;
|
|
317
|
+
}
|
|
318
|
+
h4 {
|
|
319
|
+
font-weight: 600;
|
|
320
|
+
line-height: 1.3;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
:focus-visible {
|
|
324
|
+
outline: 2px solid var(--color-primary);
|
|
325
|
+
outline-offset: 2px;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
[id] {
|
|
329
|
+
scroll-margin-top: 80px;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
@layer utilities {
|
|
334
|
+
.typo-display {
|
|
335
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
336
|
+
font-weight: 900;
|
|
337
|
+
letter-spacing: -0.03em;
|
|
338
|
+
line-height: 1.05;
|
|
339
|
+
}
|
|
340
|
+
.typo-section-label {
|
|
341
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
342
|
+
font-weight: 600;
|
|
343
|
+
letter-spacing: 0.12em;
|
|
344
|
+
text-transform: uppercase;
|
|
345
|
+
line-height: 1;
|
|
346
|
+
}
|
|
347
|
+
.typo-micro-label {
|
|
348
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
349
|
+
font-weight: 600;
|
|
350
|
+
letter-spacing: 0.08em;
|
|
351
|
+
text-transform: uppercase;
|
|
352
|
+
line-height: 1;
|
|
353
|
+
}
|
|
354
|
+
.typo-pull-quote {
|
|
355
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
356
|
+
font-weight: 400;
|
|
357
|
+
font-style: italic;
|
|
358
|
+
line-height: 1.4;
|
|
359
|
+
}
|
|
360
|
+
.typo-editorial {
|
|
361
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
362
|
+
font-weight: 400;
|
|
363
|
+
line-height: 1.55;
|
|
364
|
+
}
|
|
365
|
+
.typo-caption {
|
|
366
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
367
|
+
font-weight: 400;
|
|
368
|
+
line-height: 1.5;
|
|
369
|
+
}
|
|
370
|
+
.typo-body {
|
|
371
|
+
font-family: var(--font-inter, system-ui, sans-serif);
|
|
372
|
+
font-weight: 400;
|
|
373
|
+
line-height: 1.65;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/* =========================================================
|
|
378
|
+
REDUCED MOTION — safety net
|
|
379
|
+
When animations are skipped, all GSAP-controlled elements
|
|
380
|
+
must be immediately visible in their final state.
|
|
381
|
+
The [data-gsap-target] selector assumes Phase 2 hooks mark
|
|
382
|
+
animated elements with this attribute.
|
|
383
|
+
========================================================= */
|
|
384
|
+
|
|
385
|
+
@media (prefers-reduced-motion: reduce) {
|
|
386
|
+
*,
|
|
387
|
+
*::before,
|
|
388
|
+
*::after {
|
|
389
|
+
animation-duration: 0.01ms !important;
|
|
390
|
+
animation-iteration-count: 1 !important;
|
|
391
|
+
transition-duration: 0.01ms !important;
|
|
392
|
+
scroll-behavior: auto !important;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/* Ensure any GSAP-controlled elements default to visible */
|
|
396
|
+
[data-gsap-target] {
|
|
397
|
+
opacity: 1 !important;
|
|
398
|
+
transform: none !important;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* app/layout.tsx — scaffold motion-premium v1.0.0
|
|
3
|
+
*
|
|
4
|
+
* Root layout. Defines the provider nesting order, the pre-hydration
|
|
5
|
+
* scroll-restoration script, and the inline reduced-motion safety-net
|
|
6
|
+
* style block. User customizes metadata, font loading, analytics,
|
|
7
|
+
* and site chrome (header/footer) on top of this scaffold.
|
|
8
|
+
*
|
|
9
|
+
* Non-obvious choices:
|
|
10
|
+
*
|
|
11
|
+
* - Provider nesting order is load-bearing:
|
|
12
|
+
* Preloader first (sibling, NOT wrapping) — it needs to cover the
|
|
13
|
+
* children while Lenis/GSAP boot. Wrapping inside Lenis would delay
|
|
14
|
+
* the preloader behind Lenis's dynamic import.
|
|
15
|
+
* Then, deepest-to-shallowest:
|
|
16
|
+
* LenisProvider
|
|
17
|
+
* ↳ BackgroundCrossfadeProvider (depends on ScrollTrigger; Lenis
|
|
18
|
+
* must be live for positions to be
|
|
19
|
+
* correct)
|
|
20
|
+
* ↳ PageTransitionWrapper (exits must complete before the
|
|
21
|
+
* next ScrollTrigger registration
|
|
22
|
+
* from the new route)
|
|
23
|
+
* ↳ children (user pages)
|
|
24
|
+
*
|
|
25
|
+
* - Inline `<script>` (pre-hydration) sets `history.scrollRestoration =
|
|
26
|
+
* 'manual'` and scrolls to 0 BEFORE React hydrates. This closes the
|
|
27
|
+
* brief window where the browser's default scroll-restoration would
|
|
28
|
+
* jump to the prior scroll position on back-nav, only to have Lenis
|
|
29
|
+
* re-scroll to top a few frames later. The flash is jarring without
|
|
30
|
+
* this script. Duplicate of the post-hydration useEffect in
|
|
31
|
+
* LenisProvider — both layers are needed.
|
|
32
|
+
*
|
|
33
|
+
* - Inline `<style>` (pre-hydration) for reduced-motion mirrors the
|
|
34
|
+
* `@media (prefers-reduced-motion)` block in globals.css. Inline
|
|
35
|
+
* declaration guarantees the rule applies BEFORE external CSS loads,
|
|
36
|
+
* so reduced-motion users on slow networks never see a flash of
|
|
37
|
+
* animation on first paint.
|
|
38
|
+
*
|
|
39
|
+
* - `suppressHydrationWarning` on <html> — the pre-hydration scroll
|
|
40
|
+
* script and style can cause mismatch warnings in React strict mode
|
|
41
|
+
* (server-rendered <html> has no effect from the script, client does).
|
|
42
|
+
* This suppression is scoped to <html> only; component-level mismatches
|
|
43
|
+
* still surface.
|
|
44
|
+
*
|
|
45
|
+
* - Metadata block is a placeholder — users should fill in their site
|
|
46
|
+
* name, description, OpenGraph, Twitter, JSON-LD, robots, etc.
|
|
47
|
+
* Intentionally NOT parameterized via scaffold placeholders because
|
|
48
|
+
* metadata is project-specific boilerplate, not brand-tied.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
import type { Metadata } from 'next';
|
|
52
|
+
import './globals.css';
|
|
53
|
+
import { LenisProvider } from '@/components/animation/LenisProvider';
|
|
54
|
+
import { BackgroundCrossfadeProvider } from '@/components/animation/BackgroundCrossfadeProvider';
|
|
55
|
+
import { PageTransitionWrapper } from '@/components/animation/PageTransitionWrapper';
|
|
56
|
+
import { Preloader } from '@/components/animation/Preloader';
|
|
57
|
+
|
|
58
|
+
// TODO: Fill in per project. See https://nextjs.org/docs/app/building-your-application/optimizing/metadata
|
|
59
|
+
export const metadata: Metadata = {
|
|
60
|
+
title: {
|
|
61
|
+
default: 'Your Project Name',
|
|
62
|
+
template: '%s | Your Project Name',
|
|
63
|
+
},
|
|
64
|
+
description: 'Your project description.',
|
|
65
|
+
// metadataBase: new URL('https://yourdomain.com'),
|
|
66
|
+
// openGraph: { ... },
|
|
67
|
+
// twitter: { ... },
|
|
68
|
+
// robots: { index: true, follow: true },
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export default function RootLayout({
|
|
72
|
+
children,
|
|
73
|
+
}: {
|
|
74
|
+
children: React.ReactNode;
|
|
75
|
+
}) {
|
|
76
|
+
return (
|
|
77
|
+
<html lang="en" suppressHydrationWarning>
|
|
78
|
+
<head>
|
|
79
|
+
{/* Pre-hydration: manual scroll restoration + scroll to top.
|
|
80
|
+
Partners with LenisProvider's post-hydration useEffect. */}
|
|
81
|
+
<script
|
|
82
|
+
dangerouslySetInnerHTML={{
|
|
83
|
+
__html: `(function(){try{if('scrollRestoration' in history){history.scrollRestoration='manual';}window.scrollTo(0,0);}catch(e){}})();`,
|
|
84
|
+
}}
|
|
85
|
+
/>
|
|
86
|
+
{/* Pre-hydration reduced-motion safety net. Duplicates globals.css
|
|
87
|
+
so the rule applies before external CSS parses. */}
|
|
88
|
+
<style
|
|
89
|
+
dangerouslySetInnerHTML={{
|
|
90
|
+
__html: `@media (prefers-reduced-motion: reduce){*,*::before,*::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;}[data-gsap-target]{opacity:1 !important;transform:none !important;}}`,
|
|
91
|
+
}}
|
|
92
|
+
/>
|
|
93
|
+
{/* TODO: Add font preloads, favicon, JSON-LD, analytics tags here. */}
|
|
94
|
+
</head>
|
|
95
|
+
<body className="antialiased">
|
|
96
|
+
{/* Preloader is a sibling of the provider tree, not a parent:
|
|
97
|
+
it covers the viewport while Lenis/GSAP boot dynamically. */}
|
|
98
|
+
<Preloader />
|
|
99
|
+
|
|
100
|
+
<LenisProvider>
|
|
101
|
+
<BackgroundCrossfadeProvider>
|
|
102
|
+
<PageTransitionWrapper>
|
|
103
|
+
{children}
|
|
104
|
+
</PageTransitionWrapper>
|
|
105
|
+
</BackgroundCrossfadeProvider>
|
|
106
|
+
</LenisProvider>
|
|
107
|
+
</body>
|
|
108
|
+
</html>
|
|
109
|
+
);
|
|
110
|
+
}
|