تصور کنید یک بازی حافظه آماده برای تولید (Production-ready) میسازید که در آن هر تم، هر کارت و هر راهنما در لحظه توسط مدلهای زبانی بزرگ (LLMs) تولید میشود. این پروژه پتانسیل و قابلیت اجرایی معماریهای اپلیکیشن «AI-native» یا بومیِ هوش مصنوعی را به نمایش میگذارد و با بهرهگیری از OpenRouter بهعنوان موتور اصلی، تضمین میکند که هیچ دو جلسه بازی هرگز یکسان نباشند.
در اکثر بازیهای حافظه، شما با داراییهای ایستایی مانند ایموجیها یا پرچمهای تکراری سر و کار دارید که بعد از سه بار بازی خستهکننده میشوند. اما در این پیادهسازی، کاربر میتواند درخواستی مانند «دسرهای کاوایی در فضای بیرونی» (kawaii desserts in outer space) وارد کند و هوش مصنوعی در عرض چند ثانیه ۸ جفت کارت را طراحی کرده، راهنماها را مینویسد، گرادینتهای رنگی را انتخاب میکند و نام تخته بازی را تعیین مینماید. این یعنی جایگزینی کامل محتوای ثابت و سختافزاری با یک مولد پویا و هوشمند.
طبق گزارش فنی این پروژه، زیرساخت آن بر پایه Next.js 15 با App Router و React 19 بنا شده است. معماری پروژه یک مرز سختگیرانه را حفظ میکند: کلاینت وظیفه رندرینگ، انیمیشنها و مدیریت وضعیت بازی (Game State) را بر عهده دارد، در حالی که سرور تمامی فراخوانیهای LLM را مدیریت میکند تا کلیدهای API از دسترس مرورگر در امان بمانند و امنیت سیستم حفظ شود. اهمیت مدیریت صحیح دسترسیها در این مرحله بسیار زیاد است، چرا که همانطور که در بررسیهای پیشین اشاره شد، کلید API در واقع نخستین تست یکپارچهسازی سیستم است و نباید به عنوان گام آخر دیده شود. در این میان، OpenRouter مسیریابی مدلها را به همراه جایگزینهای خودکار (Fallbacks) مدیریت میکند.
انتخابهای تک پشته (Tech Stack)
- Next.js 15: بهرهگیری از Server Actions و مسیرهای API برای فراخوانیهای امن هوش مصنوعی و استقرار تک-کلیکی سریع در Vercel.
- Direct Fetch: برای کنترل کاملتر و سادگی در پیادهسازی، به جای استفاده از Vercel AI SDK، مستقیماً به نقطه اتصال (Endpoint) سازگار با OpenAI در OpenRouter متصل شده است.
- Framer Motion: به دلیل اینکه چرخشهای سهبعدی کارتها نیازمند ویژگی
preserve-3dو فیزیک فنری (Spring Physics) هستند و CSS استاندارد در این زمینه کافی نیست، از این کتابخانه استفاده شده است. - LocalStorage: برای مدیریت رکوردهای متوالی (Streaks) و جدول امتیازات در نسخه اول (v1)، در حالی که یک ساختار آماده (Stub) برای Supabase جهت گسترشهای دادهای در آینده تعبیه شده است.
- مدلهای رایگان OpenRouter: مجموعهای منتخب و کیوریت شده از مدلهایی که نیازی به شارژ اعتبار (Credits) ندارند و برای پروژههای کمهزینه ایدهآل هستند.
غلبه بر گلوگاه «Fetch Failed»
تلاشهای اولیه برای تولید ۱۶ کارت در یک فراخوانی واحد LLM، منجر به زمان پاسخدهی بسیار طولانی (۷۷ ثانیه) در مدلهای رایگان شد. این تأخیر باعث فعال شدن Time-out در Server Actionهای Vercel میشد که در مرورگر به صورت خطاهای مبهم و گیجکننده «Fetch failed» ظاهر میشد. برای حل این مشکل، توسعهدهنده مکانیزم دستهبندی موازی (Parallel Batching) را پیاده کرد.

