تصور کنید یک تصویر PNG ساده، همزمان هم پیشنمایش بصری باشد و هم یک برنامه گرافیکی کامل و قابل اجرا. این ایده هسته اصلی pngine است؛ یک فرمت و محیط اجرای اعلامی (Declarative) برای WebGPU که طی ۲.۵ سال توسعه یافته تا لولهکشیهای پیچیده GPU — از جمله شیدرها و کدهای مقداردهی اولیه — را درون یک فایل تصویر استاندارد جای دهد.
WebGPU استاندارد مدرن برای گرافیکهای با کارایی بالا در وب است، اما اشتراکگذاری «لولهکشی» (Wiring) — یعنی نحوه چیدمان خط لولهها (Pipelines)، بافرها و پاسها — تا امروز فرآیندی پراکنده بوده است. توسعهدهندگان معمولاً مجبورند روی یک زبان خاص مثل TypeScript، JavaScript یا Rust و مجموعهای از قراردادها توافق کنند تا بتوانند یک خط لوله GPU را به اشتراک بگذارند. آنها باید تصمیم بگیرند که دستگیرهها (Handles) چگونه نمایش داده شوند و منتقل گردند، و اینکه آیا خط لوله بخشی از یک بازی است، یک انیمیشن کوچک است یا چیزی کاملاً متفاوت.
تصور کنید میخواهید یک افکت بصری خاص را به اشتراک بگذارید؛ معمولاً شما یک کدبیس و مجموعهای از دستورالعملها را ارسال میکنید. pngine این روند را تغییر میدهد و نمایش برنامه را به عنوان دادههای ساختاریافته در نظر میگیرد. این ابزار با استفاده از S-expressions — شبیه به یک دستورالعمل آشپزی که هر مرحله را با دقت تعریف میکند تا هر کسی بتواند آن را اجرا کند — بستری میسازد که پیکربندی GPU پیش از رسیدن به مرورگر، قابل خواندن، سریالسازی و تولید توسط ماشین باشد. این ویژگی اجازه میدهد اعتبارسنجی، بازپخش، بازرسی و فشردهسازی همگی روی یک نمایش واحد صورت بگیرد.
سازوکار لولهکشی اعلامی
به نقل از گزارش hugodaniel.com، ابزار pngine کدهای تکراری و دستوری (Procedural) جاوااسکریپت را با یک نگاشت یکبهیک از مشخصات WebGPU جایگزین میکند. در این روش، توسعهدهنده بهجای فراخوانی توابعی مانند device.createRenderPipeline در یک توالی از دستورات امری، وضعیت خط لوله را بهعنوان «داده» تعریف میکند.
برای مثال، رسم یک مثلث قرمز ساده با S-expressions تعریف میشود که شامل موارد زیر است:
- Shader-module: تعریف کد شیدر.
- Render-pipeline: تعیین چیدمان (Layout) بهصورت خودکار (
layout auto). - Render-pass: مدیریت مقدار پاکسازی (
clear-value [0 0 0 0])، عملیات بارگذاری (load-op clear) و عملیات ذخیرهسازی (store-op store). - Frame: اجرای نهایی پاس گرافیکی که عملیات رسم را انجام میدهد.
این رویکرد اعلامی دقیقاً بازتابدهنده مشخصات WebGPU است و ماهیت «گلآلود و پیچیده» لولهکشیهای سنتی گرافیک را از بین میبرد. این روش مزایای فنی مشخصی دارد:
- اعتبارسنجی استاتیک: سیستم با استفاده از بازتاب (Reflection) WGSL و بررسی مشخصات، خطاها را هنگام تایپ شناسایی میکند. این قابلیت توسط یک پروتکل سرور زبان (LSP) اختصاصی پشتیبانی میشود و باعث میشود خطاها و هشدارها بدون نیاز به یک محیط زنده WebGPU تولید شوند.
- پشتیبانی چندپلتفرمی: این فرمت علاوه بر وب، با wgpu در زبان Rust سازگار است و پلیرهایی برای اندروید و iOS دارد.
- استقلال از ترتیب: بیشتر لولهکشیهای WebGPU استاتیک هستند. با انتقال به فضای اعلامی، ترتیب تعریف المانها دیگر اهمیتی ندارد و تنها توالی نهایی که در بلوک
:performیک فریم تعریف شده است، تعیینکننده است.
جزئیات پیادهسازی فنی
برای درک این تغییر، میتوان فرمت S-expression را با کد جاوااسکریپت معادل آن مقایسه کرد. در یک محیط استاندارد JS، توسعهدهنده باید بهصورت دستی یک ShaderModule بسازد، سپس یک RenderPipeline ایجاد کند، سپس یک CommandEncoder تعریف نماید و در نهایت یک RenderPass بسازد تا کار را به device.queue ارسال کند.
در pngine، این مراحل در یک ساختار دادهای ادغام شدهاند:
- ماژولهای شیدر: بهصورت
(shader-module :name code :code """)تعریف میشوند که شامل منبع WGSL است. در مثال مثلث، این شامل تابع@vertexبه نامvertexMainو تابع@fragmentبه نامfragMainاست که رنگ قرمزvec4(1.0, 0.0, 0.0, 1.0)را برمیگرداند. - خط لولهها: بهصورت
(render-pipeline :name pipeline :layout auto ...)تعریف میشوند که ماژولهای ورتکس و فرگمنت را به هم متصل میکند. این بخش نقاط ورودی (:entry) و ماژولها را برای هر دو مرحله مشخص کرده و فرمت هدف را رویpreferred-canvas-formatتنظیم میکند. - پاسها: بهصورت
(render-pass :name trianglePass ...)تعریف میشوند که اتصالات رنگی را مدیریت میکند؛ بهویژه ازcontext-current-textureبرای نمایش (View) استفاده کرده و فراخوانی رسم را از طریق(draw :vertex-count 3)مدیریت میکند. - فریمها: بهصورت
(frame :name main :perform [trianglePass])تعریف میشوند تا توالی اجرا را سازماندهی کنند.
این ساختار توسط SJON پشتیبانی میشود که اجازه میدهد زبانهای دامنه-ویژه (DSL) بهصورت خودکار اعتبارسنجی شوند و به روشی سازگار و ترکیبپذیر تحویل داده شوند. نکته مهم این است که pngine زبان WGSL را گسترش نمیدهد؛ بلکه با WGSL به عنوان یک DSL مستقل و خالص برخورد کرده و تنها «لولهکشی» اطراف آن را مدیریت میکند.
توالی و اجرا
در حالی که لولهکشیها اعلامی هستند، اما اجرا همچنان توالیمحور است. در pngine، «فریم» یکی از معدود جاهایی است که ترتیب در آن اهمیت دارد. هر نام در لیست :perform به یک پاس اشاره میکند که در جای دیگری از فایل تعریف شده است.
یک توالی نمونه ممکن است به این شکل باشد:
update-uniforms(بهروزرسانی یکنواختها)update-textures(بهروزرسانی بافتها)sdf-pass(پاس SDF)post-processing(پسپردازش)
این ساختار، «چیستی» (پیکربندی خط لوله و بافر) را از «چه زمانی» (ترتیب اجرا) جدا میکند و به توسعهدهندگان اجازه میدهد بلوکها را بدون بههم ریختن وضعیت GPU جابهجا کنند.
از S-expressions تا فایل PNG
متمایزترین ویژگی این پروژه، خط لوله خروجی آن است. S-expressions به یک نمایش باینری کامپایل میشوند که توسط یک محیط اجرای بسیار کوچک (Runtime) تفسیر میگردد. سپس این محیط اجرا و دادههای برنامه در یک بخش (Chunk) اضافی از فایل PNG ذخیره میشوند.
وقتی کاربر فایل را باز میکند، تصویر PNG بهعنوان پوستر نمایش داده میشود. سپس یک پلیر کوچک، بخش باینری را خوانده و کد WebGPU را اجرا میکند. این فایلها بهطور خودکار اجرا نمیشوند و صرفاً حاوی بایتکدها هستند و نیاز به پلیر دارند تا در صورت درخواست اجرا شوند. این امر توزیع شبیهسازیهای پیچیده GPU را بهعنوان فایلهای تک و قابل حمل ممکن میسازد.
علاوه بر PNG، این ابزار میتواند خروجیهای زیر را تولید کند:
- یک فایل تک
.html - یک بسته
.zip - بایتکد باینری خام
نمونههای عملکرد در دنیای واقعی
برای اثبات قدرت این «بستر»، نویسنده چندین نمونه با پیچیدگی بالا ارائه کرده است که گلوگاههای سنتی CPU را دور میزنند:
- فوارۀ ذرات GPU: سیستمی با ۲۰۴۸ ذره همراه با بافر پولینگ (Buffer Pooling). این شبیهسازی گرانش، گسیل از نازل و بازتولید سرعت تصادفی را کاملاً روی GPU مدیریت میکند. در این مثال، بافر ویژگیها (Attribute Buffer) همان شیئی است که شبیهسازی در آن مینویسد، به این معنی که دادهها هرگز نیازی به لمس CPU ندارند. مستندات کامل این نمونه در صفحه مربوط به فوارۀ ذرات در دسترس است.
- جنگل نمونهبرداری شده (Instanced Forest): صحنهای با ۴۰۰ درخت کم-پلیگون. هندسه یک درخت (۱۲ ورتکس) مستقیماً در سند بهصورت یک فرم
(data ...)تعریف شده که شامل یک چهارضلعی برای تنه و دو مثلث برای شاخ و برگ است. سپس یک پاس محاسباتی (Compute pass)، ۴۰۰ رکورد نمونه برای جایگذاری، مقیاس، چرخش و رنگ را پر میکند. هر دو، بافرهای ورتکس در یک خط لوله هستند — یکی برای هر ورتکس و دیگری برای هر نمونه (Instance). کل جنگل تنها با یک دستور رسم رندر میشود:(draw :vertex-count 12 :instance-count NUM_TREES).
فلسفه «بستر» (Substrate)
هدف pngine تبدیل شدن به محیطی شبیه به Shadertoy یا compute.toys نیست. در حالی که آن ابزارها برای یادگیری WGSL یا استفاده از ماکروها برای پیکربندی خط لوله فوقالعاده هستند، pngine بهعنوان یک زیربنای سطح پایین طراحی شده است.
با حفظ خلوص کدهای شیدر WGSL و انتزاع لولهکشیها، این ابزار اجازه میدهد سایر ابزارها — مانند گرافهای صحنه (Scene Graphs) یا ویرایشگرهای گرهای متریال — روی یک فرمت دادهای سازگار و معتبر بنا شوند. نویسنده این را به عنوان یک «بستر در حال رشد» میبیند، شبیه به خاک، که تکیهگاه ساختاری برای ریشهها فراهم میکند، آب را نگه میدارد و در عین حال تبادل اکسیژن را ممکن میسازد و مواد مغذی را برای آزمایشهای سطح بالاتر فراهم میکند.
این تغییر از کد دستوری به دادههای ساختاریافته، امکان فشردهسازی خودکار و بازپخش را فراهم میکند. چون برنامه صرفاً «داده» است، یک ماشین میتواند لولهکشی GPU را بدون نیاز به اجرای کد، بازرسی یا تولید کند. این امر توسط SJON ممکن شده است که راهی برای ساخت DSLهای اعتبارسنجی شده و ترکیبپذیر فراهم کرد.
برای توسعهدهنده، این یعنی سطح مشترک برای اشتراکگذاری بهشدت کاهش مییابد. دیگر نیازی نیست نگران باشید که گیرنده از جاوااسکریپت استفاده میکند یا Rust؛ شما صرفاً یک PNG را تحویل میدهید که تمام وضعیت GPU را در خود دارد. این رویکرد بهطور موثری خط لوله GPU را به جای یک «نرمافزار»، به عنوان یک «محتوا» (Asset) در نظر میگیرد و توسعه WebGPU را به روشی نزدیک میکند که هنرمندان داراییهای خود را به اشتراک میگذارند؛ جایی که خودِ دارایی حاوی منطق لازم برای رندر صحیح در محیطهای مختلف است. این کد تحت مجوز CC0 منتشر شده و در گیتهاب برای بحث و گزارش خطاها در دسترس است و نسخههای نهایی از یک مخزن خودمیزبان (Self-hosted) ارائه میشوند.
گام بعدی شما
- اگر با WebGPU کار میکنید، مستندات pngine را در گیتهاب بررسی کنید تا لولهکشیهای تکراری خود را کاهش دهید.
- سعی کنید یک افکت ساده را با S-expressions تعریف کرده و آن را به فرمت PNG صادر کنید تا قابلیت حمل آن را بسنجید.
- برای درک بهتر نحوه مدیریت بافرها در GPU، نمونه «فوارۀ ذرات» این پروژه را تحلیل کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما درباره تراشههای Blackwell مراجعه کنید.




گفتگو