QuickTile Studio: پہلی کمٹ سے Asset Store پیکیج تک
QuickTile Studio ایک Unity ایڈیٹر ٹول ہے جو کسی material کو ایک seamless، ٹائل ہونے والے ٹیکسچر میں بدلتا ہے اور اسے sprite کے لیے تیار PNG کی صورت میں ایکسپورٹ کرتا ہے۔ یہ ورژن 1.0.0 کے طور پر Unity Asset Store پر موجود ہے۔
ریپوزٹری 13 جنوری 2026 کو بنائی گئی۔ 18 جنوری تک اس میں نئے سرے سے ترتیب دیا گیا پیکیج، ایک ڈیمو سین، ایک changelog اور ایک PDF مینول موجود تھا۔ git ہسٹری اور اسٹور لسٹنگ سے:
| ریپوزٹری بنی | 2026-01-13 (UTC) |
| پیکیج کی تنظیمِ نو اور PDF مینول | 2026-01-18 |
| کمٹس | 35، ابتدائی کمٹ سمیت |
| شپ کیا گیا C# | 20 فائلیں، 3,017 سطریں (13 رن ٹائم فائلیں، 7 ایڈیٹر فائلیں) |
| ڈیمو ٹیکسچرز | 43.9 MB سے کم ہو کر 4.6 MB |
| اسٹور لسٹنگ | 1.0.0، Unity 6000.3.2f1، Built-in اور URP کے ساتھ مطابقت، HDRP نہیں، 5.3 MB، ریلیز کی تاریخ 20 فروری 2026 |
یہ کہاں سے آیا
CandyRush کو زمین کے ایسے ٹیکسچرز چاہییں جو دہرائے جائیں مگر جوڑ نظر نہ آئیں۔ 29 اکتوبر 2025 کو گیم کی ریپوزٹری میں ایک "Seamless Tiling Preview" کمپوننٹ شامل ہوا: 2x2 گرڈ میں چار quads جن کے UVs ایک دوسرے کا عکس تھے، ان کو فریم کرتا ایک orthographic کیمرہ، اور ایک Randomize بٹن۔ یہ دو پل ریکوئسٹس کے ذریعے بڑھا۔ #113 (14 نومبر) نے rotation، آٹھ lock flags، material کی tiling اور offset کنٹرولز، اور sprite میں capture شامل کیا جس میں importer کو Repeat wrap پر سیٹ کیا جاتا ہے۔ #150 (13 دسمبر) نے سلائیڈرز کی فوری اپ ڈیٹ، ہر capture کے ساتھ محفوظ ہونے والی JSON سیٹنگز فائل، اور نامیاتی دھبوں کے لیے ایک دوسرا ٹول شامل کیا۔ یہ کمٹس ایک AI کوڈنگ ایجنٹ نے میری ہدایت پر لکھیں؛ تقاضے میں نے طے کیے اور نتائج کا جائزہ میں نے لیا۔
جنوری تک اس ٹول میں CandyRush سے مخصوص کچھ بھی باقی نہیں تھا۔ کسی اندرونی ٹول کے پروڈکٹ بن سکنے کو میں اسی ٹیسٹ سے پرکھتا ہوں: گیم کو ہٹا دیں، اور دیکھیں کہ کیا ٹول اپنے طور پر بھی معنی رکھتا ہے۔ اس نے رکھا۔
تکنیک: پہلے عکس، پھر 2x2 کا capture
عکس بنانا seamless ٹائلز کے لیے امیج ایڈیٹر کی ترکیب ہے، یہاں UVs کے ذریعے۔ چار quads ایک ہی material استعمال کرتے ہیں:
- اوپر بائیں: عام UVs
- اوپر دائیں: افقی طور پر پلٹا ہوا
- نیچے بائیں: عمودی طور پر پلٹا ہوا
- نیچے دائیں: دونوں محوروں پر پلٹا ہوا
ہر اندرونی کنارہ اپنے ہی عکس سے ملتا ہے، اس لیے اس کے آر پار پکسلز یکساں ہوتے ہیں۔
بیرونی کنارے بھی ملتے ہیں: اوپر بائیں quad کا بایاں کنارہ اور اوپر دائیں quad کا دایاں
کنارہ دونوں source کے ایک ہی کالم کو sample کرتے ہیں۔ چنانچہ capture کیا گیا 2x2 بلاک
پیٹرن کا ایک مکمل دور (period) ہے، اور یہ عام Repeat wrap mode کے ساتھ ٹائل ہو جاتا
ہے۔ اسی لیے capture کے وقت PNG کو wrapMode = Repeat کے ساتھ لکھا جاتا ہے اور مزید کسی
پروسیسنگ کی ضرورت نہیں پڑتی۔
اس کا مرکزی حصہ، QuickTileGenerator سے:
// Base UV corners (vertex order: BL, BR, TL, TR)
Vector2 bl = new(0, 0), br = new(1, 0), tl = new(0, 1), tr = new(1, 1);
// Apply mirroring by swapping UV corners
if (sx < 0) { (bl, br) = (br, bl); (tl, tr) = (tr, tl); }
if (sy < 0) { (bl, tl) = (tl, bl); (br, tr) = (tr, br); }
// Apply UV rotation around center (0.5, 0.5)
if (rot != 0f)
{
bl = RotateUV(bl, rot); br = RotateUV(br, rot);
tl = RotateUV(tl, rot); tr = RotateUV(tr, rot);
}
دو فیصلے جو ہسٹری میں درج ہیں
پروڈکٹ 2x2 بلاک ہے، مرکزی quad نہیں
پہلے دن ایک مختصر proof of concept بھی بنا (کمٹ میسج: "PoC my brain hurts")۔ اس میں ایک مرکزی quad کو سچائی کا واحد ماخذ مانا گیا، اس کے گرد عکسی پڑوسیوں کے حلقے تھے (3x3، 5x5، 7x7)، اور کیمرہ صرف مرکزی quad کو فریم کرتا تھا۔
پریویو seamless دکھتا تھا۔ capture ایسا نہ ہوتا: ایک اکیلے quad کے کنارے صرف اس لیے ملتے ہیں کہ اس کے پڑوسی پلٹے ہوئے ہیں۔ اکیلے capture کیا جائے تو چاروں طرف جوڑ ہوتے ہیں۔ تقریباً چھ گھنٹے بعد ایک کمٹ میسج کہتا ہے: "2x2 necessary for seamless tiling. at some point I knew this and forgot." (seamless tiling کے لیے 2x2 ضروری ہے۔ کبھی مجھے یہ معلوم تھا اور میں بھول گیا۔) CandyRush والا ٹول اکتوبر سے 2x2 ہی استعمال کر رہا تھا۔ proof of concept کو 15 جنوری کو حذف کر دیا گیا۔
میرا سبق: اس خاصیت کی تصدیق کریں جس پر آؤٹ پٹ منحصر ہے، نہ کہ اس کی جو پریویو دکھاتا ہے۔
جیومیٹری نہیں، sampling کو گھمائیں
CandyRush #113 میں rotation ایک parent GameObject پر لگائی جاتی تھی، جو پریویو میں ہر زاویے پر عکسی تشاکل برقرار رکھتی ہے۔ لیکن ایک مقررہ، محوروں کے متوازی capture کیمرے کے نیچے، گھومی ہوئی جیومیٹری کا مطلب ہے کہ capture کیا گیا مربع عموماً پیٹرن کا ایک دور نہیں رہتا۔
QuickTile Studio اس کی بجائے عکس بنانے کے بعد ہر quad کے مرکز کے گرد UVs کو گھماتا ہے۔ مشترک کنارے اب بھی انہی UV نقاط کو sample کرتے ہیں، اور 2x2 دور ہر زاویے پر capture مربع کے متوازی رہتا ہے۔ کوڈ کا تبصرہ یہ تقاضا براہِ راست بیان کرتا ہے: rotation کو "baked into texture sampling rather than world-space, which is required for correct tiling across independent chunks" (world-space کی بجائے ٹیکسچر sampling میں شامل کیا جاتا ہے، جو الگ الگ chunks میں درست tiling کے لیے ضروری ہے)۔
"ٹھیک لگنے" کو اسکور میں بدلنا
عکس اس بات کی ضمانت دیتا ہے کہ پکسلز مل جائیں۔ یہ اس بات کی ضمانت نہیں دیتا کہ نتیجہ اچھا لگے۔ جہاں بھی کوئی نمایاں چیز خود میں منعکس ہوتی ہے، آنکھ fold لائنیں، یعنی 2x2 کا مرکزی صلیب، ڈھونڈ لیتی ہے۔ پانچ مسلسل پیرامیٹرز (tiling X اور Y، offset X اور Y، rotation) اور materials کی ایک فہرست کے ساتھ، اس وقت تک Randomize دبانا جب تک کچھ ٹھیک نہ لگے، قابلِ توسیع طریقہ نہیں۔
اس لیے پیکیج میں دو اسکینرز ہیں۔ Random Sampling پیرامیٹرز کی پوری رینج کو کھنگالتا ہے۔ Guided Refinement موجودہ اقدار کے گرد ایک چھوٹے دائرے میں تلاش کرتا ہے: اگر وہ دائرہ evaluation بجٹ میں سما جائے تو odometer ترتیب میں مکمل طور پر، ورنہ random sampling سے۔
ہر امیدوار ایک بار render ہوتا ہے اور تین heuristics اسے اسکور کرتے ہیں، سب fold لائنوں کو دیکھتے ہیں:
| Heuristic | یہ کیا ناپتا ہے |
|---|---|
| Fold Line Variance | fold لائنوں کے ساتھ ساتھ contrast |
| Fold Gradient | folds کے عمودی رخ پر روشنی کا gradient |
| Fold Edge Detection | folds کے گرد ایک پٹی میں edges کی شدت |
وہ تفصیلات جو اسے ایڈیٹر میں قابلِ استعمال بناتی ہیں:
- دہرانے کے قابل۔ امیدوار بنانے والا ایک seed لیتا ہے (ڈیفالٹ 12345)، اس لیے ایک جیسی اسکین سیٹنگز ایک جیسے امیدوار پیدا کرتی ہیں۔
- ایڈیٹر رکتا نہیں۔ اسکین ایک
IEnumerableہے جسےEditorApplication.updateسے آگے بڑھایا جاتا ہے، ہر tick میں پانچ evaluations۔ ایڈیٹر متحرک رہتا ہے، اسکین کے دوران Cancel کام کرتا ہے، اور ختم یا منسوخ ہونے پر generator کے اصل پیرامیٹرز بحال ہو جاتے ہیں۔ - ایک render، کئی اسکور۔ ہر امیدوار اسکین ریزولوشن (ڈیفالٹ 256 px) پر render ہوتا ہے، اور ہر فعال heuristic انہی پکسلز کو اسکور کرتا ہے۔ ہر heuristic کی اپنی top-K فہرست رکھی جاتی ہے، اس لیے ایک ہی اسکین میں heuristics کا موازنہ ہو سکتا ہے۔
- کچھ ضائع نہیں ہوتا۔ قبولیت کی حد (ڈیفالٹ 0.7) سے اوپر کے امیدوار JSON کے طور پر محفوظ ہوتے ہیں، اور چاہیں تو تصویر بھی۔
- ہموار playback۔ Guided Refinement میں sample کیے گئے امیدواروں کو اس طرح ترتیب دیا جاتا ہے کہ inspector کا سب سے اوپر والا سلائیڈر سب سے کم بدلے۔ اسکین چلتا دیکھیں تو سلائیڈرز اچھلنے کی بجائے ہموار انداز میں سرکتے ہیں۔
- قابلِ توسیع۔ Heuristics reflection کے ذریعے دریافت ہوتے ہیں، اس لیے نیا شامل کرنا صرف ایک کلاس لکھنا ہے:
[TileHeuristic(DefaultEnabled = true, Order = 3)]
public sealed class FoldEdgeDetectionHeuristic : ITileQualityHeuristic
{
public string Name => "Fold Edge Detection";
public TileScanScore Evaluate(Color32[] px, int w, int h) { /* ... */ }
}
اسکیننگ کی منطق رن ٹائم اسمبلی میں ہے اور ونڈوز ایڈیٹر اسمبلی میں، ہر ایک کی اپنی
.asmdef کے ساتھ، اس لیے اسکورنگ کوڈ کا UnityEditor پر کوئی انحصار نہیں۔
حدود کے بارے میں صاف بات: یہ heuristics ادراک کے متبادل پیمانے (proxies) ہیں۔ میرے پاس کوئی ناپی ہوئی تحقیق نہیں کہ یہ انسانی رائے سے کتنا متفق ہیں۔ ٹول بھی انہیں اسی طرح پیش کرتا ہے: یہ امیدواروں کی درجہ بندی کرتے ہیں تاکہ کوئی انسان ان کا جائزہ لے۔
شپ کرنے کے لیے میں نے کیا کاٹا
پیکیج تک پہنچنے کا تیز ترین راستہ چیزیں نکالنا تھا:
- دھبے بنانے والا generator۔ یہ پہلی کمٹ میں ساتھ آیا (794 سطری
FeatureGenerator) اور اسی دن نکال دیا گیا۔ یہ ایک الگ پروڈکٹ تھا۔ - ہوسٹ کیا گیا WebGL ورژن۔ میری سائٹ پر ایک براؤزر ڈیمو پر غور ہوا، اسے ایک عارضی
نوٹس فائل میں درج کیا گیا، اور مؤخر کر دیا گیا۔ 15 جنوری کو عارضی نوٹس کی جگہ ایک
TODO.mdنے لے لی۔ - URP پر لازمی انحصار۔ پیکیج ڈیفالٹ طور پر Built-in render pipeline استعمال کرتا
ہے، اور URP materials ایک شامل
.unitypackageکی صورت میں آتے ہیں جسے URP صارفین import کرتے ہیں۔ ایک ہی پیکیج دونوں pipelines کا احاطہ کرتا ہے، کسی ایک پر انحصار مسلط کیے بغیر۔ - خود generator کا حجم۔ پہلی کمٹ والا generator 697 سطروں کا تھا؛ شپ ہونے والا
QuickTileGenerator226 سطروں کا ہے۔
پیکیجنگ، 14 تا 18 جنوری
آخری مرحلہ فیچرز کا نہیں، پروڈکٹ کا کام تھا:
- 14 جنوری کو "to prep for asset store" (Asset Store کی تیاری کے لیے) نام کی تبدیلی
- فوٹو ریئلسٹک اور اسٹائلائزڈ material سیٹس کے ساتھ ایک ڈیمو سین
- ایک ہی
Assets/QuickTileStudioفولڈر میں تنظیمِ نو،IrsikSoftware.QuickTileStudionamespace کے تحت الگ Runtime اور Editor اسمبلیوں کے ساتھ (111 فائلیں متاثر) - ڈیمو ٹیکسچرز دوبارہ ایکسپورٹ ہو کر 43.9 MB سے 4.6 MB، تقریباً 90% چھوٹے؛ پیکیج کا زیادہ تر وزن کوڈ کا نہیں، ڈیمو assets کا تھا
- Keep a Changelog فارمیٹ میں ایک changelog اور ایک مینول، جو 18 جنوری کو PDF میں ایکسپورٹ ہوا
اسٹور لسٹنگ ورژن 1.0.0 اور 20 فروری 2026 کی ریلیز تاریخ کے ساتھ لائیو ہوئی۔
ایک متعلقہ چھوٹا ٹول: LogSmith
اسی مہینے میں نے LogSmith کی پہلی عوامی ریلیزز ٹیگ کیں۔ یہ Unity کے لیے ایک logging پیکیج ہے جو UPM git URL کے ذریعے انسٹال ہوتا ہے۔
0.1.0 کو 3 جنوری کو 02:08 UTC پر ٹیگ کیا گیا۔ 54 منٹ بعد 0.2.0 ایک سوچی سمجھی breaking
change کے طور پر آیا: static entry point کا نام LogSmith سے بدل کر Log رکھا گیا۔ ایک
کلاس جس کا نام اس کے namespace جیسا ہو، ناموں کے ٹکراؤ کی صورت میں کال کرنے والوں کو
LogSmith.LogSmith لکھنے پر مجبور کرتی ہے۔ ریلیز کے ساتھ find-and-replace کی ایک
migration جدول تھی:
LogSmith.GetLogger -> Log.GetLogger
LogSmith.Logger -> Log.Logger
LogSmith.Router -> Log.Router
کسی breaking rename کا سب سے سستا وقت وہ ہے جب ابھی کوئی اس نام پر منحصر نہ ہو۔
جو بات عمومی طور پر لاگو ہوتی ہے
اندرونی ٹول کو اس کے میزبان کو ہٹا کر پرکھیں۔ اگر گیم کے بغیر بھی وہ معنی رکھتا ہے تو وہ پروڈکٹ بن سکتا ہے۔
آؤٹ پٹ کے invariant کی تصدیق کریں، پریویو کے نہیں۔ مرکزی quad کا پریویو seamless دکھتا تھا مگر capture میں جوڑ آتے۔ اہم خاصیت 2x2 دور ہے۔
جس چیز کی ضمانت بناوٹ نہیں دیتی اسے خودکار بنائیں، اور proxies کو proxies ہی کہیں۔ عکس پکسلز کے تسلسل کا مسئلہ حل کرتا ہے۔ اسکینرز ادراک کا معاملہ دیکھتے ہیں، اور فیصلہ کرنے کا دعویٰ کرنے کی بجائے کسی انسان کے لیے امیدواروں کی درجہ بندی کرتے ہیں۔
دائرۂ کار جلد کاٹیں۔ دوسرا generator، WebGL ڈیمو اور render pipeline کا انحصار، سب انتظار کرتے رہے، اور پیکیج شپ ہو گیا۔