ขั้น 2 — src/MotionRef.tsx
คัดลอก// src/MotionRef.tsx
import type { CSSProperties } from "react";
import { AbsoluteFill, interpolate, useCurrentFrame, useVideoConfig } from "remotion";
const hold = { extrapolateLeft: "clamp", extrapolateRight: "clamp" } as const;
export const MotionRef = () => {
const frame = useCurrentFrame();
const { durationInFrames, fps } = useVideoConfig();
// ── ใบสั่งการเคลื่อนไหว: หนึ่งบรรทัด = หนึ่งเหตุการณ์ ──
const walk = interpolate(frame, [0, 60], [0, 1], hold); // เดินเข้าหากล้อง
const turn = interpolate(frame, [60, 90], [0, 90], hold); // หันตัว
const arm = interpolate(frame, [95, 125], [10, -150], hold); // ยกแขนขึ้น
const dolly = interpolate(frame, [0, durationInFrames], [1, 1.3]); // กล้องค่อย ๆ เข้า
const step = walk < 1 ? Math.sin((frame / fps) * 9) * 26 : 0; // ขาสลับตอนเดิน
const scale = 0.45 + walk * 0.55;
const face = Math.cos((turn * Math.PI) / 180) * 0.7 + 0.3;
// หมุนชิ้นส่วนรอบปลายบนของมัน (ข้อต่อ) ไม่ใช่รอบกลางชิ้น
const turnOn = (deg: number, at = "0%") => ({
transformOrigin: `50% ${at}`,
transform: `rotate(${deg}deg)`,
});
// ชิ้นส่วนของหุ่น: ซ้าย บน กว้าง สูง — สี่ตัวเลขนี้คือทั้งหมดที่ร่างต้องการ
const limb = (l: number, t: number, w: number, h: number, more: CSSProperties = {}) => ({
position: "absolute" as const,
left: l,
top: t,
width: w,
height: h,
borderRadius: Math.min(w, h) / 2,
backgroundColor: "#d0d0d0",
...more,
});
return (
<AbsoluteFill style={{ backgroundColor: "#6b6b6b" }}>
<AbsoluteFill style={{ transform: `scale(${dolly})` }}>
{/* พื้น — เส้นขอบฟ้าบอกระยะให้โมเดลรู้ว่ากล้องสูงแค่ไหน */}
<div style={{ position: "absolute", inset: "62% 0 0 0", backgroundColor: "#8c8c8c" }} />
<div
style={{
position: "absolute",
left: "50%",
bottom: `${34 - walk * 20}%`,
width: 220,
height: 460,
marginLeft: -110,
transform: `scale(${scale}) scaleX(${face})`,
transformOrigin: "50% 100%",
}}
>
{/* หัว · ลำตัว */}
<div style={limb(74, 0, 72, 72, { backgroundColor: "#e6e6e6" })} />
<div style={limb(62, 84, 96, 210, { backgroundColor: "#d8d8d8" })} />
{/* ขาสองข้างสลับกันตอนเดิน */}
<div style={limb(74, 296, 32, 164, turnOn(step))} />
<div style={limb(114, 296, 32, 164, turnOn(-step))} />
{/* แขนที่ยกขึ้นท้ายคลิป */}
<div style={limb(150, 96, 28, 190, { backgroundColor: "#f0f0f0", ...turnOn(arm, "8%") })} />
</div>
</AbsoluteFill>
</AbsoluteFill>
);
};