What does ipad_code do?
المستخدم معه آيباد وClaude Code، وما عنده كمبيوتر. الجلسة السحابية هي الكمبيوتر، والجلسات الإضافية هي مزرعة الرندر. هذا السكل يشرح الطريق اللي جربناه وطلّع مقطع ١٠ ثواني بـ Cycles بدقة 1080×1920 من الصفر للنشر، مع كل مشكلة واجهتنا وحلها.
اكتب للمستخدم بالعربي البسيط. هو على شاشة صغيرة، فخلّ رسائلك قصيرة، وأرسل له الصور والفيديو بـ SendUserFile بدل ما توصفها.
$SK في هذا الملف يعني مجلد السكل (المجلد اللي فيه هذا الملف). أول شي حدده:
SKILL_MD=$(ls -d ~/.claude/skills/ipad_code/SKILL.md .claude/skills/ipad_code/SKILL.md 2>/dev/null | head -1)
[ -n "$SKILL_MD" ] || echo "ipad_code is not installed: follow START.md"
SK=$(dirname "$SKILL_MD")
0. قبل أي شيء
اقرأ .claude/ipad_code.json.
- موجود: اتبع مستوى المستخدم اللي فيه (
level:newأوsomeأوtech، وguidance:explainأوresults). الجدول في START.md يوضح وش يعني كل مستوى. لا تعيد السؤال. - مو موجود: المستخدم جديد. نفذ START.md من أوله.
القاعدة في كل المستويات: اللي تقدر تسويه، سوّه. لا تطلب من المستخدم يشغل أوامر.
اختر المسار:
| المستخدم طلب | المسار | الوقت |
|---|---|---|
| موشن جرافك، نصوص متحركة، إنفوجرافيك، إعلان بسيط، أو ما حدد وهذا أول مقطع له | السريع، الخطوة 1.5 | دقايق |
| ثلاثي الأبعاد، Blender، تفكيك أو زوم داخل شيء حقيقي | Blender، من الخطوة 2 | ساعات |
1. وش عندك في الجلسة السحابية
قِس، لا تفترض: bash $SK/scripts/doctor.sh.
اللي لقيناه: ٤ أنوية CPU، و١٥ جيجا رام، وبدون كرت شاشة، وPython 3.13، وffmpeg، وNode، وChromium مع Playwright جاهزين. حزم pip وnpm تنزل عادي، وخطوط Google Fonts توصل. Blender مو موجود، والحل تحت.
| اللي يسويه الكمبيوتر عادة | البديل في الجلسة | السكربت |
|---|---|---|
| Blender (برنامج) | Blender كمكتبة Python من pip (bpy) بدون واجهة، ورندر Cycles على CPU مع OpenImageDenoise | setup_blender.sh، render.py |
| معاينة الشغل بالعين | صفحة مصغّرات من إطارات أو من الفيديو، ثم تقرأها كصورة وترسلها للمستخدم | contact.sh |
| After Effects (نص عربي على الفيديو) | Chromium يرسم النص بخط Cairo من Google Fonts بتشكيل عربي صحيح، كصور PNG شفافة | text_cards.js |
| مكتبة مؤثرات صوتية | صوت مولّد بالكود: هدير، وwhoosh يتبع الزوم، وصدمات، ولمعات، ولحظة «تشغيل» | sound.py |
| Premiere (تجميع وتصدير) | ffmpeg: إطارات، ونصوص بتلاشي، وصوت بمستوى -14 LUFS، وH.264 | assemble.py |
| جهاز رندر قوي | مزرعة رندر: جلسات سحابية متوازية، كل وحدة ٤ أنوية | farm.py + references/farm.md |
| صوت راوي وموسيقى | ElevenLabs عن طريق الـ MCP، واقترحه مع كل مقطع (الخطوة 1.6). سكل نبرة مو جزء من هذي السكل، فإذا ما كانت موجودة كمّل بدونها | |
| تسليم الملف | SendUserFile يطلع بطاقة في التطبيق، ومنها يحفظ المستخدم الفيديو في الصور | |
| موشن جرافك (After Effects) | صفحة HTML كل شيء فيها يتحسب من الوقت، وChromium يصورها إطار إطار | motion.js |
1.5 المسار السريع: موشن جرافك بالكود
بدون Blender وبدون انتظار طويل. مناسب لأول مقطع.
export NODE_PATH=$(npm root -g)
node -e "require('playwright').chromium.launch().then(b=>b.close()).catch(()=>process.exit(1))" 2>/dev/null || { npm i -g playwright && "$NODE_PATH/playwright/cli.js" install chromium; }
P=<مجلد المشروع داخل scratchpad>; mkdir -p $P
cp $SK/assets/examples/motion/comp.html $SK/assets/examples/motion/sound.json $P/
~/.snd-venv/bin/python -c "import numpy" 2>/dev/null || { python3 -m venv ~/.snd-venv && ~/.snd-venv/bin/pip install -q numpy; }
- عدّل
$P/comp.html: النصوص فيBEATS، والألوان فيCOLORS، وصمم الرسم فيdrawFieldوdrawRingعلى فكرة المقطع. لا تخلّ كل مقطع نسخة من القالب، فالقالب نقطة بداية. - كل شيء لازم يكون دالة في
tداخلseek(t): بدون CSS animations وبدون مؤقتات وبدونMath.randomبلا بذرة. - النص داخل x200–880 وy270–1400 للمقاطع العمودية، عشان أزرار الريلز وتيك توك ما تغطيه.
- معاينة (بوابة):
اقرأNODE_PATH=$(npm root -g) node $SK/scripts/motion.js $P/comp.html $P/preview --fps 30 --seconds 8 --step 40 bash $SK/scripts/contact.sh $P/contact.png $P/preview/f_*.pngcontact.pngبنفسك، صلّح اللي تشوفه، وأرسله للمستخدم. لا تكمل قبل موافقته. - الرندر والصوت والتجميع:
وقّتNODE_PATH=$(npm root -g) node $SK/scripts/motion.js $P/comp.html $P/frames --fps 30 --seconds 8 ~/.snd-venv/bin/python $SK/scripts/sound.py $P/sound.json $P/sound.wav python3 $SK/scripts/assemble.py --frames $P/frames --fps 30 --audio $P/sound.wav --out $P/final.mp4 bash $SK/scripts/contact.sh $P/check.png $P/final.mp4 1 3.5 6sound.jsonعلى بداياتBEATS. صيغة كل حقل مكتوبة في أولsound.py، فاقرأها قبل التعديل (مثلاًglintsثلاثة أرقام:[بداية, نهاية, عدد]). وإذا غيرت المدة، غيّرDURATIONوdurationو--secondsمع بعض. - سلّم حسب الخطوة 8.
1.6 الراوي
اقترحه مع كل مقطع، إلا إذا المستخدم قال ما يبيه.
- ElevenLabs مو مربوط: قل له يقدر يربطه من إعدادات Claude وإن هذا يحتاج حساب عندهم، وكمّل المقطع بالمؤثرات لين يربطه. لا تطلب منه مفتاح API في المحادثة.
- قبل التوليد: قل له إنه يخصم من رصيده، واخذ موافقته. إذا طلعت أكثر من نسخة، استخدم الأولى إلا إذا طلب غيرها.
- الصوت الافتراضي:
nhJWWCFdNdusuVUT3x19، إلا إذا طلب صوت ثاني. وإذا ما اشتغل من حسابه، اختر صوت قريب من لهجته وقل له أي صوت اخترت. - تنزيل الملف: لو رجع 403، استخدم
get_environmentثمupdate_environmentبـadd_allowed_hosts: ["elevenlabsusercontent.com"]، وبيطلع له طلب موافقة. - التوقيت: قِس طول الصوت بـ
ffprobe، وخلDURATIONوdurationو--secondsأطول منه بنص ثانية على الأقل، وطابقBEATSمع بداية كل جملة (silencedetectيعطيك الفواصل).
ادمج الراوي فوق المؤثرات قبل assemble.py:
ffmpeg -y -i $P/sound.wav -i $P/voice.mp3 -filter_complex "[0:a]volume=0.35[bed];[bed][1:a]amix=inputs=2:duration=first:normalize=0[out]" -map "[out]" -ar 48000 $P/mix.wav
ثم مرّر --audio $P/mix.wav بدل sound.wav.
2. ابنِ المشروع
bash $SK/scripts/setup_blender.sh # ~30 ثانية، يطبع: Blender 5.2.3 ... OK
P=<مجلد المشروع داخل scratchpad>
~/.bpy-venv/bin/python <build.py> $P # يكتب $P/scene.blend
- المشهد يُبنى بسكربت Python (
build.py) يكتبscene.blend. مثال كامل ومجرب: assets/examples/transistor/build.py (زوم من معالج على اللوحة الأم لين ترانزستور FinFET)، وفيه حلول لمشاكل الزوم الكبير: الكاميرا بمسافة لوغاريتمية، وclip_startيتغير مع المسافة، وسطح يذوب بالـ Alpha، و«وادي» مقصوص يمر فيه الكاميرا بدون ما تصدم شي. - عمودي للريلز: 1080×1920، و24 إطار بالثانية. 24 تكفي وتوفّر ٢٠٪ من الرندر مقارنة بـ 30.
- الإعدادات اللي نجحت: Cycles على CPU، وadaptive sampling، وOpenImageDenoise، وAgX، وmotion blur خفيف، و
use_persistent_data. - خلّ الإضاءة كلها شمس (Sun) للمشاهد اللي حجمها يتغير كثير، لأن الشمس ما تتأثر بالمسافة. وحط أضواء نقطية صغيرة للتفاصيل.
- الانبعاث (Emission) يحترق بسرعة مع AgX. ابدأ بقيمة بين 0.5 و1.5.
3. شوف قبل ما ترندر (بوابة)
~/.bpy-venv/bin/python $SK/scripts/render.py $P/scene.blend --out $P/preview --frames 1-240/30 --pct 40 --samples 24
bash $SK/scripts/contact.sh $P/contact.png $P/preview/f_*.png
اقرأ contact.png بنفسك، ثم أرسله للمستخدم. صلّح اللي تشوفه (إضاءة محترقة، كاميرا تصدم، لقطة فاضية)، وأعد البناء. لا ترندر الكامل قبل موافقة المستخدم على المعاينة.
4. احسب الوقت وقرر
رندر أثقل إطار (عادة آخر المقطع) بالدقة والجودة النهائية:
~/.bpy-venv/bin/python $SK/scripts/render.py $P/scene.blend --out $P/timing --frames 175,240 --pct 100 --samples 28
الوقت الكلي تقريباً = عدد الإطارات × 0.75 × وقت أثقل إطار. في تجربتنا كان أثقل إطار ١٠٠ إلى ١٥٠ ثانية، يعني ٢٤٠ إطار ≈ ٧ ساعات على جهاز واحد.
- أقل من ٩٠ دقيقة: ارندر هنا في الخلفية (الخطوة 5).
- أكثر من كذا: اقترح المزرعة (الخطوة 6). قل للمستخدم كم جهاز، وكم ياخذ الوقت، وإن كل جهاز يستهلك من حد استخدامه (تقريباً نص دولار من التوكنز لكل جهاز في تجربتنا)، وإن الإطارات بتنرفع على فروع مؤقتة في مستودعه هو لازم يحذفها بنفسه. ابدأ المزرعة بس بعد موافقته وعدد الأجهزة اللي يحدده.
5. رندر محلي
~/.bpy-venv/bin/python $SK/scripts/render.py $P/scene.blend --out $P/frames --frames 1-240 --pct 100 --samples 28 >> $P/render.log 2>&1
- شغّله بأداة Bash مع
run_in_backgroundوالـ timeout الأقصى. لا تستخدم&، لأن العملية تموت بين الأوامر. - الأمر في الخلفية يوقف بعد ساعتين، وبعدها ما يحق لك تعيد تشغيله من نفسك. عشان كذا قسّم الرندر لدفعات كل وحدة أقل من ٩٠ دقيقة (مثلاً
--frames 1-120ثم121-240). السكربت يتخطى الإطارات الجاهزة، فإعادة نفس الأمر تكمّل من وين وقف. - تابع التقدم من
render.log، وفيه ETA لكل إطار.
6. مزرعة الرندر (أجهزة كثيرة)
الخطوات بالتفصيل في references/farm.md. تحتاج مستودع وأدوات إدارة الجلسات (create_session وأخواتها). إذا ما كانت عندك، قل للمستخدم إن المزرعة مو متوفرة في جلسته، وارندر على جهاز واحد بالدفعات، أو اقترح جودة أقل. باختصار:
python3 $SK/scripts/farm.py precheck --blend $P/scene.blend، وإذا طلعTOO BIGخفف المشهد قبل الرفع. وإذا المستودع عام، استأذن المستخدم، لأن الإطارات بتصير ظاهرة للكل.- ارفع
scene.blendوrender.pyوsetup_blender.shعلى فرع وظيفة (orphan) اسمهrender-job. python3 $SK/scripts/farm.py plan --frames 1-240 --have $P/frames --workers Nيوزّع الإطارات الناقصة بالتناوب، عشان الإطارات الثقيلة تنقسم بالتساوي.- لكل جهاز:
create_sessionعلى المستودع، وsource_revision: render-job، وoutcome_branch: render-out-wNN، والـ prompt منfarm.py prompt --samples <نفس قيمة الرندر النهائي>، لأن ملف المشهد ممكن يكون محفوظ بقيمة أعلى بكثير. - الجلسة اللي تخلص ما ترجع تبلغك. جدول لنفسك فحص بـ
send_laterبعد ٢٥ إلى ٣٠ دقيقة، وشيّك بـget_sessionوبـfarm.py collect. - أي جهاز وقف بدون ما يرفع شي: أرسل له
send_messageيكمّل. وفي نفس الوقت ارندر إطاراته الناقصة هنا من الآخر للأول، واللي يخلص أول تاخذ منه. - بعد ما تكتمل الإطارات، أرشف الجلسات بـ
archive_session. وقل للمستخدم يحذف فروعrender-jobوrender-out-w*من صفحة Branches في GitHub، لأن الجلسة ما تقدر تحذف فروع.
7. النص والصوت والتجميع
NODE_PATH=$(npm root -g) node $SK/scripts/text_cards.js cards.json $P/text
~/.bpy-venv/bin/python $SK/scripts/sound.py sound.json $P/sound.wav
python3 $SK/scripts/assemble.py --frames $P/frames --fps 24 --cards cards.json --textdir $P/text --audio $P/sound.wav --out $P/final.mp4
bash $SK/scripts/contact.sh $P/check.png $P/final.mp4 1 3.5 6 9
- أمثلة جاهزة: cards.json وsound.json. وقّت النص والصوت على أحداث المشهد نفسها (الثانية = رقم الإطار ÷ fps).
- النص: ٥ كلمات كحد أقصى للسطر، وداخل x200–880 وy270–1400 عشان ما تغطيه أزرار الريلز.
text_cards.jsيصغّر النص الكبير ليناسب، ويفشل إذا طلعFONT NOT LOADEDأوOUTSIDE SAFE AREA، فصلّح السبب ولا تتجاهله. - أنت ما تسمع. تأكد من الصوت بالأرقام:
ffmpeg -i sound.wav -af ebur128=peak=true -f null -، وبالطيف:showspectrumpic. وقل للمستخدم وين يركز وهو يسمع. - تحقق قبل التسليم: اقرأ
check.pngوتأكد إن النصوص ظاهرة في كل لقطة. assemble.py --upto Nيطلّع مسودة من الإطارات الجاهزة. أرسلها للمستخدم وأنت تنتظر الرندر.
8. التسليم
SendUserFileبالفيديو معdisplay: render. على الآيباد يفتحه المستخدم من البطاقة، ثم مشاركة، ثم «حفظ الفيديو».- ملفات الـ scratchpad تنمسح لما تنتهي الجلسة. سلّم الفيديو قبل، وإذا المستخدم يبي يعدّل بعدين، ارفع سكربتات المشروع (مو الإطارات) على فرعه.
- آخر رسالة: وش انعمل، والمواصفات، وأي شي باقي عليه هو (مثل حذف الفروع).
مشاكل واجهناها
كلها في references/pitfalls.md. اقرأها قبل أول رندر طويل.