ডেভেলপমেন্ট নোট
ভিজ্যুয়াল নভেল হলো ছবির সমষ্টি। Builder এত জটিল হয়ে উঠল কেন?
Fibber নামের ছোট একটি প্রোটোটাইপ কীভাবে সহযোগিতা, সংস্করণভিত্তিক প্রকাশনা এবং একটি যৌথ স্টোরি runtime-সহ বিতরণকৃত প্ল্যাটফর্মে পরিণত হলো।
বাইরে থেকে ভিজ্যুয়াল নভেলকে প্রায় তুচ্ছ মনে হয়: একটি পটভূমি, স্বচ্ছতাসহ একটি চরিত্র, একটি টেক্সট বক্স, পরের দৃশ্যে নিয়ে যাওয়া কয়েকটি পছন্দ এবং কিছু সংগীত। প্রথম সংস্করণ বানাতে শুরু করার সময় আমিও ঠিক এভাবেই দেখেছিলাম।
আমি এখনও মনে করি মূল বিষয়টি সহজ। আজ, বিশেষ করে AI পাশে থাকলে, প্রায় যেকোনো ডেভেলপার একটি ভিজ্যুয়াল নভেল player বানাতে পারেন। কঠিন অংশ শুরু হয় যখন লক্ষ্য একটি গল্প বানানো নয়, বরং এমন একটি টুল তৈরি করা যেখানে অন্য কেউ, হয়তো একটি শিশুও, নিজের গল্প তৈরি, পরীক্ষা, প্রকাশ এবং ক্রমাগত উন্নত করতে পারে।
প্রথম সংস্করণের কাজ ছিল একটিই
Romergo নাম পাওয়ার আগে এটি ছিল Fibber। সংযুক্ত দৃশ্য থেকে একটি quest তৈরি করত, আমাকে সেই দৃশ্যগুলোতে লেখা ও ছবি যোগ করতে দিত এবং শাখাবিশিষ্ট পছন্দ সমর্থন করত। Stack ছিল TypeScript, React, Strapi এবং Ant Design।
সেই সংস্করণ নিজের কাজ করেছিল। Flow graph গল্পটিকে দৃশ্যমান করেছিল, দৃশ্য সম্পাদনা করা যেত এবং ফলাফল preview করা যেত। একটি prototype-এর জন্য এটুকুই যথেষ্ট ছিল। আসল সমস্যাটি প্রকাশ করার জন্যও যথেষ্ট ছিল।
প্রথম আসল বাধা কোড ছিল না
বাস্তব একটি quest-এ লেখা ও ছবি ভরা শুরু করলে দশ মিনিটের একটি দৃশ্য সাজাতে প্রায় পুরো দিন লেগে যেত। দৃশ্য তৈরি করুন। পটভূমি upload করুন। চরিত্র upload করুন। তাদের বসান। সংলাপ যোগ করুন। পরের দৃশ্য যুক্ত করুন। আবার করুন।
এর কিছুটা ছিল interface-এর সমস্যা। আমি UX উন্নত করেছি, upload দ্রুত করেছি এবং প্রকাশনাকে আরও নির্ভরযোগ্য করেছি। কিন্তু সবচেয়ে বড় খরচ অপরিবর্তিত ছিল: প্রতিটি ছোট কাজ এখনও একজন মানুষকে হাতে করতে হতো।
দুজন যদি একই সময়ে তৈরি করতে পারে?
প্রথম উত্তরটি সহজ ছিল: একজন যদি bottleneck হন, তবে কয়েকজনকে একই গল্পে কাজ করতে দেওয়া যাক। Liveblocks দিয়ে শুরু করে সেই model থেকে শিখেছি, পরে Yjs-কে কেন্দ্রে রেখে নিজের collaboration layer-এর দিকে এগিয়েছি।
নিচের পরীক্ষায় দুটি editor window একসঙ্গে বদলাতে দেখা যায়। এর নিচে product-এর চিন্তায় আরও বড় পরিবর্তন আছে: edit আলাদা form submission না থেকে shared document-এর update হয়ে যায়। এখান থেকেই presence, reconnect, conflict handling, permission এবং project সব সময় জীবন্ত থাকার প্রত্যাশা আসে।
প্রতিটি উপকারী shortcut শেষ পর্যন্ত একটি সীমা হয়েছে
Strapi দ্রুত backend পাওয়ার দারুণ উপায় ছিল, কিন্তু গল্পনির্ভর প্রতিটি নতুন feature CMS-কে একটু কম CMS-এর মতো আচরণ করতে বলত। Ant Design প্রথম interface-কে গতি ও সামঞ্জস্য দিয়েছিল, পরে ধীরে ধীরে product-কে অন্য কারও visual system-এর মধ্যে সীমাবদ্ধ করেছিল।
পরে Remix-ভিত্তিক serverless iteration একটি গুরুত্বপূর্ণ অগ্রগতি ছিল। তবু application, media এবং deployment একত্র করার পদ্ধতি product-এর প্রয়োজনীয় horizontal স্বাধীনতা দেয়নি। কোনো সিদ্ধান্তই ভুল ছিল না। প্রতিটি আমাকে পরের সীমাটি খুঁজে পাওয়ার মতো সময় দিয়েছে।
ছবি attachment নয়। এগুলো infrastructure।
Media নিজেই একটি শিক্ষা হয়ে উঠেছিল। গল্পের ছবি একবার upload করতে হবে, প্রয়োজনে বদলাতে হবে, নিরাপদে রাখতে হবে এবং বিশ্বের যেকোনো player-এর কাছে দ্রুত পৌঁছাতে হবে। বাড়তে থাকা application server-এর পাশে রাখলে backend আরও ভারী হচ্ছিল, তাই প্রথম আলাদা সমাধান ছিল Cloudinary।
এক সন্ধ্যায় dashboard খুলে দেখলাম, একজন user একই ছবি শত শত বার upload করে প্রায় 500 MB খরচ করেছেন। জরুরি fix-এ image hash মিলিয়ে duplicate প্রত্যাখ্যান করেছিলাম। এটি কাজ করেছিল, তবে rate limit ও quota আচরণটিকে আরও সরাসরি নিয়ন্ত্রণ করত। বড় বিস্ময় ছিল bandwidth: এক সন্ধ্যার testing-এই free allowance-এর দশ শতাংশের বেশি শেষ হতে পারত।
ঘटनাটি model বদলে দিয়েছিল। Media আর scene-এর একটি field হতে পারত না। Storage, deduplication, delivery, caching এবং access-এর জন্য তার নিজস্ব pipeline দরকার ছিল।
সেই সহজ ধারণাটি আজ যেমন
বর্তমান Romergo Builder-কে player থেকে আলাদা রাখে, তবে দুটিই একই story runtime ব্যবহার করে। Editor-এর preview এবং প্রকাশিত playthrough একই নিয়ম মেনে চলে, তাই contract drift তৈরি করা অনেক কঠিন।
Yjs সহযোগীদের মধ্যে সম্পাদনাযোগ্য project sync করে। প্রকাশনা story data ও media-এর যাচাই করা snapshot তৈরি করে, ফলে creators খেলোয়াড়দের চলমান version না বদলিয়েই draft সম্পাদনা চালিয়ে যেতে পারেন। API Hono-তে তৈরি, interface shadcn ও Radix primitive ব্যবহার করে এবং cloud layer distributed coordination, object storage ও CDN delivery দেয়।
এই shared runtime এখন browser ও PWA, Telegram এবং synchronized Discord experience-এ গল্প নিয়ে যায়। Version compatibility, offline behavior এবং multiplayer state আর page-এর পাশের side effect নয়। এগুলো স্বতন্ত্র product system।
বর্তমান architecture
একটি সম্পাদনাযোগ্য গল্প। একটি প্রকাশিত contract।
Romergo-র বর্তমান architecture-এর সাধারণ চিত্র।
1. সম্পাদনাযোগ্য project
- Builder UI: দৃশ্য · flow · media
- AI / MCP: প্রমাণীকৃত editing operation
- Realtime / Yjs: Durable Objects · shared working document
- Editor API: CAS write · draft materialization
- Draft runtime snapshot: PublishedQuestLocalizedContentV2 · D1 / R2
- Draft media: R2 object · D1 metadata
2. সংস্করণভিত্তিক প্রকাশনা
- প্রকাশনার পরীক্ষা: Runtime schema · লেখকের নিশ্চয়তা · media-এর উপস্থিতি
- অপরিবর্তনীয় প্রকাশনা vN: Runtime snapshot · copy ও remap করা media
- দৃশ্যমানতার contract: Public · unlisted · private
3. একটি execution contract
- Draft snapshot: সর্বশেষ সম্পাদনাযোগ্য অবস্থা
- প্রকাশনা vN: স্থিতিশীল player state
- Shared player-runtime: দৃশ্য · transition · condition · variable · save
- Builder preview: একই engine-এ draft চালায়
4. Playback channel
- Web / PWA: Browser player
- Telegram Mini App: Embedded player
- Discord Activity: Synchronized group play
5. Platform infrastructure
- Clerk + OAuth: পরিচয় ও MCP access
- Hono Workers: API ও MCP service
- Cloudflare D1: Project · version · metadata
- Cloudflare R2: Media · বড় runtime snapshot
- Durable Objects: Yjs room · Discord session
- খেলোয়াড়ের অগ্রগতি: D1 sync · local offline queue
নভেল এখনও কেবল ছবির সমষ্টি
মজার বিষয় হলো মূল ধারণাটি টিকে আছে। ভিজ্যুয়াল নভেল এখনও পটভূমি, চরিত্র, লেখা, পছন্দ এবং শব্দ। Romergo জটিল হয়েছে কারণ এই সহজ কেন্দ্রের চারপাশের সবকিছুকে নির্ভরযোগ্য হতে হয়েছে: collaboration, media, publishing, versioning, offline play এবং একই গল্প উপভোগের বিভিন্ন পথ।
এই বিবর্তন আমাকে একটি বিষয় শিখিয়ে থাকলে তা হলো, কেবল শেষ screen render করা code নয়, মানুষের পুরো পথটি মাপতে হবে। Player-এর পাঁচটি মৌলিক উপাদানই যথেষ্ট হতে পারে। কিন্তু একটি idea-কে সম্পূর্ণ, খেলার উপযোগী গল্পে বদলাতে সাহায্য করা product-এর একটি system দরকার।