Skip to content
Draft

Large diffs are not rendered by default.

117 changes: 117 additions & 0 deletions examples/skinned-crowd/playtests/crowd-rate.playtest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{
"name": "crowd-rate-measured-baseline",
"schemaVersion": 1,
"subject": "Run with ?tnFrameSpans=1&crowdCount=32|128|256&crowdArm=animated|held|static. CPU spans cover actual AnimationPlayer.update and SkinnedBatch.write calls; held versus baked static controls report main and shadow GPU buckets separately.",
"target": "web",
"viewport": {
"width": 1280,
"height": 720
},
"warmupFrames": 120,
"artifacts": {
"screenshots": false
},
"steps": [
{
"label": "completed-post-warmup-window",
"timeoutMs": 30000,
"waitForResource": {
"id": "state",
"path": "crowdRate.window",
"gte": 2
}
},
{
"label": "complete-cpu-window-and-resolved-gpu-samples",
"timeoutMs": 30000,
"waitForResource": {
"id": "state",
"path": "crowdRate.ready",
"equals": true
}
}
],
"assert": {
"diagnostics": {
"noConsoleErrors": true,
"noNetworkErrors": true,
"runtimeReady": true
},
"resources": [
{
"id": "state",
"path": "crowdRate.measuring",
"equals": true,
"allowTrivial": "The crowdCount URL selects measurement mode before the startup observation; the post-baseline measured.window and measurement checks remain unwaived."
},
{
"id": "state",
"path": "crowdRate.count",
"gte": 32,
"lte": 256,
"allowTrivial": "The crowdCount URL fixes the cohort size at boot; the post-baseline measured.window and measurement checks remain unwaived."
},
{
"id": "state",
"path": "crowdRate.projectedRigs",
"gte": 32,
"allowTrivial": "Crowd.enter computes a projected held-pose observation per rig before startup sampling; the post-baseline measured.window and measurement checks remain unwaived."
},
{
"id": "state",
"path": "crowdRate.ready",
"equals": true
},
{
"id": "state",
"path": "crowdRate.measured.gpuSamples",
"gte": 1
},
{
"id": "state",
"path": "crowdRate.measured.gpuMainSamples",
"gte": 1
},
{
"id": "state",
"path": "crowdRate.measured.gpuShadowSamples",
"gte": 1
},
{
"id": "state",
"path": "crowdRate.measured.gpuMainMs",
"gte": 0
},
{
"id": "state",
"path": "crowdRate.measured.gpuShadowMs",
"gte": 0
},
{
"id": "state",
"path": "crowdRate.measured.mainDraws",
"gte": 1
},
{
"id": "state",
"path": "crowdRate.measured.shadowDraws",
"gte": 1
},
{
"id": "state",
"path": "crowdRate.measured.window",
"gte": 2
},
{
"id": "state",
"path": "crowdRate.measured.renderFrames",
"equals": 120
},
{
"id": "state",
"path": "crowdRate.window",
"gte": 2
}
]
}
}
10 changes: 8 additions & 2 deletions examples/skinned-crowd/src/game.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { defineGame } from "@threenative/core";
import { playtest } from "@threenative/core/playtest";
import { Crowd } from "./scenes/Crowd.js";
import { Crowd, crowdBudget, crowdRate, crowdSpans } from "./scenes/Crowd.js";

/**
* A crowd of animated rigs written the way any game writes one: ordinary `SkinnedMesh` objects
Expand All @@ -9,7 +9,13 @@ import { Crowd } from "./scenes/Crowd.js";
*/
const game = defineGame({
plugins: [playtest()],
initialState: {},
initialState: { crowdRate: {} },
frameBudget: crowdRate.measuring
? { reportEvery: 120, onWindow: crowdBudget, report: crowdSpans }
: undefined,
renderer: crowdRate.measuring
? { gpuTimestampFrameInterval: 1, resolutionScale: 1, pixelRatio: 1 }
: undefined,
render: { preferWebGPU: true },
scenes: { crowd: Crowd },
start: "crowd",
Expand Down
Loading