Remotion — إنشاء فيديوهات باستخدام React و TypeScript (دليل 2026)

فيديوهات، لكن على طريقة React. Remotion يمكّنك من إنشاء رسوم متحركة ومقدمات وتصورات بيانات وإنتاجات فيديو كاملة — بالكامل في TypeScript. بدون After Effects. بدون محررات خط زمني. فقط كود.
ما ستتعلمه
بنهاية هذا الدليل، ستتمكن من:
- فهم بنية Remotion ومفاهيمه الأساسية
- إعداد مشروع Remotion من الصفر باستخدام TypeScript
- بناء تركيبات متحركة باستخدام مكونات React
- التعامل مع النوابض والاستيفاء والصوت
- إنشاء فيديو مبني على البيانات يعرض محتوى ديناميكي
- تصدير الفيديو كملف MP4
- نشر خط أنابيب للتصيير الآلي للفيديوهات
المتطلبات المسبقة
قبل البدء، تأكد من توفر:
- Node.js 20+ مثبت (
node --version) - معرفة بـ React و TypeScript (hooks، مكونات، JSX)
- محرر أكواد — يُنصح بـ VS Code
- ffmpeg مثبت للتصيير (
brew install ffmpegعلى macOS) - فهم أساسي لتحريكات CSS والتحويلات
لماذا Remotion؟
أدوات تحرير الفيديو التقليدية ممتازة للمشاريع الفردية. لكن ماذا لو احتجت إلى:
- إنشاء مئات الفيديوهات المخصصة لحملات تسويقية
- بناء تصورات بيانية تتحدث تلقائياً
- تصميم مقدمات وخواتم متسقة عبر كل محتواك
- إنتاج مقاطع وسائل التواصل على نطاق واسع مع نصوص ديناميكية
يحل Remotion هذه المشكلة بمعاملة إطارات الفيديو كمكونات React. كل إطار هو دالة في الزمن — تكتب JSX، ويحوّله Remotion إطاراً تلو الآخر إلى ملف فيديو حقيقي.
المفاهيم الأساسية
| المفهوم | الوصف |
|---|---|
| Composition | تعريف فيديو بالعرض والارتفاع ومعدل الإطارات والمدة |
| Sequence | غلاف لتأخير ظهور المكون في الخط الزمني |
| useCurrentFrame() | خطاف يُرجع رقم الإطار الحالي |
| useVideoConfig() | خطاف يُرجع بيانات الفيديو الوصفية |
| interpolate() | يربط نطاق إطارات بنطاق قيم خرج |
| spring() | منحنى تحريك فيزيائي لحركة طبيعية |
الخطوة 1: إعداد المشروع
أنشئ مشروع Remotion جديد باستخدام القالب الرسمي:
npx create-video@latest my-video --template blank
cd my-videoهذا ينشئ مشروع TypeScript مُعَدّ بالكامل. لنلقِ نظرة على الهيكل:
my-video/
├── src/
│ ├── Root.tsx # نقطة الدخول — تسجيل التركيبات
│ ├── Composition.tsx # مكون الفيديو الأول
│ └── index.ts # مدخل Remotion
├── remotion.config.ts # إعدادات Remotion
├── package.json
└── tsconfig.json
ثبّت التبعيات وشغّل خادم المعاينة:
npm install
npm startهذا يفتح Remotion Studio على http://localhost:3000 — بيئة معاينة في المتصفح تتيح لك التنقل عبر الخط الزمني في الوقت الفعلي.
الخطوة 2: فهم التركيبة
افتح src/Root.tsx. هنا تُسجَّل تركيبات الفيديو:
import { Composition } from "remotion";
import { MyComposition } from "./Composition";
export const RemotionRoot: React.FC = () => {
return (
<>
<Composition
id="MyVideo"
component={MyComposition}
durationInFrames={150}
fps={30}
width={1920}
height={1080}
/>
</>
);
};الخصائص الرئيسية:
- id — معرّف فريد يُستخدم عند التصيير
- durationInFrames — إجمالي الإطارات (150 إطار عند 30fps = 5 ثوانٍ)
- fps — إطارات في الثانية (30 قياسي، 60 لحركة سلسة)
- width/height — دقة الفيديو بالبكسل
الخطوة 3: بناء أول تحريك
استبدل src/Composition.tsx ببطاقة عنوان متحركة:
import { useCurrentFrame, useVideoConfig, interpolate, spring } from "remotion";
import React from "react";
export const MyComposition: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// تحريك نابضي للعنوان
const titleScale = spring({
frame,
fps,
config: {
damping: 12,
stiffness: 200,
mass: 0.5,
},
});
// إظهار العنوان الفرعي بعد 20 إطار
const subtitleOpacity = interpolate(frame, [20, 40], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// تحريك العنوان الفرعي للأعلى
const subtitleY = interpolate(frame, [20, 40], [30, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<div
style={{
flex: 1,
background: "linear-gradient(135deg, #0f0c29, #302b63, #24243e)",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
fontFamily: "Inter, sans-serif",
}}
>
<h1
style={{
fontSize: 80,
color: "white",
fontWeight: 900,
transform: `scale(${titleScale})`,
textAlign: "center",
}}
>
مرحباً، Remotion
</h1>
<p
style={{
fontSize: 32,
color: "#a8a8ff",
opacity: subtitleOpacity,
transform: `translateY(${subtitleY}px)`,
marginTop: 20,
}}
>
فيديوهات مدعومة بـ React
</p>
</div>
);
};احفظ الملف وتحقق من Remotion Studio — سترى تحريكاً سلساً حيث يظهر العنوان بتأثير نابضي، يتبعه عنوان فرعي يتلاشى ويتحرك للأعلى.
كيف يعمل
useCurrentFrame()يُرجع الإطار الحالي (0، 1، 2، ... 149)spring()ينشئ منحنى فيزيائي يبدأ من 0 ويستقر عند 1interpolate()يربط نطاقات الإطارات بقيم الخرج — الإطار 20-40 يربط الشفافية من 0 إلى 1extrapolateLeft/Right: "clamp"يمنع القيم من تجاوز 0 أو 1
الخطوة 4: استخدام التسلسلات للتوقيت
تتيح لك التسلسلات تركيب أقسام متحركة متعددة بتوقيت دقيق:
import {
useCurrentFrame,
useVideoConfig,
interpolate,
spring,
Sequence,
AbsoluteFill,
} from "remotion";
import React from "react";
const Title: React.FC<{ text: string }> = ({ text }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const scale = spring({ frame, fps, config: { damping: 12 } });
const opacity = interpolate(frame, [0, 15], [0, 1], {
extrapolateRight: "clamp",
});
return (
<AbsoluteFill
style={{
justifyContent: "center",
alignItems: "center",
}}
>
<h1
style={{
fontSize: 72,
color: "white",
transform: `scale(${scale})`,
opacity,
fontWeight: 800,
}}
>
{text}
</h1>
</AbsoluteFill>
);
};
const FadeOut: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 10], [1, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return <AbsoluteFill style={{ opacity }}>{children}</AbsoluteFill>;
};
export const MyComposition: React.FC = () => {
return (
<AbsoluteFill
style={{
background: "linear-gradient(135deg, #0f0c29, #302b63, #24243e)",
}}
>
{/* المشهد 1: المقدمة (الإطارات 0-59) */}
<Sequence from={0} durationInFrames={60}>
<Title text="مرحباً" />
</Sequence>
{/* المشهد 2: الرسالة الرئيسية (الإطارات 45-119) */}
<Sequence from={45} durationInFrames={75}>
<Title text="ابنِ فيديوهات بالكود" />
</Sequence>
{/* المشهد 3: الخاتمة مع تلاشي (الإطارات 110-150) */}
<Sequence from={110} durationInFrames={40}>
<FadeOut>
<Title text="!هيّا بنا" />
</FadeOut>
</Sequence>
</AbsoluteFill>
);
};لاحظ كيف يُعيد Sequence تعيين useCurrentFrame() إلى 0 داخل أبنائه. هذا يعني أن كل مكون يبدأ تحريكه من الإطار 0، بغض النظر عن موعد ظهوره في الخط الزمني.
الخطوة 5: إضافة الصوت
يدعم Remotion الصوت مع مزامنة دقيقة على مستوى الإطار:
import { Audio, Sequence, staticFile } from "remotion";
// ضع ملف الصوت في مجلد /public
// مثال: public/music.mp3
export const MyComposition: React.FC = () => {
return (
<AbsoluteFill style={{ background: "#0f0c29" }}>
{/* موسيقى خلفية تبدأ من الإطار 0 */}
<Audio src={staticFile("music.mp3")} volume={0.3} />
{/* مؤثر صوتي عند الإطار 30 */}
<Sequence from={30}>
<Audio src={staticFile("whoosh.mp3")} volume={0.8} />
</Sequence>
{/* المحتوى المرئي */}
<Sequence from={0}>
<Title text="!مع الصوت" />
</Sequence>
</AbsoluteFill>
);
};يمكنك أيضاً التحكم في مستوى الصوت ديناميكياً:
<Audio
src={staticFile("music.mp3")}
volume={(f) =>
interpolate(f, [0, 30, 120, 150], [0, 0.5, 0.5, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
})
}
/>الخطوة 6: فيديوهات مبنية على البيانات
هنا يتألق Remotion حقاً. لنبنِ فيديو يعرض بيانات ديناميكية — تخيّل إنشاء فيديوهات إحصائيات أسبوعية تلقائياً:
import React from "react";
import {
useCurrentFrame,
useVideoConfig,
interpolate,
spring,
Sequence,
AbsoluteFill,
} from "remotion";
interface StatsProps {
title: string;
stats: Array<{ label: string; value: number; color: string }>;
}
const AnimatedBar: React.FC<{
label: string;
value: number;
maxValue: number;
color: string;
delay: number;
}> = ({ label, value, maxValue, color, delay }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const progress = spring({
frame: frame - delay,
fps,
config: { damping: 15, stiffness: 100 },
});
const width = interpolate(progress, [0, 1], [0, (value / maxValue) * 100]);
const labelOpacity = interpolate(frame, [delay, delay + 10], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<div style={{ marginBottom: 24, opacity: labelOpacity }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
marginBottom: 8,
fontSize: 24,
color: "white",
fontFamily: "Inter, sans-serif",
}}
>
<span>{label}</span>
<span style={{ fontWeight: 700 }}>
{Math.round(value * progress)}
</span>
</div>
<div
style={{
height: 32,
background: "rgba(255,255,255,0.1)",
borderRadius: 16,
overflow: "hidden",
}}
>
<div
style={{
height: "100%",
width: `${width}%`,
background: `linear-gradient(90deg, ${color}, ${color}aa)`,
borderRadius: 16,
}}
/>
</div>
</div>
);
};
export const StatsVideo: React.FC<StatsProps> = ({ title, stats }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const titleScale = spring({ frame, fps, config: { damping: 12 } });
const maxValue = Math.max(...stats.map((s) => s.value));
return (
<AbsoluteFill
style={{
background: "linear-gradient(180deg, #1a1a2e, #16213e)",
padding: 80,
justifyContent: "center",
}}
>
<h1
style={{
fontSize: 56,
color: "white",
fontWeight: 900,
marginBottom: 60,
transform: `scale(${titleScale})`,
fontFamily: "Inter, sans-serif",
}}
>
{title}
</h1>
{stats.map((stat, i) => (
<AnimatedBar
key={stat.label}
label={stat.label}
value={stat.value}
maxValue={maxValue}
color={stat.color}
delay={i * 15 + 10}
/>
))}
</AbsoluteFill>
);
};سجّل التركيبة مع خصائص افتراضية في Root.tsx:
<Composition
id="WeeklyStats"
component={StatsVideo}
durationInFrames={180}
fps={30}
width={1080}
height={1080}
defaultProps={{
title: "أداء هذا الأسبوع",
stats: [
{ label: "مستخدمون جدد", value: 1247, color: "#6366f1" },
{ label: "مشاهدات الصفحة", value: 8432, color: "#22d3ee" },
{ label: "التحويلات", value: 342, color: "#f43f5e" },
{ label: "الإيرادات ($)", value: 5890, color: "#10b981" },
],
}}
/>الآن لديك مكون فيديو إحصائيات قابل لإعادة الاستخدام. غيّر الخصائص وستحصل على فيديو مختلف تماماً.
الخطوة 7: تحميل الخطوط المخصصة
استخدم @remotion/google-fonts أو حمّل الخطوط يدوياً:
npm install @remotion/google-fontsimport { loadFont } from "@remotion/google-fonts/Inter";
const { fontFamily } = loadFont();
// استخدمه في مكوناتك
<h1 style={{ fontFamily }}>مُنسّق بـ Inter</h1>للخطوط المحلية، ضعها في مجلد public/ واستخدم staticFile():
import { staticFile } from "remotion";
const fontFace = new FontFace("MyFont", `url(${staticFile("fonts/MyFont.woff2")})`);
React.useEffect(() => {
document.fonts.add(fontFace);
fontFace.load();
}, []);الخطوة 8: تصيير الفيديو
التصيير عبر سطر الأوامر
صدّر الفيديو كملف MP4:
npx remotion render MyVideo out/my-video.mp4خيارات التخصيص:
npx remotion render MyVideo out/my-video.mp4 \
--codec h264 \
--quality 80 \
--concurrency 4| العلامة | الوصف |
|---|---|
--codec | h264 (MP4)، vp8/vp9 (WebM)، prores (MOV) |
--quality | 0-100، جودة JPEG للإطارات |
--concurrency | عدد خيوط التصيير المتوازية |
--props | سلسلة JSON لتجاوز الخصائص الافتراضية |
التصيير مع خصائص مخصصة
npx remotion render WeeklyStats out/stats-week-14.mp4 \
--props='{"title":"إحصائيات الأسبوع 14","stats":[{"label":"المستخدمون","value":2000,"color":"#6366f1"}]}'الخطوة 9: التصيير عبر واجهة Node.js البرمجية
للأنابيب الآلية، استخدم الواجهة البرمجية:
import { bundle } from "@remotion/bundler";
import { renderMedia, selectComposition } from "@remotion/renderer";
import path from "path";
async function renderVideo() {
const bundleLocation = await bundle({
entryPoint: path.resolve("./src/index.ts"),
});
const composition = await selectComposition({
serveUrl: bundleLocation,
id: "WeeklyStats",
inputProps: {
title: "تقرير أبريل 2026",
stats: [
{ label: "الإيرادات", value: 12500, color: "#10b981" },
{ label: "المستخدمون", value: 3400, color: "#6366f1" },
],
},
});
await renderMedia({
composition,
serveUrl: bundleLocation,
codec: "h264",
outputLocation: "out/april-report.mp4",
onProgress: ({ progress }) => {
console.log(`التصيير: ${Math.round(progress * 100)}%`);
},
});
console.log("!تم تصيير الفيديو بنجاح");
}
renderVideo();الخطوة 10: تقنيات متقدمة
دوال التسهيل
يوفر Remotion منحنيات تسهيل مدمجة:
import { Easing, interpolate } from "remotion";
const value = interpolate(frame, [0, 30], [0, 1], {
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
extrapolateRight: "clamp",
});التحريكات المتتابعة
أنشئ تأثيرات دخول متتابعة بإزاحة التأخيرات:
const items = ["React", "TypeScript", "Remotion"];
return (
<>
{items.map((item, i) => {
const delay = i * 10;
const opacity = interpolate(frame, [delay, delay + 15], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const x = interpolate(frame, [delay, delay + 15], [-50, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<p
key={item}
style={{
opacity,
transform: `translateX(${x}px)`,
fontSize: 36,
color: "white",
}}
>
{item}
</p>
);
})}
</>
);استخدام الصور والفيديوهات
يمكن لـ Remotion تركيب الصور وتضمين فيديوهات أخرى:
import { Img, Video, staticFile } from "remotion";
// صورة ثابتة
<Img src={staticFile("logo.png")} style={{ width: 200 }} />
// تضمين فيديو
<Video src={staticFile("background.mp4")} />استكشاف الأخطاء وإصلاحها
المشاكل الشائعة
"ffmpeg not found"
ثبّت ffmpeg: brew install ffmpeg (macOS) أو apt install ffmpeg (Ubuntu).
تصيير بطيء
زِد التوازي بـ --concurrency 8.
الخطوط لا تُحمَّل
استخدم delayRender() لإيقاف التصيير مؤقتاً حتى تُحمَّل الخطوط:
import { delayRender, continueRender } from "remotion";
const [handle] = React.useState(() => delayRender());
React.useEffect(() => {
const font = new FontFace("MyFont", `url(${staticFile("font.woff2")})`);
font.load().then(() => {
document.fonts.add(font);
continueRender(handle);
});
}, [handle]);أفكار لمشاريع
- قوالب مقدمات YouTube — تحريكات ذات علامة تجارية لقناتك
- مولّد قصص وسائل التواصل — ملء معلومات المنتج ديناميكياً في قوالب القصص
- فيديوهات شرح الكود — تحريك ظهور الكود سطراً سطراً
- مؤقتات العد التنازلي — عد تنازلي متحرك لتاريخ إطلاق
- أوديوغرامات البودكاست — تصورات موجات صوتية متزامنة مع الصوت
الخطوات التالية
- استكشف وثائق Remotion للميزات المتقدمة مثل
OffthreadVideoوتصيير Lambda وتضمين Player - تعرّف على قوالب Remotion الجاهزة للإنتاج
- تعلّم عن Remotion Lambda لتصيير الفيديوهات على نطاق واسع على AWS
- ادمج مع Motion (Framer Motion) لتحريكات واجهة معقدة داخل فيديوهاتك
الخلاصة
يحوّل Remotion إنشاء الفيديو من عملية يدوية تعتمد على أدوات إبداعية إلى سير عمل قابل للبرمجة والتكرار والتوسع. بمعاملة كل إطار كمكون React، تحصل على القوة الكاملة لـ TypeScript وحزم npm وتركيب المكونات — مطبّقة على الفيديو.
سواء كنت تبني محتوى تسويقي آلي أو تصورات بيانات أو قوالب ذات علامة تجارية، يمنحك Remotion تجربة المطور التي تعرفها وتحبها بالفعل. ابدأ بتحريكات بسيطة، ركّبها في تسلسلات، وقريباً ستصدّر فيديوهات بجودة إنتاجية بالكامل من الكود.
ناقش مشروعك معنا
نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.
دعنا نجد أفضل الحلول لاحتياجاتك.
مقالات ذات صلة

Capacitor + React — بناء تطبيقات موبايل متعددة المنصات من تطبيقك الويب (2026)
حوّل تطبيق React الخاص بك إلى تطبيق iOS و Android أصلي باستخدام Capacitor. يغطي هذا الدليل العملي الإعداد، الإضافات الأصلية، الكاميرا، التخزين المحلي، النشر على المتاجر، وأفضل ممارسات الإنتاج.

بناء تطبيقات تعاونية محلية أولاً باستخدام Yjs و React
تعلم كيفية بناء تطبيقات تعاونية تعمل في الوقت الفعلي حتى بدون اتصال بالإنترنت باستخدام تقنية CRDTs ومكتبة Yjs مع React. يغطي هذا الدليل مزامنة البيانات بدون تعارضات، والهندسة المعمارية المحلية أولاً، وبناء محرر مستندات مشترك من الصفر.

إضافة المصادقة لتطبيق Next.js 15 باستخدام Auth.js v5: البريد الإلكتروني وOAuth والتحكم بالأدوار
تعلم كيفية إضافة نظام مصادقة جاهز للإنتاج لتطبيق Next.js 15 باستخدام Auth.js v5. يغطي هذا الدليل الشامل تسجيل الدخول عبر Google OAuth وبيانات الاعتماد بالبريد الإلكتروني وكلمة المرور والمسارات المحمية والتحكم بالوصول حسب الأدوار.