Installs into .claude/skills of the current project.
Sponsors
SSkills DirectorySkills Directory
Is that skill safe to install?
SSkills DirectorySkills Directory
Know which skills are safe — weekly.
Are you the author of Web 3d Graphics Expert?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/roedyrustam-web-3d-graphics-expert-vibes-plug)
---
name: web-3d-graphics-expert
description: "WebGPU & WebGL 3D graphics in browser with Three.js, Babylon, and R3F / Grafis 3D WebGPU & WebGL di browser dengan Three.js, Babylon, dan R3F."
author: "Roedy Rustam"
version: "4.8.0"
---
# Web 3D Graphics & Spatial Reasoning Expert (WebGPU, Three.js, Babylon.js & 3Dviz)
[English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
---
<a name="english"></a>
## English
### Orchestration & Integration
Connects and orchestrates with relevant domain skills:
- `senior-frontend` — Integrating React Three Fiber (R3F) in React 19 / Next.js 15.
- `vue-frontend-expert` — Integrating TresJS in Vue 3 / Nuxt 3.
- `svelte-sveltekit-expert` — Integrating Threlte in Svelte 5 (Runes).
- `web-game-engine-expert` — Physics simulations (Rapier, Jolt, Havok), game loops, and ECS.
- `glsl-shader-expert` — Shading languages, WGSL compute shaders, and TSL nodes.
- `webxr-ar-vr-expert` — WebXR immersive VR/AR experiences.
- `data-visualization-expert` — 3D scientific data visualization and spatial explainers.
- `ui-ux-pro-max` — Spatial UI design systems, canvas viewport ergonomics, and HUD controls.
- `visual-ui-auditor` — Multimodal vision auditing of 3D canvases, frame rates, and lighting fidelity.
- `anti-slop` — 3D visual anti-slop, eliminating generic glowing orbs and proxy meshes.
- `performance-web-vitals` — Minimizing Total Blocking Time (TBT), asset streaming, and bundle sizing.
### Description
Production-grade guidance for architecting high-fidelity, high-framerate 3D experiences in the browser combined with grounded spatial reasoning (3Dviz Protocol). Covers the modern **WebGPU-first** paradigm with automatic WebGL2 fallbacks, **Three.js (r170+) WebGPURenderer** and **TSL (Three Shading Language)**, **Babylon.js WebGPUEngine** with Snapshot Rendering, **PlayCanvas Engine** for ultra-lightweight mobile delivery, and rigorous **object craft across 3 scales** (silhouette, construction, surface).
### Trigger Conditions
Activate this skill when:
- Initializing a WebGPU or WebGL 3D scene, explainer, or interactive model.
- Using `three` (`three/webgpu`), `@react-three/fiber`, `@babylonjs/core`, `playcanvas`, `@tresjs/core`, or `@threlte/core`.
- Designing expressive 3D models, scientific visualizations, or spatial puzzles from scratch.
- Authoring custom geometry, shaders in TSL/WGSL, or procedural meshes.
- Diagnosing object craft weaknesses: accidental seams, pinching highlights, floating geometry, or proxy meshes disguised with high-res textures.
- Implementing physical collision bounds, fixed-timestep physics, or continuous collision detection.
- Compressing 3D assets (`.glb`) with KTX2 Basis Universal and Meshopt.
- Eliminating draw call bottlenecks, FPS drops, or VRAM memory leaks.
---
## 1. The 10-Step Spatial Reasoning & Construction Workflow
A runnable 3D scene requires disciplined spatial judgment. Follow these 10 decisions:
```
STEP 1 STEP 2 STEP 3 STEP 4
Visual Intent ───► Object Reasoning ───► Grounded Truth ───► Construction Route
(Direction) (The 3 Scales) (Scientific Claim) (Kit / Custom / Scan)
│
▼
STEP 5 STEP 6 STEP 7 STEP 8
Join Continuity ───► Material & Light ───► Physical Bounds ───► Real Frame Inspection
(Skin / Layers) (PBR Identity) (Colliders & Time) (Multi-Angle Capture)
│
▼
STEP 9 STEP 10
Visual Review ───► Honest Reporting
(Anti-Slop 3D) (Limitations & State)
```
1. **Intent & Visual Direction**: Identify what the viewer should understand, feel, or do. Decide viewing distance (overview vs. inspection vs. macro close-up). Establish how silhouette, material, lighting, camera, and motion coordinate together.
2. **Object Reasoning (The 3 Scales)**: Before selecting a template, define the silhouette, proportions, connections, surface identity, and behavior that make the hero object convincing. Solve the hardest or most distinctive object first.
3. **Grounded Representation & Scientific Truth**: Choose whether the scene is an illustration, discrete state machine, physical simulation, or recorded playback. For academic/scientific subjects, verify the chain: **Claim → Mathematical Model → Rendered Visual**. An aesthetic mesh does not certify a scientific claim.
4. **Construction Routing per Object**: Choose the right construction route (see Routing Table below) based on requirements rather than habit.
5. **Join Continuity & Topology**: At junctions where parts attach, decide whether the object requires a continuous skin, an overlapping layered covering, or separate articulated mechanical parts.
6. **Material & Lighting Direction**: Build distinct PBR responses (soft tissue, satin, brushed metal, stone, glass, diagrammatic hue). Direct lighting to reveal form: avoid clipped highlights, crushed shadows, and muddy reflections.
7. **Physical Interaction & Spatial Constraints**: Ensure colliders follow visible meshes (including roofs, overhangs, wings, and swept envelopes). Decouple simulation steps from render frames using fixed-timestep accumulators (`accumulatedTime`).
8. **Real Output Inspection**: Never describe an unobserved frame. Inspect overview, oblique angles, meaningful close-ups, and interactive states in an actual browser viewport.
9. **Visual Review & 3D Anti-Slop**: Evaluate against the 16-point 3D visual review checklist. Fix structural shape defects before adding superficial textures or post-processing bloom.
10. **Honest Reporting**: Clearly separate what was mathematically modeled, visually observed, numerically verified, and what remains an artistic simplification.
---
## 2. Construction Routing Table
| Route | When to Choose | What to Preserve |
| :--- | :--- | :--- |
| **Reuse Kit Directly** | Shape, structure, behavior, and finish perfectly match the project brief. | Inspect at intended viewing distance; a well-crafted kit can serve as a hero. |
| **Adapt Kit or Compose Parts** | Common construction is useful, but silhouette, scale, or articulation differs. | Change silhouette, proportions, joins, and materials; recoloring alone is insufficient. |
| **Author Custom Geometry / Rigs** | Distinctive hero, analytical form, scientific mechanism, or unique organic creature. | Reuse low-level mathematical operations and helpers; custom does not mean rebuilding basic infrastructure. |
| **External Authored Asset / Scan** | Real-world scanned CAD, photogrammetry, or museum-grade model fits better than procedural recreation. | Verify provenance, license rights, physical scale (1 unit = 1 meter), registration, and clean topology. |
| **Hybrid Combination** | Different elements require different methods (e.g., procedural terrain + scanned hero + particle effects). | Keep visual style, lighting scale, state ownership, and interaction interfaces coherent. |
---
## 3. Object Craft: Form, Material & Continuity Across 3 Scales
Adding more scattered objects never fixes weak modeling of the primary subject. Craft must be resolved across three distinct visual scales:
```
┌────────────────────────────────────────────────────────────────────────┐
│ THE 3 SCALES OF OBJECT CRAFT │
├───────────────────┬────────────────────────────┬───────────────────────┤
│ SILHOUETTE │ CONSTRUCTION │ SURFACE │
│ Proportions & Mass│ Thickness, Joints, Joins │ Texture Grain & Seams │
│ (Readable in B&W) │ (Mechanical / Biological) │ (Viewing Scale Only)│
└───────────────────┴────────────────────────────┴───────────────────────┘
```
### Scale 1: Silhouette (The Outline Test)
- **Rule**: An object must be immediately recognizable by its silhouette alone without relying on surface color or lighting.
- A windmill, inn, and observatory must remain distinguishable in pure black-and-white. Distinct creature species require distinct anatomical skeletal proportions, not recolored copies of the same base mesh.
- Model silhouette-changing features as **actual geometry**, not normal maps or bump textures.
### Scale 2: Construction & Join Continuity
When attached volumes look like unrelated lumps, diagnose the join relationship:
| Observed Weakness | Root Cause | Sovereign Intervention |
| :--- | :--- | :--- |
| **Accidental seams or bulging seams** | Separate meshes intersecting clumsily on what should be one organic skin. | Author shared continuous surface loops, bridge boundary edges, or perform selective remeshing/CSG union. |
| **Pinching or faceted highlights** | Non-uniform vertex normals, bad winding, or excessive triangulation at joints. | Inspect vertex normals, local curvature, and topology loops before adding polygons. |
| **Disconnected floating layers** | Armor plates, roof tiles, or feathers floating without roots or overlap order. | Refine overlap sequence, root anchorage, thickness, and realistic spacing. |
| **Redundant internal geometry** | Meshes joined without deleting internal hidden polygons, wasting GPU vertex budgets. | Purge hidden internal faces unless revealed by dynamic cutaways or animation. |
> ⚠️ **BufferGeometryUtils Note**: Three.js `mergeGeometries` merely merges attribute buffers into a single draw call. It does **NOT** perform a solid CSG boolean union and does not delete interior hidden faces. Use deliberate topological authoring.
### Scale 3: Surface & Material Response
- Detail must survive at the actual camera distance. Avoid uniform procedural noise, random scratches, or gratuitous subdivision.
- Give materials distinct physical identities: soft tissue requires subsurface scattering/transmission; metal requires low roughness and high metallic response; stone requires directional grain and worn contact areas.
---
## 4. Modern Web 3D Engine Implementations
### A. Three.js WebGPU + TSL (Three Shading Language)
```typescript
import * as THREE from 'three/webgpu';
import { color, float, positionLocal, time, vec3, Fn } from 'three/tsl';
const canvas = document.querySelector('#canvas') as HTMLCanvasElement;
const renderer = new THREE.WebGPURenderer({ canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
await renderer.init();
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 3, 6);
// TSL Node Material: Compiles to WGSL on WebGPU, GLSL on WebGL2 fallback
const customMaterial = new THREE.MeshStandardNodeMaterial({ roughness: 0.2, metalness: 0.8 });
const animatedDisplacement = Fn(() => {
const t = time.mul(1.5);
return positionLocal.y.add(t).sin().mul(0.1);
});
customMaterial.positionNode = positionLocal.add(vec3(0, animatedDisplacement(), 0));
const geometry = new THREE.IcosahedronGeometry(1.5, 32);
const mesh = new THREE.Mesh(geometry, customMaterial);
scene.add(mesh);
renderer.setAnimationLoop(() => {
mesh.rotation.y += 0.005;
renderer.render(scene, camera);
});
```
### B. React Three Fiber (R3F) with React 19
```tsx
import { Canvas } from '@react-three/fiber';
import { OrbitControls, Environment, useGLTF, Float } from '@react-three/drei';
import * as THREE from 'three/webgpu';
function HeroModel() {
const { scene } = useGLTF('/models/scientific-apparatus.glb');
return (
<Float speed={1.5} rotationIntensity={0.2} floatIntensity={0.5}>
<primitive object={scene} />
</Float>
);
}
export function SceneViewer() {
return (
<Canvas
gl={(canvas) => new THREE.WebGPURenderer({ canvas, antialias: true })}
camera={{ position: [0, 2, 5], fov: 45 }}
dpr={[1, 2]}
>
<ambientLight intensity={0.4} />
<directionalLight position={[5, 8, 5]} castShadow intensity={1.2} />
<HeroModel />
<Environment preset="studio" />
<OrbitControls makeDefault enableDamping dampingFactor={0.05} />
</Canvas>
);
}
useGLTF.preload('/models/scientific-apparatus.glb');
```
### C. Babylon.js WebGPUEngine, 3D Gaussian Splatting & CSG 2.0 (Manifold Math)
```typescript
import {
WebGPUEngine,
Engine,
Scene,
Vector3,
HemisphericLight,
MeshBuilder,
Constants,
GaussianSplattingMesh,
CSG2
} from '@babylonjs/core';
export async function createBabylonWebGPUScene(canvas: HTMLCanvasElement) {
// 1. Initialize WebGPUEngine with automatic WebGL2 fallback
let engine: WebGPUEngine | Engine;
const isWebGPUSupported = await WebGPUEngine.IsSupportedAsync;
if (isWebGPUSupported) {
const webgpuEngine = new WebGPUEngine(canvas, {
antialias: true,
adaptToDeviceRatio: true
});
await webgpuEngine.initAsync();
// Enable Snapshot Rendering for up to 10x draw call CPU performance boost
webgpuEngine.snapshotRendering = true;
webgpuEngine.snapshotRenderingMode = Constants.SNAPSHOTRENDERING_FAST;
engine = webgpuEngine;
} else {
engine = new Engine(canvas, true);
}
const scene = new Scene(engine);
// 2. 3D Gaussian Splatting (.spz / .splat / .ply) with WebGPU compute radix sort
const splatMesh = new GaussianSplattingMesh('heroSplat', null, scene);
await splatMesh.loadFileAsync('https://assets.babylonjs.com/splats/lod.spz');
splatMesh.position.set(0, 0, 0);
// 3. CSG 2.0 Procedural Boolean Modeling (Manifold Math Kernel)
// Ensures seamless join continuity and purges hidden internal faces
const baseBox = MeshBuilder.CreateBox('baseBox', { size: 2 }, scene);
const drillHole = MeshBuilder.CreateCylinder('drillHole', { diameter: 1.2, height: 3 }, scene);
const csgBase = CSG2.FromMesh(baseBox);
const csgDrill = CSG2.FromMesh(drillHole);
const hollowCSG = csgBase.subtract(csgDrill);
const manufacturedMesh = hollowCSG.toMesh('perforatedStructure', null, scene);
baseBox.dispose();
drillHole.dispose();
const light = new HemisphericLight('ambientLight', new Vector3(0, 1, 0), scene);
light.intensity = 0.8;
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener('resize', () => {
engine.resize();
});
return { engine, scene };
}
```
---
## 6. Isometric Mechanical Anatomy & World-Space Shader Fusion
When authoring technical explainer figures (Anatomy Standard), 3D shaders must not live as isolated generic canvas backgrounds. Instead, bind WebGL/WebGPU shaders directly into the physical geometry of an isometric machine:
### The 3-Layer Sandwich Architecture
```
┌────────────────────────────────────────────────────────┐
│ 1. Back SVG Layer : Rear frame, chassis, bedplate │
│ 2. WebGL Canvas : Fire, fluid, plasma, caustics │ (World-space camera ray-match)
│ 3. Front SVG Layer : Front rails, glass bezels, dial │
└────────────────────────────────────────────────────────┘
```
1. **World-Space Camera Registration**:
- The WebGL shader camera must match the exact isometric projection of the enclosing SVG (`Azimuth: 45°`, `Elevation: 30°`).
- Reconstruct each pixel's world-space ray via `rayOf(uv) + t * towardViewer()`.
- Ensure fluid surfaces, sparks, and laser beams align 1:1 with SVG nozzles, pipes, and glass windows.
2. **Zero-Pop Envelopes**:
- Every shader parameter (intensity, turbulent speed, expansion) must ride on continuous mathematical attack/decay envelopes (`burst` for discrete event pulses, `settle` for continuous setpoint transitions).
- Abrupt `if-else` color snaps or hard step boundaries are strictly forbidden.
3. **Dual-Theme Shader Craft**:
- **Dark Theme**: Output premultiplied alpha with `mix-blend-mode: screen` for additive light pools, plasma arcs, and incandescent embers.
- **Light Theme (Paper-Ink Invariant)**: Never invert dark glow into a dark-rimmed neon blob. Calculate the physical ink density on paper: glow has a saturated body with a pale core and a clean alpha floor, where ink monotonically accumulates with light intensity and cleanly terminates at SVG stroke boundaries.
---
## 7. The 16-Point Visual Review & Self-Correction Checklist
When an object occupies space, its physical presence must match its visual boundaries:
### Collider Envelopes Must Follow Visible Meshes
- **The Rule**: Derive colliders from actual mesh geometry. A bounding box that excludes a building's roof will allow airborne characters to fly straight through the roof.
- Moving creatures require **articulated compound colliders** or conservative whole-body capsules that encompass wings, antlers, horns, and turning clearance. A single point at the actor's root is strictly insufficient.
### Discrete Simulation vs. Render Interpolation (Fixed Timestep)
Decouple physics integration from display refresh rates (60Hz, 120Hz, ProMotion) to prevent physics tunneling and non-deterministic behavior:
```typescript
// Fixed Timestep Accumulator Pattern (Fix Your Timestep - Glenn Fiedler)
const PHYSICS_TIMESTEP = 1 / 60; // 60Hz fixed simulation rate
let accumulatedTime = 0;
let lastTime = performance.now();
export function updatePhysicsLoop(currentTime: number, physicsWorld: any) {
const frameDelta = (currentTime - lastTime) / 1000;
lastTime = currentTime;
// Cap max frame delta to prevent "spiral of death" on tab resume
accumulatedTime += Math.min(frameDelta, 0.1);
while (accumulatedTime >= PHYSICS_TIMESTEP) {
physicsWorld.step(PHYSICS_TIMESTEP);
accumulatedTime -= PHYSICS_TIMESTEP;
}
// Alpha factor for visual transform interpolation between physics states
const interpolationAlpha = accumulatedTime / PHYSICS_TIMESTEP;
return interpolationAlpha;
}
```
---
## 6. Scientific Visualization & Grounded Truth Protocol
For models conveying scientific, anatomical, or engineering concepts:
1. **Fact-Check the Chain**: **Source Standard / Formula → Mathematical Model → Rendered Result**. An accurate formula in code does not certify a visual result if coordinate axes or scales are inverted.
2. **Expose Physical Units & Scale**: Never let the viewer guess scale. Include explicit metric units, a 3D scale bar, or known reference objects. Distinguish physical simulation from visual magnification.
3. **True Controls & State Transparency**: Controls must alter the modeled state truthfully. Adjusting a "pressure" slider must alter the underlying physics model or state machine, not just trigger a decorative particle effect. Reset buttons must restore declared initial conditions.
---
## 7. GPU Asset Pipeline & Memory Optimization
1. **KTX2 + Basis Universal GPU Textures (`KHR_texture_basisu`)**:
- Compresses textures directly in GPU VRAM (saving 75%-85% VRAM compared to PNG/JPG).
- Transcodes on the fly into native desktop (BC7) or mobile (ASTC) texture formats.
```bash
npx @gltf-transform/cli optimize input.glb output.glb --texture-compress ktx2
```
2. **Meshopt Geometry Compression (`EXT_meshopt_compression`)**:
- Decompresses at gigabytes per second on WASM (10x faster than Draco on mobile CPUs) and optimizes vertex cache locality.
```bash
npx @gltf-transform/cli meshopt input.glb output.glb
```
3. **Strict Memory Lifecycle Management (`.dispose()`)**:
- Explicitly traverse and dispose geometries, materials, and textures when unmounting scenes:
```typescript
export function purgeThreeObject(root: THREE.Object3D) {
root.traverse((node) => {
if ((node as THREE.Mesh).isMesh) {
const mesh = node as THREE.Mesh;
mesh.geometry?.dispose();
if (Array.isArray(mesh.material)) {
mesh.material.forEach((m) => m.dispose());
} else if (mesh.material) {
mesh.material.dispose();
}
}
});
}
```
4. **Zero-Allocation `THREE.InstancedMesh` Batch Transforms**:
- Pre-allocate a single module-level scratch `THREE.Object3D` dummy outside the animation loop so updating 10,000+ instances produces zero garbage-collection pauses:
```typescript
import * as THREE from 'three/webgpu';
const scratchDummy = new THREE.Object3D();
export function updateInstancedField(
instancedMesh: THREE.InstancedMesh,
positions: Float32Array,
elapsedSeconds: number
): void {
const count = instancedMesh.count;
for (let i = 0; i < count; i++) {
const base = i * 3;
const x = positions[base];
const y = positions[base + 1] + Math.sin(elapsedSeconds + i * 0.15) * 0.08;
const z = positions[base + 2];
scratchDummy.position.set(x, y, z);
scratchDummy.rotation.set(0, elapsedSeconds * 0.25, 0);
scratchDummy.updateMatrix();
instancedMesh.setMatrixAt(i, scratchDummy.matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true;
}
```
---
## 8. 16-Point 3D Visual Anti-Slop & Quality Checklist
Evaluate every 3D scene against this checklist before completion:
- [ ] **1. Silhouette Clarity**: Does the hero object read distinctly by silhouette alone without color?
- [ ] **2. Plausible Construction**: Do parts connect with realistic thickness, joints, and recesses rather than floating?
- [ ] **3. Join Continuity**: Are skin junctions smooth and mechanical joints cleanly articulated without accidental seams?
- [ ] **4. Viewing-Scale Detail**: Is detail budgeted for the actual camera viewing scale without meaningless micro-noise?
- [ ] **5. Distinct Material Response**: Do materials exhibit varied, physically accurate PBR responses (metal, tissue, stone)?
- [ ] **6. Purposeful Lighting**: Is lighting arranged to reveal form without blown-out highlights or crushed shadows?
- [ ] **7. Effects Earned**: Are bloom, fog, and depth-of-field used purposefully without hiding modeling flaws?
- [ ] **8. Guided Composition**: Does the camera framing, depth, and contrast guide focus to the hero element?
- [ ] **9. Legible Scale**: Are physical dimensions, scale bars, or units clear to the viewer?
- [ ] **10. Appropriate Projection**: Is the camera projection (perspective vs. orthographic) suited to the subject?
- [ ] **11. Intentional Repetition**: Is instancing (`InstancedMesh`) used for repetitive assets without accidental visual jitter?
- [ ] **12. Meaningful Motion**: Is animation purposeful, respecting `prefers-reduced-motion`, with stillness used when appropriate?
- [ ] **13. Spatial Clearance**: Do moving objects avoid clipping through floors, roofs, or surrounding obstacles?
- [ ] **14. Collider Fidelity**: Do collision envelopes enclose actual geometry (including overhangs and wings)?
- [ ] **15. Truthful Controls**: Do sliders, toggles, and resets accurately change the modeled state and restore initial values?
- [ ] **16. Grounded Scientific Claims**: Are anatomical, chemical, or physical models grounded in verified references?
---
## 8. Shared-Canvas DOM-Synced WebGL Planes (`OGL` + `data-gl`)
For editorial, studio, and Awwwards-grade sites, never spawn multiple WebGL contexts per page (browsers cap active contexts at 8–16) and never trap content inside WebGL where SEO, screen readers, and right-click break. Instead, use **One Shared `#gl` Canvas (`z-index: 0`)** behind `<main>` (`z-index: 1`) paired with DOM `<figure data-gl>` elements whose `<img>` stays in the DOM at `opacity: 0` once texture upload succeeds:
```typescript
// src/engine/gl/index.ts — Shared OGL Canvas + DOM-Synced Planes on gsap.ticker
import { Renderer, Camera, Transform, Plane, Mesh, Program, Texture, Vec2 } from 'ogl';
import { registerGLTick, env } from '../index';
const VERT = /* glsl */ `
attribute vec3 position;
attribute vec2 uv;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform float uVelocity;
uniform float uHover;
uniform vec2 uMouse;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
// Scroll velocity wave bend + subtle pointer push
float wave = sin(uv.x * 3.14159265) * clamp(uVelocity * 0.0018, -0.18, 0.18);
float dist = distance(uv, uMouse);
pos.y += wave;
pos.z += smoothstep(0.45, 0.0, dist) * uHover * 0.08;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`;
const FRAG = /* glsl */ `
precision highp float;
uniform sampler2D tMap;
uniform vec2 uImageSizes;
uniform vec2 uPlaneSizes;
uniform float uHover;
uniform float uVelocity;
uniform vec2 uMouse;
varying vec2 vUv;
vec2 coverUv(vec2 uv, vec2 planeSize, vec2 imageSize) {
vec2 ratio = vec2(
min((planeSize.x / planeSize.y) / (imageSize.x / imageSize.y), 1.0),
min((planeSize.y / planeSize.x) / (imageSize.y / imageSize.x), 1.0)
);
return vec2(
uv.x * ratio.x + (1.0 - ratio.x) * 0.5,
uv.y * ratio.y + (1.0 - ratio.y) * 0.5
);
}
void main() {
vec2 uv = coverUv(vUv, uPlaneSizes, uImageSizes);
// Subtle zoom + RGB chromatic split proportional to velocity & hover
uv = (uv - 0.5) * (1.0 - 0.04 * uHover) + 0.5;
float shift = (abs(uVelocity) * 0.00015 + uHover * 0.0035);
float r = texture2D(tMap, uv + vec2(shift, 0.0)).r;
float g = texture2D(tMap, uv).g;
float b = texture2D(tMap, uv - vec2(shift, 0.0)).b;
gl_FragColor = vec4(r, g, b, 1.0);
}
`;
interface SyncedPlane {
el: HTMLElement;
mesh: Mesh;
program: Program;
}
export function mountSharedGL(canvas: HTMLCanvasElement): () => void {
if (env.reduced || env.coarse) return () => undefined;
const renderer = new Renderer({
canvas,
alpha: true,
antialias: false,
dpr: Math.min(window.devicePixelRatio, 2),
});
const gl = renderer.gl;
const camera = new Camera(gl, { fov: 45 });
camera.position.z = 5;
const scene = new Transform();
const geometry = new Plane(gl, { widthSegments: 24, heightSegments: 24 });
const planes: SyncedPlane[] = [];
let vpWidth = window.innerWidth;
let vpHeight = window.innerHeight;
let fovHeight = 2 * Math.tan((camera.fov * Math.PI) / 360) * camera.position.z;
let fovWidth = fovHeight * camera.aspect;
const onResize = () => {
vpWidth = window.innerWidth;
vpHeight = window.innerHeight;
renderer.setSize(vpWidth, vpHeight);
camera.perspective({ aspect: vpWidth / vpHeight });
fovHeight = 2 * Math.tan((camera.fov * Math.PI) / 360) * camera.position.z;
fovWidth = fovHeight * camera.aspect;
};
onResize();
window.addEventListener('resize', onResize);
document.documentElement.classList.add('gl-on');
document.querySelectorAll<HTMLElement>('[data-gl]').forEach((el) => {
const img = el.querySelector<HTMLImageElement>('img');
if (!img) return;
const texture = new Texture(gl, { generateMipmaps: false });
const image = new Image();
image.crossOrigin = 'anonymous';
image.src = img.currentSrc || img.src;
image.onload = () => {
texture.image = image;
program.uniforms.uImageSizes.value.set(image.naturalWidth, image.naturalHeight);
img.style.opacity = '0';
};
const program = new Program(gl, {
vertex: VERT,
fragment: FRAG,
uniforms: {
tMap: { value: texture },
uImageSizes: { value: new Vec2(1, 1) },
uPlaneSizes: { value: new Vec2(1, 1) },
uVelocity: { value: 0 },
uHover: { value: 0 },
uMouse: { value: new Vec2(0.5, 0.5) },
},
transparent: true,
});
const mesh = new Mesh(gl, { geometry, program });
mesh.setParent(scene);
planes.push({ el, mesh, program });
});
registerGLTick((_time, velocity) => {
for (const p of planes) {
const rect = p.el.getBoundingClientRect();
p.mesh.scale.x = (fovWidth * rect.width) / vpWidth;
p.mesh.scale.y = (fovHeight * rect.height) / vpHeight;
p.mesh.position.x = fovWidth * ((rect.left + rect.width / 2) / vpWidth - 0.5);
p.mesh.position.y = fovHeight * (0.5 - (rect.top + rect.height / 2) / vpHeight);
p.program.uniforms.uPlaneSizes.value.set(rect.width, rect.height);
p.program.uniforms.uVelocity.value = velocity;
}
renderer.render({ scene, camera });
});
return () => {
registerGLTick(null);
window.removeEventListener('resize', onResize);
document.documentElement.classList.remove('gl-on');
};
}
```
> **Critical CSS Invariant (`glHidden` Prevention)**: When `.gl-on` is active on `<html>`, any opaque `background` on `<figure data-gl>` will cover the `#gl` canvas behind it (`z-index: 0`). Always include:
> ```css
> html.gl-on [data-gl] { background: none !important; }
> ```
### Hard Guardrails (Declarative Invariants)
- **Zero Per-Frame Object Allocations in Render Loops**: MUST pre-allocate reusable scratch `THREE.Vector3`, `THREE.Matrix4`, `THREE.Quaternion`, and `THREE.Color` instances outside `setAnimationLoop` / `useFrame` to prevent GC frame stutters.
- **Bounded Device Pixel Ratio (`dpr <= 2`)**: MUST cap pixel ratio via `renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))` or `<Canvas dpr={[1, 2]}>` so 3x/4x mobile screens do not exhaust fill-rate and VRAM.
- **Explicit GPU Resource Disposal on Unmount**: MUST traverse unmounted scene subtrees and call `.dispose()` on every `BufferGeometry`, `Material`, `Texture`, and `RenderTarget`.
- **Fixed-Timestep Physics Decoupling**: MUST advance physics simulations using a fixed-timestep accumulator (`1 / 60` s with clamped `Math.min(frameDelta, 0.1)`) rather than passing raw variable `frameDelta` directly to `physicsWorld.step()`.
- **Single Shared WebGL/WebGPU Context per Page**: MUST reuse a single `<canvas>` context across DOM-synced viewports (`data-gl` / `View`scissor) and respect `prefers-reduced-motion: reduce`.
### Sovereign Execution, Token Efficiency & Invariants
| Dimension | Sovereign Mandate & Deterministic Contract |
| :--- | :--- |
| **Frontier Model Cascade** | Medium / High (`GPT-5.6 Sol Medium`, `Gemini 4 Argon`, `Claude Sonnet 5.5 High`, `Grok 4.7 High Fast`) |
| **Availability Fallback** | `Gemini 4 Argon/Pro` -> `Gemini 3.8 Flash`; `Claude Opus 5.5` -> `Claude Opus 4.6` (Zero unhandled missing-model errors) |
| **KV-Cache & Token Protocol** | Pin static instructions & schemas at prompt prefix (`kv-cache-prefix-optimizer`); pass surgical `CONTEXT_MAP.md` slices (<250 tokens/call) during Swarm Fan-Out |
| **SaaT CLI & MCP Dispatch** | CLI: `vibes skill exec web-3d-graphics-expert <audit\|eval\|verify\|generate\|blueprint>` / MCP: `vibes_skill_dispatch`, `vibes_ast_query`, `vibes_compile_cache`, `vibes_optimize_budget`, `vibes_verify_gate` |
| **NFR & Anti-Slop Invariants** | P99 API Gateway Latency < 85ms, OpenAPI 3.1 / TypeSpec strict schema parity, RFC 9457 Problem Details error contracts, Idempotency-Key enforcement; 100% complete zero-placeholder output verified via `node scripts/check-anti-slop.js --strict` |
---
---
<a name="bahasa-indonesia"></a>
## Bahasa Indonesia
### Integrasi Orkestrasi
Terhubung dan mengorkestrasi skill domain yang relevan:
- `senior-frontend` — Integrasi React Three Fiber (R3F) pada React 19 / Next.js 15.
- `vue-frontend-expert` — Integrasi TresJS pada Vue 3 / Nuxt 3.
- `svelte-sveltekit-expert` — Integrasi Threlte pada Svelte 5 (Runes).
- `web-game-engine-expert` — Simulasi fisika (Rapier, Jolt, Havok), game loop, dan ECS.
- `glsl-shader-expert` — Bahasa shader, compute shader WGSL, dan node TSL.
- `webxr-ar-vr-expert` — Pengalaman WebXR VR/AR imersif.
- `data-visualization-expert` — Visualisasi data ilmiah 3D dan explainer spasial.
- `ui-ux-pro-max` — Sistem desain antarmuka spasial, ergonomi viewport kanvas, dan kontrol HUD.
- `visual-ui-auditor` — Audit visual multimodal untuk kanvas 3D, frame rate, dan fidelitas pencahayaan.
- `anti-slop` — Anti-slop visual 3D, membasmi orbe bersinar generik dan model proksi murahan.
- `performance-web-vitals` — Meminimalkan TBT (Total Blocking Time) dan optimasi ukuran bundle.
### Deskripsi
Panduan produksi untuk membangun grafis 3D performa tinggi di browser yang dipadukan dengan penalaran spasial mendalam (*Protokol 3Dviz*). Mengutamakan paradigma modern **WebGPU-first** dengan fallback otomatis ke WebGL2, **Three.js (r170+) WebGPURenderer** dan **TSL (Three Shading Language)**, **Babylon.js WebGPUEngine** dengan Snapshot Rendering, **PlayCanvas Engine** untuk performa mobile ekstrem, serta keahlian bentuk objek (*object craft*) lintas **3 skala visual** (siluet, konstruksi, permukaan).
### Kondisi Pemicu
Aktifkan skill ini ketika:
- Menginisialisasi *scene* WebGPU atau WebGL 3D, visualisasi ilmiah, atau model interaktif.
- Menggunakan `three` (`three/webgpu`), `@react-three/fiber`, `@babylonjs/core`, `playcanvas`, `@tresjs/core`, atau `@threlte/core`.
- Merancang model 3D ekspresif atau teka-teki spasial dari awal.
- Menulis shader khusus dalam TSL/WGSL atau geometri prosedural.
- Memperbaiki kelemahan bentuk objek: sambungan robek, artefak pencahayaan (*pinching*), objek mengambang tanpa dasar, atau model generik yang ditutupi tekstur resolusi tinggi.
- Mengonfigurasi batas tabrakan fisik (*collider envelopes*), fisika *fixed-timestep*, atau *continuous collision detection*.
- Mengompresi aset 3D (`.glb`) dengan KTX2 Basis Universal dan Meshopt.
- Mengatasi penurunan FPS (*frame drop*), hambatan *draw call*, atau kebocoran memori VRAM.
---
## 1. Alur Kerja Penalaran Spasial & Konstruksi 3Dviz (10 Langkah)
Sebuah scene 3D yang dapat dijalankan membutuhkan pertimbangan visual yang matang. Ikuti 10 keputusan ini:
1. **Arah & Maksud Visual**: Tentukan apa yang harus dipahami, dirasakan, atau dilakukan oleh pengguna. Tentukan jarak pandang utama (*overview*, inspeksi, atau *close-up* mikro). Pastikan siluet, material, cahaya, kamera, dan gerakan bekerja selaras.
2. **Penalaran Objek (3 Skala Visual)**: Sebelum memilih template, rumuskan siluet, proporsi, sambungan, karakter permukaan, dan perilaku objek utama. Selesaikan objek yang paling menantang terlebih dahulu.
3. **Representasi Berpijak & Kebenaran Ilmiah**: Tentukan apakah scene berupa ilustrasi, state machine diskrit, simulasi fisika, atau pemutaran animasi. Untuk visualisasi ilmiah, verifikasi rantai: **Klaim/Rumus → Model Matematis → Hasil Visual**.
4. **Rute Konstruksi per Objek**: Pilih rute konstruksi yang tepat (gunakan kit langsung, modifikasi kit, buat geometri kustom, atau gunakan aset pindaian/CAD eksternal).
5. **Kontinuitas Sambungan (*Join Continuity*)**: Pada area sambungan, tentukan apakah objek membutuhkan kulit organik menyatu (*continuous skin*), lapisan bersusun (*layered covering*), atau bagian artikulasi mekanis terpisah.
6. **Arah Material & Pencahayaan**: Rancang respons PBR yang berbeda untuk setiap material (jaringan lunak, logam, batu, kaca). Arahkan cahaya untuk mempertegas bentuk; hindari highlight terpotong (*clipped highlights*) atau bayangan terlalu gelap.
7. **Interaksi Fisik & Batas Spasial**: Pastikan batas tabrakan (*collider*) membungkus mesh visual secara akurat (termasuk atap, sayap, tanduk). Pisahkan tick fisika dari rendering menggunakan akumulator *fixed-timestep*.
8. **Inspeksi Output Nyata di Browser**: Jangan pernah menyimpulkan kualitas visual dari frame yang belum dilihat langsung. Periksa dari sudut overview, oblique, close-up, dan saat interaksi berjalan.
9. **Review Visual & Anti-Slop 3D**: Evaluasi terhadap 16 poin checklist visual. Perbaiki kelemahan bentuk dasar sebelum menambal dengan tekstur atau efek post-processing berlebih.
10. **Laporan Jujur**: Jelaskan secara transparan apa yang dimodelkan secara matematis, apa yang diverifikasi secara numerik, dan bagian mana yang merupakan penyederhanaan artistik.
---
## 2. Keahlian Bentuk Objek: 3 Skala Visual (*Object Craft*)
Menambahkan banyak objek pendukung tidak akan menutupi kelemahan pemodelan pada objek utama. Kualitas bentuk harus diselesaikan pada tiga skala:
### Skala 1: Siluet (*The Silhouette Test*)
- Objek harus dapat dikenali seketika hanya dari siluet hitam-putih tanpa mengandalkan warna atau cahaya.
- Spesies makhluk yang berbeda memerlukan struktur proporsi tulang yang berbeda, bukan sekadar model yang sama yang diberi warna berbeda.
- Fitur yang mengubah garis luar objek wajib dimodelkan sebagai **geometri nyata**, bukan sekadar peta normal (*normal map*).
### Skala 2: Konstruksi & Kontinuitas Sambungan
- **Sambungan Kulit Organik**: Hindari batas persimpangan mesh yang canggung; buat sambungan topologi kontinu atau lakukan remeshing/CSG union yang halus.
- **Lapisan Armor / Bulu**: Pastikan memiliki ketebalan nyata, urutan tumpang-tindih yang teratur, dan jangkar pangkal yang jelas.
- **Artikulasi Mekanis**: Poros dan bantalan harus memiliki toleransi ruang (*clearance*) visual yang masuk akal.
### Skala 3: Perlakuan Permukaan & Material
- Berikan detail permukaan (arah serat kayu, jahitan kain, area kontak aus) hanya pada skala yang terlihat oleh kamera.
- Hindari kebisingan prosedural (*random procedural noise*) yang seragam di seluruh permukaan.
### Implementasi Babylon.js WebGPU, Gaussian Splatting & CSG 2.0
```typescript
import {
WebGPUEngine,
Engine,
Scene,
Vector3,
HemisphericLight,
MeshBuilder,
Constants,
GaussianSplattingMesh,
CSG2
} from '@babylonjs/core';
export async function inisialisasiSceneBabylon(canvas: HTMLCanvasElement) {
// 1. Inisialisasi WebGPUEngine dengan fallback otomatis ke WebGL2
let engine: WebGPUEngine | Engine;
if (await WebGPUEngine.IsSupportedAsync) {
const webgpuEngine = new WebGPUEngine(canvas, { antialias: true, adaptToDeviceRatio: true });
await webgpuEngine.initAsync();
// Snapshot Rendering mode FAST: mereduksi overhead CPU draw call hingga 10x lipat
webgpuEngine.snapshotRendering = true;
webgpuEngine.snapshotRenderingMode = Constants.SNAPSHOTRENDERING_FAST;
engine = webgpuEngine;
} else {
engine = new Engine(canvas, true);
}
const scene = new Scene(engine);
// 2. 3D Gaussian Splatting (.spz / .splat / .ply) dengan GPU compute radix sorting
const splatMesh = new GaussianSplattingMesh('heroSplat', null, scene);
await splatMesh.loadFileAsync('https://assets.babylonjs.com/splats/lod.spz');
// 3. CSG 2.0 (Manifold Math Kernel): operasi boolean solid tanpa cacat internal face
const kotak = MeshBuilder.CreateBox('kotak', { size: 2 }, scene);
const silinder = MeshBuilder.CreateCylinder('silinder', { diameter: 1.2, height: 3 }, scene);
const csgKotak = CSG2.FromMesh(kotak);
const csgSilinder = CSG2.FromMesh(silinder);
const hasilCSG = csgKotak.subtract(csgSilinder);
const meshHasil = hasilCSG.toMesh('strukturBerlubang', null, scene);
kotak.dispose();
silinder.dispose();
const light = new HemisphericLight('cahaya', new Vector3(0, 1, 0), scene);
light.intensity = 0.8;
engine.runRenderLoop(() => {
scene.render();
});
return { engine, scene };
}
```
---
## 3. Fisika & Batas Tabrakan Spasial
1. **Collider Wajib Mengikuti Geometri Nyata**:
- Kotak pembatas (*bounding box*) dasar yang mengecualikan atap bangunan akan menyebabkan karakter melayang menembus atap.
- Karakter makhluk hidup membutuhkan gabungan collider kapsul majemuk (*compound colliders*) yang mencakup bentang sayap, tanduk, dan ruang gerak putar.
2. **Integrasi Fixed-Timestep (Memisahkan Fisika dari Refresh Rate)**:
- Gunakan laju simulasi tetap (misal: 60Hz) dengan akumulator waktu untuk mencegah penembusan objek (*tunneling*) dan memastikan stabilitas matematis pada layar 120Hz/ProMotion.
---
## 4. Pipeline Aset GPU & Optimasi Memori
1. **Kompresi Tekstur KTX2 + Basis Universal**:
- Menghemat 75%-85% VRAM GPU dibanding PNG/JPG karena tetap terkompresi di dalam memori kartu grafis.
2. **Kompresi Geometri Meshopt**:
- Dekompresi WASM berkecepatan gigabyte per detik (10x lebih cepat dari Draco pada perangkat mobile).
3. **Pembersihan Siklus Hidup Memori (`.dispose()`)**:
- Telusuri seluruh hierarki objek dan panggil `.dispose()` pada geometri, material, dan tekstur saat komponen di-unmount agar tidak terjadi kebocoran memori VRAM GPU.
---
## 5. Fusi Anatomi Mekanis Isometrik & Shader WebGL World-Space
Saat merancang figur penjelasan teknis (*Standar Anatomi*), shader 3D tidak boleh berdiri sendiri sebagai latar belakang kanvas generik. Integrasikan shader WebGL/WebGPU langsung ke dalam geometri mesin isometrik nyata:
### Arsitektur Berlapis (3-Layer Sandwich)
```
┌────────────────────────────────────────────────────────┐
│ 1. Lapisan Back SVG : Rangka belakang, chassis, alas │
│ 2. Kanvas WebGL : Api, fluida, plasma, caustics │ (Kamera world-space presisi)
│ 3. Lapisan Front SVG : Rel depan, kaca dial, jarum │
└────────────────────────────────────────────────────────┘
```
1. **Registrasi Kamera World-Space**:
- Kamera shader WebGL wajib merefleksikan proyeksi isometrik SVG pembungkusnya secara presisi (`Azimuth: 45°`, `Elevasi: 30°`).
- Rekonstruksi ray tiap piksel melalui `rayOf(uv) + t * towardViewer()`.
- Pastikan permukaan fluida, percikan bunga api, atau sinar laser tersinkronisasi 1:1 terhadap nozzle, pipa, dan bezel kaca SVG.
2. **Amplop Matematika Tanpa Pop-in (Zero-Pop Envelopes)**:
- Setiap parameter shader (intensitas, turbulensi, ekspansi) wajib mengikuti kurva amplop kontinu (*attack/decay*): `burst` untuk pulsa sesaat, `settle` untuk transisi kontinu. Dilarang menggunakan peralihan warna mendadak atau fungsi step kaku.
3. **Standar Desain Dua Tema**:
- **Mode Gelap**: Output premultiplied alpha dengan `mix-blend-mode: screen` untuk pendaran cahaya, busur plasma, dan bara pijar.
- **Mode Terang (Invarian Tinta Kertas)**: Dilarang membalikkan cahaya gelap menjadi gumpalan neon bertepi hitam. Hitung densitas tinta fisik pada kertas: pendaran memiliki inti terang dengan tepi tersaturasi dan dasar alpha bersih yang berhenti tegas pada batas goresan stroke SVG.
---
## 6. Checklist Mandiri Kualitas Grafis 3D (16 Poin)
- [ ] **1. Kejelasan Siluet**: Apakah objek utama terbaca jelas hanya dari siluet hitam-putih?
- [ ] **2. Konstruksi Masuk Akal**: Apakah setiap bagian terhubung dengan ketebalan dan sambungan yang meyakinkan?
- [ ] **3. Kontinuitas Sambungan**: Apakah sambungan kulit halus dan sambungan mekanis terartikulasi tanpa robekan visual?
- [ ] **4. Detail Sesuai Jarak Kamera**: Apakah detail difokuskan pada area yang terlihat oleh kamera tanpa noise acak?
- [ ] **5. Respons PBR Berkarakter**: Apakah setiap material merespons cahaya secara akurat (logam, jaringan lunak, batu)?
- [ ] **6. Pencahayaan Mempertegas Bentuk**: Apakah pencahayaan menghindari highlight terpotong atau bayangan terlalu gelap?
- [ ] **7. Efek Berdasar**: Apakah bloom, fog, dan depth-of-field digunakan secara terarah tanpa menutupi cacat model?
- [ ] **8. Komposisi Terarah**: Apakah framing kamera dan kontras mengarahkan pandangan ke fokus utama?
- [ ] **9. Skala Terbaca**: Apakah satuan metrik, scale bar, atau objek pembanding ditampilkan secara jelas?
- [ ] **10. Proyeksi Kamera Sesuai**: Apakah perspektif atau ortografis dipilih sesuai tujuan komunikasi?
- [ ] **11. Instancing Efisien**: Apakah objek berulang menggunakan `InstancedMesh` tanpa jitter acak yang merusak struktur?
- [ ] **12. Gerakan Bermakna**: Apakah animasi bertujuan jelas dan mematuhi aturan aksesibilitas `prefers-reduced-motion`?
- [ ] **13. Bebas Tembus Spasial**: Apakah objek bergerak terbebas dari tabrakan menembus lantai, atap, atau rintangan?
- [ ] **14. Akurasi Batas Collider**: Apakah collider fisik mencakup seluruh bentuk visual (termasuk atap dan sayap)?
- [ ] **15. Kontrol & Reset Jujur**: Apakah slider dan tombol reset benar-benar mengubah state model dan mengembalikan nilai awal?
- [ ] **16. Kebenaran Klaim Ilmiah**: Apakah model ilmiah/teknis berakar pada referensi yang terverifikasi?
---
## 7. Plane WebGL Tersinkronisasi DOM pada Kanvas Bersama (`OGL` + `data-gl`)
Untuk situs editorial, studio kreatif, dan standar Awwwards, jangan pernah membuat banyak konteks WebGL terpisah (browser membatasi 8–16 konteks) atau menyembunyikan gambar di luar DOM. Gunakan **Satu Kanvas `#gl` Bersama (`z-index: 0`)** di belakang `<main>` yang menyinkronkan `<figure data-gl>` menggunakan `getBoundingClientRect()` di atas `gsap.ticker`:
1. **SEO, Aksesibilitas & LCP Utuh**: Tag `<img alt="...">` tetap berada di dalam DOM dan baru diubah ke `opacity: 0` setelah tekstur GPU selesai dimuat. Pada perangkat mobile (`pointer: coarse`) atau `prefers-reduced-motion`, kanvas `#gl` dilewati sehingga `<img>` tampil secara native.
2. **Pencegahan Bug `glHidden`**: Saat `html.gl-on` aktif, wajib terapkan `html.gl-on [data-gl] { background: none !important; }` agar warna latar kontainer placeholder tidak menutupi plane WebGL di belakangnya (`glHidden.length === 0`).
### Matriks Eksekusi Berdaulat, Efisiensi Token & Invarian
| Dimensi | Mandat Berdaulat & Kontrak Deterministik |
| :--- | :--- |
| **Kaskade Model Frontier** | Medium / High (`GPT-5.6 Sol Medium`, `Gemini 4 Argon`, `Claude Sonnet 5.5 High`, `Grok 4.7 High Fast`) |
| **Invarian Fallback Ketersediaan** | `Gemini 4 Argon/Pro` -> `Gemini 3.8 Flash`; `Claude Opus 5.5` -> `Claude Opus 4.6` (Bebas gagal saat model belum tersedia/kuota penuh) |
| **Protokol Hemat Token & KV-Cache** | Kunci instruksi & skema statis di prefix awal (`kv-cache-prefix-optimizer`); kirim potongan `CONTEXT_MAP.md` (<250 token/panggilan) saat Fan-Out |
| **Eksekusi SaaT CLI & MCP** | CLI: `vibes skill exec web-3d-graphics-expert <audit\|eval\|verify\|generate\|blueprint>` / MCP: `vibes_skill_dispatch`, `vibes_ast_query`, `vibes_compile_cache`, `vibes_optimize_budget`, `vibes_verify_gate` |
| **Invarian NFR & Anti-Slop** | Latensi P99 API < 85ms, paritas skema ketat OpenAPI 3.1 / TypeSpec, kontrak error RFC 9457 Problem Details, penegakan Idempotency-Key; kode 100% tuntas tanpa placeholder diverifikasi melalui `node scripts/check-anti-slop.js --strict` |