GPU Manual Scene Language - barocss/barocss GitHub Wiki

GPU scene language: primitives, rounded boxes, rigid rotation and style rules

Manual index · CAD ↔ GPU transfer

Availability

Integrated source0 scene language and independent compiler #552. This language has its own supported syntax and semantics.

Last checked: 2026-10-06. Both packages remain private experimental. API snippets use built local ES modules. Save Node snippets at the repository root after building the relevant package. Browser snippets require their stated host/canvas context.

Author a scene

@scene demo {
  version:0; background:#101820;
  sphere #ball; box #cube;
}
sphere {radius:1;color:#e08040;}
#ball {translate:-1 0 0;}
#cube {size:1 2 1;translate:1 0 0;color:#4090e0;}

Default calls require exactly one scene with version0. Shape declarations assign unique IDs; style rules select one type or one ID. ID specificity wins over type; later declarations break ties. size is a box's full extent. GPU numbers have no mm/cm units; these are scene units.

import {compileGpu,parseScene,compileScene} from './packages/barocss-gpu/dist/index.js';
const source=`@scene demo {
  version:0; background:#101820;
  sphere #ball; box #cube;
}
sphere {radius:1;color:#e08040;}
#ball {translate:-1 0 0;}
#cube {size:1 2 1;translate:1 0 0;color:#4090e0;}`;
const compiled=compileGpu({kind:'scene',source});
if(!compiled.ok) throw new Error(compiled.diagnostics[0].message);
console.log(compiled.ir.pipeline,compiled.ir.draws.map(d=>d.id));
const scene=parseScene(source);
console.log(compileScene(scene).fragment.length);

Expected SDF pipeline with ball then cube. CPU compilation creates shaders but makes no WebGL call. Render using the renderer lifecycle page.

Fields and defaults

Field Applies to Default
background Scene only #101820
color Sphere/box; opaque #rgb/#rrggbb #e08040
radius Sphere only 1
size Box only, XYZ full extents 2 2 2
translate Both, XYZ scene coordinates 0 0 0

Vectors have exactly three whitespace-separated numbers. Whitespace/comments are accepted. Unknown IDs/properties, wrong shape properties, duplicate scene metadata and unsupported syntax fail with source ranges.

Limits and supported scope

Source≤64 KiB UTF-8; objects≤32; rules≤128; style declarations≤512. Coordinates are finite within ±1000; dimensions are positive,≤1000 and remain positive after Float32 conversion. Classes, selector lists/groups/pseudos, URLs, expressions, textures, scale, CSG and arbitrary shaders are unsupported. Tiny accepted dimensions may be below ray-hit epsilon and not visibly render. Fixed shading uses ambient .35 plus Lambert .65 with world light normalize(-.6,.8,1), gamma2.2 color conversion, and unchanged background color. The mesh path uses supplied world normals, depth LESS and no face culling; the SDF path chooses the smallest distance, with declaration order breaking equal-distance ties.

Evidence and related work

#499 scene foundation · #552 own compiler. Reference: GPU README.md, src/scene-front.ts, src/gpu-compiler.ts.

Source1 rigid rotation — prototype integrated

At local merge 917da5ad30799551865a3c8a7805ef75f5afd4e8, explicit source1 adds rotate-x, rotate-y and rotate-z to sphere/box. Each is one finite decimal literal with deg, within[-360,+360], default0. Unitless/rad/expressions reject. ID/type specificity and source order apply per axis. Right-handed column vectors rotate X then Y then Z, R=Rz*Ry*Rx, then translate. Shader queries use transpose(R)*(world-translate); rigid motion preserves distances. Sphere accepts rotation but its shape is rotationally symmetric.

import {compileGpu,parseScene,mountScene} from './packages/barocss-gpu/dist/index.js';
const source=`@scene tilted{version:1;box #block;}
#block{size:1 2 .8;rotate-x:20deg;rotate-y:35deg;rotate-z:-10deg;}`;
const result=compileGpu({kind:'scene',source,sourceVersion:1});
if(!result.ok) throw new Error(result.diagnostics[0].message);
console.log(result.ir.schemaVersion, result.execution.scene.objects[0].rotateDegrees);
const scene=parseScene(source,{sourceVersion:1});
// Browser only; canvas is a dedicated HTMLCanvasElement. Camera remains third.
// const renderer=mountScene(canvas,source,undefined,{sourceVersion:1});

Expected IR2 and[20,35,-10]. Scene1 objects own rotateDegrees; old Scene0 objects do not gain fields. Default calls retain source0/IR1; header/version mismatch rejects. Renderer source1 opt-in is the fourth argument and remains fixed during update. Mesh IR1 remains distinct. Structured Scene1 must supply bounded own rotation data.

Use local root GPU · Rotated box at /#rotated-box. Actual affected build and short Chrome WebGL2/SwiftShader smoke passed: combined-axis CPU inverse controls, non-cubic-box pixel edits, invalid input retained frame, orbit retained source, and unchanged source0 shader hashes/render. Exact receipt. Evidence prototype-570-post/index.json retains source/AST/IR/execution/camera/PNG/backend/head. Software rendering establishes functional pixels, not physical GPU speed. Broader validation is deferred.

Cylinder — prototype integrated

#573 is integrated at 532d4c9aaddf6983883375e01fe66ebd96d8292d: explicit source1 cylinder, localY radius/full height, rigid rotation and real GPU · Cylinder. Affected build and actual browser smoke passed; broader validation is deferred. Usage/defaults/version boundaries and actual evidence. Default source0 still rejects cylinder. Capsule574 is now prototype-integrated at bd7489609c0805e08134b596b378abac8616c66e; endpoint/radius usage and actual evidence.

Source1 rounded box593 — prototype integrated

Task b6e426027bee09e63c1d54f3839acc5766faece4, merge 481d946220ae2c3a98daa0c12aee3f1b9ad63f74. Completion receipt. Exact affected GPU build and one actual source/compiler/browser run passed before/after integration (35.0s/29.6s). Actual source→ranged AST→semantic cascade→Scene1→IR2→GLSL and software pixels were recorded. Broader validation deferred.

@scene rounded {
  version:1;
  rounded-box #block;
}
#block { size:2 2 2; radius:.35; color:#7cd8ca; }
import {compileGpu,parseScene,compileScene} from './packages/barocss-gpu/dist/index.js';
const source='@scene rounded{version:1;rounded-box #block;}#block{size:2 2 2;radius:.35;color:#7cd8ca;}';
const result=compileGpu({kind:'scene',source,sourceVersion:1});
if(!result.ok) throw new Error(result.diagnostics[0].message);
const scene=parseScene(source,{sourceVersion:1});
console.log(scene.objects[0].size, scene.objects[0].radius, result.ir.schemaVersion);
compileScene(scene);

size is full OUTER XYZ extent in scene units. Default size2/2/2, radius.25; require0<radius<=smallest half-extent after complete cascade and represented Float32 admission. Radius0 or an oversized radius rejects; equality is supported. Size2/radius1 produced the same recorded pixels as radius1 sphere. Existing color/translate/rotate-x/y/z and inverse rigid-rotation semantics apply. height/start/end are unsupported for rounded-box. Default source0 still rejects the new kind; old box/sphere/cylinder/capsule semantics stay strict.

Local shader distance uses boxDistance(p,size/2-radius)-radius, retaining requested outer size. It does not add radius outside an unchanged box. No implicit radius clamp/rescale. Actual centre pixel stayed material while projected box corner became background, radius.6/orbit worked, and invalid updates kept the accepted source/IR/frame. Observed software backend SwiftShader, GL0/pageerrors[]. No physical GPU performance or CAD fillet/solid certificate.

Use Rounded box example. Execute GPU reported fresh IABtab10 and preserved older intent/draft tabs; Planner inspected actual recorded rounded-box PNG. Reproduce the short checkpoint:

pnpm --filter @barocss/gpu build:library
node examples/gpu-scene/rounded-box-smoke.mjs

Source1 ring torus597 — prototype integrated

Choose GPU · Torus from the root Example menu. Native CAD data is not involved in this own GPU primitive. Task d6991ff5e899ec2b85f7799febb11b33c0d21062, local merge 232f445302210f1afaecde227a4378a23f1594ba. Actual receipt. Exact affected GPU build and one source/API/helper-distance/pixel/editor run passed pre/post0 (23.0s/20.6s); broader validation deferred. Fresh supported IABtab12 was shown and Planner inspected actual ring PNG/source/IR/pixel lineage.

Syntax and compiler use

@scene ring { version:1; torus #ring; }
#ring { major-radius:1; minor-radius:.25; color:#7cd8ca; }
import {parseScene, compileGpu} from './packages/barocss-gpu/dist/index.js';
const source='@scene ring{version:1;torus #ring;}#ring{major-radius:1;minor-radius:.25;color:#7cd8ca;}';
const scene=parseScene(source,{sourceVersion:1});
const compiled=compileGpu({kind:'scene',source,sourceVersion:1});
console.log(scene.objects[0].majorRadius,scene.objects[0].minorRadius); // 1,.25
console.log(compiled.ok); // true

Original tokens/AST/cascade/Scene1/renderIR2 and structured shader path retain the same radii and rigid rotation. Major radius measures origin-to-tube-centreline distance; minor radius measures tube radius. Defaults1/.25 in scene units. The ring lies in localXZ with localY axis. Full outer X/Z extent=2*(major+minor), full Y extent=2*minor, hole radius=major-minor. Existing color/translate/rotate-x/y/z apply; source1 explicit opt-in remains. Scene common radius/size fields are compatibility placeholders, not accepted torus properties.

Edit and diagnose

In the original GPU source editor select the Torus preset and explicit source version1, then Apply scene. Changing minor-radius from.25 to.4 widens the annulus. Cross-version Apply prepares a complete candidate renderer before replacing the accepted canvas. Malformed source, header/version mismatch or rejected radii retain the prior accepted view and camera; correct the source and apply again. Drag the gallery canvas to orbit without changing authored source.

Require finite0<minor<major and major+minor<=1000. Represented Float32 radii must remain positive/finite with minor<major and sum<=1000; collapsed ring holes are refused. The final selector cascade is admitted after type rules/ID overrides. Radius0, equal/oversized minor, extent overflow/nonfinite values and generic radius/size/height/start/end properties reject for torus. New major/minor properties reject on old primitives. Source0/default calls reject torus; old source0 fragment bytes stayed exact in the actual run. No silent clamp, horn/spindle family or version migration.

Actual evidence and limits

Generated original GLSL helper controls observed approximately.75,-.25,0,.25 distance (RGBA8 observation tolerance2/255). Actual centre/exterior stayed background, tube interior was material and .4 filled an inner-ring pixel left open by.25. Rotate-X90 with corresponding camera and orbit retained original rotation/source. Actual malformed/cross-version editor candidate failures preserved prior scene/camera/hash. GL0/pageerrors[] on software SwiftShader. These are bounded functional observations, not numerical/performance certification. Own GPU torus does not implement native CAD torus/NURBS/B-Rep/solid or substitute for596 curved CAD mesh.

pnpm --filter @barocss/gpu build:library
node examples/gpu-scene/torus-smoke.mjs

Standalone opaque Mesh material source —779 native checkpoint

Native implementation 265e6718050d73405a0629090d842ff9ea0ba928; sole Integration adoption is separate. This additive material grammar does not alter the scene-source0/1 SDF grammar above. Existing scene-expression/arbitrary-shader refusals still apply there.

@shader #wave {
  @uniform timeSeconds: float(0,2,0);
  @fragment {
    color: mix(#204080,#E08020,sin(timeSeconds*1.5707963267948966)*0.5+0.5);
  }
}

compileMeshMaterial is DOM-free source→typed material IR with UTF16 half-open diagnostics. validateMeshMaterialIR source-reconstructs imported data; lowerMeshMaterial trusted-lowers only this profile. MeshRenderer.setMaterial({material,uniforms:{timeSeconds:1}}) stages its existing GPU candidate lifecycle; .material returns an owned accepted binding; setMaterial(null) restores exact old shader/pixels. Native Surface positions/normals/UV/IDs/source/coefficients remain. No rawGLSL/eval/import/script or hidden clock.

Profile mesh-opaque-fragment-v0: one opaque color output, float uniforms, decimal/exponent/#RRGGBB literals, unary± and float+,-,*, sin/cos, mix(color,color,float), clamp(float,float,float). Source64KiBUTF8/tokens4096/uniforms16/AST256/depth16; namesASCII32/shaderID64; literal/uniformbounds±1000, intermediates±1e6, sin/cosarguments±1000, mixratio0..1. Defined target semantics clamp admitted mix ratios and final linear RGB0..1 for Float32 color bounds. Material arithmetic zeros normalize to+0; native signed-zero coefficients do not.

Hex literals decode with legacy gamma2.2 once; linear expressions receive existing light once and gamma2.2 encode once, alpha1. No CSSColor4/exact sRGB/PBR certificate. No division/color-uniform/UV/texture/vertex-deformation/graph/WGSL. Only single MeshRenderer is adopted; Scene/Primitive/Viewport/Viewer/Canvas material APIs are separate. Overlay/face/object highlight combinations explicitly refuse. Material/values restage program/buffers/frame; no uniform-only reuse/performance promise. Missing declared values use defaults; unknown/getter/nonfinite/out-of-range/forged IR fail before GL. Failures retain accepted source/material/program/native/pixels; owned resources alone are released.

Actual native source0/nonunit affine Surface flow passed compiled CPU+GPU build, Node no-DOM source/IR/lowering, one browser time0/1/2 independent linear/light/gamma pixels, original actual buffers/UV/source/-0, source/type/range/budget/IR/uniform refusals, explicit injected createProgram-null retention, exact legacy restoration and cleanup0. Injection is not physical exhaustion. First TypeScript error-helper narrowing build failure was preserved and fixed without weakening guards; first CPU/browser runs passed. Issue779 tracks native/Integration/consumer/publication separately. Broader quality/readers/packed/parent/performance remain deferred.

Qualified native Surface material — #837

Native receipt: 08735579f9f8eed532ce29a0035323755c17b27a → 1e865dc0afd9e8a9ccc0604849242a6d9a5314c9; Integration pending. PrimitiveSceneRendererV2 and PrimitiveViewport expose setMaterial(ref, binding|null) and copied materials:PrimitiveSceneMaterial[]. The exact accepted Surface reference is {modelId,geometryId}; native IDs are unchanged. Binding reuses the existing opaque material source/IR/uniform/trusted lowering contract. Null resets only that Surface. Other Surfaces/Curves retain their legacy paths. No entry/options/schema version changes or new parser/renderer.

Successful whole-scene update explicitly resets all material bindings; refused update retains state. Resize/render retain bindings. Viewport clear drops them after successful empty adoption; empty binding requests refuse. Full frame/programs/buffers restage, with no reuse/performance claim. Primitive renderers have no selection/highlight/edge-overlay API; imported overlay fields refuse and preserve accepted feedback/state. MeshRenderer's separate policy stays unchanged. Material is derived appearance, not CAD source/UV/pose/identity.

Affected GPU build passed after repairing a missing isolated local CAD dependency link; first actual native/source/API/WebGL2 flow passed. Two genuine same-native-ID planes under different qualified models plus a native Line shared one canvas/context/depth. Time0/1/2 independent linear/light/gamma RGB matched; other-object pixels and actual position/normal/index/source/UV remained unchanged. Copy/ref/Curve/IR/uniform/overlay and test-injected program allocation failures retained full accepted state. Exact legacy reset, scene replacement, viewport empty/clear/restore/resize and double-dispose seven resource classes0 passed. Injected failure is not hardware exhaustion. No Viewer/editor adoption, PBR/texture/deform/shadow/global quality or publication claim follows.

Native shared-depth particle layer — #850

Native receipt: 386a018982c5bbcc7a57282a06fb5d188801953f → a6b524a081f9fd762fe575fac83987f1ebc4d8f7; Integration pending. The actual agreed API on qualified V2/viewport is setParticleLayer(frame|null), copied particleLayer, and atomic update(input,options,particles?). ParticleLayerV0 has exact version0/contextId/sceneRevision/stepIndex/coordinateSystem/positions fields; copied dense XYZ number[]1..256/finite±1000 scene units. Original caller binary64 positions remain separate from derived Float32 buffers. GPU never converts metres/mm, simulates Physics or owns time.

Fixed opaque6px cyan circular POINTS uses the native camera/framebuffer and true LESS depth/write. Target point-size range must contain6. Incremental context/revision and monotonic/equal-step bit checks retain accepted state on refusal; reset clears or uses full update with a new context. Omitted/null third argument clears particles after successful scene replacement. Whole scene update retains #837 material-reset rule; particle-only updates retain current materials. Native-empty binding refuses; clear drops both; resize/render retain; context loss remount/dispose follow the existing lifecycle. Submitted count differs from visible/occluded samples.

Affected GPU build passed after repairing Array.length descriptor typing without weakening runtime guards. FIRST actual source/API/WebGL2 flow passed: actual integrated813256-particle states0/60/240 matched all supplied raw Float64 metre SHA hashes; one host conversion and actual Float32 upload checksums were separate. Native Surface/source/packet/parameters/position-normal-index buffers stayed unchanged. A real display occluder reduced cyan pixels3686→3195 in the same camera/depth; those are pixel counts, not individual visibility. Invalid count/NaN/tags/regression/equal-step changes/getter/camera and injected program allocation failures retained the frame. Clear/exact native restore/reset/new generation/atomic restore/resize/viewport empty/restore/double-dispose seven resource classes0 passed, GL0/errors[]. Point-size range[1,511] and three local staging API wall times270.6/4.2/3.9ms were observed; timings include native restage/upload/submit/present, exclude Physics/capture and do not measure completed GPU execution or certify performance. Viewer851/full814/CFD/exact CAD collision/publication remain separate.

Explicit complete appearance frame — #868

Native receipt: base 589d08cc0ab5bb6c9a3d2082c7d465be2fc4565e → child 0992339049963da3a5b1bffa8b1218503ff96a1d; local Integration receipt complete at af28c0e0ce73183a5402879f09d7761a0a603231 (adoption cef7990ed62398031bde2a7ad82a67816afcb684). Separate merged-head Node22 affected build and actual complete-frame source/API/WebGL2 flow passed, with atomic refusal retention, copied query, legacy reset/empty/restore and seven resource classes at0. Viewer869 adoption and publication remain separate. Viewer confirmed the contract before code. PrimitiveSceneRendererV2 and PrimitiveViewport expose updateFrame(PrimitiveSceneFrameV0) and copied frame. Exact five required own fields: version0, scene2, options, particles(null or current layer), materials(dense0..4 unique candidate Surface refs/bindings). Missing binding means default, explicit []/null clear; no implicit old namespace transfer. Current source/IR/uniform/scene/particle limits and existing validators/lowering/backend remain authority.

Native geometry/camera/material/particles validate/stage/present/adopt as one frame. CPU or GL refusal retains all accepted queries/resources/pixels. Existing update retains material reset and setters retain their behavior. Resize/render retain full state; Viewport alone accepts explicit scene2 empty with no appearance/layer; clear/dispose/context-loss policies remain. Queries follow candidate native entry order and return copies. No new parser/renderer/clock, program/buffer reuse/performance or selected-material overlay is supplied; Viewer869 must declare feedback refusal and owns its separate adoption.

Node22 affected GPU build and FIRST actual mixed source/API/WebGL2 flow passed: two original same-ID/different-model Surfaces plus native Line, independent material/light/gamma/default pixels, full camera/pose retention with copied actual850 step0 POINTS256 data, new candidate namespace refs, native/actual GL uploads and copied-query isolation. Ref/Curve/duplicate/getter/IR/uniform/camera/particle/profile and injected program failures retained full prior state; no unexpected failure/retry. Explicit clears, legacy reset, empty/clear/restore/resize and double-dispose seven resource classes0 passed, GL0/errors[]. Physics was not regenerated. This proves the GPU contract only; Viewer adoption/all-target/performance/publication remain separate.

Native scene annotation addition — #1034

The isolated native implementation #1034 now supports // annotations in source0 and explicitly opted-in source1. The exact grammar and diagnostic contract retains original source and half-open UTF-16 ranges. Comments end at LF, CR, U+2028, U+2029 or EOF; inherited diagnostic lines still count LF only. Existing /* ... */ remains supported. New commented source needs the new parser. First CPU compilation/file flow compares actual generated shader strings against block controls; no new pixel or editor adoption is claimed. Integration of the immutable parent chain is still separate.