feat: Stage 2D hardware perf PASS, SPEC_DERIVED_CAD mechanism, device-test
Measure GTX 1080 matrix (A/B/C 60 FPS p95~17ms); selective CAD shadows and DPR 1.25; ship SPEC_DERIVED_CAD sorter mechanism GLB/STEP; add /device-test; document domain blocker and phone NOT_TESTED. Co-authored-by: Cursor <cursoragent@cursor.com>
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-07-30T12:27:01.613Z",
|
||||
"generatedAt": "2026-07-30T12:48:49.673Z",
|
||||
"sim": "headless Rapier via simulateDrop (deterministic, dt=1/60, settle 6s)",
|
||||
"runs": 10,
|
||||
"routes": [
|
||||
|
||||
3
docs/stage2d/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Stage 2D — Performance / Mechanism / Phone-ready
|
||||
|
||||
See `STAGE2D_REPORT.md`.
|
||||
132
docs/stage2d/STAGE2D_REPORT.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# STAGE 2D REPORT — Performance Recovery / Real Mechanism / Phone-Ready
|
||||
|
||||
## 1. STAGE_2D_STATUS
|
||||
|
||||
**PARTIAL_SORTER_PERFORMANCE_AND_MECHANISM**
|
||||
|
||||
Hardware GPU performance PASS (GTX 1080). SPEC_DERIVED_CAD mechanism shipped (not author REAL_CAD). Domain/phone blocked or untested. Runtime WebM partial.
|
||||
|
||||
## 2. EXECUTIVE_SUMMARY
|
||||
|
||||
- Stage 2C performance FAIL root cause: **no hardware measurements** (`NOT_REMEASURED`), not proven low FPS.
|
||||
- Stage 2D measured on **NVIDIA GTX 1080** (ANGLE Vulkan): Profiles A/B/C **60 FPS**, p95 ≈17 ms, draws ≤174, tris ≤216k.
|
||||
- Optimizations: selective CAD shadows, shadow map 1024, demo DPR 1.25, maxVisibleItems 4.
|
||||
- Author junction CAD still missing; created **SPEC_DERIVED_CAD** STEP+GLB from documented PUSHER dimensions; runtime loads GLB (JSX fallback only).
|
||||
- Drop 7/7×10/10; runtime/headless hash `7ee15ad3e879a44a` unchanged equal.
|
||||
- `/device-test` added; real phone **NOT_TESTED**; `sorter.arhipovdan.ru` still **BLOCKED**.
|
||||
|
||||
## 3. GIT_SAFETY
|
||||
|
||||
- Backup `/tmp/ozone-before-stage2d/`
|
||||
- Tag `backup/pre-stage2d-performance-mechanism-20260730-1241`
|
||||
- Branch `feature/ozon-sorter-stage-2d-performance-mechanism`
|
||||
|
||||
## 4. PERFORMANCE_ROOT_CAUSE
|
||||
|
||||
See `performance-root-cause.md`. Stage 2C FAIL = missing hardware matrix.
|
||||
|
||||
## 5. PERFORMANCE_OPTIMIZATIONS
|
||||
|
||||
| Change | Before | After | Impact | Tradeoff |
|
||||
|---|---|---|---|---|
|
||||
| CAD shadow casters | all meshes | frame/belt/gate/inspection/motor | fewer shadow draws | rollers no cast |
|
||||
| Shadow map | 2048 | 1024 | cheaper shadows | softer edges |
|
||||
| Environment res | 128 | 64 | less GPU | slightly flatter IBL |
|
||||
| demo/high dprMax | 1.5 | 1.25 | pixel fill ↓ | less retina sharpness |
|
||||
| maxVisibleItems demo | 6 | 4 | fewer SKUs | demo density |
|
||||
| Mechanism visual | JSX boxes | SPEC_DERIVED_CAD GLB | CAD source | still not author CAD |
|
||||
|
||||
## 6. PERFORMANCE_RESULTS
|
||||
|
||||
GPU: NVIDIA GeForce GTX 1080 (ANGLE Vulkan)
|
||||
|
||||
| Profile | GPU | Avg FPS | Min | P95 | Physics P95 | Draw calls | Tris | Result |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| A CAD Light | GTX 1080 | 60 | — | 16.8 | N/A* | 162 | 182k | PASS |
|
||||
| B CAD+Physics | GTX 1080 | 60 | — | 17.0 | N/A* | 152 | 197k | PASS |
|
||||
| C Full runtime | GTX 1080 | 60 | — | 17.1 | N/A* | 174 | 216k | PASS |
|
||||
| D Cinematic full | GTX 1080 | 60 | 33 | 17.1 | N/A* | (instr.) | (instr.) | PASS FPS |
|
||||
| E Mobile SVG 390 | policy | — | — | — | — | SVG | — | PASS_SVG_POLICY |
|
||||
| E Low 3D 800 | GTX 1080 | 60 | 48 | 17.1 | N/A* | 109 | 177k | PASS |
|
||||
|
||||
\*Physics step timing not separately instrumented (fixed 1/60, ≤4 substeps).
|
||||
|
||||
## 7. MECHANISM_SOURCE_SEARCH
|
||||
|
||||
See `mechanism-source-search.md`. No author junction paddle in any branch/archive.
|
||||
|
||||
## 8. MECHANISM_CAD
|
||||
|
||||
- Status: **SPEC_DERIVED_CAD**
|
||||
- Files: `3d_models/sorter_mechanism.step`, `.params.json`, `public/models/sorter/mechanism-web.glb`
|
||||
- Dimensions from PUSHER + mechanism-map (documented)
|
||||
|
||||
## 9. RUNTIME_MECHANISM
|
||||
|
||||
- Domain: `getPusherState` / kinematic Rapier
|
||||
- Collider: cuboid matching PUSHER (parity)
|
||||
- Visual: CAD GLB default; JSX Suspense fallback
|
||||
|
||||
## 10. RUNTIME_PHYSICS_REALISM
|
||||
|
||||
Headless contact PASS; runtime WebM missing → PARTIAL visual.
|
||||
|
||||
## 11. DROP_VALIDATION
|
||||
|
||||
7/7 × 10/10, 0 teleport, pusher contact on C/D. See `drop-validation.json`.
|
||||
|
||||
## 12. RUNTIME_HEADLESS_PARITY
|
||||
|
||||
Hash `7ee15ad3e879a44a` equal — PASS.
|
||||
|
||||
## 13. REAL_PRODUCT_FIDELITY
|
||||
|
||||
Scale unchanged; real STL default preserved.
|
||||
|
||||
## 14. MOBILE
|
||||
|
||||
`/device-test` + SVG policy at <640px. Real phone NOT_TESTED.
|
||||
|
||||
## 15. PUBLIC_DOMAIN
|
||||
|
||||
BLOCKED_BY_DEPLOYMENT_ACCESS — openresty/SNI.
|
||||
|
||||
## 16. DEPLOYMENT
|
||||
|
||||
`:3100` updated Stage 2D; rollback retained.
|
||||
|
||||
## 17. TEST_RESULTS
|
||||
|
||||
- tsc / vitest 199 / build PASS
|
||||
- drop 7/7 PASS
|
||||
- stage2c layout e2e previously green
|
||||
|
||||
## 18. KNOWN_LIMITATIONS
|
||||
|
||||
- Not author REAL_CAD mechanism
|
||||
- No FreeCAD binary → STEP+params instead of FCStd
|
||||
- No runtime WebM
|
||||
- Physics p95 not separately metered
|
||||
- Domain/phone incomplete
|
||||
- Profile D drawCall counter unreliable under post
|
||||
|
||||
## 19. DECISION
|
||||
|
||||
| Question | Answer |
|
||||
|---|---|
|
||||
| Performance FAIL fixed? | YES (root cause was missing data; hardware PASS) |
|
||||
| GPU | NVIDIA GTX 1080 |
|
||||
| CAD mechanism? | SPEC_DERIVED_CAD (not REAL_CAD) |
|
||||
| Contact? | PASS (headless + kinematic) |
|
||||
| Runtime falls realistic? | PARTIAL (no WebM) |
|
||||
| Runtime/headless? | PASS |
|
||||
| Domain? | BLOCKED |
|
||||
| Phone? | NOT_TESTED |
|
||||
|
||||
## 20. FILES_CHANGED
|
||||
|
||||
See git commit.
|
||||
|
||||
## 21. FINAL_GIT_CHECK
|
||||
|
||||
(after commit)
|
||||
6
docs/stage2d/bundle-impact.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Bundle impact — Stage 2D
|
||||
|
||||
- Twin chunk ~4.72 MB (unchanged order of magnitude)
|
||||
- Added `mechanism-web.glb` (~8 KB)
|
||||
- Device test page tiny
|
||||
- DPR cap 1.25 demo/high; shadow map 1024; selective CAD shadow casters
|
||||
5
docs/stage2d/console-errors.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"spotCheck": "/?perf=1&playback=paused",
|
||||
"errors": [],
|
||||
"note": "No automated console scrape matrix; spot-check during perf runs"
|
||||
}
|
||||
22
docs/stage2d/deployment-report.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Deployment — Stage 2D
|
||||
|
||||
## Local
|
||||
|
||||
- Preview: `http://127.0.0.1:3101/`
|
||||
- Production container `owl-web-1` on `127.0.0.1:3100` updated with Stage 2D dist (`index-Br8LRV1M.js`)
|
||||
- Rollback: previous image `owl-web:20260730-121615` not deleted
|
||||
|
||||
## Public
|
||||
|
||||
- `sorter.arhipovdan.ru` A→185.160.137.162 openresty 404 / TLS unrecognized_name
|
||||
- Cloudflare Named Tunnel: no origin cert in environment → cannot bind hostname
|
||||
- Status: **BLOCKED_BY_DEPLOYMENT_ACCESS**
|
||||
|
||||
## Required DNS (owner)
|
||||
|
||||
```
|
||||
Type: CNAME
|
||||
Name: sorter
|
||||
Target: <tunnel-id>.cfargotunnel.com
|
||||
Proxy: enabled
|
||||
```
|
||||
138
docs/stage2d/drop-validation.json
Normal file
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"generatedAt": "2026-07-30T12:48:49.673Z",
|
||||
"sim": "headless Rapier via simulateDrop (deterministic, dt=1/60, settle 6s)",
|
||||
"runs": 10,
|
||||
"routes": [
|
||||
{
|
||||
"sku": "SKU-001",
|
||||
"route": "box → B",
|
||||
"expectedZone": "B",
|
||||
"runs": 10,
|
||||
"correctLandings": 10,
|
||||
"penetrations": 0,
|
||||
"teleports": 0,
|
||||
"outOfBounds": 0,
|
||||
"frozenInAir": 0,
|
||||
"pusherContacts": "n/a",
|
||||
"sampleFinalPositions": [
|
||||
"(3.00,0.23,-0.00)",
|
||||
"(3.00,0.23,-0.00)",
|
||||
"(3.00,0.23,-0.00)"
|
||||
],
|
||||
"result": "PASS"
|
||||
},
|
||||
{
|
||||
"sku": "SKU-009",
|
||||
"route": "pen → C",
|
||||
"expectedZone": "C",
|
||||
"runs": 10,
|
||||
"correctLandings": 10,
|
||||
"penetrations": 0,
|
||||
"teleports": 0,
|
||||
"outOfBounds": 0,
|
||||
"frozenInAir": 0,
|
||||
"pusherContacts": 10,
|
||||
"sampleFinalPositions": [
|
||||
"(1.66,0.08,2.32)",
|
||||
"(1.66,0.08,2.32)",
|
||||
"(1.66,0.08,2.32)"
|
||||
],
|
||||
"result": "PASS"
|
||||
},
|
||||
{
|
||||
"sku": "SKU-005",
|
||||
"route": "pouf → C",
|
||||
"expectedZone": "C",
|
||||
"runs": 10,
|
||||
"correctLandings": 10,
|
||||
"penetrations": 0,
|
||||
"teleports": 0,
|
||||
"outOfBounds": 0,
|
||||
"frozenInAir": 0,
|
||||
"pusherContacts": 10,
|
||||
"sampleFinalPositions": [
|
||||
"(1.96,0.27,1.68)",
|
||||
"(1.96,0.27,1.68)",
|
||||
"(1.96,0.27,1.68)"
|
||||
],
|
||||
"result": "PASS"
|
||||
},
|
||||
{
|
||||
"sku": "SKU-004",
|
||||
"route": "oversized → C",
|
||||
"expectedZone": "C",
|
||||
"runs": 10,
|
||||
"correctLandings": 10,
|
||||
"penetrations": 0,
|
||||
"teleports": 0,
|
||||
"outOfBounds": 0,
|
||||
"frozenInAir": 0,
|
||||
"pusherContacts": 10,
|
||||
"sampleFinalPositions": [
|
||||
"(1.95,0.30,1.58)",
|
||||
"(1.95,0.30,1.58)",
|
||||
"(1.95,0.30,1.58)"
|
||||
],
|
||||
"result": "PASS"
|
||||
},
|
||||
{
|
||||
"sku": "SKU-007",
|
||||
"route": "bottle → D",
|
||||
"expectedZone": "D",
|
||||
"runs": 10,
|
||||
"correctLandings": 10,
|
||||
"penetrations": 0,
|
||||
"teleports": 0,
|
||||
"outOfBounds": 0,
|
||||
"frozenInAir": 0,
|
||||
"pusherContacts": 10,
|
||||
"sampleFinalPositions": [
|
||||
"(2.34,0.12,-1.95)",
|
||||
"(2.34,0.12,-1.95)",
|
||||
"(2.34,0.12,-1.95)"
|
||||
],
|
||||
"result": "PASS"
|
||||
},
|
||||
{
|
||||
"sku": "SKU-006",
|
||||
"route": "plate → D",
|
||||
"expectedZone": "D",
|
||||
"runs": 10,
|
||||
"correctLandings": 10,
|
||||
"penetrations": 0,
|
||||
"teleports": 0,
|
||||
"outOfBounds": 0,
|
||||
"frozenInAir": 0,
|
||||
"pusherContacts": 10,
|
||||
"sampleFinalPositions": [
|
||||
"(1.89,0.09,-1.80)",
|
||||
"(1.89,0.09,-1.80)",
|
||||
"(1.89,0.09,-1.80)"
|
||||
],
|
||||
"result": "PASS"
|
||||
},
|
||||
{
|
||||
"sku": "SKU-008",
|
||||
"route": "cylinder → D",
|
||||
"expectedZone": "D",
|
||||
"runs": 10,
|
||||
"correctLandings": 10,
|
||||
"penetrations": 0,
|
||||
"teleports": 0,
|
||||
"outOfBounds": 0,
|
||||
"frozenInAir": 0,
|
||||
"pusherContacts": 10,
|
||||
"sampleFinalPositions": [
|
||||
"(2.22,0.10,-2.28)",
|
||||
"(2.22,0.10,-2.28)",
|
||||
"(2.22,0.10,-2.28)"
|
||||
],
|
||||
"result": "PASS"
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"totalRoutes": 7,
|
||||
"passedRoutes": 7,
|
||||
"result": "PASS"
|
||||
}
|
||||
}
|
||||
36
docs/stage2d/mechanism-cad-report.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Mechanism CAD report — SPEC_DERIVED_CAD
|
||||
|
||||
## Status
|
||||
|
||||
`SPEC_DERIVED_CAD` — **not** original author FreeCAD.
|
||||
|
||||
## Origin of dimensions
|
||||
|
||||
1. `src/domain/pusherMotion.ts` — paddle half-extents, stroke, yaw, engage point
|
||||
2. `docs/stage2_real_sorter/mechanism-map.md` — pneumatic angled paddle class
|
||||
3. Prior Stage 2B visual housing sizes (servo Ø90×160 mm)
|
||||
|
||||
## Geometry (mm)
|
||||
|
||||
| Part | Size |
|
||||
|---|---|
|
||||
| Paddle plate | 1000 × 280 × 50 |
|
||||
| Leading edge | 1000 × 280 × 4 |
|
||||
| Servo body | Ø90 × 160 |
|
||||
| Shaft | Ø20 × 60 |
|
||||
| Bracket / housing | documented in params JSON |
|
||||
| Axis height above belt | 142 |
|
||||
| Stroke | 1620 |
|
||||
| Yaw | ≈20.4° |
|
||||
|
||||
## Files
|
||||
|
||||
- `3d_models/sorter_mechanism.step`
|
||||
- `3d_models/sorter_mechanism.params.json`
|
||||
- `public/models/sorter/mechanism-web.glb` (~244 tris)
|
||||
- Pivot: plate center = Rapier body origin (matches collider)
|
||||
|
||||
## Runtime
|
||||
|
||||
`PusherMechanism` loads GLB; collider remains domain cuboid for headless parity.
|
||||
JSX mesh is Suspense fallback only.
|
||||
80
docs/stage2d/mechanism-source-inventory.json
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"status": "SPEC_DERIVED_CAD",
|
||||
"notAuthorCad": true,
|
||||
"sourceOfDimensions": [
|
||||
"src/domain/pusherMotion.ts PUSHER constants",
|
||||
"docs/stage2_real_sorter/mechanism-map.md",
|
||||
"PusherMechanism.tsx visual housing sizes"
|
||||
],
|
||||
"units": "mm",
|
||||
"paddle": {
|
||||
"length": 1000,
|
||||
"height": 280,
|
||||
"thickness": 50
|
||||
},
|
||||
"leadingEdge": {
|
||||
"thickness": 4
|
||||
},
|
||||
"servo": {
|
||||
"diameter": 90,
|
||||
"length": 160
|
||||
},
|
||||
"shaft": {
|
||||
"diameter": 20,
|
||||
"length": 60
|
||||
},
|
||||
"axisHeightAboveBeltMm": 142,
|
||||
"strokeMm": 1620,
|
||||
"yawDeg": 20.4,
|
||||
"homeDistanceMm": 400,
|
||||
"glb": "public/models/sorter/mechanism-web.glb",
|
||||
"step": "3d_models/sorter_mechanism.step",
|
||||
"parts": [
|
||||
{
|
||||
"name": "paddle-plate",
|
||||
"triangles": 12,
|
||||
"stl": "paddle-plate.stl"
|
||||
},
|
||||
{
|
||||
"name": "rib-l",
|
||||
"triangles": 12,
|
||||
"stl": "rib-l.stl"
|
||||
},
|
||||
{
|
||||
"name": "rib-c",
|
||||
"triangles": 12,
|
||||
"stl": "rib-c.stl"
|
||||
},
|
||||
{
|
||||
"name": "rib-r",
|
||||
"triangles": 12,
|
||||
"stl": "rib-r.stl"
|
||||
},
|
||||
{
|
||||
"name": "servo-body",
|
||||
"triangles": 96,
|
||||
"stl": "servo-body.stl"
|
||||
},
|
||||
{
|
||||
"name": "servo-shaft",
|
||||
"triangles": 64,
|
||||
"stl": "servo-shaft.stl"
|
||||
},
|
||||
{
|
||||
"name": "bracket",
|
||||
"triangles": 12,
|
||||
"stl": "bracket.stl"
|
||||
},
|
||||
{
|
||||
"name": "housing",
|
||||
"triangles": 12,
|
||||
"stl": "housing.stl"
|
||||
},
|
||||
{
|
||||
"name": "leading-edge",
|
||||
"triangles": 12,
|
||||
"stl": "leading-edge.stl"
|
||||
}
|
||||
],
|
||||
"sha256_glb": "eb973217d4ec7288f784d93e6f539b4f3d29fb3163d6788b5467c97451588ed6"
|
||||
}
|
||||
31
docs/stage2d/mechanism-source-search.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Mechanism source search — Stage 2D
|
||||
|
||||
## Scope (read-only)
|
||||
|
||||
- Current working tree
|
||||
- Local + remote branches (`git branch -a`)
|
||||
- Git history (add/delete) for pusher/paddle/diverter/actuator/servo/mechanism/толкатель/заслонка
|
||||
- `*.FCStd` / `*.step` / `*.stp` / archives under `input_info/` and `releases/`
|
||||
- Git LFS listing
|
||||
|
||||
## Findings
|
||||
|
||||
| Source | Result |
|
||||
|---|---|
|
||||
| Author CAD | Only `3d_models/conveer.FCStd` — metering servos + barriers, **no junction paddle** |
|
||||
| Archives (`input_info/*.zip`) | No FCStd/STEP paddle/diverter solids |
|
||||
| Git history | No deleted junction CAD; Stage 2B added `pusherMotion.ts` + JSX `PusherMechanism` |
|
||||
| Branches | No alternate FCStd mechanism on `main` / `dan_branch` / stage2 branches |
|
||||
| LFS | Empty / unused for CAD |
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Author REAL_CAD junction mechanism: MISSING.**
|
||||
|
||||
Stage 2D delivers **SPEC_DERIVED_CAD**:
|
||||
- `3d_models/sorter_mechanism.step`
|
||||
- `3d_models/sorter_mechanism.params.json`
|
||||
- `public/models/sorter/mechanism-web.glb`
|
||||
- Built by `tools/stage2d-mechanism/` from documented `PUSHER` dimensions
|
||||
|
||||
FreeCAD `.FCStd` binary not generated (FreeCAD package unavailable in environment). STEP + parametric JSON + GLB are the engineering CAD source.
|
||||
27
docs/stage2d/mobile-device-test.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Mobile / phone test
|
||||
|
||||
## Local diagnostics
|
||||
|
||||
- Route: `/device-test`
|
||||
- Shows UA, WebGL renderer, DPR, mobile tier, Telegram WebView flag
|
||||
- Screenshot: `screenshots/09-mobile-device-test.png`
|
||||
|
||||
## Real devices
|
||||
|
||||
**NOT_TESTED_ON_REAL_PHONE**
|
||||
|
||||
No physical Android/iPhone session in this Stage 2D run.
|
||||
|
||||
## Public HTTPS for phone
|
||||
|
||||
Blocked: `sorter.arhipovdan.ru` → A `185.160.137.162` openresty without vhost/TLS SNI.
|
||||
Named Tunnel credentials unavailable (`cloudflared tunnel list` needs origin cert).
|
||||
|
||||
Owner DNS action for Named Tunnel (when credentials exist):
|
||||
|
||||
```
|
||||
Type: CNAME
|
||||
Name: sorter
|
||||
Target: <tunnel-id>.cfargotunnel.com
|
||||
Proxy: enabled
|
||||
```
|
||||
95
docs/stage2d/performance-cad-light.json
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"profile": "A-cad-light",
|
||||
"generatedAt": "2026-07-30T12:50:34.566Z",
|
||||
"baseUrl": "http://127.0.0.1:3101",
|
||||
"gpuArgs": [
|
||||
"--no-sandbox",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--enable-gpu",
|
||||
"--use-angle=vulkan",
|
||||
"--disable-software-rasterizer"
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 52.08,
|
||||
"p95FrameTimeMs": 16.8,
|
||||
"p99FrameTimeMs": 16.9,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 162,
|
||||
"triangles": 182201,
|
||||
"geometries": 161,
|
||||
"textures": 6,
|
||||
"programs": 14,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
},
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 43.67,
|
||||
"p95FrameTimeMs": 16.8,
|
||||
"p99FrameTimeMs": 17,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 162,
|
||||
"triangles": 182201,
|
||||
"geometries": 161,
|
||||
"textures": 6,
|
||||
"programs": 14,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
},
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 53.76,
|
||||
"p95FrameTimeMs": 16.8,
|
||||
"p99FrameTimeMs": 16.9,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 162,
|
||||
"triangles": 182201,
|
||||
"geometries": 161,
|
||||
"textures": 6,
|
||||
"programs": 14,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
}
|
||||
],
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"minFps": 52.08,
|
||||
"p95Ms": 16.8,
|
||||
"p99Ms": 16.9,
|
||||
"drawCalls": 162,
|
||||
"triangles": 182201,
|
||||
"heapMb": 28.04
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"hardwareAccelerated": true,
|
||||
"budget": {
|
||||
"avgFpsMin": 45,
|
||||
"avgFpsTarget": 55,
|
||||
"p95Max": 28,
|
||||
"p95Target": 20,
|
||||
"drawCallsMax": 250,
|
||||
"trisMax": 500000,
|
||||
"trisTarget": 350000
|
||||
},
|
||||
"pass": "PASS"
|
||||
}
|
||||
95
docs/stage2d/performance-cad-physics.json
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"profile": "B-cad-physics",
|
||||
"generatedAt": "2026-07-30T12:52:18.106Z",
|
||||
"baseUrl": "http://127.0.0.1:3101",
|
||||
"gpuArgs": [
|
||||
"--no-sandbox",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--enable-gpu",
|
||||
"--use-angle=vulkan",
|
||||
"--disable-software-rasterizer"
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 43.1,
|
||||
"p95FrameTimeMs": 17.1,
|
||||
"p99FrameTimeMs": 18.7,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 149,
|
||||
"triangles": 197061,
|
||||
"geometries": 166,
|
||||
"textures": 6,
|
||||
"programs": 15,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
},
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 46.73,
|
||||
"p95FrameTimeMs": 17,
|
||||
"p99FrameTimeMs": 17.6,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 152,
|
||||
"triangles": 197087,
|
||||
"geometries": 166,
|
||||
"textures": 6,
|
||||
"programs": 15,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
},
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 38.46,
|
||||
"p95FrameTimeMs": 16.91,
|
||||
"p99FrameTimeMs": 17.6,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 168,
|
||||
"triangles": 216049,
|
||||
"geometries": 166,
|
||||
"textures": 6,
|
||||
"programs": 15,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
}
|
||||
],
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"minFps": 43.1,
|
||||
"p95Ms": 17,
|
||||
"p99Ms": 17.6,
|
||||
"drawCalls": 152,
|
||||
"triangles": 197087,
|
||||
"heapMb": 28.04
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"hardwareAccelerated": true,
|
||||
"budget": {
|
||||
"avgFpsMin": 45,
|
||||
"avgFpsTarget": 55,
|
||||
"p95Max": 28,
|
||||
"p95Target": 20,
|
||||
"drawCallsMax": 250,
|
||||
"trisMax": 500000,
|
||||
"trisTarget": 350000
|
||||
},
|
||||
"pass": "PASS"
|
||||
}
|
||||
38
docs/stage2d/performance-cinematic-full.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"profile": "D-cinematic-full",
|
||||
"generatedAt": "2026-07-30T12:58:50.823Z",
|
||||
"note": "Remeasured after matrix; prior draws=1 was reset race",
|
||||
"runs": [
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 33.33,
|
||||
"p95FrameTimeMs": 17.1,
|
||||
"p99FrameTimeMs": 17.6,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 1,
|
||||
"triangles": 1,
|
||||
"geometries": 155,
|
||||
"textures": 29,
|
||||
"programs": 19,
|
||||
"heapMb": 26.32,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
}
|
||||
],
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"minFps": 33.33,
|
||||
"p95Ms": 17.1,
|
||||
"drawCalls": 1,
|
||||
"triangles": 1,
|
||||
"heapMb": 26.32
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"hardwareAccelerated": true,
|
||||
"pass": "PASS"
|
||||
}
|
||||
100
docs/stage2d/performance-comparison.json
Normal file
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"generatedAt": "2026-07-30T13:00:00Z",
|
||||
"gpu": "NVIDIA GeForce GTX 1080 via ANGLE Vulkan",
|
||||
"stage2cRootCause": "NOT_REMEASURED / insufficient hardware data \u2014 not a measured FPS fail",
|
||||
"profiles": [
|
||||
{
|
||||
"id": "A-cad-light",
|
||||
"pass": "PASS",
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"minFps": 52.08,
|
||||
"p95Ms": 16.8,
|
||||
"p99Ms": 16.9,
|
||||
"drawCalls": 162,
|
||||
"triangles": 182201,
|
||||
"heapMb": 28.04
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"extra": {}
|
||||
},
|
||||
{
|
||||
"id": "B-cad-physics",
|
||||
"pass": "PASS",
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"minFps": 43.1,
|
||||
"p95Ms": 17,
|
||||
"p99Ms": 17.6,
|
||||
"drawCalls": 152,
|
||||
"triangles": 197087,
|
||||
"heapMb": 28.04
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"extra": {}
|
||||
},
|
||||
{
|
||||
"id": "C-full-runtime",
|
||||
"pass": "PASS",
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"minFps": 34.01,
|
||||
"p95Ms": 17.1,
|
||||
"p99Ms": 18.8,
|
||||
"drawCalls": 174,
|
||||
"triangles": 216149,
|
||||
"heapMb": 28.04
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"extra": {}
|
||||
},
|
||||
{
|
||||
"id": "D-cinematic-full",
|
||||
"pass": "PASS",
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"minFps": 33.33,
|
||||
"p95Ms": 17.1,
|
||||
"drawCalls": 1,
|
||||
"triangles": 1,
|
||||
"heapMb": 26.32
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"extra": {
|
||||
"note": "Remeasured after matrix; prior draws=1 was reset race"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "E-mobile-low",
|
||||
"pass": "PASS_SVG_POLICY",
|
||||
"median": {
|
||||
"avgFps": null,
|
||||
"p95Ms": null,
|
||||
"drawCalls": null,
|
||||
"triangles": null
|
||||
},
|
||||
"renderer": "N/A (SVG)",
|
||||
"extra": {
|
||||
"note": "At 390px prefer3DByDefault=false \u2192 SVG fallback by design (no WebGL canvas)",
|
||||
"svgFallback": true,
|
||||
"low3dAt800px": {
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"p95Ms": 17.1,
|
||||
"drawCalls": 109,
|
||||
"triangles": 177389
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"hardwareAccelerated": true,
|
||||
"pass": "PASS"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"desktopVerdict": "PASS",
|
||||
"notes": [
|
||||
"PerfCollector drawCalls/triangles are Three.js last-frame counters after reset",
|
||||
"Profile D drawCalls=1 is instrumentation artifact under stage0+post; FPS/p95 still hardware-valid",
|
||||
"Physics p95 not separately instrumented; fixed dt=1/60, max 4 substeps"
|
||||
]
|
||||
}
|
||||
95
docs/stage2d/performance-full-runtime.json
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"profile": "C-full-runtime",
|
||||
"generatedAt": "2026-07-30T12:54:01.434Z",
|
||||
"baseUrl": "http://127.0.0.1:3101",
|
||||
"gpuArgs": [
|
||||
"--no-sandbox",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--enable-gpu",
|
||||
"--use-angle=vulkan",
|
||||
"--disable-software-rasterizer"
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 41.32,
|
||||
"p95FrameTimeMs": 17.2,
|
||||
"p99FrameTimeMs": 18.2,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 174,
|
||||
"triangles": 216149,
|
||||
"geometries": 170,
|
||||
"textures": 6,
|
||||
"programs": 16,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
},
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 34.01,
|
||||
"p95FrameTimeMs": 17.1,
|
||||
"p99FrameTimeMs": 19.3,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 151,
|
||||
"triangles": 197075,
|
||||
"geometries": 166,
|
||||
"textures": 6,
|
||||
"programs": 15,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
},
|
||||
{
|
||||
"mode": "demo",
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"averageFps": 60,
|
||||
"minimumFps": 33.11,
|
||||
"p95FrameTimeMs": 17.01,
|
||||
"p99FrameTimeMs": 18.8,
|
||||
"longFramesOver33": 0,
|
||||
"longFramesOver50": 0,
|
||||
"drawCalls": 174,
|
||||
"triangles": 216149,
|
||||
"geometries": 170,
|
||||
"textures": 6,
|
||||
"programs": 16,
|
||||
"heapMb": 28.04,
|
||||
"dpr": 1,
|
||||
"shadows": true,
|
||||
"antialias": true,
|
||||
"hardwareAccelerated": true
|
||||
}
|
||||
],
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"minFps": 34.01,
|
||||
"p95Ms": 17.1,
|
||||
"p99Ms": 18.8,
|
||||
"drawCalls": 174,
|
||||
"triangles": 216149,
|
||||
"heapMb": 28.04
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"hardwareAccelerated": true,
|
||||
"budget": {
|
||||
"avgFpsMin": 45,
|
||||
"avgFpsTarget": 55,
|
||||
"p95Max": 28,
|
||||
"p95Target": 20,
|
||||
"drawCallsMax": 250,
|
||||
"trisMax": 500000,
|
||||
"trisTarget": 350000
|
||||
},
|
||||
"pass": "PASS"
|
||||
}
|
||||
29
docs/stage2d/performance-mobile-low.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"profile": "E-mobile-low",
|
||||
"note": "At 390px prefer3DByDefault=false → SVG fallback by design (no WebGL canvas)",
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 844
|
||||
},
|
||||
"svgFallback": true,
|
||||
"pass": "PASS_SVG_POLICY",
|
||||
"hardwareAccelerated": true,
|
||||
"renderer": "N/A (SVG)",
|
||||
"median": {
|
||||
"avgFps": null,
|
||||
"p95Ms": null,
|
||||
"drawCalls": null,
|
||||
"triangles": null
|
||||
},
|
||||
"low3dAt800px": {
|
||||
"median": {
|
||||
"avgFps": 60,
|
||||
"p95Ms": 17.1,
|
||||
"drawCalls": 109,
|
||||
"triangles": 177389
|
||||
},
|
||||
"renderer": "ANGLE (NVIDIA, Vulkan 1.4.312 (NVIDIA NVIDIA GeForce GTX 1080 (0x00001B80)), NVIDIA)",
|
||||
"hardwareAccelerated": true,
|
||||
"pass": "PASS"
|
||||
}
|
||||
}
|
||||
43
docs/stage2d/performance-root-cause.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Performance root cause — Stage 2C FAIL
|
||||
|
||||
## Verdict
|
||||
|
||||
Stage 2C `performance: FAIL` was **not** a measured hardware FPS failure.
|
||||
|
||||
Evidence from `docs/stage2c_cad_visual/performance-*.json`:
|
||||
|
||||
- `status: NOT_REMEASURED` / `measured: null`
|
||||
- Explicit note: formal multi-run GPU profile deferred
|
||||
|
||||
## Classification
|
||||
|
||||
**INSUFFICIENT_HARDWARE_PERFORMANCE_DATA** (Stage 2C) — profiles never run on a hardware renderer.
|
||||
|
||||
## Environment (Stage 2D probe)
|
||||
|
||||
| Path | Renderer |
|
||||
|---|---|
|
||||
| Playwright default / SwiftShader | `ANGLE (... SwiftShader Device (Subzero) ...)` |
|
||||
| Playwright `--use-angle=vulkan` | `ANGLE (NVIDIA, ... GeForce GTX 1080 ...)` |
|
||||
| Host | 2× NVIDIA GeForce GTX 1080 (driver 580.126.09) |
|
||||
|
||||
SwiftShader results must **not** be used for PASS/FAIL.
|
||||
|
||||
## Likely cost drivers (code audit, pre-optimization)
|
||||
|
||||
1. CAD GLB ~159k tris, every mesh `castShadow` when shadows on
|
||||
2. Demo quality: `dprMax 1.5`, AA on, PCFSoft shadows
|
||||
3. Hybrid Rapier always mounted on continuous twin
|
||||
4. Modular belt extensions add extra meshes/rollers
|
||||
5. ACES + soft shadows default (Stage 2 premium look)
|
||||
|
||||
## Regression narrative
|
||||
|
||||
| Stage | Note |
|
||||
|---|---|
|
||||
| Stage 0 | Cinematic light / optional post — measured in Stage 0 docs |
|
||||
| Stage 1 | Real STL products |
|
||||
| Stage 2B | CAD GLB + Rapier drops + soft shadows default |
|
||||
| Stage 2C | UI/layout/motor cleanup; **no new GPU matrix** → FAIL by omission |
|
||||
|
||||
No single commit proves FPS regression without Stage 2C numbers; Stage 2D supplies hardware matrix.
|
||||
8
docs/stage2d/public-domain-smoke.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"hostname": "sorter.arhipovdan.ru",
|
||||
"aRecord": "185.160.137.162",
|
||||
"http": { "status": 404, "server": "openresty" },
|
||||
"https": { "status": "TLS unrecognized_name alert 112", "certificate": null },
|
||||
"localProduction": "http://127.0.0.1:3100/",
|
||||
"status": "BLOCKED_BY_DEPLOYMENT_ACCESS"
|
||||
}
|
||||
13
docs/stage2d/runtime-drop-review.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Runtime drop review — Stage 2D
|
||||
|
||||
| SKU | Route | Headless | Runtime | Contact | Visual realism | Result |
|
||||
|---|---|---|---|---|---|---|
|
||||
| SKU-001 box | B | 10/10 | stills only | n/a | PARTIAL (no WebM) | PARTIAL |
|
||||
| SKU-009 pen | C | 10/10 | stills | yes | PARTIAL | PARTIAL |
|
||||
| SKU-005 pouf | C | 10/10 | stills | yes | PARTIAL | PARTIAL |
|
||||
| SKU-004 oversized | C | 10/10 | stills | yes | PARTIAL | PARTIAL |
|
||||
| SKU-007 bottle | D | 10/10 | stills | yes | PARTIAL | PARTIAL |
|
||||
| SKU-006 plate | D | 10/10 | stills | yes | PARTIAL | PARTIAL |
|
||||
| SKU-008 cylinder | D | 10/10 | stills | yes | PARTIAL | PARTIAL |
|
||||
|
||||
Headless: 7/7 PASS. Runtime WebM not recorded → overall visual review **PARTIAL**.
|
||||
8
docs/stage2d/runtime-headless-config-hash.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"generatedAt": "2026-07-30T12:48:51.344Z",
|
||||
"runtime": "7ee15ad3e879a44a",
|
||||
"headless": "7ee15ad3e879a44a",
|
||||
"equal": true,
|
||||
"timestepEqual": true,
|
||||
"note": "canonical PHYSICS_TIMESTEP_SEC parity"
|
||||
}
|
||||
BIN
docs/stage2d/screenshots/01-performance-overlay-cad-light.png
Normal file
|
After Width: | Height: | Size: 306 KiB |
BIN
docs/stage2d/screenshots/02-performance-overlay-physics.png
Normal file
|
After Width: | Height: | Size: 326 KiB |
BIN
docs/stage2d/screenshots/03-real-mechanism-source.png
Normal file
|
After Width: | Height: | Size: 304 KiB |
BIN
docs/stage2d/screenshots/04-real-mechanism-runtime.png
Normal file
|
After Width: | Height: | Size: 325 KiB |
BIN
docs/stage2d/screenshots/05-mechanism-contact.png
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
docs/stage2d/screenshots/06-runtime-route-b.png
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
docs/stage2d/screenshots/07-runtime-route-c.png
Normal file
|
After Width: | Height: | Size: 337 KiB |
BIN
docs/stage2d/screenshots/08-runtime-route-d.png
Normal file
|
After Width: | Height: | Size: 274 KiB |
BIN
docs/stage2d/screenshots/09-mobile-device-test.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
docs/stage2d/screenshots/10-public-domain.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
10
docs/stage2d/videos/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Stage 2D runtime videos
|
||||
|
||||
WebM recordings are **not** included in this drop (no automated MediaRecorder capture in CI/agent).
|
||||
|
||||
Evidence substitutes:
|
||||
- Hardware GPU performance JSON (GTX 1080, profiles A–E)
|
||||
- Headless drop validation 7/7 × 10/10 with pusher contact
|
||||
- Still screenshots of mechanism / routes
|
||||
|
||||
`runtime_visual_review: PARTIAL` until WebM is captured on a desktop session.
|
||||