Replace addons with conventional handles

Provide the single-loadout Scene API, SAB-backed meshes, cameras, materials, lights, workers, post effects, and tutorial playgrounds. Batch matching row growth so active GPU loadouts refresh once.

Amp-Thread-ID: https://ampcode.com/threads/T-01a01380-b478-77d0-84a0-102880a5c5ae
Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-08-20 06:39:30 +00:00
co-authored by heaust
parent 239b1d25b0
commit 9768765d74
62 changed files with 2749 additions and 798 deletions
+12
View File
@@ -77,6 +77,18 @@ export class YawnCore {
return array;
}
async createRowsBatch(rows) {
await this.ready;
if (!Array.isArray(rows) || !rows.length) throw new TypeError("ROWS");
const descriptors = await this.#request("create-rows-batch", { rows });
return descriptors.map(descriptor => {
const array = this.#arrays.get(descriptor.name)?.update(descriptor)
?? new SharedRows(this.#buffer, descriptor);
this.#arrays.set(descriptor.name, array);
return array;
});
}
async deleteRows(name) {
await this.ready;
await this.#request("delete-rows", { name });
+39
View File
@@ -1,6 +1,7 @@
use std::cell::RefCell;
use std::rc::Rc;
use serde::Deserialize;
use wasm_bindgen::prelude::*;
#[path = "render_graph/compiler.rs"]
@@ -22,6 +23,14 @@ use render::RenderLoop;
use render_data::RenderData;
use store::Store;
#[derive(Deserialize)]
struct RowRequest {
name: String,
rows: u32,
stride: u32,
format: String,
}
#[wasm_bindgen]
pub struct Core {
data: Rc<RefCell<RenderData>>,
@@ -79,6 +88,36 @@ impl Core {
Ok(serde_json::to_string(&rows).unwrap())
}
pub fn create_rows_batch(&self, source: &str) -> Result<String, JsError> {
let requests: Vec<RowRequest> =
serde_json::from_str(source).map_err(|_| JsError::new("ROWS"))?;
if requests.is_empty() {
return Err(JsError::new("ROWS"));
}
let refresh = requests
.iter()
.any(|request| self.store.borrow().uses_rows(&request.name));
let descriptors = {
let mut data = self.data.borrow_mut();
requests
.into_iter()
.map(|request| {
data.create_rows(request.name, request.rows, request.stride, request.format)
.map_err(JsError::new)
})
.collect::<Result<Vec<_>, _>>()?
};
if refresh {
if let Some(gpu) = self.gpu.borrow().as_ref() {
self.store
.borrow_mut()
.refresh(gpu, &self.data.borrow())
.map_err(|error| JsError::new(&error))?;
}
}
Ok(serde_json::to_string(&descriptors).unwrap())
}
pub fn delete_rows(&self, name: String) -> Result<(), JsError> {
if self.store.borrow().uses_rows(&name) {
return Err(JsError::new("ROWS_ACTIVE"));
+8 -1
View File
@@ -54,7 +54,14 @@ impl Store {
if !self.uses_rows(name) {
return Ok(());
}
let graph = self.active.as_ref().unwrap().graph.clone();
self.refresh(gpu, data)
}
pub fn refresh(&mut self, gpu: &Wgpu, data: &RenderData) -> Result<(), String> {
let Some(active) = self.active.as_ref() else {
return Ok(());
};
let graph = active.graph.clone();
let resources = GpuResources::activate(&graph, gpu, data)?;
self.active = Some(Loadout { graph, resources });
Ok(())
+3
View File
@@ -21,6 +21,9 @@ addEventListener("message", async ({ data: message }) => {
case "create-rows":
result = JSON.parse(core.create_rows(message.name, message.rows, message.stride, message.format));
break;
case "create-rows-batch":
result = JSON.parse(core.create_rows_batch(JSON.stringify(message.rows)));
break;
case "delete-rows":
core.delete_rows(message.name);
break;