chore: stabilize apps/web (lint, build, typecheck fixes)
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 1m27s
Build & Deploy / 🏗️ Build (push) Failing after 1m31s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 1m27s
Build & Deploy / 🏗️ Build (push) Failing after 1m31s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
This commit is contained in:
@@ -1,292 +1,339 @@
|
||||
import React, { useMemo, useEffect, useState } from 'react';
|
||||
import React, { useMemo, useEffect, useState } from "react";
|
||||
import {
|
||||
AbsoluteFill,
|
||||
interpolate,
|
||||
useCurrentFrame,
|
||||
useVideoConfig,
|
||||
Easing,
|
||||
Img,
|
||||
delayRender,
|
||||
continueRender,
|
||||
spring,
|
||||
Audio,
|
||||
staticFile,
|
||||
} from 'remotion';
|
||||
import { MouseCursor } from '../components/MouseCursor';
|
||||
import { ContactForm } from '@/src/components/ContactForm';
|
||||
import { BackgroundGrid } from '@/src/components/Layout';
|
||||
import { initialState } from '@/src/components/ContactForm/constants';
|
||||
AbsoluteFill,
|
||||
interpolate,
|
||||
useCurrentFrame,
|
||||
useVideoConfig,
|
||||
delayRender,
|
||||
continueRender,
|
||||
spring,
|
||||
Img,
|
||||
} from "remotion";
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
import { MouseCursor } from "../components/MouseCursor";
|
||||
import { ContactForm } from "@/src/components/ContactForm";
|
||||
import { BackgroundGrid } from "@/src/components/Layout";
|
||||
import { initialState } from "@/src/components/ContactForm/constants";
|
||||
|
||||
// Brand Assets
|
||||
import IconWhite from '@/src/assets/logo/Icon White Transparent.svg';
|
||||
import IconWhite from "@/src/assets/logo/Icon White Transparent.svg";
|
||||
|
||||
export const ContactFormShowcase: React.FC = () => {
|
||||
const frame = useCurrentFrame();
|
||||
const { width, height, fps } = useVideoConfig();
|
||||
const [handle] = useState(() => delayRender('Initializing Deep Interaction Script'));
|
||||
const frame = useCurrentFrame();
|
||||
const { width, height, fps } = useVideoConfig();
|
||||
const [handle] = useState(() =>
|
||||
delayRender("Initializing Deep Interaction Script"),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined') (window as any).isRemotion = true;
|
||||
const timer = setTimeout(() => continueRender(handle), 500);
|
||||
return () => clearTimeout(timer);
|
||||
}, [handle]);
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") (window as any).isRemotion = true;
|
||||
const timer = setTimeout(() => continueRender(handle), 500);
|
||||
return () => clearTimeout(timer);
|
||||
}, [handle]);
|
||||
|
||||
// ---- TIMELINE CONSTANTS (1500 Frames / 25s) ----
|
||||
const T = useMemo(() => ({
|
||||
ENTER: 0,
|
||||
// Step 0: Type Selection
|
||||
SELECT_WEBSITE: 60,
|
||||
NEXT_0: 100,
|
||||
// ---- TIMELINE CONSTANTS (1500 Frames / 25s) ----
|
||||
const T = useMemo(
|
||||
() => ({
|
||||
ENTER: 0,
|
||||
// Step 0: Type Selection
|
||||
SELECT_WEBSITE: 60,
|
||||
NEXT_0: 100,
|
||||
|
||||
// Step 1: Company Profile
|
||||
COMPANY_TYPE_START: 150,
|
||||
COMPANY_TYPE_END: 250,
|
||||
NEXT_1: 300,
|
||||
// Step 1: Company Profile
|
||||
COMPANY_TYPE_START: 150,
|
||||
COMPANY_TYPE_END: 250,
|
||||
NEXT_1: 300,
|
||||
|
||||
// Step 2: Presence
|
||||
URL_TYPE_START: 350,
|
||||
URL_TYPE_END: 450,
|
||||
NEXT_2: 500,
|
||||
// Step 2: Presence
|
||||
URL_TYPE_START: 350,
|
||||
URL_TYPE_END: 450,
|
||||
NEXT_2: 500,
|
||||
|
||||
// Step 3: Scope & Services (Multi-clicks)
|
||||
SCOPE_CLICK_1: 550,
|
||||
SCOPE_CLICK_2: 600,
|
||||
SCOPE_CLICK_3: 650,
|
||||
NEXT_3: 750,
|
||||
// Step 3: Scope & Services (Multi-clicks)
|
||||
SCOPE_CLICK_1: 550,
|
||||
SCOPE_CLICK_2: 600,
|
||||
SCOPE_CLICK_3: 650,
|
||||
NEXT_3: 750,
|
||||
|
||||
// Step 4: Design Vibe
|
||||
VIBE_SELECT: 850,
|
||||
NEXT_4: 950,
|
||||
// Step 4: Design Vibe
|
||||
VIBE_SELECT: 850,
|
||||
NEXT_4: 950,
|
||||
|
||||
// Step 5: Contact Info
|
||||
NAME_TYPE_START: 1050,
|
||||
NAME_TYPE_END: 1120,
|
||||
EMAIL_TYPE_START: 1150,
|
||||
EMAIL_TYPE_END: 1250,
|
||||
MESSAGE_TYPE_START: 1280,
|
||||
MESSAGE_TYPE_END: 1400,
|
||||
SUBMIT: 1450,
|
||||
// Step 5: Contact Info
|
||||
NAME_TYPE_START: 1050,
|
||||
NAME_TYPE_END: 1120,
|
||||
EMAIL_TYPE_START: 1150,
|
||||
EMAIL_TYPE_END: 1250,
|
||||
MESSAGE_TYPE_START: 1280,
|
||||
MESSAGE_TYPE_END: 1400,
|
||||
SUBMIT: 1450,
|
||||
|
||||
EXIT: 1500,
|
||||
}), []);
|
||||
EXIT: 1500,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
// ---- FORM STATE LOGIC ----
|
||||
const formState = useMemo(() => {
|
||||
const state = { ...initialState };
|
||||
// ---- FORM STATE LOGIC ----
|
||||
const formState = useMemo(() => {
|
||||
const state = { ...initialState };
|
||||
|
||||
// Step 0: Fixed to website per request
|
||||
state.projectType = 'website';
|
||||
// Step 0: Fixed to website per request
|
||||
state.projectType = "website";
|
||||
|
||||
// Step 1: Company
|
||||
if (frame > T.COMPANY_TYPE_START) {
|
||||
const text = "Mintel Studios";
|
||||
const progress = interpolate(frame, [T.COMPANY_TYPE_START, T.COMPANY_TYPE_END], [0, text.length], { extrapolateRight: 'clamp' });
|
||||
state.companyName = text.substring(0, Math.round(progress));
|
||||
}
|
||||
// Step 1: Company
|
||||
if (frame > T.COMPANY_TYPE_START) {
|
||||
const text = "Mintel Studios";
|
||||
const progress = interpolate(
|
||||
frame,
|
||||
[T.COMPANY_TYPE_START, T.COMPANY_TYPE_END],
|
||||
[0, text.length],
|
||||
{ extrapolateRight: "clamp" },
|
||||
);
|
||||
state.companyName = text.substring(0, Math.round(progress));
|
||||
}
|
||||
|
||||
// Step 2: URL
|
||||
if (frame > T.URL_TYPE_START) {
|
||||
const text = "mintel.me";
|
||||
const progress = interpolate(frame, [T.URL_TYPE_START, T.URL_TYPE_END], [0, text.length], { extrapolateRight: 'clamp' });
|
||||
state.existingWebsite = text.substring(0, Math.round(progress));
|
||||
}
|
||||
// Step 2: URL
|
||||
if (frame > T.URL_TYPE_START) {
|
||||
const text = "mintel.me";
|
||||
const progress = interpolate(
|
||||
frame,
|
||||
[T.URL_TYPE_START, T.URL_TYPE_END],
|
||||
[0, text.length],
|
||||
{ extrapolateRight: "clamp" },
|
||||
);
|
||||
state.existingWebsite = text.substring(0, Math.round(progress));
|
||||
}
|
||||
|
||||
// Step 3: Selections
|
||||
if (frame > T.SCOPE_CLICK_1) state.selectedPages = ['Home', 'About'];
|
||||
if (frame > T.SCOPE_CLICK_2) state.selectedPages = ['Home', 'About', 'Services'];
|
||||
if (frame > T.SCOPE_CLICK_3) state.features = ['blog_news'];
|
||||
// Step 3: Selections
|
||||
if (frame > T.SCOPE_CLICK_1) state.selectedPages = ["Home", "About"];
|
||||
if (frame > T.SCOPE_CLICK_2)
|
||||
state.selectedPages = ["Home", "About", "Services"];
|
||||
if (frame > T.SCOPE_CLICK_3) state.features = ["blog_news"];
|
||||
|
||||
// Step 4: Design
|
||||
if (frame > T.VIBE_SELECT) state.designVibe = 'tech';
|
||||
// Step 4: Design
|
||||
if (frame > T.VIBE_SELECT) state.designVibe = "tech";
|
||||
|
||||
// Step 5: Contact
|
||||
if (frame > T.NAME_TYPE_START) {
|
||||
const text = "Marc Mintel";
|
||||
const progress = interpolate(frame, [T.NAME_TYPE_START, T.NAME_TYPE_END], [0, text.length], { extrapolateRight: 'clamp' });
|
||||
state.name = text.substring(0, Math.round(progress));
|
||||
}
|
||||
if (frame > T.EMAIL_TYPE_START) {
|
||||
const text = "marc@mintel.me";
|
||||
const progress = interpolate(frame, [T.EMAIL_TYPE_START, T.EMAIL_TYPE_END], [0, text.length], { extrapolateRight: 'clamp' });
|
||||
state.email = text.substring(0, Math.round(progress));
|
||||
}
|
||||
if (frame > T.MESSAGE_TYPE_START) {
|
||||
const text = "Hi folks! Let's build something cinematic and smooth.";
|
||||
const progress = interpolate(frame, [T.MESSAGE_TYPE_START, T.MESSAGE_TYPE_END], [0, text.length], { extrapolateRight: 'clamp' });
|
||||
state.message = text.substring(0, Math.round(progress));
|
||||
}
|
||||
// Step 5: Contact
|
||||
if (frame > T.NAME_TYPE_START) {
|
||||
const text = "Marc Mintel";
|
||||
const progress = interpolate(
|
||||
frame,
|
||||
[T.NAME_TYPE_START, T.NAME_TYPE_END],
|
||||
[0, text.length],
|
||||
{ extrapolateRight: "clamp" },
|
||||
);
|
||||
state.name = text.substring(0, Math.round(progress));
|
||||
}
|
||||
if (frame > T.EMAIL_TYPE_START) {
|
||||
const text = "marc@mintel.me";
|
||||
const progress = interpolate(
|
||||
frame,
|
||||
[T.EMAIL_TYPE_START, T.EMAIL_TYPE_END],
|
||||
[0, text.length],
|
||||
{ extrapolateRight: "clamp" },
|
||||
);
|
||||
state.email = text.substring(0, Math.round(progress));
|
||||
}
|
||||
if (frame > T.MESSAGE_TYPE_START) {
|
||||
const text = "Hi folks! Let's build something cinematic and smooth.";
|
||||
const progress = interpolate(
|
||||
frame,
|
||||
[T.MESSAGE_TYPE_START, T.MESSAGE_TYPE_END],
|
||||
[0, text.length],
|
||||
{ extrapolateRight: "clamp" },
|
||||
);
|
||||
state.message = text.substring(0, Math.round(progress));
|
||||
}
|
||||
|
||||
return state;
|
||||
}, [frame, T]);
|
||||
return state;
|
||||
}, [frame, T]);
|
||||
|
||||
// ---- STEP NAVIGATION ----
|
||||
const stepIndex = useMemo(() => {
|
||||
if (frame < T.NEXT_0) return 0;
|
||||
if (frame < T.NEXT_1) return 1;
|
||||
if (frame < T.NEXT_2) return 2;
|
||||
if (frame < T.NEXT_3) return 3;
|
||||
if (frame < T.NEXT_4) return 6; // Mapping depends on actual component order, let's assume standard sequence
|
||||
if (frame < T.SUBMIT) return 12; // Final Contact step
|
||||
return 13; // Success
|
||||
}, [frame, T]);
|
||||
// ---- STEP NAVIGATION ----
|
||||
const stepIndex = useMemo(() => {
|
||||
if (frame < T.NEXT_0) return 0;
|
||||
if (frame < T.NEXT_1) return 1;
|
||||
if (frame < T.NEXT_2) return 2;
|
||||
if (frame < T.NEXT_3) return 3;
|
||||
if (frame < T.NEXT_4) return 6; // Mapping depends on actual component order, let's assume standard sequence
|
||||
if (frame < T.SUBMIT) return 12; // Final Contact step
|
||||
return 13; // Success
|
||||
}, [frame, T]);
|
||||
|
||||
// ---- CAMERA ANCHORS ----
|
||||
const anchors = useMemo(() => ({
|
||||
'overview': { z: 0.85, x: 0, y: 0 },
|
||||
'type': { z: 1.15, x: 250, y: 150 },
|
||||
'company': { z: 1.3, x: 100, y: 50 },
|
||||
'presence': { z: 1.3, x: 100, y: -50 },
|
||||
'scope': { z: 1.1, x: -100, y: 0 },
|
||||
'design': { z: 1.15, x: 150, y: 100 },
|
||||
'contact': { z: 1.25, x: 0, y: 400 },
|
||||
'success': { z: 0.9, x: 0, y: 0 },
|
||||
}), []);
|
||||
// ---- CAMERA ANCHORS ----
|
||||
const anchors = useMemo(
|
||||
() => ({
|
||||
overview: { z: 0.85, x: 0, y: 0 },
|
||||
type: { z: 1.15, x: 250, y: 150 },
|
||||
company: { z: 1.3, x: 100, y: 50 },
|
||||
presence: { z: 1.3, x: 100, y: -50 },
|
||||
scope: { z: 1.1, x: -100, y: 0 },
|
||||
design: { z: 1.15, x: 150, y: 100 },
|
||||
contact: { z: 1.25, x: 0, y: 400 },
|
||||
success: { z: 0.9, x: 0, y: 0 },
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const activeAnchor = useMemo(() => {
|
||||
if (frame < T.SELECT_WEBSITE) return anchors.overview;
|
||||
if (frame < T.NEXT_0) return anchors.type;
|
||||
if (frame < T.NEXT_1) return anchors.company;
|
||||
if (frame < T.NEXT_2) return anchors.presence;
|
||||
if (frame < T.NEXT_3) return anchors.scope;
|
||||
if (frame < T.NEXT_4) return anchors.design;
|
||||
if (frame < T.SUBMIT) return anchors.contact;
|
||||
return anchors.success;
|
||||
}, [frame, anchors, T]);
|
||||
const activeAnchor = useMemo(() => {
|
||||
if (frame < T.SELECT_WEBSITE) return anchors.overview;
|
||||
if (frame < T.NEXT_0) return anchors.type;
|
||||
if (frame < T.NEXT_1) return anchors.company;
|
||||
if (frame < T.NEXT_2) return anchors.presence;
|
||||
if (frame < T.NEXT_3) return anchors.scope;
|
||||
if (frame < T.NEXT_4) return anchors.design;
|
||||
if (frame < T.SUBMIT) return anchors.contact;
|
||||
return anchors.success;
|
||||
}, [frame, anchors, T]);
|
||||
|
||||
const camera = useMemo(() => {
|
||||
// Continuous organic spring follow
|
||||
const s = spring({
|
||||
frame,
|
||||
fps,
|
||||
config: { stiffness: 45, damping: 20 },
|
||||
});
|
||||
const _camera = useMemo(() => {
|
||||
// Continuous organic spring follow
|
||||
const _s = spring({
|
||||
frame,
|
||||
fps,
|
||||
config: { stiffness: 45, damping: 20 },
|
||||
});
|
||||
|
||||
// This is a simplified lerp since spring() is stateless per frame in remotion,
|
||||
// for true chasing we'd need a custom reducer or just accept the "settle" behavior.
|
||||
// Actually, we'll use interpolate for predictable transitions between keyframes.
|
||||
return activeAnchor;
|
||||
}, [frame, activeAnchor, fps]);
|
||||
return activeAnchor;
|
||||
}, [frame, activeAnchor, fps]);
|
||||
|
||||
// Simple smooth camera interpolation for the actual movement
|
||||
const smoothCamera = useMemo(() => {
|
||||
// To avoid jumpiness when anchor switches, we could use a custom useSpring alternative,
|
||||
// but for now let's just use the active anchor and let the frame-based spring handle the property drift if planned.
|
||||
// Actually, let's just use Interpolation for reliability.
|
||||
return activeAnchor;
|
||||
}, [activeAnchor]);
|
||||
// Simple smooth camera interpolation for the actual movement
|
||||
const smoothCamera = useMemo(() => {
|
||||
return activeAnchor;
|
||||
}, [activeAnchor]);
|
||||
|
||||
// ---- MOUSE PATH ----
|
||||
const mouse = useMemo(() => {
|
||||
const targets = {
|
||||
off: { x: width * 1.2, y: height * 1.2 },
|
||||
type_website: { x: 200, y: 50 },
|
||||
btn_next: { x: 450, y: 450 },
|
||||
company_input: { x: 0, y: 0 },
|
||||
url_input: { x: 0, y: -50 },
|
||||
scope_1: { x: -300, y: -100 },
|
||||
scope_2: { x: -300, y: 0 },
|
||||
scope_3: { x: 0, y: 200 },
|
||||
vibe_tech: { x: 250, y: 100 },
|
||||
contact_name: { x: -200, y: 200 },
|
||||
contact_email: { x: 200, y: 200 },
|
||||
contact_msg: { x: 0, y: 400 },
|
||||
btn_submit: { x: 400, y: 550 },
|
||||
};
|
||||
// ---- MOUSE PATH ----
|
||||
const mouse = useMemo(() => {
|
||||
const targets = {
|
||||
off: { x: width * 1.2, y: height * 1.2 },
|
||||
type_website: { x: 200, y: 50 },
|
||||
btn_next: { x: 450, y: 450 },
|
||||
company_input: { x: 0, y: 0 },
|
||||
url_input: { x: 0, y: -50 },
|
||||
scope_1: { x: -300, y: -100 },
|
||||
scope_2: { x: -300, y: 0 },
|
||||
scope_3: { x: 0, y: 200 },
|
||||
vibe_tech: { x: 250, y: 100 },
|
||||
contact_name: { x: -200, y: 200 },
|
||||
contact_email: { x: 200, y: 200 },
|
||||
contact_msg: { x: 0, y: 400 },
|
||||
btn_submit: { x: 400, y: 550 },
|
||||
};
|
||||
|
||||
const path = [
|
||||
{ f: 0, ...targets.off },
|
||||
{ f: T.SELECT_WEBSITE, ...targets.type_website },
|
||||
{ f: T.NEXT_0, ...targets.btn_next },
|
||||
{ f: T.COMPANY_TYPE_START, ...targets.company_input },
|
||||
{ f: T.NEXT_1, ...targets.btn_next },
|
||||
{ f: T.URL_TYPE_START, ...targets.url_input },
|
||||
{ f: T.NEXT_2, ...targets.btn_next },
|
||||
{ f: T.SCOPE_CLICK_1, ...targets.scope_1 },
|
||||
{ f: T.SCOPE_CLICK_2, ...targets.scope_2 },
|
||||
{ f: T.SCOPE_CLICK_3, ...targets.scope_3 },
|
||||
{ f: T.NEXT_3, ...targets.btn_next },
|
||||
{ f: T.VIBE_SELECT, ...targets.vibe_tech },
|
||||
{ f: T.NEXT_4, ...targets.btn_next },
|
||||
{ f: T.NAME_TYPE_START, ...targets.contact_name },
|
||||
{ f: T.EMAIL_TYPE_START, ...targets.contact_email },
|
||||
{ f: T.MESSAGE_TYPE_START, ...targets.contact_msg },
|
||||
{ f: T.SUBMIT, ...targets.btn_submit },
|
||||
{ f: T.EXIT, ...targets.off },
|
||||
];
|
||||
const path = [
|
||||
{ f: 0, ...targets.off },
|
||||
{ f: T.SELECT_WEBSITE, ...targets.type_website },
|
||||
{ f: T.NEXT_0, ...targets.btn_next },
|
||||
{ f: T.COMPANY_TYPE_START, ...targets.company_input },
|
||||
{ f: T.NEXT_1, ...targets.btn_next },
|
||||
{ f: T.URL_TYPE_START, ...targets.url_input },
|
||||
{ f: T.NEXT_2, ...targets.btn_next },
|
||||
{ f: T.SCOPE_CLICK_1, ...targets.scope_1 },
|
||||
{ f: T.SCOPE_CLICK_2, ...targets.scope_2 },
|
||||
{ f: T.SCOPE_CLICK_3, ...targets.scope_3 },
|
||||
{ f: T.NEXT_3, ...targets.btn_next },
|
||||
{ f: T.VIBE_SELECT, ...targets.vibe_tech },
|
||||
{ f: T.NEXT_4, ...targets.btn_next },
|
||||
{ f: T.NAME_TYPE_START, ...targets.contact_name },
|
||||
{ f: T.EMAIL_TYPE_START, ...targets.contact_email },
|
||||
{ f: T.MESSAGE_TYPE_START, ...targets.contact_msg },
|
||||
{ f: T.SUBMIT, ...targets.btn_submit },
|
||||
{ f: T.EXIT, ...targets.off },
|
||||
];
|
||||
|
||||
let idx = 0;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
if (frame >= path[i].f) idx = i;
|
||||
}
|
||||
let idx = 0;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
if (frame >= path[i].f) idx = i;
|
||||
}
|
||||
|
||||
const p1 = path[idx];
|
||||
const p2 = path[idx + 1] || p1;
|
||||
const p1 = path[idx];
|
||||
const p2 = path[idx + 1] || p1;
|
||||
|
||||
const s = spring({
|
||||
frame: frame - p1.f,
|
||||
fps,
|
||||
config: { stiffness: 60, damping: 25 },
|
||||
});
|
||||
const s = spring({
|
||||
frame: frame - p1.f,
|
||||
fps,
|
||||
config: { stiffness: 60, damping: 25 },
|
||||
});
|
||||
|
||||
return {
|
||||
x: interpolate(s, [0, 1], [p1.x, p2.x]),
|
||||
y: interpolate(s, [0, 1], [p1.y, p2.y]),
|
||||
};
|
||||
}, [frame, width, height, fps, T]);
|
||||
return {
|
||||
x: interpolate(s, [0, 1], [p1.x, p2.x]),
|
||||
y: interpolate(s, [0, 1], [p1.y, p2.y]),
|
||||
};
|
||||
}, [frame, width, height, fps, T]);
|
||||
|
||||
const isClicking = useMemo(() => {
|
||||
const clicks = [
|
||||
T.SELECT_WEBSITE, T.NEXT_0, T.NEXT_1, T.NEXT_2,
|
||||
T.SCOPE_CLICK_1, T.SCOPE_CLICK_2, T.SCOPE_CLICK_3, T.NEXT_3,
|
||||
T.VIBE_SELECT, T.NEXT_4, T.SUBMIT
|
||||
];
|
||||
return clicks.some(c => frame >= c && frame < c + 8);
|
||||
}, [frame, T]);
|
||||
const isClicking = useMemo(() => {
|
||||
const clicks = [
|
||||
T.SELECT_WEBSITE,
|
||||
T.NEXT_0,
|
||||
T.NEXT_1,
|
||||
T.NEXT_2,
|
||||
T.SCOPE_CLICK_1,
|
||||
T.SCOPE_CLICK_2,
|
||||
T.SCOPE_CLICK_3,
|
||||
T.NEXT_3,
|
||||
T.VIBE_SELECT,
|
||||
T.NEXT_4,
|
||||
T.SUBMIT,
|
||||
];
|
||||
return clicks.some((c) => frame >= c && frame < c + 8);
|
||||
}, [frame, T]);
|
||||
|
||||
return (
|
||||
<AbsoluteFill className="bg-white">
|
||||
<BackgroundGrid />
|
||||
return (
|
||||
<AbsoluteFill className="bg-white">
|
||||
<BackgroundGrid />
|
||||
|
||||
<style>{`
|
||||
<style>{`
|
||||
* { transition: none !important; animation: none !important; -webkit-font-smoothing: antialiased; }
|
||||
.focus-layer { transform-style: preserve-3d; backface-visibility: hidden; will-change: transform; }
|
||||
`}</style>
|
||||
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center focus-layer"
|
||||
style={{
|
||||
transform: `translate3d(${Math.round(smoothCamera.x)}px, ${Math.round(smoothCamera.y)}px, 0) scale(${smoothCamera.z.toFixed(4)})`,
|
||||
}}
|
||||
>
|
||||
<div style={{ transform: 'scale(0.85) translate3d(0,0,0)', width: '1200px' }} className="focus-layer">
|
||||
<ContactForm initialStepIndex={stepIndex} initialState={formState} />
|
||||
</div>
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center focus-layer"
|
||||
style={{
|
||||
transform: `translate3d(${Math.round(smoothCamera.x)}px, ${Math.round(smoothCamera.y)}px, 0) scale(${smoothCamera.z.toFixed(4)})`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
transform: "scale(0.85) translate3d(0,0,0)",
|
||||
width: "1200px",
|
||||
}}
|
||||
className="focus-layer"
|
||||
>
|
||||
<ContactForm initialStepIndex={stepIndex} initialState={formState} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '50%', left: '50%',
|
||||
transform: `translate3d(${Math.round(mouse.x)}px, ${Math.round(mouse.y)}px, 0)`,
|
||||
zIndex: 1000,
|
||||
marginTop: -12, marginLeft: -6,
|
||||
}}
|
||||
className="focus-layer"
|
||||
>
|
||||
<MouseCursor isClicking={isClicking} x={0} y={0} />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: `translate3d(${Math.round(mouse.x)}px, ${Math.round(mouse.y)}px, 0)`,
|
||||
zIndex: 1000,
|
||||
marginTop: -12,
|
||||
marginLeft: -6,
|
||||
}}
|
||||
className="focus-layer"
|
||||
>
|
||||
<MouseCursor isClicking={isClicking} x={0} y={0} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Logo HUD */}
|
||||
<div className="absolute top-28 left-28 z-50 focus-layer">
|
||||
<div className="w-40 h-40 bg-black rounded-[3.5rem] flex items-center justify-center shadow-2xl">
|
||||
<Img src={IconWhite} className="w-24 h-24" />
|
||||
</div>
|
||||
</div>
|
||||
{/* Logo HUD */}
|
||||
<div className="absolute top-28 left-28 z-50 focus-layer">
|
||||
<div className="w-40 h-40 bg-black rounded-[3.5rem] flex items-center justify-center shadow-2xl">
|
||||
<Img src={IconWhite} className="w-24 h-24" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AbsoluteFill
|
||||
className="bg-white pointer-events-none"
|
||||
style={{ opacity: interpolate(frame, [0, 15], [1, 0], { extrapolateRight: 'clamp' }) }}
|
||||
/>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
<AbsoluteFill
|
||||
className="bg-white pointer-events-none"
|
||||
style={{
|
||||
opacity: interpolate(frame, [0, 15], [1, 0], {
|
||||
extrapolateRight: "clamp",
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user