React Three Fiber + Next.js: بناء تجارب ويب ثلاثية الأبعاد تفاعلية من الصفر

مقدمة
لم يعد الويب محصوراً في الواجهات المسطحة. من مُعدِّلات المنتجات وتصوير البيانات إلى المعارض التفاعلية والألعاب في المتصفح، أصبح المحتوى ثلاثي الأبعاد على الويب أداة أساسية في ترسانة كل مطور. كانت Three.js منذ فترة طويلة المكتبة المفضلة لعرض WebGL، لكن واجهتها الأمرية قد تبدو غريبة على مطوري React المعتادين على المكونات التصريحية.
React Three Fiber (R3F) يسد هذه الفجوة. إنه مُصيِّر React لـ Three.js يتيح لك بناء مشاهد ثلاثية الأبعاد باستخدام مكونات JSX والخطافات ونفس النموذج الذهني الذي تستخدمه بالفعل لواجهة المستخدم. بالاقتران مع @react-three/drei (مجموعة من المساعدات المفيدة) و @react-three/rapier (محرك فيزياء)، يمكنك إنشاء تجارب ثلاثية الأبعاد بمستوى إنتاجي دون كتابة أي WebGL خام.
في هذا الدليل، ستبني عرض منتج ثلاثي الأبعاد تفاعلي كامل — كرة عائمة يمكن للمستخدمين تدويرها، والنقر عليها لتغيير الألوان، ومشاهدتها ترتد بفيزياء واقعية. على طول الطريق، ستتقن المفاهيم الأساسية لـ R3F وتتعلم كيفية دمجه بشكل نظيف في تطبيق Next.js.
ما ستبنيه
بنهاية هذا الدليل، سيكون لديك:
- تطبيق Next.js مع لوحة رسم ثلاثية الأبعاد بملء الشاشة
- مشهد ثلاثي الأبعاد مع إضاءة وظلال وخرائط بيئة
- تحكم مداري تفاعلي لحركة الكاميرا
- كائنات ثلاثية الأبعاد متحركة بفيزياء نابضية
- تغيير ألوان المواد بالنقر
- أرضية مُمَكَّنة بالفيزياء مع كائنات مرتدة
- تحسينات أداء للنشر الإنتاجي
المتطلبات الأساسية
قبل البدء، تأكد من أن لديك:
- Node.js 20+ مثبت على جهازك
- معرفة أساسية بـ React و TypeScript
- إلمام بـ Next.js App Router (الصفحات تعمل أيضاً، لكننا نستخدم App Router)
- محرر أكواد مثل VS Code مع إضافة ES7+ React
- لا تحتاج خبرة سابقة في Three.js أو الأبعاد الثلاثية — نبدأ من الصفر
الخطوة 1: إعداد المشروع
أنشئ مشروع Next.js جديد وثبّت التبعيات المطلوبة:
npx create-next-app@latest r3f-showcase --typescript --tailwind --app --src-dir
cd r3f-showcaseالآن ثبّت React Three Fiber وحزم النظام البيئي:
npm install three @react-three/fiber @react-three/drei @react-three/rapier
npm install -D @types/threeإليك ما يفعله كل حزمة:
| الحزمة | الغرض |
|---|---|
three | مكتبة Three.js الأساسية |
@react-three/fiber | مُصيِّر React لـ Three.js |
@react-three/drei | مساعدات جاهزة (تحكم، محمّلات، مواد) |
@react-three/rapier | تكامل محرك الفيزياء |
@types/three | تعريفات أنواع TypeScript |
الخطوة 2: فهم Canvas
أساس كل تطبيق R3F هو مكون Canvas. يُنشئ سياق WebGL ويدير حلقة عرض Three.js لك.
أنشئ ملفاً جديداً في src/components/Scene.tsx:
"use client";
import { Canvas } from "@react-three/fiber";
export default function Scene() {
return (
<div className="h-screen w-full">
<Canvas
camera={{ position: [0, 2, 5], fov: 50 }}
shadows
>
{/* مشهدنا ثلاثي الأبعاد سيكون هنا */}
<mesh>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="royalblue" />
</mesh>
</Canvas>
</div>
);
}بعض النقاط المهمة:
"use client"مطلوب لأن R3F يستخدم واجهات برمجة المتصفح (WebGL) وخطافات React داخلياًcameraيحدد الموضع الأولي وزاوية الرؤيةshadowsيُفعّل خرائط الظل عالمياًmeshهو لبنة البناء الأساسية — هندسة مع مادة
حدّث src/app/page.tsx لعرض المشهد:
import dynamic from "next/dynamic";
const Scene = dynamic(() => import("@/components/Scene"), {
ssr: false,
loading: () => (
<div className="flex h-screen w-full items-center justify-center bg-black">
<p className="text-white">جارٍ تحميل المشهد ثلاثي الأبعاد...</p>
</div>
),
});
export default function Home() {
return <Scene />;
}استخدم دائماً الاستيراد dynamic مع ssr: false لمكونات R3F في Next.js. Three.js يصل إلى window و document اللذين لا يوجدان أثناء العرض من جانب الخادم.
شغّل خادم التطوير لرؤية أول مكعب ثلاثي الأبعاد:
npm run devيجب أن ترى مكعباً أزرق على خلفية سوداء. يبدو مسطحاً لأنه ليس لدينا إضاءة بعد.
الخطوة 3: إضافة الإضاءة والبيئة
الإضاءة هي ما يحول الكائنات المسطحة إلى مرئيات ثلاثية الأبعاد واقعية. أنشئ src/components/Lighting.tsx:
"use client";
import { Environment } from "@react-three/drei";
export default function Lighting() {
return (
<>
{/* إضاءة محيطة للإنارة الأساسية */}
<ambientLight intensity={0.3} />
{/* ضوء اتجاهي رئيسي (مثل الشمس) */}
<directionalLight
position={[5, 8, 5]}
intensity={1.5}
castShadow
shadow-mapSize-width={2048}
shadow-mapSize-height={2048}
shadow-camera-far={20}
shadow-camera-left={-5}
shadow-camera-right={5}
shadow-camera-top={5}
shadow-camera-bottom={-5}
/>
{/* ضوء تعبئة من الجانب المعاكس */}
<directionalLight
position={[-3, 4, -5]}
intensity={0.4}
/>
{/* خريطة بيئة HDR لانعكاسات واقعية */}
<Environment preset="city" />
</>
);
}مكون Environment من drei يحمّل خريطة بيئة HDR توفر انعكاسات واقعية على الأسطح المعدنية واللامعة. خاصية preset تقدم عدة خيارات مدمجة: city، sunset، dawn، night، warehouse، forest، apartment، studio، park، و lobby.
الخطوة 4: إنشاء الكائن ثلاثي الأبعاد التفاعلي
الآن لنبني نجم عرضنا — كرة ثلاثية الأبعاد تفاعلية تستجيب لأحداث التمرير والنقر. أنشئ src/components/InteractiveSphere.tsx:
"use client";
import { useRef, useState } from "react";
import { useFrame } from "@react-three/fiber";
import { MeshDistortMaterial } from "@react-three/drei";
import type { Mesh } from "three";
const COLORS = ["#ff6b6b", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57"];
export default function InteractiveSphere() {
const meshRef = useRef<Mesh>(null);
const [colorIndex, setColorIndex] = useState(0);
const [hovered, setHovered] = useState(false);
// حلقة الرسوم المتحركة — تعمل كل إطار (~60fps)
useFrame((state, delta) => {
if (!meshRef.current) return;
// حركة طفو لطيفة
meshRef.current.position.y =
Math.sin(state.clock.elapsedTime * 0.8) * 0.3 + 1.5;
// دوران بطيء
meshRef.current.rotation.y += delta * 0.3;
// تكبير عند التمرير
const targetScale = hovered ? 1.2 : 1;
meshRef.current.scale.lerp(
{ x: targetScale, y: targetScale, z: targetScale } as any,
0.1
);
});
const handleClick = () => {
setColorIndex((prev) => (prev + 1) % COLORS.length);
};
return (
<mesh
ref={meshRef}
castShadow
onClick={handleClick}
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
>
<sphereGeometry args={[1, 64, 64]} />
<MeshDistortMaterial
color={COLORS[colorIndex]}
roughness={0.2}
metalness={0.8}
distort={hovered ? 0.4 : 0.2}
speed={2}
/>
</mesh>
);
}المفاهيم الرئيسية المُقدمة هنا:
useFrame— خطاف الرسوم المتحركة في R3F. يعمل في كل إطار عرض، مما يمنحك الوصول إلى ساعة Three.js ووقت الدلتا. لا تستخدم أبداًrequestAnimationFrameمباشرة —useFrameمتكامل مع حلقة عرض R3F.MeshDistortMaterial— مساعد drei ينشئ تأثير سطح متموج ومشوه. خاصيتاdistortوspeedتتحكمان في التشويه.- أحداث المؤشر — R3F يدعم
onClick،onPointerOver،onPointerOutوالمزيد، تماماً مثل عناصر DOM في React العادية. في الخلفية، يستخدم إسقاط الأشعة لتحديد أي كائن ثلاثي الأبعاد يتفاعل معه الماوس. lerp— الاستيفاء الخطي للانتقالات السلسة. بدلاً من القفز إلى المقياس المستهدف، ننتقل بسلاسة نحوه في كل إطار.
الخطوة 5: إضافة التحكم المداري
اسمح للمستخدمين بتدوير الكاميرا وتقريبها حول المشهد. حدّث مكون Scene:
"use client";
import { Canvas } from "@react-three/fiber";
import { OrbitControls, ContactShadows } from "@react-three/drei";
import Lighting from "./Lighting";
import InteractiveSphere from "./InteractiveSphere";
export default function Scene() {
return (
<div className="h-screen w-full bg-gradient-to-b from-gray-900 to-black">
<Canvas
camera={{ position: [0, 2, 5], fov: 50 }}
shadows
>
<Lighting />
<InteractiveSphere />
{/* أرضية مع ظلال تلامسية */}
<ContactShadows
position={[0, -0.5, 0]}
opacity={0.5}
scale={10}
blur={2}
far={4}
/>
{/* تحكم الكاميرا */}
<OrbitControls
enablePan={false}
minDistance={3}
maxDistance={10}
minPolarAngle={Math.PI / 6}
maxPolarAngle={Math.PI / 2.2}
/>
</Canvas>
</div>
);
}تهيئة OrbitControls تحد من حركة الكاميرا لمنع المستخدمين من الذهاب تحت الأرض أو التقريب بعيداً جداً. ContactShadows ينشئ ظلاً ناعماً تحت الكائن دون الحاجة إلى أرضية فعلية.
الخطوة 6: تحميل نماذج ثلاثية الأبعاد
غالباً ما تستخدم المشاريع الحقيقية نماذج ثلاثية الأبعاد بدلاً من الأشكال البدائية. R3F يدعم نماذج GLTF/GLB أصلياً عبر خطاف useGLTF من drei.
أنشئ مكون محمّل النماذج في src/components/Model.tsx:
"use client";
import { useRef } from "react";
import { useFrame } from "@react-three/fiber";
import { useGLTF, Float } from "@react-three/drei";
import type { Group } from "three";
interface ModelProps {
url: string;
scale?: number;
position?: [number, number, number];
}
export default function Model({ url, scale = 1, position = [0, 0, 0] }: ModelProps) {
const groupRef = useRef<Group>(null);
const { scene } = useGLTF(url);
useFrame((state) => {
if (!groupRef.current) return;
groupRef.current.rotation.y = state.clock.elapsedTime * 0.2;
});
return (
<Float
speed={1.5}
rotationIntensity={0.3}
floatIntensity={0.5}
>
<group ref={groupRef} position={position} scale={scale}>
<primitive object={scene.clone()} castShadow receiveShadow />
</group>
</Float>
);
}مكون Float من drei يضيف حركة طفو لطيفة تلقائياً. خطاف useGLTF يتعامل مع التحميل والتخزين المؤقت والتخلص من نماذج GLTF.
يمكنك العثور على نماذج ثلاثية الأبعاد مجانية في poly.pizza و sketchfab.com و market.pmnd.rs. حمّلها بتنسيق GLB وضعها في مجلد public/models/.
لتحميل النماذج مسبقاً وتجنب ومضات التحميل:
// في أسفل ملف مكون Model
useGLTF.preload("/models/sneaker.glb");الخطوة 7: إضافة الفيزياء
الفيزياء تبث الحياة في مشهدك بتفاعلات واقعية. أنشئ src/components/PhysicsScene.tsx:
"use client";
import { Physics, RigidBody, CuboidCollider } from "@react-three/rapier";
import { useState } from "react";
function BouncingBall({ position }: { position: [number, number, number] }) {
const [color, setColor] = useState("#ff6b6b");
return (
<RigidBody
position={position}
restitution={0.8}
friction={0.5}
colliders="ball"
>
<mesh
castShadow
onClick={() => setColor(`hsl(${Math.random() * 360}, 70%, 60%)`)}
>
<sphereGeometry args={[0.3, 32, 32]} />
<meshStandardMaterial color={color} roughness={0.3} metalness={0.6} />
</mesh>
</RigidBody>
);
}
function Ground() {
return (
<RigidBody type="fixed">
<CuboidCollider args={[10, 0.1, 10]} position={[0, -1, 0]} />
<mesh receiveShadow position={[0, -1, 0]}>
<boxGeometry args={[20, 0.2, 20]} />
<meshStandardMaterial color="#1a1a2e" />
</mesh>
</RigidBody>
);
}
export default function PhysicsScene() {
const balls = Array.from({ length: 10 }, (_, i) => ({
id: i,
position: [
(Math.random() - 0.5) * 4,
3 + Math.random() * 5,
(Math.random() - 0.5) * 4,
] as [number, number, number],
}));
return (
<Physics gravity={[0, -9.81, 0]}>
<Ground />
{balls.map((ball) => (
<BouncingBall key={ball.id} position={ball.position} />
))}
</Physics>
);
}مكون Physics يغلف مشهدك ويطبق الجاذبية. RigidBody يجعل الكائنات تشارك في محاكاة الفيزياء. الخصائص الرئيسية:
restitution— الارتداد (0 = بدون ارتداد، 1 = ارتداد مثالي)friction— احتكاك السطح (0 = جليد، 1 = مطاط)type="fixed"— يجعل الكائن غير قابل للتحريك (مثالي للأرضيات والجدران)colliders— ينشئ تلقائياً أشكال التصادم (ball،cuboid،hull،trimesh)
الخطوة 8: تأثيرات ما بعد المعالجة
أضف جودة سينمائية مع المعالجة اللاحقة. ثبّت حزمة التأثيرات:
npm install @react-three/postprocessingأنشئ src/components/Effects.tsx:
"use client";
import { EffectComposer, Bloom, ChromaticAberration, Vignette } from "@react-three/postprocessing";
export default function Effects() {
return (
<EffectComposer>
<Bloom
luminanceThreshold={0.6}
luminanceSmoothing={0.9}
intensity={0.5}
/>
<Vignette eskil={false} offset={0.1} darkness={0.5} />
<ChromaticAberration offset={[0.0005, 0.0005]} />
</EffectComposer>
);
}- Bloom — ينشئ تأثير توهج على الأسطح اللامعة
- Vignette — يعتّم حواف الشاشة لإحساس سينمائي
- ChromaticAberration — يضيف تأثير انحراف لوني خفيف
تأثيرات ما بعد المعالجة يمكن أن تؤثر بشكل كبير على الأداء في الأجهزة المحمولة. وفّر دائماً طريقة لتعطيلها، أو استخدم خطاف useDetectGPU من drei لضبط الجودة تلقائياً.
الخطوة 9: جودة متجاوبة وتكيفية
تطبيقات الأبعاد الثلاثية في الإنتاج يجب أن تعمل على كل شيء من الحواسيب عالية الأداء إلى الهواتف ذات الميزانية المحدودة. أنشئ src/components/AdaptiveScene.tsx:
"use client";
import { useThree } from "@react-three/fiber";
import { useDetectGPU, PerformanceMonitor } from "@react-three/drei";
import { useState, useEffect } from "react";
export function AdaptivePixelRatio() {
const { gl } = useThree();
const GPUTier = useDetectGPU();
useEffect(() => {
if (GPUTier.tier === 0 || GPUTier.isMobile) {
gl.setPixelRatio(1);
} else if (GPUTier.tier === 1) {
gl.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
} else {
gl.setPixelRatio(Math.min(window.devicePixelRatio, 2));
}
}, [GPUTier, gl]);
return null;
}
export function AdaptivePerformance({
children,
}: {
children: (dpr: number) => React.ReactNode;
}) {
const [dpr, setDpr] = useState(1.5);
return (
<PerformanceMonitor
onIncline={() => setDpr(Math.min(dpr + 0.5, 2))}
onDecline={() => setDpr(Math.max(dpr - 0.5, 0.5))}
>
{children(dpr)}
</PerformanceMonitor>
);
}PerformanceMonitor يراقب معدلات الإطارات ويضبط الجودة تلقائياً. عندما تنخفض الإطارات، يقلل نسبة البكسل؛ وعندما يكون الأداء جيداً، يزيد الجودة.
الخطوة 10: تجميع كل شيء معاً
الآن اجمع كل شيء في المشهد النهائي. حدّث src/components/Scene.tsx:
"use client";
import { Suspense } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls, ContactShadows, Html, Preload } from "@react-three/drei";
import Lighting from "./Lighting";
import InteractiveSphere from "./InteractiveSphere";
import Effects from "./Effects";
import { AdaptivePixelRatio } from "./AdaptiveScene";
function Loader() {
return (
<Html center>
<div className="flex flex-col items-center gap-2">
<div className="h-8 w-8 animate-spin rounded-full border-2 border-white border-t-transparent" />
<p className="text-sm text-white">جارٍ تحميل المشهد...</p>
</div>
</Html>
);
}
export default function Scene() {
return (
<div className="relative h-screen w-full bg-gradient-to-b from-gray-900 to-black">
{/* طبقة واجهة المستخدم */}
<div className="absolute right-0 top-0 z-10 p-6">
<h1 className="text-3xl font-bold text-white">عرض منتج ثلاثي الأبعاد</h1>
<p className="mt-2 text-gray-400">انقر على الكرة لتغيير الألوان</p>
<p className="text-gray-400">اسحب للتدوير • مرر للتقريب</p>
</div>
<Canvas
camera={{ position: [0, 2, 5], fov: 50 }}
shadows
dpr={[1, 2]}
gl={{ antialias: true, alpha: false }}
>
<AdaptivePixelRatio />
<Suspense fallback={<Loader />}>
<Lighting />
<InteractiveSphere />
<ContactShadows
position={[0, -0.5, 0]}
opacity={0.5}
scale={10}
blur={2}
far={4}
/>
<Effects />
<Preload all />
</Suspense>
<OrbitControls
enablePan={false}
minDistance={3}
maxDistance={10}
minPolarAngle={Math.PI / 6}
maxPolarAngle={Math.PI / 2.2}
autoRotate
autoRotateSpeed={0.5}
/>
</Canvas>
</div>
);
}الإضافات الرئيسية:
SuspenseمعLoaderمخصص — يعرض مؤشر تحميل أثناء تحميل الأصولPreload all— يحمّل جميع الأصول في شجرة المشهد مسبقاًdpr={[1, 2]}— يحد نطاق نسبة البكسل لأداء ثابتautoRotate— يدور الكاميرا ببطء عندما لا يتفاعل المستخدمHtml— يعرض HTML عادي داخل المشهد ثلاثي الأبعاد، دائماً مواجهاً للكاميرا
أفضل ممارسات الأداء
عند نشر R3F في الإنتاج، تذكر هذه القواعد:
- الشبكات المُنسَخة — إذا كان لديك العديد من الكائنات المتطابقة، استخدم
InstancedMeshبدلاً من شبكات فردية. هذا يقلل من مكالمات الرسم بشكل كبير.
import { Instances, Instance } from "@react-three/drei";
function Particles() {
return (
<Instances limit={1000}>
<sphereGeometry args={[0.05, 8, 8]} />
<meshStandardMaterial color="white" />
{positions.map((pos, i) => (
<Instance key={i} position={pos} />
))}
</Instances>
);
}-
تحرير الموارد — R3F يتعامل مع هذا تلقائياً للمكونات التي تُفصل، لكن إذا أنشأت مواد أو هندسات يدوياً، استدعِ دائماً
.dispose(). -
ضغط القوام — استخدم تنسيق KTX2 للقوام بدلاً من PNG/JPG. drei يوفر
useKTX2لهذا. -
استخدم
frameloop="demand"— إذا كان مشهدك ثابتاً في الغالب، اضبط هذا على Canvas للعرض فقط عندما يتغير شيء:
<Canvas frameloop="demand">- تجنب إعادة العرض — استخدم
useFrameللرسوم المتحركة بدلاً من حالة React. تغييرات حالة React تُحفّز إعادة عرض المكونات؛useFrameيعمل خارج مصالحة React.
استكشاف الأخطاء وإصلاحها
خطأ "window is not defined"
يحدث هذا عندما يعمل كود R3F أثناء العرض من جانب الخادم. استخدم دائماً الاستيرادات الديناميكية مع ssr: false:
const Scene = dynamic(() => import("@/components/Scene"), { ssr: false });شاشة سوداء بدون أخطاء
عادةً مشكلة إضاءة. تأكد من وجود مصدر ضوء واحد على الأقل. جرّب إضافة <ambientLight intensity={1} /> للتحقق من وجود الكائنات.
أداء ضعيف على الهاتف المحمول
- قلل تعقيد الهندسة (شرائح أقل)
- خفّض نسبة البكسل:
dpr={[0.5, 1]} - عطّل الظلال: احذف خاصية
shadowsمن Canvas - احذف تأثيرات ما بعد المعالجة
الكائنات لا تستقبل النقرات
R3F يستخدم إسقاط الأشعة لأحداث المؤشر. تأكد من أن الشبكة لديها هندسة مرفقة — الهندسات غير المرئية أو ذات الحجم الصفري لن تسجل النقرات.
الخطوات التالية
الآن بعد أن أتقنت الأساسيات، استكشف هذه المجالات:
- مواد الشيدر — اكتب شيدرات GLSL مخصصة مع
shaderMaterialمن drei - نص ثلاثي الأبعاد — استخدم
Text3Dمن drei مع خطوط مخصصة - رسوم متحركة مبنية على التمرير — اجمع R3F مع
ScrollControlsلتجارب ثلاثية الأبعاد مدفوعة بالتمرير - VR/AR — R3F يدعم WebXR أصلياً مع مكون
XR - متعدد اللاعبين — اجمع مع WebSockets لتجارب ثلاثية الأبعاد مشتركة
الخلاصة
React Three Fiber يحوّل تطوير الويب ثلاثي الأبعاد من مهارة متخصصة إلى شيء يمكن لأي مطور React تعلمه. من خلال معاملة الكائنات ثلاثية الأبعاد كمكونات، واستخدام الخطافات للرسوم المتحركة، والاستفادة من مكتبة مساعدات drei الواسعة، يمكنك بناء تجارب ثلاثية الأبعاد بمستوى إنتاجي دون خبرة عميقة في Three.js.
النقاط الرئيسية من هذا الدليل:
- Canvas هو نقطة دخولك — غلّف دائماً محتوى R3F فيه
- useFrame هو حلقة الرسوم المتحركة — لا تستخدم أبداً
requestAnimationFrame - drei هو صندوق أدواتك — تحقق منه قبل بناء حلول مخصصة
- الاستيرادات الديناميكية مع تعطيل SSR إلزامية في Next.js
- الأداء يتطور مع الوعي — نسبة البكسل والنسخ ومستوى التفصيل مهمة
ابدأ ببساطة، كرر، ودع الطبيعة التصريحية لـ React توجه بنية مشهدك ثلاثي الأبعاد. الويب ثلاثي الأبعاد في بدايته فقط، وأنت الآن مجهز لبنائه.
ناقش مشروعك معنا
نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.
دعنا نجد أفضل الحلول لاحتياجاتك.
مقالات ذات صلة

بناء تطبيق كامل يعمل بالوقت الحقيقي باستخدام Convex و Next.js 15
تعلّم كيفية بناء تطبيق كامل يعمل بالوقت الحقيقي باستخدام Convex و Next.js 15. يغطي هذا الدليل تصميم المخططات والاستعلامات والتعديلات والاشتراكات الفورية والمصادقة ورفع الملفات — مع أمان أنواع شامل.

بناء تطبيق كامل مع Firebase و Next.js 15: المصادقة، Firestore والتحديث الفوري
تعلم كيفية بناء تطبيق full-stack مع Next.js 15 و Firebase. يغطي هذا الدليل المصادقة، Firestore، التحديثات الفورية، Server Actions والنشر على Vercel.

Motion لـ React: بناء رسوم متحركة وإيماءات وانتقالات بمستوى إنتاجي
أتقن مكتبة Motion للرسوم المتحركة (المعروفة سابقاً بـ Framer Motion) لـ React. تعلم بناء رسوم متحركة سلسة وإيماءات تفاعلية وانتقالات التخطيط وتأثيرات التمرير ورسوم الخروج المتحركة مع TypeScript.