خط لولهی جدید، فرآیند تولید را به سه درخواست همزمان تقسیم میکند تا بار پردازشی توزیع شود:
- تولید متادیتا: مدیریت نام تم، پسزمینه، مخزن راهنماها و طراحی پشت کارتها (که حجم آن حدود ۱ کیلوبایت JSON است).
- دسته کارت ۱: تولید ۴ جفت اول (۸ کارت) با استفاده از شناسههای جفت مشخص (مثلاً a, b, c, d).
- دسته کارت ۲: تولید ۴ جفت دوم (۸ کارت) با استفاده از شناسههای باقیمانده (مثلاً e, f, g, h).
با اجرای موازی این درخواستها، کل زمان تولید از ۷۷ ثانیه به حدود ۱۲ ثانیه کاهش یافت. این تغییر استراتژیک تضمین میکند که بازی حتی در مدلهای محدود سطح رایگان نیز قابل بازی و روان باشد. همچنین در مسیر تولید (Generation Route)، مقدار export const maxDuration = 120 بهطور خاص برای استقرارهای Vercel Pro تنظیم شده تا از قطع شدن اتصال در اثر زمانبر بودن پاسخها جلوگیری شود.
تضمین قابلیت اطمینان JSON
مدلهای رایگان اغلب «ردپای استدلالی» (Reasoning Traces) یا متنهای زنجیره تفکر (Chain-of-Thought) را در پاسخهای خود ارسال میکنند که باعث شکست در تجزیه (Parsing) JSON و کرش کردن برنامه میشود. اپلیکیشن یک JSON_SYSTEM_PROMPT سختگیرانه را اجرا میکند: «شما یک مولد محتوای بازی هستید. فقط و فقط JSON معتبر برگردانید. بدون markdown، بدون کد-فنس، بدون ردپای استدلالی و بدون زنجیره تفکر. پاسخ خود را با { شروع کنید».

برای کوتاه نگه داشتن فیلدها و جلوگیری از قطع شدن متن در اثر محدودیت توکن (Truncation)، پرامپت کاربر بهطور مشخص ساختاری شامل id ،pairId ،imagePrompt و emoji را درخواست میکند. برای اطمینان بیشتر، مقدار response_format صراحتاً روی json_object تنظیم شده است تا مدل را مجبور به تولید ساختار دادهای کند.
برای مدیریت پاسخهای ناقص یا بریده شده، توسعهدهنده تابعی به نام repairTruncatedJson نوشت. این ابزار کاربردی تلاش میکند براکتهای باز مانده در JSON را با حذف تکرارکنندهی کاراکترهای انتهایی و بازخوانی مجدد (Re-parsing) تا ۶ مرتبه ترمیم کند، تا از کرش کردن اپلیکیشن در زمان رسیدن مدل به حد توکن (Token Limit) در میانه پاسخ جلوگیری شود.
زنجیره جایگزین مدلها (Model Fallback Chain)
از آنجایی که لایههای رایگان هوش مصنوعی به شدت ناپایدار هستند و مستعد محدودیت نرخ درخواست (Rate-limiting) میباشند، اپلیکیشن به یک مدل واحد تکیه نمیکند. سیستم روی مجموعهای رتبهبندی شده از مدلهای رایگان OpenRouter پیمایش میکند، از جمله:
- tencent/hy3:free
- nvidia/nemotron-3-ultra-550b-a55b:free
- poolside/laguna-m.1:free
- cohere/north-mini-code:free
- openrouter/free (به عنوان آخرین گزینه در مسیریاب خودکار)

اگر مدلی خطای ۴۰۴، خطای ۴۲۹ (محدودیت نرخ) یا محتوای خالی برگرداند، سیستم بهطور خودکار مدل بعدی در زنجیره را امتحان میکند. این فرآیند در یک حلقه تودرتو قرار دارد: برای هر مدل، تا دو تلاش صورت میگیرد. در تلاش دوم، مقدار max_tokens (که پایه آن ۱۰۰۰ است) ۴۰۰ واحد افزایش مییابد تا اطمینان حاصل شود که JSON به دلیل محدودیت توکن قطع نشده و پاسخ کامل دریافت میشود.
وضعیت بازی و منطق کلاینت
گیمپلی توسط یک ماشین وضعیت (State Machine) ساده در GameApp.tsx با چهار مرحله مدیریت میشود: فرود (Landing)، بارگذاری (Loading)، بازی (Playing) و پیروزی (Won). یک AbortController در مرحله بارگذاری با مهلت ۱۱۰ ثانیهای برای فراخوانی /api/generate-game استفاده شده است تا اگر پاسخ مدل بیش از حد طول کشید، درخواست متوقف شود.

چرخش کارتها برای جلوگیری از لگ شبکهای و ایجاد تجربه روان، کاملاً در سمت کلاینت مدیریت میشود. با استفاده از Framer Motion، اپلیکیشن به افکت سهبعدی با انتقال فنری ۰.۶ ثانیهای و سختی (Stiffness) ۲۰۰ دست یافت. موارد ضروری CSS شامل perspective: 1000px در کانتینر و backface-visibility: hidden در رویههای کارت است تا چرخش تمی ایجاد شده و پشت کارتها در زمان چرخش دیده نشود. هر کارت یا یک URL تصویر تولید شده توسط AI را نشان میدهد یا یک ایموجی غنی و پسزمینه گرادینت را به عنوان جایگزین (Fallback) نمایش میدهد.
مکانیزم هوشمند راهنما (Hint)
برای حفظ سرعت تجربه کاربری و جلوگیری از فراخوانیهای مکرر API، راهنماها از استراتژی «ابتدا-مخزن» (Pool-first) پیروی میکنند. در مرحله تولید اولیه، LLM یک hintPool شامل ۵ تا ۸ راهنمای متنی تولید میکند.

- راهنماهای فوری: وقتی کاربر روی دکمه راهنمای دستی کلیک میکند یا راهنمای خودکار فعال میشود، اپلیکیشن ابتدا از آرایه پیشتولید شده در حافظه استفاده میکند.
- راهنماهای تولیدی AI: اگر مخزن راهنماهای اولیه خالی شود، اپلیکیشن میتواند یک درخواست
POST /api/get-hintبا ارسال بافت (Context) فعلی تخته بازی ارسال کند تا راهنمایی جدید تولید شود (حداکثر ۲ مورد در هر بازی). - محرک راهنمای خودکار: یک
useEffectمقدارstats.missesرا رصد میکند. هر ۴ اشتباه کاربر (HINT_MISS_THRESHOLD)، یک راهنما بهطور خودکار آشکار میشود تا کاربر را کمک کند.
لازم به ذکر است که توسعهدهنده با یک باگ در React مواجه شد که در آن فراخوانی یک Server Action در داخل یک آپدیتور setStats باعث خطای «Cannot update Router while rendering GameBoard» میشد. انتقال منطق راهنما به useEffect این تداخل رندرینگ را کاملاً حل کرد.
ماندگاری و امتیازدهی
اپلیکیشن از LocalStorage برای ردیابی رکوردهای متوالی (Winning Streaks) و مجموع پیروزیها استفاده میکند. تابع updateStreakOnWin بررسی میکند که آیا lastPlayedDate دقیقاً مربوط به دیروز بوده است یا خیر تا رکورد را افزایش دهد؛ در غیر این صورت، اگر تاریخ امروز نباشد، رکورد را به ۱ باز میگرداند تا نظم روزانه حفظ شود.

SessionStorage برای کش کردن بازیهای تولید شده با استفاده از کلیدی ترکیبی از تم، سختی و تنظیمات تولید تصویر به کار میرود. این کار به کاربران اجازه میدهد همان تم را بدون نیاز به فراخوانیهای جدید و هزینهبر LLM دوباره بازی کنند.
امتیازدهی توسط فرمول دقیقی محاسبه میشود تا رقابت را جذاب کند:
- پایه: تعداد جفتها ضرب در ۱۰۰.
- پاداش زمان:
Math.max(0, 300 - elapsedSeconds * 2). - پاداش دقت:
(matches / moves) * 50. - جریمهها: هر حرکت (-۳)، هر اشتباه (-۸) و هر راهنمای استفاده شده (-۱۵).
- کف امتیاز: امتیاز نهایی گرد شده و حداقل روی ۱۰۰ امتیاز تثبیت میشود تا کاربر هیچگاه با امتیاز صفر مواجه نشود.
این تغییر به سمت طراحی AI-native نشان میدهد که برای اپلیکیشنهای مقیاس کوچک، LLM میتواند جایگزین کل پایگاه داده محتوای ایستا شود. با برخورد با AI به عنوان یک API پویا به جای یک رابط چت ساده، توسعهدهندگان میتوانند تجربههای بسیار شخصیسازی شدهای خلق کنند که کدنویسی دستی و سختافزاری آنها غیرممکن یا بسیار زمانبر بود.
نتیجه کلیدی برای توسعهدهندگان این است که موازیسازی هنگام کار با LLMهای سطح رایگان یک ضرورت است. تکیه بر یک پرامپت بزرگ و واحد، راهی به سوی Time-out و ناپایداری سیستم است. استفاده از زنجیره جایگزین (Fallback Chain) نیز تضمین میکند که اپلیکیشن با وجود نوسانات و قطعیهای نقاط اتصال AI رایگان، تابآور باقی بماند و تجربه کاربری را مختل نکند.




گفتگو