真トップ

import React, { useLayoutEffect, useRef, useEffect, useState } from ‘react’; export default function App() { const mainRef = useRef(null); const scrollContainerRef = useRef(null); // Refs for animation const heroRef = useRef(null); const textRef = useRef([]); const imageRef = useRef([]); // State to track if GSAP is loaded const [isGsapLoaded, setIsGsapLoaded] = useState(false); // — 1. Load Scripts Dynamically (GSAP) — useEffect(() => { if (typeof window !== ‘undefined’ && window.gsap && window.ScrollTrigger) { setIsGsapLoaded(true); return; } const loadScript = (src) => { return new Promise((resolve, reject) => { const script = document.createElement(‘script’); script.src = src; script.async = true; script.onload = resolve; script.onerror = reject; document.body.appendChild(script); }); }; const loadGSAP = async () => { try { if (!window.gsap) await loadScript(‘https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js’); if (!window.ScrollTrigger) await loadScript(‘https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js’); setIsGsapLoaded(true); } catch (err) { console.error(‘Failed to load GSAP scripts’, err); } }; loadGSAP(); }, []); // — 2. GSAP Animations — useLayoutEffect(() => { if (!isGsapLoaded || !window.gsap || !window.ScrollTrigger) return; const gsap = window.gsap; const ScrollTrigger = window.ScrollTrigger; gsap.registerPlugin(ScrollTrigger); const ctx = gsap.context(() => { // Hero: Title Fade In (Slow & Elegant) gsap.from(‘.hero-char’, { y: 40, opacity: 0, duration: 2, stagger: 0.15, ease: “power2.out”, delay: 0.5 }); gsap.from(‘.hero-sub’, { opacity: 0, duration: 2, delay: 1.5, ease: “power2.out” }); // Images: Parallax & Reveal gsap.utils.toArray(‘.reveal-image’).forEach((img) => { gsap.fromTo(img, { clipPath: “inset(10% 10% 10% 10%)”, scale: 1.1, filter: “blur(10px) grayscale(100%)” }, { clipPath: “inset(0% 0% 0% 0%)”, scale: 1, filter: “blur(0px) grayscale(0%)”, duration: 1.8, ease: “power2.out”, scrollTrigger: { trigger: img, start: “top 80%”, } } ); gsap.to(img, { yPercent: -15, ease: “none”, scrollTrigger: { trigger: img, start: “top bottom”, end: “bottom top”, scrub: true } }); }); // Text: Vertical Writing Fade Up gsap.utils.toArray(‘.vertical-fade’).forEach((text) => { gsap.from(text, { y: 30, opacity: 0, duration: 1.5, ease: “power3.out”, scrollTrigger: { trigger: text, start: “top 85%”, } }); }); // Background Color Shift (Subtle) ScrollTrigger.create({ trigger: “.indigo-section”, start: “top 60%”, end: “bottom 60%”, onEnter: () => gsap.to(mainRef.current, { backgroundColor: “#1a2433”, color: “#f0f0f0”, duration: 1.5 }), // Deep Indigo onLeaveBack: () => gsap.to(mainRef.current, { backgroundColor: “#f4f3ef”, color: “#1a2433”, duration: 1.5 }) // Washi White }); }, mainRef); return () => ctx.revert(); }, [isGsapLoaded]); return (
{/* Styles & Fonts */} {/* Global Texture Overlay */}
{/* Navigation (Minimalist) */} {/* SECTION 1: HERO (The Concept) */}
{/* Big Circle Background (Enso-like) */}
{/* Main Title – Vertical */}

{[‘藍’, ‘の’, ‘呼’, ‘吸’].map((char, i) => ( {char} ))}

{/* Subtitle / Description – Vertical */}

時は流れ、色は深まる。

自然の恵みを纏うよろこび。

拝見
{/* SECTION 2: PHILOSOPHY (Text & Image Composition) */}
{/* Text Block (Right on Desktop due to flex-row) */}

一枚の布に込められた

職人の手の温もりと、

四季の移ろい。

風合いは、時間とともに
その表情を変えていく。

{/* Image Block */}
Indigo Fabric
{/* SECTION 3: INDIGO IMMERSION (Dark Background) */}
{/* Image 1 */}
Craftsmanship

手間を惜しまず、
心を込めて。

{/* Image 2 */}
Indigo Dyeing

本物の藍色

科学染料には出せない、
深く、透き通るような青。
それが「ジャパン・ブルー」。

{/* SECTION 4: GALLERY / PRODUCT */}
{[ { title: “手紡ぎ”, sub: “Hand Spinning”, img: “https://images.unsplash.com/photo-1605367396695-128a3f52b828?q=80&w=2670&auto=format&fit=crop” }, { title: “手織り”, sub: “Hand Weaving”, img: “https://images.unsplash.com/photo-1524231757912-21f4fe3a7200?q=80&w=2671&auto=format&fit=crop” }, { title: “手洗い”, sub: “Washing”, img: “https://images.unsplash.com/photo-1620917670397-99636a0d2a4a?q=80&w=2669&auto=format&fit=crop” } ].map((item, i) => (
{item.title}

{item.title}

{item.sub}

))}
{/* FOOTER */}
); }