@@ -451,6 +456,37 @@ const examples = [
.hero-install {
margin-top: var(--s-5);
max-width: 420px;
+ display: grid;
+ gap: var(--s-3);
+ justify-items: start;
+ }
+
+ /*
+ * `/releases/latest` rather than a tag built from the package version:
+ * GitHub resolves it to whatever is newest, while the version in
+ * `package.json` is the one being developed and is ahead of the last
+ * release for most of a cycle - which would link a tag that does not exist
+ * yet.
+ */
+ .hero-download {
+ display: grid;
+ gap: 2px;
+ text-decoration: none;
+ color: var(--fg-muted);
+ font-size: 13px;
+ }
+
+ .hero-download-label {
+ color: var(--accent);
+ font-weight: 500;
+ }
+
+ .hero-download:hover .hero-download-label {
+ text-decoration: underline;
+ }
+
+ .hero-download-note {
+ color: var(--fg-faint);
}
.home .btn {
From 50f8d12670b955a0d11e924a783b9df694fb94e2 Mon Sep 17 00:00:00 2001
From: Exoridus
Date: Sat, 12 Sep 2026 05:38:38 +0200
Subject: [PATCH 14/28] release: summarize a changelog entry and fold the rest,
and ship a stable ZIP name
A squash commit's body is the pull request description, and the changelog put
all of it under the bullet. Fifteen of those end to end made the v0.17.0 release
page several thousand words of unbroken prose - the entries stopped being
scannable, which is the one thing release notes are for. An entry now leads with
its opening paragraph and keeps the rest in a `` fold: nothing is lost,
neither on the release page nor in `CHANGELOG.md`.
The release also uploads a second copy of the Full ZIP under a version-less
name. GitHub serves the newest release's assets at
`/releases/latest/download/`, which is a permanent direct-download URL
only for a name that does not move with the version - so the site's download
button can link the archive itself rather than the release page.
---
.github/workflows/release.yml | 10 ++++++
scripts/release/changelogFromCommits.ts | 35 ++++++++++++++++++++-
site/src/components/pages/HomePage.astro | 16 +++++-----
test/release/changelog-from-commits.test.ts | 19 +++++++++++
4 files changed, 72 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 967e80f03..c4bbedcc8 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -162,6 +162,15 @@ jobs:
--repo "${GITHUB_REPOSITORY}" \
--out ".release/release-notes.md"
+ # A second copy under a version-less name. GitHub serves the assets of the
+ # newest release at /releases/latest/download/, which is a
+ # permanent direct-download URL only for a name that does not move with
+ # the version - so the site can link the archive itself instead of the
+ # release page. The versioned name stays: it is what a downloaded file
+ # should be called once it is on disk.
+ - name: Add the version-less Full ZIP alias
+ run: cp ".release/exojs-${TARGET_TAG}-full.zip" .release/exojs-full.zip
+
- name: Create GitHub release with Full ZIP
uses: softprops/action-gh-release@v3
with:
@@ -170,5 +179,6 @@ jobs:
files: |
.release/exojs-${{ env.TARGET_TAG }}-full.zip
.release/exojs-${{ env.TARGET_TAG }}-full.zip.sha256
+ .release/exojs-full.zip
.release/artifacts/checksums.sha256
.release/artifacts/release-manifest.json
diff --git a/scripts/release/changelogFromCommits.ts b/scripts/release/changelogFromCommits.ts
index 7360cae7f..b4dd86e87 100644
--- a/scripts/release/changelogFromCommits.ts
+++ b/scripts/release/changelogFromCommits.ts
@@ -111,12 +111,45 @@ const indentBody = (body: string): string =>
.join('\n')
.replace(/\n{3,}/gu, '\n\n');
+/**
+ * Split a body into its opening paragraph and everything after it.
+ *
+ * A pull request description is written to be read once, by a reviewer with the
+ * diff open. A release is read by someone deciding whether to upgrade, and
+ * pasting a dozen such descriptions end to end leaves them several thousand
+ * words of prose with no shape - the entries stop being scannable and the
+ * release page becomes a wall. The opening paragraph is the part that answers
+ * "what changed"; the rest is the reasoning, the measurements and the
+ * follow-ups, which belong in the release but not in front of it.
+ */
+const splitSummary = (body: string): { summary: string; detail: string } => {
+ const trimmed = body.trim();
+ const separator = trimmed.indexOf('\n\n');
+
+ return separator === -1 ? { summary: trimmed, detail: '' } : { summary: trimmed.slice(0, separator).trim(), detail: trimmed.slice(separator).trim() };
+};
+
const renderEntry = (entry: ChangelogEntry, repoUrl: string): string => {
const link = entry.pullRequest !== null ? ` ([#${entry.pullRequest}](${repoUrl}/pull/${entry.pullRequest}))` : '';
const flag = entry.breaking ? 'BREAKING: ' : '';
const head = `- **${flag}${entry.title}.**${link}`;
- return entry.body.length > 0 ? `${head}\n${indentBody(entry.body)}` : head;
+ if (entry.body.length === 0) {
+ return head;
+ }
+
+ const { summary, detail } = splitSummary(entry.body);
+ const rendered = [head, indentBody(summary)];
+
+ if (detail.length > 0) {
+ // A fold rather than a cut: everything the description said is still in the
+ // release, one click away, and still in `CHANGELOG.md` for anyone reading
+ // the file. The blank line after the `` tag is what makes the
+ // Markdown inside render instead of appearing as source.
+ rendered.push(indentBody(['', 'Details', '', detail, '', ''].join('\n')));
+ }
+
+ return rendered.join('\n');
};
/**
diff --git a/site/src/components/pages/HomePage.astro b/site/src/components/pages/HomePage.astro
index 0ae3f1c86..e1a08db9d 100644
--- a/site/src/components/pages/HomePage.astro
+++ b/site/src/components/pages/HomePage.astro
@@ -156,9 +156,9 @@ const examples = [
@@ -462,11 +462,13 @@ const examples = [
}
/*
- * `/releases/latest` rather than a tag built from the package version:
- * GitHub resolves it to whatever is newest, while the version in
- * `package.json` is the one being developed and is ahead of the last
- * release for most of a cycle - which would link a tag that does not exist
- * yet.
+ * The archive itself, through GitHub's `/releases/latest/download/`
+ * redirect, so the button downloads instead of landing on release notes.
+ * It resolves against whatever release is newest, which is why the release
+ * workflow uploads a second copy of the Full ZIP under a version-less name:
+ * a URL carrying the version would have to be rebuilt for every release,
+ * and the version in `package.json` is the one being developed and is ahead
+ * of the last release for most of a cycle.
*/
.hero-download {
display: grid;
diff --git a/test/release/changelog-from-commits.test.ts b/test/release/changelog-from-commits.test.ts
index 8ec0e843a..56bfa4be8 100644
--- a/test/release/changelog-from-commits.test.ts
+++ b/test/release/changelog-from-commits.test.ts
@@ -62,6 +62,25 @@ describe('renderUnreleasedEntries', () => {
expect(rendered).toContain(' It does things.');
});
+ test('keeps the opening paragraph in front and folds the rest away', () => {
+ const body = ['It does things.', 'And here is the long reasoning.', 'With a second paragraph of it.'].join('\n\n');
+ const rendered = renderUnreleasedEntries([classifyCommit(commit('feat: add a thing (#1)', body))!], '', REPO);
+
+ expect(rendered).toContain(' It does things.');
+ expect(rendered.indexOf('It does things.')).toBeLessThan(rendered.indexOf(''));
+ expect(rendered).toContain(' Details');
+ expect(rendered).toContain(' And here is the long reasoning.');
+ expect(rendered).toContain(' With a second paragraph of it.');
+ expect(rendered).toContain(' ');
+ });
+
+ test('leaves a single-paragraph body unfolded', () => {
+ const rendered = renderUnreleasedEntries([classifyCommit(commit('feat: add a thing (#1)', 'It does things.'))!], '', REPO);
+
+ expect(rendered).toContain(' It does things.');
+ expect(rendered).not.toContain('');
+ });
+
test('skips entries whose pull request the section already names', () => {
const entries = [classifyCommit(commit('feat: add a thing (#1)'))!, classifyCommit(commit('fix: fix a thing (#2)'))!];
const rendered = renderUnreleasedEntries(entries, '- **Hand-written.** ([#1](x/pull/1))', REPO);
From dbfcf7d0ef95eafd2e609f2ac418408552014ef4 Mon Sep 17 00:00:00 2001
From: Exoridus
Date: Sat, 12 Sep 2026 06:01:06 +0200
Subject: [PATCH 15/28] docs: one line per changelog entry, long-line prose,
subject-only commits
---
AGENTS.md | 2 +
CONTRIBUTING.md | 17 +++---
scripts/release/changelogFromCommits.ts | 57 +++++----------------
site/scripts/capture-screenshots.ts | 29 +++++++++++
test/release/changelog-from-commits.test.ts | 21 ++------
5 files changed, 57 insertions(+), 69 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index 8b34975c6..ab4eda344 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -18,6 +18,8 @@ Use `CONTRIBUTING.md` when a task touches repository conventions such as imports
package boundaries, distribution, build constants, or public API conventions.
Read package-local documentation when working inside that package.
+Prose is written in long lines: pull request descriptions, guides, `docs/`, READMEs, commit bodies. Break a line at the end of a paragraph or where the break carries meaning, never at a column width. Commits are their Conventional Commits subject (with `!` for a breaking change); the detail goes into the pull request description, which the changelog links to and does not copy.
+
`.workspace/` is private working context, not repository authority. Plans,
research, reviews, and temporary design artifacts belong there by default.
Agents may use relevant files there as context, but they are not part of the
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index eedf8fd9c..24e3eace4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -14,14 +14,15 @@ A release cuts by merging `next` into `main` and tagging; see
## Changelog: written by the release cut, not by pull requests
-`CHANGELOG.md` is not edited in a pull request. Its `## [Unreleased]` section
-is assembled at the release cut from the squash commits since the last tag:
-the Conventional Commits type files the entry (`feat` under Added, `fix` and
-`perf` under Fixed, `refactor` and any `!` under Changed, `docs` under
-Documentation; `ci`, `build`, `test`, `chore` and `style` stay out), the
-subject becomes the headline, and the pull request description becomes the
-prose. That makes the pull request description the release text - write it
-for a reader of the changelog, not for the reviewer alone.
+`CHANGELOG.md` is not edited in a pull request. Its `## [Unreleased]` section is assembled at the release cut from the squash commits since the last tag: the Conventional Commits type files the entry (`feat` under Added, `fix` and `perf` under Fixed, `refactor` and any `!` under Changed, `docs` under Documentation; `ci`, `build`, `test`, `chore` and `style` stay out), a `!` marks it breaking, and the subject becomes the line, linked to its pull request. The description is not copied in: the changelog is the quick read, the pull request is where the detail lives.
+
+## Commit subjects, pull request descriptions, and prose
+
+A commit is its Conventional Commits subject. It carries the scope, the `!` for a breaking change and the pull request number, and that is the whole of what the changelog and the release notes ever read from it. A body is optional and short; the reasoning belongs in the pull request.
+
+The pull request description is where the detail goes - what changed, why, what was measured, what a breaking change breaks and what to do about it. It is linked from the changelog line, so nothing needs saying twice.
+
+Prose - pull request descriptions, guides, `docs/`, READMEs, commit bodies where there is one - is written in long lines. Break a line where a paragraph ends or where a break carries meaning, never at a column. A wall of text wrapped at seventy characters reads as a wall of text everywhere it is rendered, and a diff over it shows every reflowed line as a change. Code comments follow the formatter; this rule is about text people read.
Two pull requests that both edited the top of the same section conflicted on
every second merge; the `lint:changelog` gate now fails a branch that touches
diff --git a/scripts/release/changelogFromCommits.ts b/scripts/release/changelogFromCommits.ts
index b4dd86e87..38ec2668a 100644
--- a/scripts/release/changelogFromCommits.ts
+++ b/scripts/release/changelogFromCommits.ts
@@ -3,12 +3,11 @@
* release instead of edited by hand in every pull request.
*
* Every squash merge carries a Conventional Commits subject with the pull
- * request number and the pull request description as its body, so the
- * changelog can be assembled at the cut: the type files the entry under a
- * Keep a Changelog heading, the subject becomes the headline, the body the
- * prose. Pull requests never touch `CHANGELOG.md`, which is what used to make
- * two of them conflict whenever both landed an entry at the top of the same
- * section.
+ * request number, so the changelog can be assembled at the cut: the type files
+ * the entry under a Keep a Changelog heading, a `!` marks it breaking, the
+ * subject becomes the line, and the pull request link is where the detail lives.
+ * Pull requests never touch `CHANGELOG.md`, which is what used to make two of
+ * them conflict whenever both landed an entry at the top of the same section.
*
* Kept apart from the cut script so it can be tested; nothing here touches git
* except {@link readCommitsSince}.
@@ -104,52 +103,20 @@ export const mentionedPullRequests = (section: string): Set => {
return found;
};
-const indentBody = (body: string): string =>
- body
- .split('\n')
- .map(line => (line.trim().length === 0 ? '' : ` ${line}`))
- .join('\n')
- .replace(/\n{3,}/gu, '\n\n');
-
/**
- * Split a body into its opening paragraph and everything after it.
+ * One line per entry: the headline and the pull request it came from.
*
- * A pull request description is written to be read once, by a reviewer with the
- * diff open. A release is read by someone deciding whether to upgrade, and
- * pasting a dozen such descriptions end to end leaves them several thousand
- * words of prose with no shape - the entries stop being scannable and the
- * release page becomes a wall. The opening paragraph is the part that answers
- * "what changed"; the rest is the reasoning, the measurements and the
- * follow-ups, which belong in the release but not in front of it.
+ * The body is not rendered on purpose. A squash commit's body is the pull
+ * request description, and a changelog that inlines it stops being a changelog:
+ * fifteen descriptions end to end are several thousand words with no shape, and
+ * the one thing release notes are for - a quick read of what changed - is gone.
+ * The description stays where it was written, one click away behind the link.
*/
-const splitSummary = (body: string): { summary: string; detail: string } => {
- const trimmed = body.trim();
- const separator = trimmed.indexOf('\n\n');
-
- return separator === -1 ? { summary: trimmed, detail: '' } : { summary: trimmed.slice(0, separator).trim(), detail: trimmed.slice(separator).trim() };
-};
-
const renderEntry = (entry: ChangelogEntry, repoUrl: string): string => {
const link = entry.pullRequest !== null ? ` ([#${entry.pullRequest}](${repoUrl}/pull/${entry.pullRequest}))` : '';
const flag = entry.breaking ? 'BREAKING: ' : '';
- const head = `- **${flag}${entry.title}.**${link}`;
-
- if (entry.body.length === 0) {
- return head;
- }
-
- const { summary, detail } = splitSummary(entry.body);
- const rendered = [head, indentBody(summary)];
-
- if (detail.length > 0) {
- // A fold rather than a cut: everything the description said is still in the
- // release, one click away, and still in `CHANGELOG.md` for anyone reading
- // the file. The blank line after the `` tag is what makes the
- // Markdown inside render instead of appearing as source.
- rendered.push(indentBody(['', 'Details', '', detail, '', ''].join('\n')));
- }
- return rendered.join('\n');
+ return `- **${flag}${entry.title}.**${link}`;
};
/**
diff --git a/site/scripts/capture-screenshots.ts b/site/scripts/capture-screenshots.ts
index 666efa8dc..d4a78d20c 100644
--- a/site/scripts/capture-screenshots.ts
+++ b/site/scripts/capture-screenshots.ts
@@ -244,6 +244,27 @@ const buildTaskUrl = (baseUrl: string, route: string): string => {
return new URL(routeWithoutLeadingSlash, baseUrl).toString();
};
+/**
+ * Open every collapsed disclosure on the page.
+ *
+ * A review pass needs both states: the page as a visitor first meets it, and the
+ * page with everything it can show already showing. The second is not reachable
+ * by scrolling, so a capture that only ever saw the default state reviews half
+ * the layout - and a `` that breaks its surroundings once open breaks
+ * it for every reader who clicks.
+ *
+ * The disclosures are opened directly rather than clicked: a click scrolls the
+ * summary into view and fires the page's own handlers, which would reorder the
+ * captures against each other.
+ */
+const openEveryDisclosure = async (page: Page): Promise => {
+ await page.evaluate(() => {
+ for (const details of document.querySelectorAll('details')) {
+ details.open = true;
+ }
+ });
+};
+
const main = async (): Promise => {
const parsed = parseArgs({
args: process.argv.slice(2),
@@ -260,6 +281,7 @@ const main = async (): Promise => {
'delay-ms': { type: 'string' },
'timeout-ms': { type: 'string' },
mobile: { type: 'boolean' },
+ expand: { type: 'boolean' },
help: { type: 'boolean', short: 'h' },
},
allowPositionals: false,
@@ -279,6 +301,7 @@ Options:
--viewport Single viewport WIDTHxHEIGHT (default: 1440x1000)
--viewports Comma-separated viewport list WIDTHxHEIGHT,...
--mobile Include extra 390x844 viewport
+ --expand Open every before capturing
--concurrency Max concurrent pages (default: 3)
--max-height Max panel split height (default: 1568)
--delay-ms Extra stabilization delay after load (default: 300)
@@ -293,6 +316,7 @@ Options:
const maxHeight = Math.max(256, Number.parseInt(parsed.values['max-height'] ?? String(DEFAULT_MAX_PANEL_HEIGHT), 10) || DEFAULT_MAX_PANEL_HEIGHT);
const delayMs = Math.max(0, Number.parseInt(parsed.values['delay-ms'] ?? String(DEFAULT_STABLE_DELAY_MS), 10) || DEFAULT_STABLE_DELAY_MS);
const timeoutMs = Math.max(5_000, Number.parseInt(parsed.values['timeout-ms'] ?? String(DEFAULT_NAVIGATION_TIMEOUT_MS), 10) || DEFAULT_NAVIGATION_TIMEOUT_MS);
+ const expandDisclosures = parsed.values.expand === true;
const routesFromList = parsed.values.routes
? parsed.values.routes
@@ -396,6 +420,11 @@ Options:
}
await page.waitForLoadState('networkidle', { timeout: timeoutMs }).catch(() => undefined);
await applyStabilization(page);
+
+ if (expandDisclosures) {
+ await openEveryDisclosure(page);
+ }
+
await waitForVisualReady(page, delayMs);
const routeSlug = routeToFileSlug(task.route);
diff --git a/test/release/changelog-from-commits.test.ts b/test/release/changelog-from-commits.test.ts
index 56bfa4be8..0fe60b16e 100644
--- a/test/release/changelog-from-commits.test.ts
+++ b/test/release/changelog-from-commits.test.ts
@@ -59,26 +59,15 @@ describe('renderUnreleasedEntries', () => {
expect(rendered.indexOf('### Changed')).toBeLessThan(rendered.indexOf('### Added'));
expect(rendered.indexOf('BREAKING: Change a contract')).toBeLessThan(rendered.indexOf('Rename a thing'));
expect(rendered).toContain(`([#1](${REPO}/pull/1))`);
- expect(rendered).toContain(' It does things.');
});
- test('keeps the opening paragraph in front and folds the rest away', () => {
- const body = ['It does things.', 'And here is the long reasoning.', 'With a second paragraph of it.'].join('\n\n');
+ test('renders the headline and the link, never the body', () => {
+ const body = ['It does things.', 'And here is the long reasoning.'].join('\n\n');
const rendered = renderUnreleasedEntries([classifyCommit(commit('feat: add a thing (#1)', body))!], '', REPO);
- expect(rendered).toContain(' It does things.');
- expect(rendered.indexOf('It does things.')).toBeLessThan(rendered.indexOf(''));
- expect(rendered).toContain(' Details');
- expect(rendered).toContain(' And here is the long reasoning.');
- expect(rendered).toContain(' With a second paragraph of it.');
- expect(rendered).toContain(' ');
- });
-
- test('leaves a single-paragraph body unfolded', () => {
- const rendered = renderUnreleasedEntries([classifyCommit(commit('feat: add a thing (#1)', 'It does things.'))!], '', REPO);
-
- expect(rendered).toContain(' It does things.');
- expect(rendered).not.toContain('');
+ expect(rendered).toContain(`- **Add a thing.** ([#1](${REPO}/pull/1))`);
+ expect(rendered).not.toContain('It does things.');
+ expect(rendered).not.toContain('long reasoning');
});
test('skips entries whose pull request the section already names', () => {
From 3c58b4df183cda235e9f9ec806043b732d59af10 Mon Sep 17 00:00:00 2001
From: Dima Giesler
Date: Sat, 12 Sep 2026 05:48:20 +0200
Subject: [PATCH 16/28] bench: re-measure the macOS reference run on the
current arms
---
.../results/m3-max-macos-27-beta-webkit.json | 3676 +++++++++--------
1 file changed, 1856 insertions(+), 1820 deletions(-)
diff --git a/packages/exojs-bench/results/m3-max-macos-27-beta-webkit.json b/packages/exojs-bench/results/m3-max-macos-27-beta-webkit.json
index 62385fd87..cfb1cdc71 100644
--- a/packages/exojs-bench/results/m3-max-macos-27-beta-webkit.json
+++ b/packages/exojs-bench/results/m3-max-macos-27-beta-webkit.json
@@ -12,7 +12,7 @@
"prerelease": true
},
"engineVersion": "0.17.0",
- "measuredAt": "2026-09-12T02:40:41.625Z",
+ "measuredAt": "2026-09-12T03:46:13.242Z",
"runs": 3
},
"rendering": {
@@ -43,7 +43,7 @@
"headless": true,
"software": false,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:06:06.620Z"
+ "timestamp": "2026-09-12T03:11:55.632Z"
},
{
"backend": "webgpu",
@@ -70,7 +70,7 @@
"software": false,
"slotTier": 16,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:13:25.798Z"
+ "timestamp": "2026-09-12T03:19:13.432Z"
}
]
},
@@ -100,7 +100,7 @@
"headless": true,
"software": false,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:18:15.735Z"
+ "timestamp": "2026-09-12T03:24:03.163Z"
},
{
"backend": "webgpu",
@@ -127,7 +127,7 @@
"software": false,
"slotTier": 16,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:25:50.325Z"
+ "timestamp": "2026-09-12T03:31:20.194Z"
}
]
},
@@ -157,7 +157,7 @@
"headless": true,
"software": false,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:30:39.988Z"
+ "timestamp": "2026-09-12T03:36:09.267Z"
},
{
"backend": "webgpu",
@@ -184,7 +184,7 @@
"software": false,
"slotTier": 16,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:38:00.061Z"
+ "timestamp": "2026-09-12T03:43:31.391Z"
}
]
}
@@ -226,19 +226,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.21000000000003638,
- "referenceP95Ms": 0.459999999999809,
- "referenceGpuMs": 16.679999999999836,
+ "referenceMs": 0.20000000000004547,
+ "referenceP95Ms": 0.42000000000007276,
+ "referenceGpuMs": 16.660000000000082,
"referenceOverFrameBudget": false,
- "competitorMs": 2.2700000000000955,
- "competitorP95Ms": 8.340000000000146,
+ "competitorMs": 2.240000000000009,
+ "competitorP95Ms": 8.180000000000291,
"competitorGpuMs": 16.660000000000082,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.09251101321587117,
- "factor": 10.809523809522391,
- "label": "ExoJS leads clearly (10.81x)",
+ "ratio": 0.08928571428573423,
+ "factor": 11.199999999997498,
+ "label": "ExoJS leads clearly (11.20x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -247,13 +247,13 @@
"runs": 3,
"reference": {
"minMs": 0.20000000000004547,
- "maxMs": 0.21000000000003638,
- "ratio": 1.0499999999999432
+ "maxMs": 0.23999999999995225,
+ "ratio": 1.1999999999994884
},
"competitor": {
- "minMs": 2.259999999999877,
- "maxMs": 2.480000000000018,
- "ratio": 1.0973451327434305
+ "minMs": 2.2199999999999704,
+ "maxMs": 2.509999999999991,
+ "ratio": 1.1306306306306415
},
"stable": true,
"rungs": [
@@ -265,19 +265,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.21000000000003638,
- "referenceP95Ms": 0.459999999999809,
- "referenceGpuMs": 16.679999999999836,
+ "referenceMs": 0.20000000000004547,
+ "referenceP95Ms": 0.42000000000007276,
+ "referenceGpuMs": 16.660000000000082,
"referenceOverFrameBudget": false,
- "competitorMs": 1.2100000000000364,
+ "competitorMs": 1.2700000000000955,
"competitorP95Ms": 1.7200000000000273,
- "competitorGpuMs": 16.660000000000082,
+ "competitorGpuMs": 16.66000000000031,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.1735537190082893,
- "factor": 5.761904761903937,
- "label": "ExoJS leads clearly (5.76x)",
+ "ratio": 0.1574803149606539,
+ "factor": 6.349999999999033,
+ "label": "ExoJS leads clearly (6.35x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -286,13 +286,13 @@
"runs": 3,
"reference": {
"minMs": 0.20000000000004547,
- "maxMs": 0.21000000000003638,
- "ratio": 1.0499999999999432
+ "maxMs": 0.23999999999995225,
+ "ratio": 1.1999999999994884
},
"competitor": {
- "minMs": 1.1700000000000728,
- "maxMs": 1.2600000000001046,
- "ratio": 1.0769230769230993
+ "minMs": 1.259999999999991,
+ "maxMs": 1.2799999999999727,
+ "ratio": 1.0158730158730016
},
"stable": true,
"rungs": [
@@ -304,19 +304,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.21000000000003638,
- "referenceP95Ms": 0.459999999999809,
- "referenceGpuMs": 16.679999999999836,
+ "referenceMs": 0.20000000000004547,
+ "referenceP95Ms": 0.42000000000007276,
+ "referenceGpuMs": 16.660000000000082,
"referenceOverFrameBudget": false,
"competitorMs": 0.18000000000017735,
- "competitorP95Ms": 0.37999999999988177,
- "competitorGpuMs": 16.660000000000025,
+ "competitorP95Ms": 0.3999999999998636,
+ "competitorGpuMs": 16.67999999999995,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.1666666666657193,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -325,17 +325,17 @@
"runs": 3,
"reference": {
"minMs": 0.20000000000004547,
- "maxMs": 0.21000000000003638,
- "ratio": 1.0499999999999432
+ "maxMs": 0.23999999999995225,
+ "ratio": 1.1999999999994884
},
"competitor": {
- "minMs": 0.18000000000006366,
- "maxMs": 0.22000000000002728,
- "ratio": 1.2222222222219414
+ "minMs": 0.1799999999998363,
+ "maxMs": 0.1999999999998181,
+ "ratio": 1.1111111111111112
},
- "stable": true,
+ "stable": false,
"rungs": [
- "level",
+ "competitor-leads",
"level",
"level"
]
@@ -357,15 +357,15 @@
"referenceP95Ms": 0.25999999999976353,
"referenceGpuMs": 16.66000000000031,
"referenceOverFrameBudget": false,
- "competitorMs": 20.329999999999927,
- "competitorP95Ms": 24.90000000000009,
- "competitorGpuMs": 21.199999999999818,
+ "competitorMs": 19.84999999999991,
+ "competitorP95Ms": 24.079999999999927,
+ "competitorGpuMs": 20.960000000000036,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.006886374815537293,
- "factor": 145.2142857144173,
- "label": "ExoJS leads clearly (145.21x)",
+ "ratio": 0.007052896725434424,
+ "factor": 141.7857142858426,
+ "label": "ExoJS leads clearly (141.79x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -373,14 +373,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.12000000000034561,
- "maxMs": 0.13999999999987267,
- "ratio": 1.1666666666622456
+ "minMs": 0.13999999999987267,
+ "maxMs": 0.17000000000007276,
+ "ratio": 1.2142857142873384
},
"competitor": {
- "minMs": 20.02000000000021,
- "maxMs": 20.86999999999989,
- "ratio": 1.0424575424575262
+ "minMs": 19.420000000000073,
+ "maxMs": 19.98999999999978,
+ "ratio": 1.02935118434602
},
"stable": true,
"rungs": [
@@ -396,15 +396,15 @@
"referenceP95Ms": 0.25999999999976353,
"referenceGpuMs": 16.66000000000031,
"referenceOverFrameBudget": false,
- "competitorMs": 3.0499999999999545,
- "competitorP95Ms": 8.279999999999745,
+ "competitorMs": 3.0800000000001546,
+ "competitorP95Ms": 9.159999999999854,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.04590163934422123,
- "factor": 21.785714285733775,
- "label": "ExoJS leads clearly (21.79x)",
+ "ratio": 0.04545454545450183,
+ "factor": 22.000000000021114,
+ "label": "ExoJS leads clearly (22.00x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -412,14 +412,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.12000000000034561,
- "maxMs": 0.13999999999987267,
- "ratio": 1.1666666666622456
+ "minMs": 0.13999999999987267,
+ "maxMs": 0.17000000000007276,
+ "ratio": 1.2142857142873384
},
"competitor": {
- "minMs": 2.9400000000000546,
- "maxMs": 3.1399999999998727,
- "ratio": 1.0680272108842905
+ "minMs": 3.0799999999999272,
+ "maxMs": 3.080000000000382,
+ "ratio": 1.0000000000001477
},
"stable": true,
"rungs": [
@@ -436,14 +436,14 @@
"referenceGpuMs": 16.66000000000031,
"referenceOverFrameBudget": false,
"competitorMs": 0.13999999999987267,
- "competitorP95Ms": 0.2800000000002001,
+ "competitorP95Ms": 0.2600000000002183,
"competitorGpuMs": 16.679999999999836,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -451,18 +451,18 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.12000000000034561,
- "maxMs": 0.13999999999987267,
- "ratio": 1.1666666666622456
+ "minMs": 0.13999999999987267,
+ "maxMs": 0.17000000000007276,
+ "ratio": 1.2142857142873384
},
"competitor": {
"minMs": 0.13999999999987267,
- "maxMs": 0.15999999999985448,
- "ratio": 1.1428571428571428
+ "maxMs": 0.13999999999987267,
+ "ratio": 1
},
- "stable": true,
+ "stable": false,
"rungs": [
- "level",
+ "competitor-leads",
"level",
"level"
]
@@ -479,15 +479,15 @@
"primary": false,
"cells": [
{
- "competitor": "phaser",
- "referenceMs": 0.05999999999994543,
- "referenceP95Ms": 0.22999999999956344,
- "referenceGpuMs": 16.659999999999854,
+ "competitor": "pixi",
+ "referenceMs": 0.06000000000040018,
+ "referenceP95Ms": 0.2599999999993088,
+ "referenceGpuMs": 16.67999999999938,
"referenceOverFrameBudget": false,
- "competitorMs": 17.925000000000182,
- "competitorP95Ms": 23.389999999999873,
- "competitorGpuMs": 18.829999999999927,
- "competitorOverFrameBudget": true,
+ "competitorMs": 0.04999999999972715,
+ "competitorP95Ms": 0.2600000000002183,
+ "competitorGpuMs": 16.660000000000764,
+ "competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
"ratio": null,
@@ -495,63 +495,62 @@
"label": "unstable across runs",
"structural": false
},
- "mechanism": "competitor issues fewer draw calls (25 vs 7 per frame)",
+ "mechanism": "competitor issues fewer draw calls (25 vs 1 per frame)",
"timer": "limited",
"aggregate": {
- "runs": 2,
+ "runs": 3,
"reference": {
"minMs": 0.05999999999949068,
"maxMs": 0.06000000000040018,
"ratio": 1.0000000000151583
},
"competitor": {
- "minMs": 17.7800000000002,
- "maxMs": 18.070000000000164,
- "ratio": 1.0163104611923488
+ "minMs": 0.03999999999996362,
+ "maxMs": 0.06999999999970896,
+ "ratio": 1.7499999999943157
},
"stable": false,
"rungs": [
- "exojs-leads-clearly",
- "exojs-leads-clearly"
+ "competitor-leads",
+ "competitor-leads",
+ "level"
]
}
},
{
- "competitor": "pixi",
+ "competitor": "phaser",
"referenceMs": 0.06000000000040018,
- "referenceP95Ms": 0.23999999999978172,
- "referenceGpuMs": 16.659999999999854,
+ "referenceP95Ms": 0.2599999999993088,
+ "referenceGpuMs": 16.67999999999938,
"referenceOverFrameBudget": false,
- "competitorMs": 0.06000000000040018,
- "competitorP95Ms": 0.2600000000002183,
- "competitorGpuMs": 16.67999999999938,
- "competitorOverFrameBudget": false,
+ "competitorMs": 16.88000000000011,
+ "competitorP95Ms": 21.82000000000062,
+ "competitorGpuMs": 18.05999999999949,
+ "competitorOverFrameBudget": true,
"verdict": {
"side": "neither",
- "ratio": 1,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
- "mechanism": "competitor issues fewer draw calls (25 vs 1 per frame)",
+ "mechanism": "competitor issues fewer draw calls (25 vs 7 per frame)",
"timer": "limited",
"aggregate": {
- "runs": 3,
+ "runs": 1,
"reference": {
- "minMs": 0.05999999999949068,
- "maxMs": 0.07000000000016371,
- "ratio": 1.1666666666792986
+ "minMs": 0.06000000000040018,
+ "maxMs": 0.06000000000040018,
+ "ratio": 1
},
"competitor": {
- "minMs": 0.05999999999949068,
- "maxMs": 0.06000000000040018,
- "ratio": 1.0000000000151583
+ "minMs": 16.88000000000011,
+ "maxMs": 16.88000000000011,
+ "ratio": 1
},
- "stable": true,
+ "stable": false,
"rungs": [
- "level",
- "level",
- "level"
+ "exojs-leads-clearly"
]
}
}
@@ -567,19 +566,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 1.699999999999818,
- "referenceP95Ms": 2.399999999999636,
- "referenceGpuMs": 16.660000000000764,
+ "referenceMs": 1.7200000000002547,
+ "referenceP95Ms": 2.480000000000473,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 26.090000000001965,
- "competitorP95Ms": 30.040000000000873,
- "competitorGpuMs": 27.279999999998836,
+ "competitorMs": 26.140000000001237,
+ "competitorP95Ms": 35.37999999999738,
+ "competitorGpuMs": 27.260000000002037,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.06515906477576427,
- "factor": 15.34705882353221,
- "label": "ExoJS leads clearly (15.35x)",
+ "ratio": 0.06579954093344198,
+ "factor": 15.19767441860312,
+ "label": "ExoJS leads clearly (15.20x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -587,14 +586,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.6900000000000546,
- "maxMs": 1.7599999999997635,
- "ratio": 1.0414201183430216
+ "minMs": 1.5399999999999636,
+ "maxMs": 1.980000000000473,
+ "ratio": 1.285714285714623
},
"competitor": {
- "minMs": 25.539999999999054,
- "maxMs": 28.3700000000008,
- "ratio": 1.1108065779170655
+ "minMs": 25.790000000000873,
+ "maxMs": 26.600000000002183,
+ "ratio": 1.031407522295513
},
"stable": true,
"rungs": [
@@ -606,19 +605,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 1.699999999999818,
- "referenceP95Ms": 2.399999999999636,
- "referenceGpuMs": 16.660000000000764,
+ "referenceMs": 1.7200000000002547,
+ "referenceP95Ms": 2.480000000000473,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 3.0299999999999727,
- "competitorP95Ms": 8.180000000000291,
- "competitorGpuMs": 16.660000000003492,
+ "competitorMs": 2.9900000000016007,
+ "competitorP95Ms": 7.960000000000036,
+ "competitorGpuMs": 16.660000000000082,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5610561056105061,
- "factor": 1.7823529411766452,
- "label": "ExoJS leads (1.78x)",
+ "ratio": 0.5752508361201786,
+ "factor": 1.738372093023929,
+ "label": "ExoJS leads (1.74x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -626,14 +625,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.6900000000000546,
- "maxMs": 1.7599999999997635,
- "ratio": 1.0414201183430216
+ "minMs": 1.5399999999999636,
+ "maxMs": 1.980000000000473,
+ "ratio": 1.285714285714623
},
"competitor": {
- "minMs": 2.9500000000007276,
- "maxMs": 3.2399999999943248,
- "ratio": 1.098305084743568
+ "minMs": 2.990000000000009,
+ "maxMs": 3.259999999999991,
+ "ratio": 1.0903010033444753
},
"stable": true,
"rungs": [
@@ -645,19 +644,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.699999999999818,
- "referenceP95Ms": 2.399999999999636,
- "referenceGpuMs": 16.660000000000764,
+ "referenceMs": 1.7200000000002547,
+ "referenceP95Ms": 2.480000000000473,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 1.3100000000004002,
- "competitorP95Ms": 2.0399999999999636,
- "competitorGpuMs": 16.660000000000764,
+ "competitorMs": 1.319999999999709,
+ "competitorP95Ms": 1.9200000000000728,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "competitor",
+ "ratio": 1.3030303030307833,
+ "factor": 1.3030303030307833,
+ "label": "competitor leads (1.30x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -665,20 +664,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.6900000000000546,
- "maxMs": 1.7599999999997635,
- "ratio": 1.0414201183430216
+ "minMs": 1.5399999999999636,
+ "maxMs": 1.980000000000473,
+ "ratio": 1.285714285714623
},
"competitor": {
- "minMs": 1.300000000000182,
- "maxMs": 1.4299999999998363,
- "ratio": 1.09999999999972
+ "minMs": 1.2599999999997635,
+ "maxMs": 1.319999999999709,
+ "ratio": 1.0476190476190133
},
- "stable": false,
+ "stable": true,
"rungs": [
"competitor-leads",
"competitor-leads",
- "level"
+ "competitor-leads"
]
}
}
@@ -694,19 +693,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 1.5799999999999272,
- "referenceP95Ms": 2.160000000000764,
- "referenceGpuMs": 16.67999999999938,
+ "referenceMs": 1.6599999999998545,
+ "referenceP95Ms": 2.2200000000002547,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 3.390000000001237,
- "competitorP95Ms": 8.360000000000582,
+ "competitorMs": 3.4200000000000728,
+ "competitorP95Ms": 6.600000000002183,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.4660766961650002,
- "factor": 2.1455696202540464,
- "label": "ExoJS leads (2.15x)",
+ "ratio": 0.48538011695901145,
+ "factor": 2.0602409638556463,
+ "label": "ExoJS leads (2.06x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -714,14 +713,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5399999999999636,
- "maxMs": 1.6399999999998727,
- "ratio": 1.0649350649350073
+ "minMs": 1.5600000000004002,
+ "maxMs": 1.7600000000002183,
+ "ratio": 1.1282051282049788
},
"competitor": {
- "minMs": 3.319999999999709,
- "maxMs": 3.430000000000291,
- "ratio": 1.0331325301206602
+ "minMs": 3.390000000001237,
+ "maxMs": 3.4899999999997817,
+ "ratio": 1.0294985250733062
},
"stable": true,
"rungs": [
@@ -733,19 +732,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 1.5799999999999272,
- "referenceP95Ms": 2.160000000000764,
- "referenceGpuMs": 16.67999999999938,
+ "referenceMs": 1.6599999999998545,
+ "referenceP95Ms": 2.2200000000002547,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 1.0299999999988358,
- "competitorP95Ms": 1.3800000000046566,
- "competitorGpuMs": 16.679999999993015,
+ "competitorMs": 1.2100000000000364,
+ "competitorP95Ms": 1.6599999999998545,
+ "competitorGpuMs": 16.679999999999836,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.533980582525935,
- "factor": 1.533980582525935,
- "label": "competitor leads (1.53x)",
+ "ratio": 1.3719008264461194,
+ "factor": 1.3719008264461194,
+ "label": "competitor leads (1.37x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -753,14 +752,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5399999999999636,
- "maxMs": 1.6399999999998727,
- "ratio": 1.0649350649350073
+ "minMs": 1.5600000000004002,
+ "maxMs": 1.7600000000002183,
+ "ratio": 1.1282051282049788
},
"competitor": {
- "minMs": 0.9800000000104774,
- "maxMs": 1.2199999999998,
- "ratio": 1.2448979591701599
+ "minMs": 1.0399999999972351,
+ "maxMs": 1.240000000000009,
+ "ratio": 1.1923076923108709
},
"stable": true,
"rungs": [
@@ -772,19 +771,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.5799999999999272,
- "referenceP95Ms": 2.160000000000764,
- "referenceGpuMs": 16.67999999999938,
+ "referenceMs": 1.6599999999998545,
+ "referenceP95Ms": 2.2200000000002547,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 0.9800000000004729,
- "competitorP95Ms": 1.360000000000582,
+ "competitorMs": 0.9800000000000182,
+ "competitorP95Ms": 1.339999999999236,
"competitorGpuMs": 16.660000000000764,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.6122448979583315,
- "factor": 1.6122448979583315,
- "label": "competitor leads (1.61x)",
+ "ratio": 1.6938775510202282,
+ "factor": 1.6938775510202282,
+ "label": "competitor leads (1.69x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -792,14 +791,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5399999999999636,
- "maxMs": 1.6399999999998727,
- "ratio": 1.0649350649350073
+ "minMs": 1.5600000000004002,
+ "maxMs": 1.7600000000002183,
+ "ratio": 1.1282051282049788
},
"competitor": {
- "minMs": 0.9600000000000364,
- "maxMs": 1,
- "ratio": 1.0416666666666272
+ "minMs": 0.9699999999997999,
+ "maxMs": 0.9900000000002365,
+ "ratio": 1.0206185567014852
},
"stable": true,
"rungs": [
@@ -821,19 +820,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 4.020000000000437,
+ "referenceMs": 4.059999999999491,
"referenceP95Ms": 5.199999999998909,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 30.80000000000109,
- "competitorP95Ms": 34.94000000000233,
- "competitorGpuMs": 31.840000000000146,
+ "competitorMs": 31.779999999998836,
+ "competitorP95Ms": 35.45999999999913,
+ "competitorGpuMs": 32.60000000000218,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.13051948051949006,
- "factor": 7.661691542287998,
- "label": "ExoJS leads clearly (7.66x)",
+ "ratio": 0.12775330396474635,
+ "factor": 7.827586206897248,
+ "label": "ExoJS leads clearly (7.83x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -841,14 +840,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.9899999999997817,
- "maxMs": 4.0600000000004,
- "ratio": 1.0175438596492787
+ "minMs": 4.019999999998618,
+ "maxMs": 4.299999999999272,
+ "ratio": 1.0696517412937192
},
"competitor": {
- "minMs": 29.900000000001455,
- "maxMs": 34.54999999999927,
- "ratio": 1.1555183946487488
+ "minMs": 31.55999999999949,
+ "maxMs": 32.25,
+ "ratio": 1.021863117870739
},
"stable": true,
"rungs": [
@@ -860,19 +859,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 4.020000000000437,
+ "referenceMs": 4.059999999999491,
"referenceP95Ms": 5.199999999998909,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 3.139999999999418,
- "competitorP95Ms": 7.8399999999965075,
- "competitorGpuMs": 16.660000000003492,
+ "competitorMs": 2.930000000000291,
+ "competitorP95Ms": 7.6599999999998545,
+ "competitorGpuMs": 16.660000000000764,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.28025477707044,
- "factor": 1.28025477707044,
- "label": "competitor leads (1.28x)",
+ "ratio": 1.3856655290099273,
+ "factor": 1.3856655290099273,
+ "label": "competitor leads (1.39x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -880,14 +879,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.9899999999997817,
- "maxMs": 4.0600000000004,
- "ratio": 1.0175438596492787
+ "minMs": 4.019999999998618,
+ "maxMs": 4.299999999999272,
+ "ratio": 1.0696517412937192
},
"competitor": {
- "minMs": 2.9600000000000364,
- "maxMs": 3.1999999999970896,
- "ratio": 1.0810810810800846
+ "minMs": 2.8400000000001455,
+ "maxMs": 2.9600000000000364,
+ "ratio": 1.0422535211267199
},
"stable": true,
"rungs": [
@@ -899,19 +898,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 4.020000000000437,
+ "referenceMs": 4.059999999999491,
"referenceP95Ms": 5.199999999998909,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.5999999999994543,
- "competitorP95Ms": 10.180000000000291,
- "competitorGpuMs": 16.660000000001673,
+ "competitorMs": 2.6700000000000728,
+ "competitorP95Ms": 11.5,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.5461538461543385,
- "factor": 1.5461538461543385,
- "label": "competitor leads (1.55x)",
+ "ratio": 1.5205992509360975,
+ "factor": 1.5205992509360975,
+ "label": "competitor leads (1.52x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -919,14 +918,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.9899999999997817,
- "maxMs": 4.0600000000004,
- "ratio": 1.0175438596492787
+ "minMs": 4.019999999998618,
+ "maxMs": 4.299999999999272,
+ "ratio": 1.0696517412937192
},
"competitor": {
- "minMs": 2.5499999999992724,
- "maxMs": 2.8599999999996726,
- "ratio": 1.121568627451172
+ "minMs": 2.5799999999999272,
+ "maxMs": 2.839999999999236,
+ "ratio": 1.1007751937981844
},
"stable": true,
"rungs": [
@@ -948,13 +947,13 @@
"cells": [
{
"competitor": "phaser",
- "referenceMs": 36.82000000000062,
- "referenceP95Ms": 43,
- "referenceGpuMs": 38.26000000000022,
+ "referenceMs": 37.57000000000062,
+ "referenceP95Ms": 43.31999999999971,
+ "referenceGpuMs": 38.70000000000073,
"referenceOverFrameBudget": true,
- "competitorMs": 21.439999999995052,
- "competitorP95Ms": 26.020000000004075,
- "competitorGpuMs": 22.15999999998894,
+ "competitorMs": 20.53999999999951,
+ "competitorP95Ms": 25.23999999999978,
+ "competitorGpuMs": 21.300000000000182,
"competitorOverFrameBudget": true,
"verdict": {
"side": "neither",
@@ -968,13 +967,13 @@
"aggregate": {
"runs": 1,
"reference": {
- "minMs": 36.82000000000062,
- "maxMs": 36.82000000000062,
+ "minMs": 37.57000000000062,
+ "maxMs": 37.57000000000062,
"ratio": 1
},
"competitor": {
- "minMs": 21.439999999995052,
- "maxMs": 21.439999999995052,
+ "minMs": 20.53999999999951,
+ "maxMs": 20.53999999999951,
"ratio": 1
},
"stable": false,
@@ -985,19 +984,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 38.22999999999956,
- "referenceP95Ms": 43.63999999999942,
- "referenceGpuMs": 39.280000000000655,
+ "referenceMs": 38.100000000000364,
+ "referenceP95Ms": 44.18000000000029,
+ "referenceGpuMs": 40.23999999999978,
"referenceOverFrameBudget": true,
- "competitorMs": 28.43000000000029,
- "competitorP95Ms": 32.20000000000073,
- "competitorGpuMs": 30.219999999999345,
+ "competitorMs": 29.01000000000022,
+ "competitorP95Ms": 32.13999999999942,
+ "competitorGpuMs": 30.200000000000728,
"competitorOverFrameBudget": true,
"verdict": {
"side": "competitor",
- "ratio": 1.3447062961659926,
- "factor": 1.3447062961659926,
- "label": "competitor leads (1.34x)",
+ "ratio": 1.3133402275077586,
+ "factor": 1.3133402275077586,
+ "label": "competitor leads (1.31x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (25 vs 1 per frame)",
@@ -1005,14 +1004,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 36.82000000000062,
- "maxMs": 40.81999999999971,
- "ratio": 1.1086366105377248
+ "minMs": 37.57000000000062,
+ "maxMs": 39.88999999999942,
+ "ratio": 1.061751397391503
},
"competitor": {
- "minMs": 28.18000000000029,
- "maxMs": 29.05999999999949,
- "ratio": 1.0312278211497228
+ "minMs": 28.31999999999971,
+ "maxMs": 29.159999999999854,
+ "ratio": 1.029661016949158
},
"stable": true,
"rungs": [
@@ -1034,19 +1033,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.5700000000006185,
- "referenceP95Ms": 0.7999999999992724,
- "referenceGpuMs": 16.679999999998472,
+ "referenceMs": 0.5599999999994907,
+ "referenceP95Ms": 0.7800000000006548,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 37.330000000001746,
- "competitorP95Ms": 56.81999999999971,
- "competitorGpuMs": 39.86000000000058,
+ "competitorMs": 28.299999999999272,
+ "competitorP95Ms": 33.599999999998545,
+ "competitorGpuMs": 29.659999999996217,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.0152692204661289,
- "factor": 65.49122807010744,
- "label": "ExoJS leads clearly (65.49x)",
+ "ratio": 0.019787985865706893,
+ "factor": 50.53571428575895,
+ "label": "ExoJS leads clearly (50.54x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1054,14 +1053,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5399999999999636,
- "maxMs": 0.5799999999999272,
- "ratio": 1.0740740740740118
+ "minMs": 0.5500000000001819,
+ "maxMs": 0.6199999999989814,
+ "ratio": 1.1272727272705023
},
"competitor": {
- "minMs": 26.970000000001164,
- "maxMs": 38.12000000000262,
- "ratio": 1.4134223210975518
+ "minMs": 27.539999999997235,
+ "maxMs": 28.80999999999767,
+ "ratio": 1.046114742193194
},
"stable": true,
"rungs": [
@@ -1073,19 +1072,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.5700000000006185,
- "referenceP95Ms": 0.7999999999992724,
- "referenceGpuMs": 16.679999999998472,
+ "referenceMs": 0.5599999999994907,
+ "referenceP95Ms": 0.7800000000006548,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 3.0900000000001455,
- "competitorP95Ms": 7.459999999999809,
+ "competitorMs": 3.0600000000000023,
+ "competitorP95Ms": 10.060000000012224,
"competitorGpuMs": 16.660000000000082,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.1844660194176672,
- "factor": 5.421052631573321,
- "label": "ExoJS leads clearly (5.42x)",
+ "ratio": 0.18300653594754585,
+ "factor": 5.464285714290688,
+ "label": "ExoJS leads clearly (5.46x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1093,14 +1092,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5399999999999636,
- "maxMs": 0.5799999999999272,
- "ratio": 1.0740740740740118
+ "minMs": 0.5500000000001819,
+ "maxMs": 0.6199999999989814,
+ "ratio": 1.1272727272705023
},
"competitor": {
- "minMs": 3.0699999999999363,
- "maxMs": 3.1700000000000728,
- "ratio": 1.0325732899023252
+ "minMs": 3.0599999999999454,
+ "maxMs": 3.109999999993306,
+ "ratio": 1.0163398692788763
},
"stable": true,
"rungs": [
@@ -1112,17 +1111,17 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.5700000000006185,
- "referenceP95Ms": 0.7999999999992724,
- "referenceGpuMs": 16.679999999998472,
+ "referenceMs": 0.5599999999994907,
+ "referenceP95Ms": 0.7800000000006548,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 0.5799999999999272,
- "competitorP95Ms": 0.7999999999992724,
- "competitorGpuMs": 16.68000000000029,
+ "competitorMs": 0.5599999999994907,
+ "competitorP95Ms": 0.8000000000010914,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9827586206908447,
+ "ratio": 1,
"factor": 1,
"label": "level",
"structural": false
@@ -1132,14 +1131,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5399999999999636,
- "maxMs": 0.5799999999999272,
- "ratio": 1.0740740740740118
+ "minMs": 0.5500000000001819,
+ "maxMs": 0.6199999999989814,
+ "ratio": 1.1272727272705023
},
"competitor": {
- "minMs": 0.5599999999994907,
- "maxMs": 0.6000000000003638,
- "ratio": 1.0714285714301954
+ "minMs": 0.5400000000008731,
+ "maxMs": 0.5799999999999272,
+ "ratio": 1.0740740740722028
},
"stable": true,
"rungs": [
@@ -1161,19 +1160,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 2.8299999999999272,
- "referenceP95Ms": 4.479999999999563,
+ "referenceMs": 2.889999999999418,
+ "referenceP95Ms": 6.240000000001601,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 25.139999999999418,
- "competitorP95Ms": 30.04000000000815,
- "competitorGpuMs": 26.679999999993015,
+ "competitorMs": 25.400000000001455,
+ "competitorP95Ms": 31.079999999987194,
+ "competitorGpuMs": 26.84000000001106,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.11256961018297505,
- "factor": 8.883392226148432,
- "label": "ExoJS leads clearly (8.88x)",
+ "ratio": 0.11377952755902568,
+ "factor": 8.788927335642413,
+ "label": "ExoJS leads clearly (8.79x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/4 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1181,14 +1180,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.5600000000013097,
- "maxMs": 2.8400000000001455,
- "ratio": 1.1093749999994893
+ "minMs": 2.8400000000001455,
+ "maxMs": 2.9500000000025466,
+ "ratio": 1.0387323943670406
},
"competitor": {
- "minMs": 25.06999999999971,
- "maxMs": 25.52999999999156,
- "ratio": 1.0183486238528863
+ "minMs": 25.360000000000582,
+ "maxMs": 25.44000000000233,
+ "ratio": 1.003154574132561
},
"stable": true,
"rungs": [
@@ -1200,19 +1199,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 2.8299999999999272,
- "referenceP95Ms": 4.479999999999563,
+ "referenceMs": 2.889999999999418,
+ "referenceP95Ms": 6.240000000001601,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 10.56000000000131,
- "competitorP95Ms": 11.200000000000728,
+ "competitorMs": 10.860000000000582,
+ "competitorP95Ms": 11.380000000001019,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.2679924242423841,
- "factor": 3.731448763251442,
- "label": "ExoJS leads (3.73x)",
+ "ratio": 0.2661141804787535,
+ "factor": 3.757785467128986,
+ "label": "ExoJS leads (3.76x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/4 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1220,14 +1219,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.5600000000013097,
- "maxMs": 2.8400000000001455,
- "ratio": 1.1093749999994893
+ "minMs": 2.8400000000001455,
+ "maxMs": 2.9500000000025466,
+ "ratio": 1.0387323943670406
},
"competitor": {
- "minMs": 10.550000000001091,
- "maxMs": 10.659999999999854,
- "ratio": 1.0104265402842418
+ "minMs": 10.590000000000146,
+ "maxMs": 10.880000000001019,
+ "ratio": 1.0273843248348318
},
"stable": true,
"rungs": [
@@ -1239,12 +1238,12 @@
},
{
"competitor": "pixi",
- "referenceMs": 2.8299999999999272,
- "referenceP95Ms": 4.479999999999563,
+ "referenceMs": 2.889999999999418,
+ "referenceP95Ms": 6.240000000001601,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.400000000001455,
- "competitorP95Ms": 8.040000000000873,
+ "competitorMs": 2.5100000000002183,
+ "competitorP95Ms": 7.580000000001746,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
@@ -1259,14 +1258,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.5600000000013097,
- "maxMs": 2.8400000000001455,
- "ratio": 1.1093749999994893
+ "minMs": 2.8400000000001455,
+ "maxMs": 2.9500000000025466,
+ "ratio": 1.0387323943670406
},
"competitor": {
- "minMs": 2.3400000000001455,
- "maxMs": 2.5600000000013097,
- "ratio": 1.0940170940175857
+ "minMs": 2.3699999999989814,
+ "maxMs": 2.6199999999989814,
+ "ratio": 1.105485232067556
},
"stable": false,
"rungs": [
@@ -1294,18 +1293,18 @@
{
"competitor": "excalibur",
"referenceMs": 0.07999999999992724,
- "referenceP95Ms": 0.12000000000080036,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.13999999999941792,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 0.6399999999994179,
- "competitorP95Ms": 0.8600000000005821,
- "competitorGpuMs": 16.639999999999418,
+ "competitorMs": 0.6200000000026193,
+ "competitorP95Ms": 0.8799999999973807,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.125,
- "factor": 8,
- "label": "ExoJS leads clearly (8.00x)",
+ "ratio": 0.12903225806385366,
+ "factor": 7.7500000000397895,
+ "label": "ExoJS leads clearly (7.75x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1318,9 +1317,9 @@
"ratio": 1
},
"competitor": {
- "minMs": 0.4500000000007276,
- "maxMs": 0.6599999999962165,
- "ratio": 1.4666666666558874
+ "minMs": 0.6199999999989814,
+ "maxMs": 0.6599999999998545,
+ "ratio": 1.0645161290337724
},
"stable": true,
"rungs": [
@@ -1333,18 +1332,18 @@
{
"competitor": "phaser",
"referenceMs": 0.07999999999992724,
- "referenceP95Ms": 0.12000000000080036,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.13999999999941792,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 0.27999999999974534,
+ "competitorMs": 0.2600000000002183,
"competitorP95Ms": 0.4600000000000364,
- "competitorGpuMs": 16.659999999999854,
+ "competitorGpuMs": 16.679999999999836,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.2857142857142857,
- "factor": 3.5,
- "label": "ExoJS leads (3.50x)",
+ "ratio": 0.30769230769176953,
+ "factor": 3.2500000000056843,
+ "label": "ExoJS leads (3.25x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1357,9 +1356,9 @@
"ratio": 1
},
"competitor": {
- "minMs": 0.25999999999976353,
- "maxMs": 0.2800000000002001,
- "ratio": 1.076923076924826
+ "minMs": 0.20000000001164153,
+ "maxMs": 0.27999999999974534,
+ "ratio": 1.399999999917236
},
"stable": true,
"rungs": [
@@ -1372,18 +1371,18 @@
{
"competitor": "pixi",
"referenceMs": 0.07999999999992724,
- "referenceP95Ms": 0.12000000000080036,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.13999999999941792,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 0.09999999999854481,
+ "competitorMs": 0.1000000000003638,
"competitorP95Ms": 0.21999999999934516,
- "competitorGpuMs": 16.679999999998472,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "exojs",
+ "ratio": 0.7999999999963621,
+ "factor": 1.2500000000056843,
+ "label": "ExoJS leads (1.25x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1396,14 +1395,14 @@
"ratio": 1
},
"competitor": {
- "minMs": 0.09999999999854481,
+ "minMs": 0.1000000000003638,
"maxMs": 0.1000000000003638,
- "ratio": 1.00000000001819
+ "ratio": 1
},
- "stable": false,
+ "stable": true,
"rungs": [
- "level",
- "level",
+ "exojs-leads",
+ "exojs-leads",
"exojs-leads"
]
}
@@ -1420,19 +1419,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 1.4099999999998545,
+ "referenceMs": 1.4000000000014552,
"referenceP95Ms": 1.819999999999709,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 19.31000000000131,
- "competitorP95Ms": 23.5,
- "competitorGpuMs": 28.459999999999127,
- "competitorOverFrameBudget": true,
+ "competitorMs": 16.159999999999854,
+ "competitorP95Ms": 17.919999999998254,
+ "competitorGpuMs": 26.89999999999418,
+ "competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.07301916105643495,
- "factor": 13.69503546099525,
- "label": "ExoJS leads clearly (13.70x)",
+ "ratio": 0.08663366336642746,
+ "factor": 11.542857142845042,
+ "label": "ExoJS leads clearly (11.54x)",
"structural": true
},
"mechanism": "ExoJS issues fewer buffer uploads (0 vs 313 per frame)",
@@ -1440,14 +1439,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.3700000000008004,
- "maxMs": 1.4200000000000728,
- "ratio": 1.0364963503644111
+ "minMs": 1.3799999999991996,
+ "maxMs": 1.4099999999998545,
+ "ratio": 1.0217391304352696
},
"competitor": {
- "minMs": 19.30000000000291,
- "maxMs": 20.780000000002474,
- "ratio": 1.0766839378238
+ "minMs": 15.869999999998981,
+ "maxMs": 19.55000000000291,
+ "ratio": 1.2318840579712769
},
"stable": true,
"rungs": [
@@ -1459,19 +1458,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 1.4099999999998545,
+ "referenceMs": 1.4000000000014552,
"referenceP95Ms": 1.819999999999709,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.7600000000002183,
- "competitorP95Ms": 7.199999999999818,
+ "competitorMs": 2.8899999999998727,
+ "competitorP95Ms": 6.819999999999709,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5108695652172982,
- "factor": 1.957446808510995,
- "label": "ExoJS leads (1.96x)",
+ "ratio": 0.48442906574446953,
+ "factor": 2.0642857142834776,
+ "label": "ExoJS leads (2.06x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 313/5000/0 vs 313/5000/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1479,14 +1478,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.3700000000008004,
- "maxMs": 1.4200000000000728,
- "ratio": 1.0364963503644111
+ "minMs": 1.3799999999991996,
+ "maxMs": 1.4099999999998545,
+ "ratio": 1.0217391304352696
},
"competitor": {
- "minMs": 2.7200000000002547,
- "maxMs": 2.9200000000000728,
- "ratio": 1.0735294117646321
+ "minMs": 2.7800000000002,
+ "maxMs": 3,
+ "ratio": 1.0791366906474043
},
"stable": true,
"rungs": [
@@ -1498,19 +1497,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.4099999999998545,
+ "referenceMs": 1.4000000000014552,
"referenceP95Ms": 1.819999999999709,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 1.2200000000002547,
+ "competitorMs": 1.180000000000291,
"competitorP95Ms": 2,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.1557377049176722,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 313/5000/0 vs 313/5000/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1518,20 +1517,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.3700000000008004,
- "maxMs": 1.4200000000000728,
- "ratio": 1.0364963503644111
+ "minMs": 1.3799999999991996,
+ "maxMs": 1.4099999999998545,
+ "ratio": 1.0217391304352696
},
"competitor": {
- "minMs": 1.2200000000002547,
- "maxMs": 1.3499999999985448,
- "ratio": 1.1065573770477566
+ "minMs": 1.139999999999418,
+ "maxMs": 1.4799999999995634,
+ "ratio": 1.2982456140353678
},
- "stable": true,
+ "stable": false,
"rungs": [
"level",
"level",
- "level"
+ "competitor-leads"
]
}
}
@@ -1547,19 +1546,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.5399999999990541,
- "referenceP95Ms": 0.7200000000011642,
- "referenceGpuMs": 16.679999999996653,
+ "referenceMs": 0.4599999999991269,
+ "referenceP95Ms": 0.7399999999979627,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 10.080000000001746,
- "competitorP95Ms": 13.480000000003201,
+ "competitorMs": 9.779999999995198,
+ "competitorP95Ms": 12.940000000002328,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.053571428571325456,
- "factor": 18.666666666702596,
- "label": "ExoJS leads clearly (18.67x)",
+ "ratio": 0.04703476482610969,
+ "factor": 21.260869565247308,
+ "label": "ExoJS leads clearly (21.26x)",
"structural": true
},
"mechanism": "competitor issues fewer draw calls (120 vs 1 per frame)",
@@ -1567,14 +1566,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.47000000000116415,
- "maxMs": 0.5399999999990541,
- "ratio": 1.1489361702079077
+ "minMs": 0.38000000000101863,
+ "maxMs": 0.5400000000008731,
+ "ratio": 1.4210526315774357
},
"competitor": {
- "minMs": 9.999999999996362,
- "maxMs": 10.349999999998545,
- "ratio": 1.035000000000231
+ "minMs": 9.590000000000146,
+ "maxMs": 9.909999999996217,
+ "ratio": 1.0333680917618422
},
"stable": true,
"rungs": [
@@ -1586,13 +1585,13 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.5399999999990541,
- "referenceP95Ms": 0.7200000000011642,
- "referenceGpuMs": 16.679999999996653,
+ "referenceMs": 0.4599999999991269,
+ "referenceP95Ms": 0.7399999999979627,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 2.4099999999998545,
- "competitorP95Ms": 4.699999999999818,
- "competitorGpuMs": 16.660000000000764,
+ "competitorMs": 2.6699999999982538,
+ "competitorP95Ms": 4.859999999999673,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -1606,38 +1605,38 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.47000000000116415,
- "maxMs": 0.5399999999990541,
- "ratio": 1.1489361702079077
+ "minMs": 0.38000000000101863,
+ "maxMs": 0.5400000000008731,
+ "ratio": 1.4210526315774357
},
"competitor": {
- "minMs": 2.399999999999636,
- "maxMs": 2.6400000000003274,
- "ratio": 1.1000000000003032
+ "minMs": 2.6299999999996544,
+ "maxMs": 2.6700000000000728,
+ "ratio": 1.0152091254754463
},
"stable": false,
"rungs": [
- "exojs-leads",
- "exojs-leads",
- "exojs-leads-clearly"
+ "exojs-leads-clearly",
+ "exojs-leads-clearly",
+ "exojs-leads"
]
}
},
{
"competitor": "pixi",
- "referenceMs": 0.5399999999990541,
- "referenceP95Ms": 0.7200000000011642,
- "referenceGpuMs": 16.679999999996653,
+ "referenceMs": 0.4599999999991269,
+ "referenceP95Ms": 0.7399999999979627,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
"competitorMs": 0.31999999999970896,
- "competitorP95Ms": 0.42000000000189175,
- "competitorGpuMs": 16.68000000000029,
+ "competitorP95Ms": 0.4400000000023283,
+ "competitorGpuMs": 16.679999999996653,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "competitor",
- "ratio": 1.687499999998579,
- "factor": 1.687499999998579,
- "label": "competitor leads (1.69x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 120/0/0 vs 158/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1645,19 +1644,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.47000000000116415,
- "maxMs": 0.5399999999990541,
- "ratio": 1.1489361702079077
+ "minMs": 0.38000000000101863,
+ "maxMs": 0.5400000000008731,
+ "ratio": 1.4210526315774357
},
"competitor": {
"minMs": 0.3000000000029104,
"maxMs": 0.31999999999970896,
"ratio": 1.0666666666553486
},
- "stable": true,
+ "stable": false,
"rungs": [
"competitor-leads",
- "competitor-leads",
+ "level",
"competitor-leads"
]
}
@@ -1680,18 +1679,18 @@
{
"competitor": "excalibur",
"referenceMs": 0.08000000000174623,
- "referenceP95Ms": 0.13999999999941792,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.12000000000261934,
+ "referenceGpuMs": 16.679999999996653,
"referenceOverFrameBudget": false,
- "competitorMs": 10.569999999999709,
- "competitorP95Ms": 14.520000000004075,
+ "competitorMs": 9.659999999999854,
+ "competitorP95Ms": 14.37999999999738,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.007568590350212718,
- "factor": 132.12499999711235,
- "label": "ExoJS leads clearly (132.12x)",
+ "ratio": 0.008281573499145697,
+ "factor": 120.74999999736247,
+ "label": "ExoJS leads clearly (120.75x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 2/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1704,9 +1703,9 @@
"ratio": 1
},
"competitor": {
- "minMs": 10.130000000001019,
- "maxMs": 10.700000000000728,
- "ratio": 1.0562685093780506
+ "minMs": 9.650000000001455,
+ "maxMs": 10.049999999999272,
+ "ratio": 1.04145077720184
},
"stable": true,
"rungs": [
@@ -1719,18 +1718,18 @@
{
"competitor": "phaser",
"referenceMs": 0.08000000000174623,
- "referenceP95Ms": 0.13999999999941792,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.12000000000261934,
+ "referenceGpuMs": 16.679999999996653,
"referenceOverFrameBudget": false,
- "competitorMs": 2.730000000000018,
- "competitorP95Ms": 5,
- "competitorGpuMs": 16.659999999999854,
+ "competitorMs": 2.600000000000364,
+ "competitorP95Ms": 4.059999999997672,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.029304029304668754,
- "factor": 34.12499999925535,
- "label": "ExoJS leads clearly (34.12x)",
+ "ratio": 0.03076923076989809,
+ "factor": 32.49999999929514,
+ "label": "ExoJS leads clearly (32.50x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 2/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1743,9 +1742,9 @@
"ratio": 1
},
"competitor": {
- "minMs": 2.5200000000004366,
- "maxMs": 2.9600000000000364,
- "ratio": 1.1746031746029855
+ "minMs": 2.4399999999996,
+ "maxMs": 2.889999999992142,
+ "ratio": 1.1844262295051704
},
"stable": true,
"rungs": [
@@ -1758,12 +1757,12 @@
{
"competitor": "pixi",
"referenceMs": 0.08000000000174623,
- "referenceP95Ms": 0.13999999999941792,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.12000000000261934,
+ "referenceGpuMs": 16.679999999996653,
"referenceOverFrameBudget": false,
"competitorMs": 0.09999999999854481,
- "competitorP95Ms": 0.21999999999752617,
- "competitorGpuMs": 16.659999999999854,
+ "competitorP95Ms": 0.18000000000029104,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -1782,9 +1781,9 @@
"ratio": 1
},
"competitor": {
- "minMs": 0.09999999999854481,
- "maxMs": 0.1000000000003638,
- "ratio": 1.00000000001819
+ "minMs": 0.08000000000174623,
+ "maxMs": 0.09999999999854481,
+ "ratio": 1.2499999999545253
},
"stable": true,
"rungs": [
@@ -1815,15 +1814,15 @@
"referenceP95Ms": 0.22000000000116415,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 6.579999999998108,
- "competitorP95Ms": 9.160000000003492,
+ "competitorMs": 6.619999999995343,
+ "competitorP95Ms": 9.440000000002328,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.01519756838939385,
- "factor": 65.7999999985448,
- "label": "ExoJS leads clearly (65.80x)",
+ "ratio": 0.015105740181609234,
+ "factor": 66.19999999850843,
+ "label": "ExoJS leads clearly (66.20x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1836,9 +1835,9 @@
"ratio": 1.0000000000363798
},
"competitor": {
- "minMs": 6.519999999996799,
- "maxMs": 7.1599999999998545,
- "ratio": 1.0981595092029708
+ "minMs": 6.580000000001746,
+ "maxMs": 6.700000000000728,
+ "ratio": 1.0182370820667097
},
"stable": true,
"rungs": [
@@ -1854,15 +1853,15 @@
"referenceP95Ms": 0.22000000000116415,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.9200000000000728,
- "competitorP95Ms": 3.9799999999995634,
- "competitorGpuMs": 16.659999999999854,
+ "competitorMs": 2.970000000001164,
+ "competitorP95Ms": 4.220000000001164,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.03424657534321243,
- "factor": 29.199999999363353,
- "label": "ExoJS leads clearly (29.20x)",
+ "ratio": 0.03367003367075542,
+ "factor": 29.699999999363353,
+ "label": "ExoJS leads clearly (29.70x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1875,9 +1874,9 @@
"ratio": 1.0000000000363798
},
"competitor": {
- "minMs": 2.8900000000003274,
- "maxMs": 2.9399999999986903,
- "ratio": 1.0173010380617153
+ "minMs": 2.8599999999996726,
+ "maxMs": 3.039999999999054,
+ "ratio": 1.062937062936854
},
"stable": true,
"rungs": [
@@ -1893,13 +1892,13 @@
"referenceP95Ms": 0.22000000000116415,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 0.10000000000218279,
- "competitorP95Ms": 0.22000000000116415,
+ "competitorMs": 0.09999999999854481,
+ "competitorP95Ms": 0.21999999999752617,
"competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1,
+ "ratio": 1.0000000000363798,
"factor": 1,
"label": "level",
"structural": false
@@ -1915,8 +1914,8 @@
},
"competitor": {
"minMs": 0.09999999999854481,
- "maxMs": 0.11999999999898137,
- "ratio": 1.200000000007276
+ "maxMs": 0.09999999999854481,
+ "ratio": 1
},
"stable": true,
"rungs": [
@@ -1938,19 +1937,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.09999999999854481,
+ "referenceMs": 0.08000000000174623,
"referenceP95Ms": 0.15999999999985448,
- "referenceGpuMs": 16.68000000000029,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 32.89999999999782,
- "competitorP95Ms": 38.400000000001455,
- "competitorGpuMs": 34.54000000000087,
+ "competitorMs": 33.390000000003056,
+ "competitorP95Ms": 38.18000000000029,
+ "competitorGpuMs": 34.63999999999942,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.003039513677767521,
- "factor": 329.00000000476575,
- "label": "ExoJS leads clearly (329.00x)",
+ "ratio": 0.0023959269242808897,
+ "factor": 417.3749999909278,
+ "label": "ExoJS leads clearly (417.37x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 3/4/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1958,14 +1957,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.09000000000014552,
+ "minMs": 0.08000000000174623,
"maxMs": 0.09999999999854481,
- "ratio": 1.1111111110931458
+ "ratio": 1.2499999999545253
},
"competitor": {
- "minMs": 32.58999999999651,
- "maxMs": 47.19000000000233,
- "ratio": 1.4479901810373546
+ "minMs": 32.85000000000218,
+ "maxMs": 33.43000000000029,
+ "ratio": 1.0176560121765013
},
"stable": true,
"rungs": [
@@ -1977,19 +1976,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.09999999999854481,
+ "referenceMs": 0.08000000000174623,
"referenceP95Ms": 0.15999999999985448,
- "referenceGpuMs": 16.68000000000029,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 6.710000000000946,
- "competitorP95Ms": 8.119999999998981,
+ "competitorMs": 6.8400000000037835,
+ "competitorP95Ms": 7.959999999999127,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.014903129657009047,
- "factor": 67.1000000009859,
- "label": "ExoJS leads clearly (67.10x)",
+ "ratio": 0.011695906432997366,
+ "factor": 85.49999999818101,
+ "label": "ExoJS leads clearly (85.50x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 4/0/4, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1997,14 +1996,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.09000000000014552,
+ "minMs": 0.08000000000174623,
"maxMs": 0.09999999999854481,
- "ratio": 1.1111111110931458
+ "ratio": 1.2499999999545253
},
"competitor": {
- "minMs": 6.6899999999996,
- "maxMs": 6.760000000000218,
- "ratio": 1.0104633781764758
+ "minMs": 6.5,
+ "maxMs": 6.899999999999636,
+ "ratio": 1.0615384615384056
},
"stable": true,
"rungs": [
@@ -2016,17 +2015,17 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.09999999999854481,
+ "referenceMs": 0.08000000000174623,
"referenceP95Ms": 0.15999999999985448,
- "referenceGpuMs": 16.68000000000029,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
"competitorMs": 0.09999999999854481,
- "competitorP95Ms": 0.21999999999752617,
- "competitorGpuMs": 16.659999999999854,
+ "competitorP95Ms": 0.2000000000007276,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1,
+ "ratio": 0.8000000000291039,
"factor": 1,
"label": "level",
"structural": false
@@ -2036,14 +2035,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.09000000000014552,
+ "minMs": 0.08000000000174623,
"maxMs": 0.09999999999854481,
- "ratio": 1.1111111110931458
+ "ratio": 1.2499999999545253
},
"competitor": {
- "minMs": 0.09000000000014552,
- "maxMs": 0.09999999999854481,
- "ratio": 1.1111111110931458
+ "minMs": 0.09999999999854481,
+ "maxMs": 0.10000000000218279,
+ "ratio": 1.0000000000363798
},
"stable": true,
"rungs": [
@@ -2065,19 +2064,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 2.539999999997235,
- "referenceP95Ms": 7.1599999999998545,
+ "referenceMs": 2.5900000000019645,
+ "referenceP95Ms": 6.400000000001455,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 7.019999999996799,
- "competitorP95Ms": 9.30000000000291,
+ "competitorMs": 7.130000000001019,
+ "competitorP95Ms": 9.660000000003492,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.36182336182313296,
- "factor": 2.7637795275608035,
- "label": "ExoJS leads (2.76x)",
+ "ratio": 0.3632538569427201,
+ "factor": 2.7528957528940583,
+ "label": "ExoJS leads (2.75x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2085,14 +2084,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.4899999999997817,
- "maxMs": 2.5799999999981083,
- "ratio": 1.036144578312584
+ "minMs": 2.460000000000946,
+ "maxMs": 2.640000000001237,
+ "ratio": 1.0731707317074073
},
"competitor": {
- "minMs": 6.930000000000291,
- "maxMs": 7.1599999999998545,
- "ratio": 1.0331890331889688
+ "minMs": 7.120000000002619,
+ "maxMs": 7.5900000000001455,
+ "ratio": 1.0660112359546845
},
"stable": true,
"rungs": [
@@ -2104,19 +2103,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 2.539999999997235,
- "referenceP95Ms": 7.1599999999998545,
+ "referenceMs": 2.5900000000019645,
+ "referenceP95Ms": 6.400000000001455,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.8200000000006185,
- "competitorP95Ms": 5.600000000000364,
+ "competitorMs": 3.0600000000004,
+ "competitorP95Ms": 4.960000000006403,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.900709219856978,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2124,18 +2123,18 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.4899999999997817,
- "maxMs": 2.5799999999981083,
- "ratio": 1.036144578312584
+ "minMs": 2.460000000000946,
+ "maxMs": 2.640000000001237,
+ "ratio": 1.0731707317074073
},
"competitor": {
- "minMs": 2.7799999999997453,
- "maxMs": 3.0200000000004366,
- "ratio": 1.0863309352520552
+ "minMs": 3.030000000000655,
+ "maxMs": 3.210000000006403,
+ "ratio": 1.0594059405959435
},
- "stable": true,
+ "stable": false,
"rungs": [
- "level",
+ "exojs-leads",
"level",
"level"
]
@@ -2143,19 +2142,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 2.539999999997235,
- "referenceP95Ms": 7.1599999999998545,
+ "referenceMs": 2.5900000000019645,
+ "referenceP95Ms": 6.400000000001455,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 4.43999999999869,
- "competitorP95Ms": 5.900000000001455,
+ "competitorMs": 4.450000000000728,
+ "competitorP95Ms": 6,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5720720720716181,
- "factor": 1.7480314960643792,
- "label": "ExoJS leads (1.75x)",
+ "ratio": 0.5820224719104586,
+ "factor": 1.718146718145696,
+ "label": "ExoJS leads (1.72x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 1/0/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2163,14 +2162,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.4899999999997817,
- "maxMs": 2.5799999999981083,
- "ratio": 1.036144578312584
+ "minMs": 2.460000000000946,
+ "maxMs": 2.640000000001237,
+ "ratio": 1.0731707317074073
},
"competitor": {
- "minMs": 4.230000000001382,
- "maxMs": 4.5,
- "ratio": 1.0638297872336948
+ "minMs": 4.3700000000008,
+ "maxMs": 4.459999999999127,
+ "ratio": 1.0205949656746705
},
"stable": true,
"rungs": [
@@ -2192,19 +2191,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 7.130000000001019,
- "referenceP95Ms": 9.139999999999418,
+ "referenceMs": 7.4099999999980355,
+ "referenceP95Ms": 8.840000000000146,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 34.44000000000233,
- "competitorP95Ms": 39.16000000000349,
- "competitorGpuMs": 36.19999999999709,
+ "competitorMs": 34.94999999999709,
+ "competitorP95Ms": 39.4800000000032,
+ "competitorGpuMs": 36.419999999998254,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.2070267131242897,
- "factor": 4.830294530153914,
- "label": "ExoJS leads (4.83x)",
+ "ratio": 0.21201716738193568,
+ "factor": 4.716599190284259,
+ "label": "ExoJS leads (4.72x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 3/4/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2212,14 +2211,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 7.1299999999992,
- "maxMs": 7.570000000001528,
- "ratio": 1.0617110799442324
+ "minMs": 7.099999999998545,
+ "maxMs": 7.469999999999345,
+ "ratio": 1.0521126760564614
},
"competitor": {
- "minMs": 34.31999999999971,
- "maxMs": 35.36000000000058,
- "ratio": 1.030303030303056
+ "minMs": 34.22999999999956,
+ "maxMs": 36.279999999998836,
+ "ratio": 1.059888986269334
},
"stable": true,
"rungs": [
@@ -2231,17 +2230,17 @@
},
{
"competitor": "phaser",
- "referenceMs": 7.130000000001019,
- "referenceP95Ms": 9.139999999999418,
+ "referenceMs": 7.4099999999980355,
+ "referenceP95Ms": 8.840000000000146,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 7,
- "competitorP95Ms": 8.55999999999949,
+ "competitorMs": 6.9399999999996,
+ "competitorP95Ms": 8.220000000001164,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.0185714285715741,
+ "ratio": 1.0677233429392599,
"factor": 1,
"label": "level",
"structural": false
@@ -2251,14 +2250,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 7.1299999999992,
- "maxMs": 7.570000000001528,
- "ratio": 1.0617110799442324
+ "minMs": 7.099999999998545,
+ "maxMs": 7.469999999999345,
+ "ratio": 1.0521126760564614
},
"competitor": {
- "minMs": 6.989999999999782,
- "maxMs": 7.130000000000109,
- "ratio": 1.020028612303338
+ "minMs": 6.930000000007567,
+ "maxMs": 7.050000000000182,
+ "ratio": 1.0173160173149327
},
"stable": true,
"rungs": [
@@ -2270,19 +2269,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 7.130000000001019,
- "referenceP95Ms": 9.139999999999418,
+ "referenceMs": 7.4099999999980355,
+ "referenceP95Ms": 8.840000000000146,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 18.910000000001673,
- "competitorP95Ms": 24.299999999999272,
- "competitorGpuMs": 20.979999999999563,
+ "competitorMs": 18.779999999998836,
+ "competitorP95Ms": 22.600000000002183,
+ "competitorGpuMs": 20.860000000000582,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.37704918032788937,
- "factor": 2.652173913043334,
- "label": "ExoJS leads (2.65x)",
+ "ratio": 0.3945686900957665,
+ "factor": 2.534412955466102,
+ "label": "ExoJS leads (2.53x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 1/0/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2290,14 +2289,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 7.1299999999992,
- "maxMs": 7.570000000001528,
- "ratio": 1.0617110799442324
+ "minMs": 7.099999999998545,
+ "maxMs": 7.469999999999345,
+ "ratio": 1.0521126760564614
},
"competitor": {
- "minMs": 18.860000000000582,
- "maxMs": 19.290000000000873,
- "ratio": 1.02279957582186
+ "minMs": 18.770000000002256,
+ "maxMs": 18.93999999999869,
+ "ratio": 1.0090570058602246
},
"stable": true,
"rungs": [
@@ -2324,19 +2323,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.3600000000005821,
- "referenceP95Ms": 0.6399999999994179,
+ "referenceMs": 0.37999999999919964,
+ "referenceP95Ms": 0.680000000000291,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.100000000000364,
- "competitorP95Ms": 3.540000000000873,
+ "competitorMs": 2.039999999999054,
+ "competitorP95Ms": 3.959999999999127,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.1714285714288189,
- "factor": 5.833333333324912,
- "label": "ExoJS leads clearly (5.83x)",
+ "ratio": 0.1862745098036156,
+ "factor": 5.3684210526403975,
+ "label": "ExoJS leads clearly (5.37x)",
"structural": true
},
"mechanism": "competitor issues fewer texture binds (9 vs 3 per frame)",
@@ -2344,14 +2343,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.3400000000001455,
+ "minMs": 0.36999999999898137,
"maxMs": 0.38000000000101863,
- "ratio": 1.117647058826047
+ "ratio": 1.0270270270326076
},
"competitor": {
- "minMs": 2.0099999999983993,
- "maxMs": 2.3099999999994907,
- "ratio": 1.1492537313439455
+ "minMs": 2.0100000000002183,
+ "maxMs": 2.0900000000001455,
+ "ratio": 1.039800995024835
},
"stable": true,
"rungs": [
@@ -2373,19 +2372,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.31999999999970896,
+ "referenceMs": 0.3100000000013097,
"referenceP95Ms": 0.5,
- "referenceGpuMs": 16.660000000003492,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 2.609999999996944,
- "competitorP95Ms": 4.1599999999962165,
+ "competitorMs": 2.4099999999998545,
+ "competitorP95Ms": 4.580000000001746,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.12260536398470637,
- "factor": 8.156249999997868,
- "label": "ExoJS leads clearly (8.16x)",
+ "ratio": 0.12863070539474208,
+ "factor": 7.774193548353782,
+ "label": "ExoJS leads clearly (7.77x)",
"structural": true
},
"mechanism": "competitor issues fewer texture binds (11 vs 3 per frame)",
@@ -2393,14 +2392,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.3100000000013097,
+ "minMs": 0.3000000000029104,
"maxMs": 0.31999999999970896,
- "ratio": 1.0322580645108292
+ "ratio": 1.0666666666553486
},
"competitor": {
- "minMs": 2.099999999998545,
- "maxMs": 2.7599999999965803,
- "ratio": 1.3142857142849966
+ "minMs": 2.349999999998545,
+ "maxMs": 2.640000000003056,
+ "ratio": 1.123404255321145
},
"stable": true,
"rungs": [
@@ -2422,19 +2421,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.27999999999883585,
- "referenceP95Ms": 0.5,
- "referenceGpuMs": 16.660000000003492,
+ "referenceMs": 0.2999999999992724,
+ "referenceP95Ms": 0.4599999999991269,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 2.570000000003347,
- "competitorP95Ms": 4.220000000001164,
- "competitorGpuMs": 16.68000000000029,
+ "competitorMs": 2.7600000000020373,
+ "competitorP95Ms": 4.440000000002328,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.10894941634181758,
- "factor": 9.178571428621543,
- "label": "ExoJS leads clearly (9.18x)",
+ "ratio": 0.10869565217356919,
+ "factor": 9.200000000029103,
+ "label": "ExoJS leads clearly (9.20x)",
"structural": true
},
"mechanism": "competitor issues fewer texture binds (15 vs 7 per frame)",
@@ -2442,14 +2441,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.27999999999883585,
- "maxMs": 0.2999999999956344,
- "ratio": 1.0714285714174347
+ "minMs": 0.26000000000203727,
+ "maxMs": 0.31999999999970896,
+ "ratio": 1.2307692307584674
},
"competitor": {
- "minMs": 2.3100000000013097,
- "maxMs": 2.599999999998545,
- "ratio": 1.1255411255398575
+ "minMs": 2.399999999997817,
+ "maxMs": 2.959999999999127,
+ "ratio": 1.2333333333340912
},
"stable": true,
"rungs": [
@@ -2471,19 +2470,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.31999999999970896,
- "referenceP95Ms": 0.6000000000058208,
- "referenceGpuMs": 16.68000000000029,
+ "referenceMs": 0.3400000000037835,
+ "referenceP95Ms": 0.5600000000049477,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
"competitorMs": 0.4599999999991269,
- "competitorP95Ms": 0.7200000000011642,
- "competitorGpuMs": 16.68000000000029,
+ "competitorP95Ms": 0.7600000000020373,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "exojs",
- "ratio": 0.6956521739137312,
- "factor": 1.4374999999985787,
- "label": "ExoJS leads (1.44x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (5 vs 8 per frame)",
@@ -2492,19 +2491,19 @@
"runs": 3,
"reference": {
"minMs": 0.31999999999970896,
- "maxMs": 0.32999999999810825,
- "ratio": 1.0312499999950262
+ "maxMs": 0.3599999999933061,
+ "ratio": 1.1249999999801048
},
"competitor": {
- "minMs": 0.41999999999825377,
- "maxMs": 0.47999999999592546,
- "ratio": 1.1428571428521932
+ "minMs": 0.42000000000552973,
+ "maxMs": 0.5599999999976717,
+ "ratio": 1.333333333310235
},
- "stable": true,
+ "stable": false,
"rungs": [
"exojs-leads",
"exojs-leads",
- "exojs-leads"
+ "level"
]
}
}
@@ -2520,19 +2519,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.250000000003638,
- "referenceP95Ms": 0.4400000000023283,
- "referenceGpuMs": 16.68000000000029,
+ "referenceMs": 0.2400000000052387,
+ "referenceP95Ms": 0.43999999999505235,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.15999999999985448,
- "competitorP95Ms": 0.27999999999883585,
- "competitorGpuMs": 16.660000000003492,
+ "competitorMs": 0.16000000000349246,
+ "competitorP95Ms": 0.26000000000203727,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.5625000000241585,
- "factor": 1.5625000000241585,
- "label": "competitor leads (1.56x)",
+ "ratio": 1.5,
+ "factor": 1.5,
+ "label": "competitor leads (1.50x)",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (4 vs 10 per frame)",
@@ -2540,9 +2539,9 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.22999999999956344,
- "maxMs": 0.26000000000203727,
- "ratio": 1.130434782619699
+ "minMs": 0.23999999999796273,
+ "maxMs": 0.25,
+ "ratio": 1.041666666675509
},
"competitor": {
"minMs": 0.13999999999941792,
@@ -2573,15 +2572,15 @@
"referenceP95Ms": 0.4400000000023283,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.4099999999998545,
- "competitorP95Ms": 0.6399999999994179,
- "competitorGpuMs": 16.660000000003492,
+ "competitorMs": 0.4000000000014552,
+ "competitorP95Ms": 0.5800000000017462,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.6341463414686087,
- "factor": 1.576923076910161,
- "label": "ExoJS leads (1.58x)",
+ "ratio": 0.6500000000027285,
+ "factor": 1.5384615384550804,
+ "label": "ExoJS leads (1.54x)",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (4 vs 10 per frame)",
@@ -2589,14 +2588,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.26000000000203727,
- "maxMs": 0.26000000000203727,
- "ratio": 1
+ "minMs": 0.2400000000016007,
+ "maxMs": 0.27999999999883585,
+ "ratio": 1.1666666666540348
},
"competitor": {
- "minMs": 0.4099999999998545,
- "maxMs": 0.4399999999986903,
- "ratio": 1.0731707317045036
+ "minMs": 0.3900000000030559,
+ "maxMs": 0.4000000000014552,
+ "ratio": 1.0256410256367203
},
"stable": true,
"rungs": [
@@ -2623,19 +2622,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.18999999999869033,
- "referenceP95Ms": 1.4400000000023283,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 0.18000000000029104,
+ "referenceP95Ms": 1.6000000000021828,
+ "referenceGpuMs": 16.679999999996653,
"referenceOverFrameBudget": false,
- "competitorMs": 0.11999999999898137,
+ "competitorMs": 0.11000000000058208,
"competitorP95Ms": 0.22000000000116415,
- "competitorGpuMs": 16.68000000000029,
+ "competitorGpuMs": 16.679999999996653,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.5833333333358597,
- "factor": 1.5833333333358597,
- "label": "competitor leads (1.58x)",
+ "ratio": 1.6363636363576233,
+ "factor": 1.6363636363576233,
+ "label": "competitor leads (1.64x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (90 vs 1 per frame)",
@@ -2644,8 +2643,8 @@
"runs": 3,
"reference": {
"minMs": 0.17999999999847205,
- "maxMs": 0.1999999999989086,
- "ratio": 1.1111111111144796
+ "maxMs": 0.18000000000029104,
+ "ratio": 1.0000000000101055
},
"competitor": {
"minMs": 0.10000000000218279,
@@ -2678,18 +2677,18 @@
{
"competitor": "excalibur",
"referenceMs": 0.18000000000029104,
- "referenceP95Ms": 1.180000000000291,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 1.1600000000034925,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 20.790000000000873,
- "competitorP95Ms": 25.69999999999709,
- "competitorGpuMs": 21.94000000000233,
+ "competitorMs": 20.810000000004948,
+ "competitorP95Ms": 25.90000000000873,
+ "competitorGpuMs": 22,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.008658008658022293,
- "factor": 115.4999999998181,
- "label": "ExoJS leads clearly (115.50x)",
+ "ratio": 0.008649687650180118,
+ "factor": 115.61111111095167,
+ "label": "ExoJS leads clearly (115.61x)",
"structural": true
},
"mechanism": "competitor issues fewer draw calls (90 vs 1 per frame)",
@@ -2697,14 +2696,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.1599999999962165,
- "maxMs": 0.18000000000029104,
- "ratio": 1.1250000000284217
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.20000000000436557,
+ "ratio": 1.1111111111335679
},
"competitor": {
- "minMs": 20.60000000000582,
- "maxMs": 21.860000000007858,
- "ratio": 1.061165048543771
+ "minMs": 20.580000000001746,
+ "maxMs": 21.060000000004948,
+ "ratio": 1.0233236151605034
},
"stable": true,
"rungs": [
@@ -2717,18 +2716,18 @@
{
"competitor": "phaser",
"referenceMs": 0.18000000000029104,
- "referenceP95Ms": 1.180000000000291,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 1.1600000000034925,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.20999999999912689,
- "competitorP95Ms": 0.38000000000101863,
+ "competitorMs": 0.2000000000007276,
+ "competitorP95Ms": 0.42000000000189175,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 0.899999999998181,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (90 vs 1 per frame)",
@@ -2736,19 +2735,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.1599999999962165,
- "maxMs": 0.18000000000029104,
- "ratio": 1.1250000000284217
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.20000000000436557,
+ "ratio": 1.1111111111335679
},
"competitor": {
- "minMs": 0.2000000000007276,
- "maxMs": 0.21999999999752617,
- "ratio": 1.0999999999836292
+ "minMs": 0.1999999999989086,
+ "maxMs": 0.20999999999912689,
+ "ratio": 1.0500000000013643
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
- "exojs-leads",
+ "level",
"level"
]
}
@@ -2756,18 +2755,18 @@
{
"competitor": "pixi",
"referenceMs": 0.18000000000029104,
- "referenceP95Ms": 1.180000000000291,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 1.1600000000034925,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
"competitorMs": 0.22000000000116415,
- "competitorP95Ms": 0.39999999999417923,
- "competitorGpuMs": 16.660000000003492,
+ "competitorP95Ms": 0.37999999999738066,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 0.8181818181788116,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (90 vs 282 per frame)",
@@ -2775,19 +2774,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.1599999999962165,
- "maxMs": 0.18000000000029104,
- "ratio": 1.1250000000284217
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.20000000000436557,
+ "ratio": 1.1111111111335679
},
"competitor": {
- "minMs": 0.2199999999938882,
- "maxMs": 0.23999999999796273,
- "ratio": 1.090909090930137
+ "minMs": 0.20000000000436557,
+ "maxMs": 0.22000000000116415,
+ "ratio": 1.0999999999818102
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
- "exojs-leads",
+ "level",
"level"
]
}
@@ -2805,18 +2804,18 @@
{
"competitor": "excalibur",
"referenceMs": 0.13999999999941792,
- "referenceP95Ms": 0.7399999999979627,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.7799999999988358,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 186.42000000000553,
- "competitorP95Ms": 196.44000000000233,
- "competitorGpuMs": 193.6999999999971,
+ "competitorMs": 180.13999999999942,
+ "competitorP95Ms": 189.39999999999418,
+ "competitorGpuMs": 183.11999999999534,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.0007509923827884013,
- "factor": 1331.5714285770043,
- "label": "ExoJS leads clearly (1331.57x)",
+ "ratio": 0.0007771733096448227,
+ "factor": 1286.7142857196313,
+ "label": "ExoJS leads clearly (1286.71x)",
"structural": true
},
"mechanism": "competitor issues fewer draw calls (30 vs 5 per frame)",
@@ -2824,14 +2823,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.12000000000261934,
- "maxMs": 0.16000000000349246,
- "ratio": 1.3333333333333333
+ "minMs": 0.11999999999898137,
+ "maxMs": 0.18000000000029104,
+ "ratio": 1.5000000000151583
},
"competitor": {
- "minMs": 182.55999999999767,
- "maxMs": 189.13999999999942,
- "ratio": 1.0360429447852861
+ "minMs": 178.79000000000087,
+ "maxMs": 182.29000000000087,
+ "ratio": 1.0195760389283517
},
"stable": true,
"rungs": [
@@ -2844,12 +2843,12 @@
{
"competitor": "phaser",
"referenceMs": 0.13999999999941792,
- "referenceP95Ms": 0.7399999999979627,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.7799999999988358,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.19000000000050932,
- "competitorP95Ms": 0.3400000000001455,
- "competitorGpuMs": 16.68000000000029,
+ "competitorMs": 0.16000000000349246,
+ "competitorP95Ms": 0.38000000000101863,
+ "competitorGpuMs": 16.700000000000728,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -2863,18 +2862,18 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.12000000000261934,
- "maxMs": 0.16000000000349246,
- "ratio": 1.3333333333333333
+ "minMs": 0.11999999999898137,
+ "maxMs": 0.18000000000029104,
+ "ratio": 1.5000000000151583
},
"competitor": {
- "minMs": 0.18000000000029104,
- "maxMs": 0.2000000000007276,
- "ratio": 1.1111111111133567
+ "minMs": 0.15999999999985448,
+ "maxMs": 0.17000000000189175,
+ "ratio": 1.0625000000127898
},
"stable": false,
"rungs": [
- "exojs-leads",
+ "level",
"exojs-leads",
"level"
]
@@ -2883,11 +2882,11 @@
{
"competitor": "pixi",
"referenceMs": 0.13999999999941792,
- "referenceP95Ms": 0.7399999999979627,
- "referenceGpuMs": 16.68000000000029,
+ "referenceP95Ms": 0.7799999999988358,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.18000000000029104,
- "competitorP95Ms": 0.41999999999825377,
+ "competitorMs": 0.22000000000116415,
+ "competitorP95Ms": 0.3600000000005821,
"competitorGpuMs": 16.659999999996217,
"competitorOverFrameBudget": false,
"verdict": {
@@ -2902,14 +2901,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.12000000000261934,
- "maxMs": 0.16000000000349246,
- "ratio": 1.3333333333333333
+ "minMs": 0.11999999999898137,
+ "maxMs": 0.18000000000029104,
+ "ratio": 1.5000000000151583
},
"competitor": {
"minMs": 0.18000000000029104,
- "maxMs": 0.21999999999752617,
- "ratio": 1.2222222222065025
+ "maxMs": 0.22000000000116415,
+ "ratio": 1.2222222222267136
},
"stable": false,
"rungs": [
@@ -2931,19 +2930,19 @@
"cells": [
{
"competitor": "phaser",
- "referenceMs": 0.7800000000024738,
+ "referenceMs": 0.750000000003638,
"referenceP95Ms": 1.319999999999709,
- "referenceGpuMs": 16.68000000000029,
+ "referenceGpuMs": 16.659999999996217,
"referenceOverFrameBudget": false,
- "competitorMs": 1.7199999999993452,
- "competitorP95Ms": 5.680000000000291,
+ "competitorMs": 1.8000000000010914,
+ "competitorP95Ms": 6,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.45348837209463416,
- "factor": 2.205128205120372,
- "label": "ExoJS leads (2.21x)",
+ "ratio": 0.4166666666684351,
+ "factor": 2.399999999989814,
+ "label": "ExoJS leads (2.40x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/3/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2951,14 +2950,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.75,
- "maxMs": 0.7900000000008731,
- "ratio": 1.0533333333344974
+ "minMs": 0.7000000000007276,
+ "maxMs": 0.8100000000013097,
+ "ratio": 1.1571428571435254
},
"competitor": {
- "minMs": 1.6200000000008004,
- "maxMs": 2.4499999999989086,
- "ratio": 1.5123456790109249
+ "minMs": 1.68000000000211,
+ "maxMs": 2.400000000001455,
+ "ratio": 1.4285714285705005
},
"stable": true,
"rungs": [
@@ -2970,19 +2969,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.7800000000024738,
+ "referenceMs": 0.750000000003638,
"referenceP95Ms": 1.319999999999709,
- "referenceGpuMs": 16.68000000000029,
+ "referenceGpuMs": 16.659999999996217,
"referenceOverFrameBudget": false,
- "competitorMs": 0.9799999999995634,
- "competitorP95Ms": 1.9399999999950523,
+ "competitorMs": 1.1299999999973807,
+ "competitorP95Ms": 1.9000000000014552,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "exojs",
+ "ratio": 0.6637168141640499,
+ "factor": 1.5066666666558661,
+ "label": "ExoJS leads (1.51x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 2/0/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2990,20 +2989,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.75,
- "maxMs": 0.7900000000008731,
- "ratio": 1.0533333333344974
+ "minMs": 0.7000000000007276,
+ "maxMs": 0.8100000000013097,
+ "ratio": 1.1571428571435254
},
"competitor": {
- "minMs": 0.7300000000032014,
- "maxMs": 1,
- "ratio": 1.3698630136926226
+ "minMs": 1.110000000000582,
+ "maxMs": 1.2600000000020373,
+ "ratio": 1.1351351351363752
},
- "stable": false,
+ "stable": true,
"rungs": [
"exojs-leads",
"exojs-leads",
- "level"
+ "exojs-leads"
]
}
}
@@ -3024,19 +3023,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.27999999999883585,
- "referenceP95Ms": 0.3800000000046566,
+ "referenceMs": 0.26000000000203727,
+ "referenceP95Ms": 0.41999999999825377,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 2.4099999999962165,
- "competitorP95Ms": 6.580000000001746,
+ "competitorMs": 2.390000000006694,
+ "competitorP95Ms": 7.419999999998254,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.11618257261380723,
- "factor": 8.607142857165131,
- "label": "ExoJS leads clearly (8.61x)",
+ "ratio": 0.10878661087920881,
+ "factor": 9.19230769226141,
+ "label": "ExoJS leads clearly (9.19x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3044,14 +3043,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2599999999947613,
+ "minMs": 0.26000000000203727,
"maxMs": 0.27999999999883585,
- "ratio": 1.0769230769402982
+ "ratio": 1.076923076910161
},
"competitor": {
- "minMs": 2.290000000000873,
- "maxMs": 2.4400000000023283,
- "ratio": 1.065502183406724
+ "minMs": 2.389999999992142,
+ "maxMs": 2.4199999999982538,
+ "ratio": 1.0125523012578286
},
"stable": true,
"rungs": [
@@ -3063,19 +3062,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.27999999999883585,
- "referenceP95Ms": 0.3800000000046566,
+ "referenceMs": 0.26000000000203727,
+ "referenceP95Ms": 0.41999999999825377,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.8800000000010186,
- "competitorP95Ms": 1.0600000000013097,
+ "competitorMs": 0.8400000000001455,
+ "competitorP95Ms": 1.0800000000017462,
"competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.318181818180127,
- "factor": 3.1428571428738477,
- "label": "ExoJS leads (3.14x)",
+ "ratio": 0.30952380952618125,
+ "factor": 3.230769230744475,
+ "label": "ExoJS leads (3.23x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3083,14 +3082,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2599999999947613,
+ "minMs": 0.26000000000203727,
"maxMs": 0.27999999999883585,
- "ratio": 1.0769230769402982
+ "ratio": 1.076923076910161
},
"competitor": {
- "minMs": 0.7999999999992724,
- "maxMs": 0.9199999999982538,
- "ratio": 1.149999999998863
+ "minMs": 0.8400000000001455,
+ "maxMs": 0.8799999999901047,
+ "ratio": 1.047619047607086
},
"stable": true,
"rungs": [
@@ -3102,19 +3101,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.27999999999883585,
- "referenceP95Ms": 0.3800000000046566,
+ "referenceMs": 0.26000000000203727,
+ "referenceP95Ms": 0.41999999999825377,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
"competitorMs": 0.13999999999941792,
- "competitorP95Ms": 0.2599999999947613,
- "competitorGpuMs": 16.68000000000029,
+ "competitorP95Ms": 0.27999999999883585,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 2,
- "factor": 2,
- "label": "competitor leads (2.00x)",
+ "ratio": 1.8571428571651305,
+ "factor": 1.8571428571651305,
+ "label": "competitor leads (1.86x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3122,9 +3121,9 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2599999999947613,
+ "minMs": 0.26000000000203727,
"maxMs": 0.27999999999883585,
- "ratio": 1.0769230769402982
+ "ratio": 1.076923076910161
},
"competitor": {
"minMs": 0.13999999999941792,
@@ -3151,19 +3150,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.4599999999991269,
- "referenceP95Ms": 0.5999999999985448,
- "referenceGpuMs": 16.660000000003492,
+ "referenceMs": 0.46000000000276486,
+ "referenceP95Ms": 0.5800000000017462,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 25.42000000000553,
- "competitorP95Ms": 28,
- "competitorGpuMs": 26.24000000000524,
+ "competitorMs": 24.489999999997963,
+ "competitorP95Ms": 26.979999999995925,
+ "competitorGpuMs": 25.460000000006403,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.018095987411448734,
- "factor": 55.2608695653343,
- "label": "ExoJS leads clearly (55.26x)",
+ "ratio": 0.018783176806974403,
+ "factor": 53.23913043445818,
+ "label": "ExoJS leads clearly (53.24x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3172,13 +3171,13 @@
"runs": 3,
"reference": {
"minMs": 0.4500000000007276,
- "maxMs": 0.4800000000032014,
- "ratio": 1.0666666666720563
+ "maxMs": 0.47999999999956344,
+ "ratio": 1.066666666663972
},
"competitor": {
- "minMs": 24.700000000004366,
- "maxMs": 25.499999999992724,
- "ratio": 1.0323886639671342
+ "minMs": 14.69999999999709,
+ "maxMs": 25.69000000000233,
+ "ratio": 1.7476190476195521
},
"stable": true,
"rungs": [
@@ -3190,19 +3189,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.4599999999991269,
- "referenceP95Ms": 0.5999999999985448,
- "referenceGpuMs": 16.660000000003492,
+ "referenceMs": 0.46000000000276486,
+ "referenceP95Ms": 0.5800000000017462,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 2.8099999999994907,
- "competitorP95Ms": 3.8800000000010186,
+ "competitorMs": 2.9800000000032014,
+ "competitorP95Ms": 3.779999999998836,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.1637010676153773,
- "factor": 6.108695652184401,
- "label": "ExoJS leads clearly (6.11x)",
+ "ratio": 0.15436241610814452,
+ "factor": 6.478260869533239,
+ "label": "ExoJS leads clearly (6.48x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3211,13 +3210,13 @@
"runs": 3,
"reference": {
"minMs": 0.4500000000007276,
- "maxMs": 0.4800000000032014,
- "ratio": 1.0666666666720563
+ "maxMs": 0.47999999999956344,
+ "ratio": 1.066666666663972
},
"competitor": {
- "minMs": 2.7600000000002183,
- "maxMs": 3.100000000000364,
- "ratio": 1.1231884057971444
+ "minMs": 2.7999999999992724,
+ "maxMs": 3.2000000000007276,
+ "ratio": 1.1428571428576997
},
"stable": true,
"rungs": [
@@ -3229,18 +3228,18 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.4599999999991269,
- "referenceP95Ms": 0.5999999999985448,
- "referenceGpuMs": 16.660000000003492,
+ "referenceMs": 0.46000000000276486,
+ "referenceP95Ms": 0.5800000000017462,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 0.11999999999534339,
+ "competitorMs": 0.11999999999898137,
"competitorP95Ms": 0.2400000000052387,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 3.83333333347481,
- "factor": 3.83333333347481,
+ "ratio": 3.8333333333889135,
+ "factor": 3.8333333333889135,
"label": "competitor leads (3.83x)",
"structural": false
},
@@ -3250,8 +3249,8 @@
"runs": 3,
"reference": {
"minMs": 0.4500000000007276,
- "maxMs": 0.4800000000032014,
- "ratio": 1.0666666666720563
+ "maxMs": 0.47999999999956344,
+ "ratio": 1.066666666663972
},
"competitor": {
"minMs": 0.11999999999534339,
@@ -3278,19 +3277,19 @@
"cells": [
{
"competitor": "phaser",
- "referenceMs": 1.6299999999973807,
- "referenceP95Ms": 2.599999999998545,
+ "referenceMs": 1.6699999999982538,
+ "referenceP95Ms": 3.1000000000058208,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 9.469999999999345,
- "competitorP95Ms": 9.80000000000291,
+ "competitorMs": 9.510000000002037,
+ "competitorP95Ms": 10.659999999999854,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.17212249207998875,
- "factor": 5.809815950929179,
- "label": "ExoJS leads clearly (5.81x)",
+ "ratio": 0.1756046267085064,
+ "factor": 5.694610778450288,
+ "label": "ExoJS leads clearly (5.69x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 7/0/7, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3298,14 +3297,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.6199999999989814,
- "maxMs": 1.8099999999976717,
- "ratio": 1.1172839506165493
+ "minMs": 1.5800000000017462,
+ "maxMs": 1.8799999999973807,
+ "ratio": 1.1898734177185462
},
"competitor": {
- "minMs": 9.380000000001019,
- "maxMs": 9.5,
- "ratio": 1.0127931769721714
+ "minMs": 9.449999999998909,
+ "maxMs": 9.6299999999992,
+ "ratio": 1.019047619047652
},
"stable": true,
"rungs": [
@@ -3317,19 +3316,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.6299999999973807,
- "referenceP95Ms": 2.599999999998545,
+ "referenceMs": 1.6699999999982538,
+ "referenceP95Ms": 3.1000000000058208,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.1499999999978172,
+ "competitorMs": 0.13999999999941792,
"competitorP95Ms": 0.27999999999883585,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 10.866666666807335,
- "factor": 10.866666666807335,
- "label": "competitor leads clearly (10.87x)",
+ "ratio": 11.928571428608551,
+ "factor": 11.928571428608551,
+ "label": "competitor leads clearly (11.93x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3337,14 +3336,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.6199999999989814,
- "maxMs": 1.8099999999976717,
- "ratio": 1.1172839506165493
+ "minMs": 1.5800000000017462,
+ "maxMs": 1.8799999999973807,
+ "ratio": 1.1898734177185462
},
"competitor": {
- "minMs": 0.13000000000101863,
- "maxMs": 0.15999999999985448,
- "ratio": 1.2307692307584674
+ "minMs": 0.13999999999941792,
+ "maxMs": 0.1499999999978172,
+ "ratio": 1.0714285714174347
},
"stable": true,
"rungs": [
@@ -3353,6 +3352,43 @@
"competitor-leads-clearly"
]
}
+ },
+ {
+ "competitor": "excalibur",
+ "referenceMs": 1.8799999999973807,
+ "referenceP95Ms": 3.1599999999962165,
+ "referenceGpuMs": 16.660000000003492,
+ "referenceOverFrameBudget": false,
+ "competitorMs": 191.07000000000698,
+ "competitorP95Ms": 195.77999999999884,
+ "competitorGpuMs": 196.6600000000035,
+ "competitorOverFrameBudget": true,
+ "verdict": {
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
+ "structural": false
+ },
+ "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 5/6/5, none of them large enough to account for the gap); the difference is CPU-side",
+ "timer": "resolved",
+ "aggregate": {
+ "runs": 1,
+ "reference": {
+ "minMs": 1.8799999999973807,
+ "maxMs": 1.8799999999973807,
+ "ratio": 1
+ },
+ "competitor": {
+ "minMs": 191.07000000000698,
+ "maxMs": 191.07000000000698,
+ "ratio": 1
+ },
+ "stable": false,
+ "rungs": [
+ "exojs-leads-clearly"
+ ]
+ }
}
]
},
@@ -3366,19 +3402,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 1.4899999999979627,
- "referenceP95Ms": 2.280000000006112,
+ "referenceMs": 1.360000000000582,
+ "referenceP95Ms": 2.279999999998836,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 25.089999999996508,
- "competitorP95Ms": 27.29999999998836,
- "competitorGpuMs": 26.479999999995925,
+ "competitorMs": 24.959999999999127,
+ "competitorP95Ms": 27.360000000000582,
+ "competitorGpuMs": 26.05999999999767,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.05938620964520407,
- "factor": 16.838926174517322,
- "label": "ExoJS leads clearly (16.84x)",
+ "ratio": 0.05448717948720471,
+ "factor": 18.352941176462092,
+ "label": "ExoJS leads clearly (18.35x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3386,14 +3422,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.4599999999991269,
- "maxMs": 1.4900000000016007,
- "ratio": 1.0205479452071862
+ "minMs": 1.3400000000001455,
+ "maxMs": 1.6599999999962165,
+ "ratio": 1.2388059701462957
},
"competitor": {
- "minMs": 24.70000000001164,
- "maxMs": 26.580000000001746,
- "ratio": 1.07611336032345
+ "minMs": 23.999999999992724,
+ "maxMs": 25.179999999993015,
+ "ratio": 1.0491666666666937
},
"stable": true,
"rungs": [
@@ -3405,19 +3441,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 1.4899999999979627,
- "referenceP95Ms": 2.280000000006112,
+ "referenceMs": 1.360000000000582,
+ "referenceP95Ms": 2.279999999998836,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 3.1599999999998545,
- "competitorP95Ms": 6.5,
+ "competitorMs": 3.1600000000034925,
+ "competitorP95Ms": 6.139999999999418,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.47151898734114917,
- "factor": 2.120805369130319,
- "label": "ExoJS leads (2.12x)",
+ "ratio": 0.43037974683515157,
+ "factor": 2.3235294117662795,
+ "label": "ExoJS leads (2.32x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3425,14 +3461,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.4599999999991269,
- "maxMs": 1.4900000000016007,
- "ratio": 1.0205479452071862
+ "minMs": 1.3400000000001455,
+ "maxMs": 1.6599999999962165,
+ "ratio": 1.2388059701462957
},
"competitor": {
- "minMs": 3.139999999999418,
- "maxMs": 3.2299999999995634,
- "ratio": 1.0286624203822172
+ "minMs": 3.1199999999989814,
+ "maxMs": 3.360000000000582,
+ "ratio": 1.076923076923615
},
"stable": true,
"rungs": [
@@ -3444,8 +3480,8 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.4899999999979627,
- "referenceP95Ms": 2.280000000006112,
+ "referenceMs": 1.360000000000582,
+ "referenceP95Ms": 2.279999999998836,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
"competitorMs": 0.9000000000014552,
@@ -3454,9 +3490,9 @@
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.6555555555506152,
- "factor": 1.6555555555506152,
- "label": "competitor leads (1.66x)",
+ "ratio": 1.5111111111093145,
+ "factor": 1.5111111111093145,
+ "label": "competitor leads (1.51x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3464,14 +3500,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.4599999999991269,
- "maxMs": 1.4900000000016007,
- "ratio": 1.0205479452071862
+ "minMs": 1.3400000000001455,
+ "maxMs": 1.6599999999962165,
+ "ratio": 1.2388059701462957
},
"competitor": {
- "minMs": 0.8799999999973807,
- "maxMs": 0.9700000000048021,
- "ratio": 1.1022727272814652
+ "minMs": 0.8900000000030559,
+ "maxMs": 0.9199999999982538,
+ "ratio": 1.033707865163028
},
"stable": true,
"rungs": [
@@ -3498,19 +3534,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.5400000000008731,
- "referenceP95Ms": 0.9000000000014552,
+ "referenceMs": 0.569999999999709,
+ "referenceP95Ms": 0.9400000000023283,
"referenceGpuMs": 16.679999999993015,
"referenceOverFrameBudget": false,
- "competitorMs": 24.04000000000815,
- "competitorP95Ms": 26.139999999999418,
- "competitorGpuMs": 25.160000000003492,
+ "competitorMs": 24.62999999999738,
+ "competitorP95Ms": 27.920000000012806,
+ "competitorGpuMs": 25.720000000001164,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.02246256239603536,
- "factor": 44.51851851846163,
- "label": "ExoJS leads clearly (44.52x)",
+ "ratio": 0.02314250913519162,
+ "factor": 43.21052631580694,
+ "label": "ExoJS leads clearly (43.21x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3519,13 +3555,13 @@
"runs": 3,
"reference": {
"minMs": 0.5400000000008731,
- "maxMs": 0.569999999996071,
- "ratio": 1.055555555546573
+ "maxMs": 0.5799999999944703,
+ "ratio": 1.074074074062097
},
"competitor": {
- "minMs": 22.64999999999418,
- "maxMs": 26.610000000015134,
- "ratio": 1.1748344370870627
+ "minMs": 24.510000000002037,
+ "maxMs": 25.810000000004948,
+ "ratio": 1.053039575683509
},
"stable": true,
"rungs": [
@@ -3537,19 +3573,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.5400000000008731,
- "referenceP95Ms": 0.9000000000014552,
+ "referenceMs": 0.569999999999709,
+ "referenceP95Ms": 0.9400000000023283,
"referenceGpuMs": 16.679999999993015,
"referenceOverFrameBudget": false,
- "competitorMs": 32.42000000000189,
- "competitorP95Ms": 35.31999999999971,
- "competitorGpuMs": 33.340000000000146,
+ "competitorMs": 32.67000000000007,
+ "competitorP95Ms": 35.43999999999869,
+ "competitorGpuMs": 33.5199999999968,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.01665638494758919,
- "factor": 60.037037036943474,
- "label": "ExoJS leads clearly (60.04x)",
+ "ratio": 0.017447199265372137,
+ "factor": 57.3157894737136,
+ "label": "ExoJS leads clearly (57.32x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3558,13 +3594,13 @@
"runs": 3,
"reference": {
"minMs": 0.5400000000008731,
- "maxMs": 0.569999999996071,
- "ratio": 1.055555555546573
+ "maxMs": 0.5799999999944703,
+ "ratio": 1.074074074062097
},
"competitor": {
- "minMs": 32.400000000001455,
- "maxMs": 33.219999999999345,
- "ratio": 1.0253086419752424
+ "minMs": 32.51000000000022,
+ "maxMs": 32.90000000000873,
+ "ratio": 1.0119963088283146
},
"stable": true,
"rungs": [
@@ -3576,19 +3612,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.5400000000008731,
- "referenceP95Ms": 0.9000000000014552,
+ "referenceMs": 0.569999999999709,
+ "referenceP95Ms": 0.9400000000023283,
"referenceGpuMs": 16.679999999993015,
"referenceOverFrameBudget": false,
- "competitorMs": 18.089999999996508,
- "competitorP95Ms": 21.760000000002037,
- "competitorGpuMs": 18.860000000000582,
+ "competitorMs": 17.169999999998254,
+ "competitorP95Ms": 21.87999999999738,
+ "competitorGpuMs": 17.839999999996508,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.029850746268710746,
- "factor": 33.49999999993936,
- "label": "ExoJS leads clearly (33.50x)",
+ "ratio": 0.03319743739078433,
+ "factor": 30.122807017556173,
+ "label": "ExoJS leads clearly (30.12x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3597,13 +3633,13 @@
"runs": 3,
"reference": {
"minMs": 0.5400000000008731,
- "maxMs": 0.569999999996071,
- "ratio": 1.055555555546573
+ "maxMs": 0.5799999999944703,
+ "ratio": 1.074074074062097
},
"competitor": {
- "minMs": 16.589999999996508,
- "maxMs": 18.36000000000422,
- "ratio": 1.106690777577341
+ "minMs": 16.56999999999971,
+ "maxMs": 17.5,
+ "ratio": 1.0561255280627826
},
"stable": true,
"rungs": [
@@ -3674,19 +3710,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.2799999999999727,
- "referenceP95Ms": 0.6000000000000227,
- "referenceGpuMs": 0.072354,
+ "referenceMs": 0.2999999999999545,
+ "referenceP95Ms": 0.5799999999999272,
+ "referenceGpuMs": 0.072688,
"referenceOverFrameBudget": false,
- "competitorMs": 0.3000000000000682,
- "competitorP95Ms": 0.5799999999999272,
- "competitorGpuMs": 0.072292,
+ "competitorMs": 0.2999999999999545,
+ "competitorP95Ms": 0.5800000000000409,
+ "competitorGpuMs": 0.07325,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9333333333330301,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3694,19 +3730,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2600000000002183,
- "maxMs": 0.3100000000000591,
- "ratio": 1.1923076923069187
+ "minMs": 0.2599999999998772,
+ "maxMs": 0.32000000000010687,
+ "ratio": 1.230769230770223
},
"competitor": {
- "minMs": 0.2999999999999545,
- "maxMs": 0.3000000000001819,
- "ratio": 1.0000000000007578
+ "minMs": 0.27999999999985903,
+ "maxMs": 0.4600000000000364,
+ "ratio": 1.6428571428580998
},
- "stable": true,
+ "stable": false,
"rungs": [
"level",
- "level",
+ "exojs-leads",
"level"
]
}
@@ -3723,13 +3759,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.1999999999998181,
+ "referenceMs": 0.20000000000004547,
"referenceP95Ms": 0.36000000000012733,
- "referenceGpuMs": 0.206208,
+ "referenceGpuMs": 0.2054165,
"referenceOverFrameBudget": false,
- "competitorMs": 0.25999999999976353,
- "competitorP95Ms": 0.4399999999995998,
- "competitorGpuMs": 0.190458,
+ "competitorMs": 0.23999999999978172,
+ "competitorP95Ms": 0.4600000000000364,
+ "competitorGpuMs": 0.18993749999999998,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -3743,14 +3779,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.18000000000029104,
- "maxMs": 0.20000000000027285,
- "ratio": 1.1111111111108305
+ "minMs": 0.14000000000032742,
+ "maxMs": 0.21000000000003638,
+ "ratio": 1.4999999999967517
},
"competitor": {
- "minMs": 0.23999999999978172,
- "maxMs": 0.2600000000002183,
- "ratio": 1.0833333333352282
+ "minMs": 0.19000000000005457,
+ "maxMs": 0.2800000000002001,
+ "ratio": 1.4736842105269456
},
"stable": false,
"rungs": [
@@ -3772,19 +3808,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.13999999999941792,
- "referenceP95Ms": 0.22000000000025466,
- "referenceGpuMs": 0.4222295,
+ "referenceMs": 0.15000000000009095,
+ "referenceP95Ms": 0.3000000000001819,
+ "referenceGpuMs": 0.429021,
"referenceOverFrameBudget": false,
- "competitorMs": 0.0999999999994543,
- "competitorP95Ms": 0.6000000000003638,
- "competitorGpuMs": 0.2353335,
+ "competitorMs": 0.13000000000010914,
+ "competitorP95Ms": 0.5,
+ "competitorGpuMs": 0.274937,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "competitor",
- "ratio": 1.400000000001819,
- "factor": 1.400000000001819,
- "label": "competitor leads (1.40x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3792,20 +3828,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.1299999999996544,
- "maxMs": 0.14000000000032742,
- "ratio": 1.0769230769284586
+ "minMs": 0.05999999999994543,
+ "maxMs": 0.15999999999985448,
+ "ratio": 2.6666666666666665
},
"competitor": {
"minMs": 0.09000000000014552,
- "maxMs": 0.10000000000081855,
- "ratio": 1.1111111111184095
+ "maxMs": 0.3599999999996726,
+ "ratio": 3.9999999999898943
},
- "stable": true,
+ "stable": false,
"rungs": [
"competitor-leads",
- "competitor-leads",
- "competitor-leads"
+ "exojs-leads",
+ "exojs-leads"
]
}
}
@@ -3821,19 +3857,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 1.8400000000001455,
- "referenceP95Ms": 2.399999999999636,
- "referenceGpuMs": 0.20729150000000002,
+ "referenceMs": 1.8900000000003274,
+ "referenceP95Ms": 2.4600000000000364,
+ "referenceGpuMs": 0.2075835,
"referenceOverFrameBudget": false,
- "competitorMs": 1.3800000000001091,
- "competitorP95Ms": 2.0600000000004,
- "competitorGpuMs": 0.19085449999999998,
+ "competitorMs": 1.300000000000182,
+ "competitorP95Ms": 1.8400000000001455,
+ "competitorGpuMs": 0.1915835,
"competitorOverFrameBudget": false,
- "verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "verdict": {
+ "side": "competitor",
+ "ratio": 1.4538461538462022,
+ "factor": 1.4538461538462022,
+ "label": "competitor leads (1.45x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/2 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3841,20 +3877,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.4200000000000728,
- "maxMs": 1.9299999999998363,
- "ratio": 1.3591549295772798
+ "minMs": 1.8599999999996726,
+ "maxMs": 1.900000000000091,
+ "ratio": 1.0215053763443147
},
"competitor": {
- "minMs": 1.2400000000006912,
- "maxMs": 1.5700000000001637,
- "ratio": 1.2661290322574907
+ "minMs": 1.0899999999996908,
+ "maxMs": 1.4200000000000728,
+ "ratio": 1.302752293578418
},
- "stable": false,
+ "stable": true,
"rungs": [
"competitor-leads",
"competitor-leads",
- "level"
+ "competitor-leads"
]
}
}
@@ -3870,19 +3906,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 1.6900000000000546,
- "referenceP95Ms": 2.2600000000002183,
- "referenceGpuMs": 0.0739165,
+ "referenceMs": 1.7199999999993452,
+ "referenceP95Ms": 2.199999999999818,
+ "referenceGpuMs": 0.073708,
"referenceOverFrameBudget": false,
- "competitorMs": 1.0799999999999272,
- "competitorP95Ms": 1.360000000000582,
- "competitorGpuMs": 0.07185449999999999,
+ "competitorMs": 0.9799999999995634,
+ "competitorP95Ms": 1.319999999999709,
+ "competitorGpuMs": 0.0729795,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "competitor",
+ "ratio": 1.7551020408164402,
+ "factor": 1.7551020408164402,
+ "label": "competitor leads (1.76x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/1 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3890,20 +3926,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.8899999999998727,
- "maxMs": 1.7399999999997817,
- "ratio": 1.9550561797753154
+ "minMs": 1.7100000000000364,
+ "maxMs": 1.7499999999995453,
+ "ratio": 1.0233918128652093
},
"competitor": {
- "minMs": 0.9699999999997999,
- "maxMs": 1.0899999999996908,
- "ratio": 1.1237113402060985
+ "minMs": 0.9399999999995998,
+ "maxMs": 1.2300000000000182,
+ "ratio": 1.3085106382984488
},
- "stable": false,
+ "stable": true,
"rungs": [
"competitor-leads",
"competitor-leads",
- "level"
+ "competitor-leads"
]
}
}
@@ -3919,19 +3955,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 4.1200000000008,
- "referenceP95Ms": 5.139999999999418,
- "referenceGpuMs": 0.21029150000000002,
+ "referenceMs": 4.220000000001164,
+ "referenceP95Ms": 10.44000000000051,
+ "referenceGpuMs": 0.211333,
"referenceOverFrameBudget": false,
- "competitorMs": 2.7200000000002547,
- "competitorP95Ms": 10.979999999999563,
- "competitorGpuMs": 0.193062,
+ "competitorMs": 2.7600000000002183,
+ "competitorP95Ms": 9.219999999999345,
+ "competitorGpuMs": 0.1934165,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.5147058823530937,
- "factor": 1.5147058823530937,
- "label": "competitor leads (1.51x)",
+ "ratio": 1.5289855072466776,
+ "factor": 1.5289855072466776,
+ "label": "competitor leads (1.53x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/1 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3939,14 +3975,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.780000000000655,
- "maxMs": 4.199999999999818,
- "ratio": 1.1111111111108705
+ "minMs": 3.7399999999997817,
+ "maxMs": 4.400000000000546,
+ "ratio": 1.1764705882355087
},
"competitor": {
- "minMs": 2.599999999998545,
- "maxMs": 2.730000000000473,
- "ratio": 1.0500000000007697
+ "minMs": 2.7100000000000364,
+ "maxMs": 2.780000000000655,
+ "ratio": 1.025830258302811
},
"stable": true,
"rungs": [
@@ -3968,19 +4004,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 37.26000000000022,
- "referenceP95Ms": 41.220000000001164,
- "referenceGpuMs": 0.9720415,
+ "referenceMs": 38.039999999999964,
+ "referenceP95Ms": 41.659999999999854,
+ "referenceGpuMs": 0.970521,
"referenceOverFrameBudget": true,
- "competitorMs": 28.49000000000069,
- "competitorP95Ms": 32.039999999999054,
- "competitorGpuMs": 0.550104,
+ "competitorMs": 28.61999999999898,
+ "competitorP95Ms": 31.81999999999971,
+ "competitorGpuMs": 0.7028755,
"competitorOverFrameBudget": true,
"verdict": {
"side": "competitor",
- "ratio": 1.3078273078272837,
- "factor": 1.3078273078272837,
- "label": "competitor leads (1.31x)",
+ "ratio": 1.329140461215979,
+ "factor": 1.329140461215979,
+ "label": "competitor leads (1.33x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/1 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3988,14 +4024,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 37.100000000000364,
- "maxMs": 37.44999999999982,
- "ratio": 1.0094339622641362
+ "minMs": 37,
+ "maxMs": 39.590000000000146,
+ "ratio": 1.0700000000000038
},
"competitor": {
- "minMs": 28.18000000000029,
- "maxMs": 28.51000000000022,
- "ratio": 1.0117104329311541
+ "minMs": 28.220000000000255,
+ "maxMs": 28.789999999999964,
+ "ratio": 1.0201984408221014
},
"stable": true,
"rungs": [
@@ -4017,19 +4053,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.5200000000004366,
- "referenceP95Ms": 0.7200000000011642,
- "referenceGpuMs": 0.2291455,
+ "referenceMs": 0.47000000000025466,
+ "referenceP95Ms": 0.6599999999998545,
+ "referenceGpuMs": 0.13700050000000003,
"referenceOverFrameBudget": false,
"competitorMs": 0.5,
- "competitorP95Ms": 0.8000000000010914,
- "competitorGpuMs": 0.21816649999999999,
+ "competitorP95Ms": 0.7400000000016007,
+ "competitorGpuMs": 0.1317705,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.0400000000008731,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/1 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4037,19 +4073,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5,
- "maxMs": 0.5600000000004002,
- "ratio": 1.1200000000008004
+ "minMs": 0.42000000000007276,
+ "maxMs": 0.47999999999956344,
+ "ratio": 1.1428571428559053
},
"competitor": {
- "minMs": 0.5,
- "maxMs": 0.5399999999999636,
- "ratio": 1.0799999999999272
+ "minMs": 0.4400000000005093,
+ "maxMs": 0.7399999999997817,
+ "ratio": 1.681818181815739
},
- "stable": true,
+ "stable": false,
"rungs": [
"level",
- "level",
+ "exojs-leads",
"level"
]
}
@@ -4066,19 +4102,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 2.819999999999709,
- "referenceP95Ms": 6.779999999998836,
- "referenceGpuMs": 0.1425,
+ "referenceMs": 2.680000000000291,
+ "referenceP95Ms": 6.479999999999563,
+ "referenceGpuMs": 0.142021,
"referenceOverFrameBudget": false,
- "competitorMs": 2.459999999999127,
- "competitorP95Ms": 8.720000000001164,
- "competitorGpuMs": 0.157458,
+ "competitorMs": 2.5799999999981083,
+ "competitorP95Ms": 7.440000000002328,
+ "competitorGpuMs": 0.1590205,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 1.038759689923355,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "competitor issues fewer buffer uploads (13 vs 3 per frame)",
@@ -4086,19 +4122,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.680000000000291,
- "maxMs": 3.0600000000013097,
- "ratio": 1.141791044776484
+ "minMs": 2.5099999999983993,
+ "maxMs": 2.7300000000013824,
+ "ratio": 1.0876494023916827
},
"competitor": {
- "minMs": 2.430000000000291,
- "maxMs": 2.5199999999986176,
- "ratio": 1.037037037036344
+ "minMs": 2.539999999999054,
+ "maxMs": 2.5899999999983265,
+ "ratio": 1.0196850393697996
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
- "competitor-leads",
+ "level",
"level"
]
}
@@ -4120,19 +4156,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.15999999999985448,
- "referenceP95Ms": 0.27999999999883585,
- "referenceGpuMs": 0.5884795,
+ "referenceMs": 0.13999999999941792,
+ "referenceP95Ms": 0.23999999999978172,
+ "referenceGpuMs": 0.589167,
"referenceOverFrameBudget": false,
"competitorMs": 0.2000000000007276,
- "competitorP95Ms": 0.37999999999919964,
- "competitorGpuMs": 0.7117709999999999,
+ "competitorP95Ms": 0.3999999999996362,
+ "competitorGpuMs": 0.6553745,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "exojs",
+ "ratio": 0.699999999994543,
+ "factor": 1.4285714285825653,
+ "label": "ExoJS leads (1.43x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4140,20 +4176,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.1400000000012369,
- "maxMs": 0.18999999999959982,
- "ratio": 1.3571428571280082
+ "minMs": 0.1000000000003638,
+ "maxMs": 0.1400000000012369,
+ "ratio": 1.4000000000072759
},
"competitor": {
- "minMs": 0.2000000000007276,
- "maxMs": 0.21999999999934516,
- "ratio": 1.0999999999927241
+ "minMs": 0.15999999999985448,
+ "maxMs": 0.38000000000101863,
+ "ratio": 2.3750000000085265
},
- "stable": false,
+ "stable": true,
"rungs": [
"exojs-leads",
"exojs-leads",
- "level"
+ "exojs-leads"
]
}
}
@@ -4169,19 +4205,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.819999999999709,
- "referenceP95Ms": 1.5800000000017462,
- "referenceGpuMs": 0.220604,
+ "referenceMs": 0.570000000001528,
+ "referenceP95Ms": 1,
+ "referenceGpuMs": 0.22197899999999998,
"referenceOverFrameBudget": false,
- "competitorMs": 0.6599999999998545,
- "competitorP95Ms": 1.0400000000008731,
- "competitorGpuMs": 0.076938,
+ "competitorMs": 0.7600000000011278,
+ "competitorP95Ms": 1.0799999999999272,
+ "competitorGpuMs": 0.1250205,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "exojs",
+ "ratio": 0.7500000000008975,
+ "factor": 1.3333333333317379,
+ "label": "ExoJS leads (1.33x)",
"structural": false
},
"mechanism": "competitor issues fewer texture binds (626 vs 314 per frame)",
@@ -4189,20 +4225,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5300000000006548,
- "maxMs": 0.9799999999995634,
- "ratio": 1.8490566037704765
+ "minMs": 0.5400000000008731,
+ "maxMs": 0.5799999999999272,
+ "ratio": 1.0740740740722028
},
"competitor": {
- "minMs": 0.6599999999998545,
- "maxMs": 0.7000000000007276,
- "ratio": 1.0606060606073968
+ "minMs": 0.7399999999979627,
+ "maxMs": 0.7999999999992724,
+ "ratio": 1.0810810810830742
},
- "stable": false,
+ "stable": true,
"rungs": [
- "level",
- "level",
- "competitor-leads"
+ "exojs-leads",
+ "exojs-leads",
+ "exojs-leads"
]
}
}
@@ -4219,18 +4255,18 @@
{
"competitor": "pixi",
"referenceMs": 0.42000000000189175,
- "referenceP95Ms": 0.5400000000008731,
- "referenceGpuMs": 0.1192915,
+ "referenceP95Ms": 0.5199999999967986,
+ "referenceGpuMs": 0.11856249999999999,
"referenceOverFrameBudget": false,
- "competitorMs": 0.5600000000013097,
- "competitorP95Ms": 0.7799999999988358,
- "competitorGpuMs": 0.1186245,
+ "competitorMs": 0.5499999999992724,
+ "competitorP95Ms": 0.7600000000020373,
+ "competitorGpuMs": 0.119646,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.7500000000016241,
- "factor": 1.333333333330446,
- "label": "ExoJS leads (1.33x)",
+ "ratio": 0.7636363636408134,
+ "factor": 1.3095238095161787,
+ "label": "ExoJS leads (1.31x)",
"structural": false
},
"mechanism": "competitor issues fewer texture binds (240 vs 159 per frame)",
@@ -4238,14 +4274,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.38999999999759893,
- "maxMs": 0.43000000000029104,
- "ratio": 1.1025641025716368
+ "minMs": 0.41999999999825377,
+ "maxMs": 0.42000000000189175,
+ "ratio": 1.000000000008662
},
"competitor": {
"minMs": 0.5400000000008731,
- "maxMs": 0.569999999999709,
- "ratio": 1.0555555555533098
+ "maxMs": 0.7200000000011642,
+ "ratio": 1.3333333333333333
},
"stable": true,
"rungs": [
@@ -4272,18 +4308,18 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.12000000000080036,
- "referenceP95Ms": 0.22000000000116415,
- "referenceGpuMs": 0.1255835,
+ "referenceMs": 0.11999999999898137,
+ "referenceP95Ms": 0.2000000000007276,
+ "referenceGpuMs": 0.12593749999999998,
"referenceOverFrameBudget": false,
"competitorMs": 0.18000000000029104,
- "competitorP95Ms": 0.31999999999970896,
- "competitorGpuMs": 0.11510400000000001,
+ "competitorP95Ms": 0.3600000000005821,
+ "competitorGpuMs": 0.1145,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.6666666666700352,
- "factor": 1.499999999992421,
+ "ratio": 0.6666666666599297,
+ "factor": 1.5000000000151583,
"label": "ExoJS leads (1.50x)",
"structural": false
},
@@ -4293,13 +4329,13 @@
"runs": 3,
"reference": {
"minMs": 0.11999999999898137,
- "maxMs": 0.12000000000261934,
- "ratio": 1.0000000000303164
+ "maxMs": 0.11999999999898137,
+ "ratio": 1
},
"competitor": {
"minMs": 0.15999999999985448,
- "maxMs": 0.2000000000007276,
- "ratio": 1.2500000000056843
+ "maxMs": 0.3999999999978172,
+ "ratio": 2.4999999999886313
},
"stable": true,
"rungs": [
@@ -4327,18 +4363,18 @@
{
"competitor": "pixi",
"referenceMs": 0.18000000000029104,
- "referenceP95Ms": 0.3600000000005821,
- "referenceGpuMs": 0.650812,
+ "referenceP95Ms": 0.2999999999992724,
+ "referenceGpuMs": 1.414479,
"referenceOverFrameBudget": false,
- "competitorMs": 0.19000000000050932,
+ "competitorMs": 0.18000000000029104,
"competitorP95Ms": 0.31999999999970896,
- "competitorGpuMs": 0.246,
+ "competitorGpuMs": 0.2457295,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9473684210516238,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4346,19 +4382,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.18000000000029104,
- "maxMs": 0.18000000000029104,
- "ratio": 1
+ "minMs": 0.13999999999941792,
+ "maxMs": 0.19999999999708962,
+ "ratio": 1.4285714285565796
},
"competitor": {
- "minMs": 0.18000000000029104,
- "maxMs": 0.2000000000007276,
- "ratio": 1.1111111111133567
+ "minMs": 0.17000000000007276,
+ "maxMs": 0.37999999999738066,
+ "ratio": 2.235294117630694
},
- "stable": true,
+ "stable": false,
"rungs": [
"level",
- "level",
+ "exojs-leads",
"level"
]
}
@@ -4375,13 +4411,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.15999999999985448,
- "referenceP95Ms": 0.2599999999983993,
- "referenceGpuMs": 3.5047085,
+ "referenceMs": 0.1500000000014552,
+ "referenceP95Ms": 0.27999999999883585,
+ "referenceGpuMs": 3.4957295000000004,
"referenceOverFrameBudget": false,
"competitorMs": 0.18000000000029104,
"competitorP95Ms": 0.3400000000001455,
- "competitorGpuMs": 0.371521,
+ "competitorGpuMs": 0.366375,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -4395,20 +4431,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.13999999999941792,
- "maxMs": 0.18000000000029104,
- "ratio": 1.28571428572171
+ "minMs": 0.11000000000058208,
+ "maxMs": 0.15999999999985448,
+ "ratio": 1.4545454545364347
},
"competitor": {
- "minMs": 0.18000000000029104,
- "maxMs": 0.18000000000029104,
- "ratio": 1
+ "minMs": 0.13999999999941792,
+ "maxMs": 0.3400000000001455,
+ "ratio": 2.4285714285825653
},
"stable": false,
"rungs": [
"level",
"exojs-leads",
- "level"
+ "exojs-leads"
]
}
}
@@ -4424,19 +4460,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 2.6700000000000728,
- "referenceP95Ms": 7.540000000000873,
- "referenceGpuMs": 1.4847085,
+ "referenceMs": 2.7000000000007276,
+ "referenceP95Ms": 7.3400000000001455,
+ "referenceGpuMs": 1.49175,
"referenceOverFrameBudget": false,
- "competitorMs": 4.5,
- "competitorP95Ms": 5.779999999998836,
- "competitorGpuMs": 0.291625,
+ "competitorMs": 4.319999999999709,
+ "competitorP95Ms": 5.919999999998254,
+ "competitorGpuMs": 0.29112499999999997,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5933333333333495,
- "factor": 1.6853932584269204,
- "label": "ExoJS leads (1.69x)",
+ "ratio": 0.6250000000002105,
+ "factor": 1.5999999999994612,
+ "label": "ExoJS leads (1.60x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/3 vs 1/2/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4444,14 +4480,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.600000000000364,
- "maxMs": 3.399999999997817,
- "ratio": 1.3076923076912852
+ "minMs": 2.6700000000000728,
+ "maxMs": 3.1300000000010186,
+ "ratio": 1.172284644195106
},
"competitor": {
- "minMs": 4.430000000000291,
- "maxMs": 4.699999999998909,
- "ratio": 1.0609480812637924
+ "minMs": 4.249999999998181,
+ "maxMs": 4.700000000000728,
+ "ratio": 1.105882352941821
},
"stable": true,
"rungs": [
@@ -4473,19 +4509,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 7.899999999999636,
- "referenceP95Ms": 9.639999999999418,
- "referenceGpuMs": 3.821021,
+ "referenceMs": 7.290000000000873,
+ "referenceP95Ms": 9.399999999997817,
+ "referenceGpuMs": 3.8783125,
"referenceOverFrameBudget": false,
- "competitorMs": 19.209999999997308,
- "competitorP95Ms": 22.739999999997963,
- "competitorGpuMs": 0.8035625,
+ "competitorMs": 19.57999999999811,
+ "competitorP95Ms": 24.42000000000189,
+ "competitorGpuMs": 0.800354,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.4112441436752079,
- "factor": 2.431645569620024,
- "label": "ExoJS leads (2.43x)",
+ "ratio": 0.3723186925434922,
+ "factor": 2.6858710562408454,
+ "label": "ExoJS leads (2.69x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/3 vs 1/2/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4493,14 +4529,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 7.249999999998181,
- "maxMs": 7.970000000001164,
- "ratio": 1.0993103448280226
+ "minMs": 7.240000000001601,
+ "maxMs": 8.089999999998327,
+ "ratio": 1.117403314916649
},
"competitor": {
- "minMs": 19.07999999999811,
- "maxMs": 19.670000000000073,
- "ratio": 1.030922431865934
+ "minMs": 19,
+ "maxMs": 19.7599999999984,
+ "ratio": 1.0399999999999157
},
"stable": true,
"rungs": [
@@ -4527,19 +4563,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.5600000000013097,
- "referenceP95Ms": 1.0600000000013097,
- "referenceGpuMs": 0.2069795,
+ "referenceMs": 0.5400000000008731,
+ "referenceP95Ms": 0.8000000000029104,
+ "referenceGpuMs": 0.223082,
"referenceOverFrameBudget": false,
- "competitorMs": 2.1599999999998545,
- "competitorP95Ms": 3.720000000001164,
- "competitorGpuMs": 0.28029200000000004,
+ "competitorMs": 1.8999999999996362,
+ "competitorP95Ms": 2.680000000000291,
+ "competitorGpuMs": 0.2800835,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.2592592592598831,
- "factor": 3.857142857133576,
- "label": "ExoJS leads (3.86x)",
+ "ratio": 0.28421052631630345,
+ "factor": 3.5185185185121557,
+ "label": "ExoJS leads (3.52x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/6/3 vs 2/4/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4547,14 +4583,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5500000000010914,
- "maxMs": 0.5800000000017462,
- "ratio": 1.054545454546537
+ "minMs": 0.41999999999825377,
+ "maxMs": 0.5400000000008731,
+ "ratio": 1.28571428572171
},
"competitor": {
- "minMs": 2.030000000000655,
- "maxMs": 2.4099999999980355,
- "ratio": 1.1871921182252503
+ "minMs": 1.8400000000001455,
+ "maxMs": 2.3799999999991996,
+ "ratio": 1.2934782608690278
},
"stable": true,
"rungs": [
@@ -4577,12 +4613,12 @@
{
"competitor": "pixi",
"referenceMs": 0.4400000000023283,
- "referenceP95Ms": 0.7000000000043656,
- "referenceGpuMs": 0.2582715,
+ "referenceP95Ms": 0.680000000000291,
+ "referenceGpuMs": 0.235958,
"referenceOverFrameBudget": false,
- "competitorMs": 2.290000000000873,
- "competitorP95Ms": 3.3399999999965075,
- "competitorGpuMs": 0.4509175,
+ "competitorMs": 2.1700000000018917,
+ "competitorP95Ms": 3.779999999998836,
+ "competitorGpuMs": 0.449771,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -4596,19 +4632,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.4099999999998545,
- "maxMs": 0.4599999999991269,
- "ratio": 1.1219512195104637
+ "minMs": 0.3600000000005821,
+ "maxMs": 0.4500000000007276,
+ "ratio": 1.25
},
"competitor": {
- "minMs": 1.9799999999995634,
- "maxMs": 2.2999999999992724,
- "ratio": 1.1616161616160503
+ "minMs": 2,
+ "maxMs": 2.400000000001455,
+ "ratio": 1.2000000000007276
},
"stable": false,
"rungs": [
"exojs-leads",
- "exojs-leads",
+ "exojs-leads-clearly",
"exojs-leads-clearly"
]
}
@@ -4625,13 +4661,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.4400000000023283,
- "referenceP95Ms": 0.680000000000291,
- "referenceGpuMs": 0.3397715,
+ "referenceMs": 0.42000000000189175,
+ "referenceP95Ms": 0.6200000000026193,
+ "referenceGpuMs": 0.30972900000000003,
"referenceOverFrameBudget": false,
- "competitorMs": 2.1600000000034925,
- "competitorP95Ms": 3.860000000000582,
- "competitorGpuMs": 0.7453745,
+ "competitorMs": 2.1699999999982538,
+ "competitorP95Ms": 3.720000000001164,
+ "competitorGpuMs": 0.8490215,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -4645,20 +4681,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.43999999999505235,
- "maxMs": 0.47999999999592546,
- "ratio": 1.0909090909120975
+ "minMs": 0.3600000000005821,
+ "maxMs": 0.4400000000023283,
+ "ratio": 1.2222222222267136
},
"competitor": {
- "minMs": 2.150000000005093,
- "maxMs": 2.319999999999709,
- "ratio": 1.079069767439169
+ "minMs": 1.9199999999982538,
+ "maxMs": 2.9099999999998545,
+ "ratio": 1.5156250000013027
},
"stable": false,
"rungs": [
"exojs-leads",
"exojs-leads-clearly",
- "exojs-leads"
+ "exojs-leads-clearly"
]
}
}
@@ -4674,19 +4710,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.4800000000032014,
- "referenceP95Ms": 0.7200000000011642,
- "referenceGpuMs": 0.316583,
+ "referenceMs": 0.4599999999991269,
+ "referenceP95Ms": 0.6999999999970896,
+ "referenceGpuMs": 0.3076675,
"referenceOverFrameBudget": false,
- "competitorMs": 0.7600000000020373,
- "competitorP95Ms": 1.0800000000017462,
- "competitorGpuMs": 0.4396245,
+ "competitorMs": 0.75,
+ "competitorP95Ms": 1.180000000000291,
+ "competitorGpuMs": 0.47770799999999997,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.6315789473709404,
- "factor": 1.5833333333270174,
- "label": "ExoJS leads (1.58x)",
+ "ratio": 0.6133333333321692,
+ "factor": 1.6304347826117902,
+ "label": "ExoJS leads (1.63x)",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (5 vs 8 per frame)",
@@ -4694,14 +4730,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.46000000000276486,
- "maxMs": 0.5099999999983993,
- "ratio": 1.1086956521637694
+ "minMs": 0.4500000000007276,
+ "maxMs": 0.5199999999967986,
+ "ratio": 1.1555555555465729
},
"competitor": {
- "minMs": 0.6599999999962165,
- "maxMs": 0.7999999999992724,
- "ratio": 1.2121212121270584
+ "minMs": 0.6999999999970896,
+ "maxMs": 1.3699999999989814,
+ "ratio": 1.957142857149539
},
"stable": true,
"rungs": [
@@ -4723,19 +4759,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.3400000000001455,
- "referenceP95Ms": 0.5400000000008731,
- "referenceGpuMs": 0.3265625,
+ "referenceMs": 0.3600000000005821,
+ "referenceP95Ms": 0.5200000000040745,
+ "referenceGpuMs": 0.3171875,
"referenceOverFrameBudget": false,
"competitorMs": 0.3000000000029104,
- "competitorP95Ms": 0.4800000000032014,
- "competitorGpuMs": 0.153188,
+ "competitorP95Ms": 0.5199999999967986,
+ "competitorGpuMs": 0.153042,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.1333333333228237,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (4 vs 10 per frame)",
@@ -4743,20 +4779,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.3100000000013097,
- "maxMs": 0.3600000000005821,
- "ratio": 1.1612903225776168
+ "minMs": 0.3000000000029104,
+ "maxMs": 0.3899999999994179,
+ "ratio": 1.2999999999854481
},
"competitor": {
- "minMs": 0.2900000000008731,
- "maxMs": 0.31999999999970896,
- "ratio": 1.103448275857743
+ "minMs": 0.2400000000016007,
+ "maxMs": 0.5200000000004366,
+ "ratio": 2.166666666654035
},
- "stable": true,
+ "stable": false,
"rungs": [
- "level",
- "level",
- "level"
+ "competitor-leads",
+ "exojs-leads",
+ "competitor-leads"
]
}
}
@@ -4772,19 +4808,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.3600000000005821,
+ "referenceMs": 0.3500000000021828,
"referenceP95Ms": 0.5,
- "referenceGpuMs": 0.32695799999999997,
+ "referenceGpuMs": 0.32100049999999997,
"referenceOverFrameBudget": false,
- "competitorMs": 0.41999999999825377,
- "competitorP95Ms": 0.6399999999994179,
- "competitorGpuMs": 0.15181250000000002,
+ "competitorMs": 0.4599999999991269,
+ "competitorP95Ms": 0.7599999999947613,
+ "competitorGpuMs": 0.121666,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.8571428571478068,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (4 vs 10 per frame)",
@@ -4792,19 +4828,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.3600000000005821,
- "maxMs": 0.37999999999738066,
- "ratio": 1.055555555546573
+ "minMs": 0.33999999999650754,
+ "maxMs": 0.3600000000005821,
+ "ratio": 1.0588235294243529
},
"competitor": {
- "minMs": 0.37999999999738066,
- "maxMs": 0.4500000000007276,
- "ratio": 1.1842105263258669
+ "minMs": 0.3400000000001455,
+ "maxMs": 0.6300000000010186,
+ "ratio": 1.8529411764727912
},
- "stable": true,
+ "stable": false,
"rungs": [
- "level",
- "level",
+ "exojs-leads",
+ "exojs-leads",
"level"
]
}
@@ -4826,13 +4862,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.2400000000016007,
+ "referenceMs": 0.23999999999978172,
"referenceP95Ms": 1.4600000000027649,
- "referenceGpuMs": 0.10002050000000001,
+ "referenceGpuMs": 0.101021,
"referenceOverFrameBudget": false,
- "competitorMs": 0.2000000000007276,
+ "competitorMs": 0.19999999999708962,
"competitorP95Ms": 0.3600000000005821,
- "competitorGpuMs": 0.0978125,
+ "competitorGpuMs": 0.097458,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -4842,24 +4878,24 @@
"structural": false
},
"mechanism": "competitor issues fewer draw calls (90 vs 1 per frame)",
- "timer": "resolved",
+ "timer": "limited",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.23999999999796273,
- "maxMs": 0.25,
- "ratio": 1.041666666675509
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.2400000000016007,
+ "ratio": 1.3333333333400703
},
"competitor": {
- "minMs": 0.2000000000007276,
- "maxMs": 0.2000000000007276,
- "ratio": 1
+ "minMs": 0.17000000000189175,
+ "maxMs": 0.36999999999898137,
+ "ratio": 2.1764705882050825
},
"stable": false,
"rungs": [
- "level",
"competitor-leads",
- "competitor-leads"
+ "exojs-leads",
+ "level"
]
}
}
@@ -4880,18 +4916,18 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.2599999999947613,
- "referenceP95Ms": 1.319999999999709,
- "referenceGpuMs": 0.06943750000000001,
+ "referenceMs": 0.2599999999983993,
+ "referenceP95Ms": 1.4799999999959255,
+ "referenceGpuMs": 0.067771,
"referenceOverFrameBudget": false,
"competitorMs": 0.41999999999825377,
- "competitorP95Ms": 0.7799999999988358,
- "competitorGpuMs": 0.077208,
+ "competitorP95Ms": 0.8399999999965075,
+ "competitorGpuMs": 0.076708,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.6190476190377198,
- "factor": 1.6153846154104472,
+ "ratio": 0.6190476190463816,
+ "factor": 1.6153846153878444,
"label": "ExoJS leads (1.62x)",
"structural": false
},
@@ -4900,14 +4936,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2400000000052387,
+ "minMs": 0.22000000000116415,
"maxMs": 0.26000000000203727,
- "ratio": 1.0833333333181752
+ "ratio": 1.1818181818211884
},
"competitor": {
- "minMs": 0.4099999999998545,
- "maxMs": 0.43000000000029104,
- "ratio": 1.0487804878059601
+ "minMs": 0.37999999999738066,
+ "maxMs": 0.6399999999994179,
+ "ratio": 1.6842105263258669
},
"stable": true,
"rungs": [
@@ -4929,34 +4965,34 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.22000000000116415,
- "referenceP95Ms": 0.8799999999973807,
- "referenceGpuMs": 0.06697900000000001,
+ "referenceMs": 0.20999999999912689,
+ "referenceP95Ms": 0.8400000000037835,
+ "referenceGpuMs": 0.06789600000000001,
"referenceOverFrameBudget": false,
- "competitorMs": 0.38000000000101863,
- "competitorP95Ms": 0.6200000000026193,
- "competitorGpuMs": 0.07572899999999999,
+ "competitorMs": 0.4400000000023283,
+ "competitorP95Ms": 0.6999999999970896,
+ "competitorGpuMs": 0.0767505,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5789473684225642,
- "factor": 1.7272727272682176,
- "label": "ExoJS leads (1.73x)",
+ "ratio": 0.4772727272682174,
+ "factor": 2.0952380952578937,
+ "label": "ExoJS leads (2.10x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (60 vs 2 per frame)",
- "timer": "limited",
+ "timer": "resolved",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.18999999999869033,
- "maxMs": 0.22000000000116415,
- "ratio": 1.1578947368562138
+ "minMs": 0.2000000000007276,
+ "maxMs": 0.22999999999956344,
+ "ratio": 1.1499999999936334
},
"competitor": {
- "minMs": 0.3600000000005821,
- "maxMs": 0.3999999999978172,
- "ratio": 1.1111111111032512
+ "minMs": 0.31999999999970896,
+ "maxMs": 0.48999999999796273,
+ "ratio": 1.5312499999950262
},
"stable": true,
"rungs": [
@@ -4978,19 +5014,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.7999999999992724,
- "referenceP95Ms": 1.2600000000020373,
- "referenceGpuMs": 0.067771,
+ "referenceMs": 0.6899999999986903,
+ "referenceP95Ms": 1.319999999999709,
+ "referenceGpuMs": 0.0669585,
"referenceOverFrameBudget": false,
- "competitorMs": 1.7799999999988358,
- "competitorP95Ms": 3.180000000000291,
- "competitorGpuMs": 0.06868750000000001,
+ "competitorMs": 2.3300000000017462,
+ "competitorP95Ms": 3.3800000000046566,
+ "competitorGpuMs": 0.069917,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.4494382022470762,
- "factor": 2.2250000000005685,
- "label": "ExoJS leads (2.23x)",
+ "ratio": 0.29613733905500994,
+ "factor": 3.376811594211839,
+ "label": "ExoJS leads (3.38x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 2/4/2 vs 2/4/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4998,14 +5034,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5999999999985448,
- "maxMs": 0.9400000000023283,
- "ratio": 1.566666666674347
+ "minMs": 0.6699999999982538,
+ "maxMs": 0.9099999999998545,
+ "ratio": 1.3582089552272034
},
"competitor": {
- "minMs": 1.5900000000001455,
- "maxMs": 1.8699999999953434,
- "ratio": 1.1761006289277813
+ "minMs": 1.7000000000007276,
+ "maxMs": 2.390000000003056,
+ "ratio": 1.4058823529423723
},
"stable": true,
"rungs": [
@@ -5032,19 +5068,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.27999999999883585,
- "referenceP95Ms": 0.4599999999991269,
- "referenceGpuMs": 0.070687,
+ "referenceMs": 0.2800000000024738,
+ "referenceP95Ms": 0.4400000000023283,
+ "referenceGpuMs": 0.07079150000000001,
"referenceOverFrameBudget": false,
"competitorMs": 0.26000000000203727,
- "competitorP95Ms": 0.43999999999505235,
- "competitorGpuMs": 0.069,
+ "competitorP95Ms": 0.5,
+ "competitorGpuMs": 0.0683335,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.076923076910161,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/2 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -5052,19 +5088,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.27999999999883585,
- "maxMs": 0.2999999999956344,
- "ratio": 1.0714285714174347
+ "minMs": 0.2599999999947613,
+ "maxMs": 0.3000000000029104,
+ "ratio": 1.1538461538805962
},
"competitor": {
- "minMs": 0.2599999999983993,
- "maxMs": 0.26000000000203727,
- "ratio": 1.0000000000139921
+ "minMs": 0.22999999999956344,
+ "maxMs": 0.4400000000023283,
+ "ratio": 1.9130434782746237
},
- "stable": true,
+ "stable": false,
"rungs": [
"level",
- "level",
+ "exojs-leads",
"level"
]
}
@@ -5081,19 +5117,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.46000000000640284,
- "referenceP95Ms": 0.6000000000058208,
- "referenceGpuMs": 0.1444375,
+ "referenceMs": 0.4599999999991269,
+ "referenceP95Ms": 0.5799999999944703,
+ "referenceGpuMs": 0.146333,
"referenceOverFrameBudget": false,
- "competitorMs": 0.22000000000116415,
- "competitorP95Ms": 0.43999999999505235,
- "competitorGpuMs": 0.232792,
+ "competitorMs": 0.23999999999796273,
+ "competitorP95Ms": 0.41999999999825377,
+ "competitorGpuMs": 0.232042,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "competitor",
- "ratio": 2.0909090909271306,
- "factor": 2.0909090909271306,
- "label": "competitor leads (2.09x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/2 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -5101,19 +5137,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.4599999999991269,
- "maxMs": 0.4900000000016007,
- "ratio": 1.0652173913098495
+ "minMs": 0.43999999999505235,
+ "maxMs": 0.47999999999592546,
+ "ratio": 1.0909090909120975
},
"competitor": {
"minMs": 0.22000000000116415,
- "maxMs": 0.23999999999796273,
- "ratio": 1.090909090894058
+ "maxMs": 0.4599999999991269,
+ "ratio": 2.090909090894058
},
- "stable": true,
+ "stable": false,
"rungs": [
"competitor-leads",
- "competitor-leads",
+ "level",
"competitor-leads"
]
}
@@ -5130,19 +5166,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 2.210000000002765,
- "referenceP95Ms": 2.680000000000291,
- "referenceGpuMs": 0.3617295,
+ "referenceMs": 2.109999999996944,
+ "referenceP95Ms": 2.5199999999967986,
+ "referenceGpuMs": 0.38845850000000004,
"referenceOverFrameBudget": false,
- "competitorMs": 0.27000000000043656,
- "competitorP95Ms": 0.41999999999825377,
- "competitorGpuMs": 0.25004149999999997,
+ "competitorMs": 0.26000000000203727,
+ "competitorP95Ms": 0.4000000000014552,
+ "competitorGpuMs": 0.261021,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 8.18518518518219,
- "factor": 8.18518518518219,
- "label": "competitor leads clearly (8.19x)",
+ "ratio": 8.115384615309273,
+ "factor": 8.115384615309273,
+ "label": "competitor leads clearly (8.12x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/2 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -5150,14 +5186,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.7800000000024738,
- "maxMs": 2.2299999999995634,
- "ratio": 1.2528089887620586
+ "minMs": 2.0200000000004366,
+ "maxMs": 2.179999999996653,
+ "ratio": 1.079207920790189
},
"competitor": {
- "minMs": 0.250000000003638,
- "maxMs": 0.2999999999956344,
- "ratio": 1.1999999999650754
+ "minMs": 0.20999999999912689,
+ "maxMs": 0.37999999999738066,
+ "ratio": 1.80952380951886
},
"stable": true,
"rungs": [
@@ -5179,19 +5215,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.6899999999986903,
- "referenceP95Ms": 0.8999999999941792,
- "referenceGpuMs": 0.2272915,
+ "referenceMs": 0.680000000000291,
+ "referenceP95Ms": 0.8600000000005821,
+ "referenceGpuMs": 0.22912500000000002,
"referenceOverFrameBudget": false,
- "competitorMs": 0.9200000000055297,
+ "competitorMs": 0.9200000000018917,
"competitorP95Ms": 1.180000000000291,
- "competitorGpuMs": 0.22462500000000002,
+ "competitorGpuMs": 0.138229,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.7499999999940685,
- "factor": 1.3333333333438782,
- "label": "ExoJS leads (1.33x)",
+ "ratio": 0.7391304347814052,
+ "factor": 1.3529411764727912,
+ "label": "ExoJS leads (1.35x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (90 vs 1 per frame)",
@@ -5199,14 +5235,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.680000000000291,
+ "minMs": 0.6600000000034925,
"maxMs": 0.6999999999970896,
- "ratio": 1.0294117647011618
+ "ratio": 1.0606060605960386
},
"competitor": {
- "minMs": 0.9200000000055297,
- "maxMs": 0.9800000000032014,
- "ratio": 1.0652173913014251
+ "minMs": 0.9199999999982538,
+ "maxMs": 1.0799999999981083,
+ "ratio": 1.1739130434784328
},
"stable": true,
"rungs": [
@@ -5233,19 +5269,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.6399999999994179,
- "referenceP95Ms": 0.9799999999959255,
- "referenceGpuMs": 0.3017085,
+ "referenceMs": 0.6100000000005821,
+ "referenceP95Ms": 0.8600000000005821,
+ "referenceGpuMs": 0.30239649999999996,
"referenceOverFrameBudget": false,
- "competitorMs": 16.350000000002183,
- "competitorP95Ms": 20.099999999998545,
- "competitorGpuMs": 0.29231300000000005,
+ "competitorMs": 16.660000000003492,
+ "competitorP95Ms": 21,
+ "competitorGpuMs": 0.294688,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.03914373088680933,
- "factor": 25.546875000026642,
- "label": "ExoJS leads clearly (25.55x)",
+ "ratio": 0.0366146458583706,
+ "factor": 27.31147540981573,
+ "label": "ExoJS leads clearly (27.31x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -5253,14 +5289,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5999999999985448,
- "maxMs": 0.6599999999962165,
- "ratio": 1.099999999996362
+ "minMs": 0.5,
+ "maxMs": 0.6200000000026193,
+ "ratio": 1.2400000000052387
},
"competitor": {
- "minMs": 16.029999999998836,
- "maxMs": 16.429999999996653,
- "ratio": 1.0249532127260041
+ "minMs": 16.280000000002474,
+ "maxMs": 17.74000000000524,
+ "ratio": 1.089680589680746
},
"stable": true,
"rungs": [
@@ -5353,7 +5389,7 @@
"nape-js arm (pure-JS peer): default single-step solver with default velocity/position iterations (10/10), sleeping and dynamic AABB broadphase at library defaults. Materials, body layouts, joints and perturbations come from the shared neutral scene descriptor. Contact count = active collision arbiters; ray queries use Space.rayCast with outer-surface semantics. These counters are engine-specific structural proxies, not a claim that every solver performs identical internal work."
],
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:16:07.435Z"
+ "timestamp": "2026-09-12T03:21:55.258Z"
},
{
"browser": "webkit",
@@ -5393,7 +5429,7 @@
"nape-js arm (pure-JS peer): default single-step solver with default velocity/position iterations (10/10), sleeping and dynamic AABB broadphase at library defaults. Materials, body layouts, joints and perturbations come from the shared neutral scene descriptor. Contact count = active collision arbiters; ray queries use Space.rayCast with outer-surface semantics. These counters are engine-specific structural proxies, not a claim that every solver performs identical internal work."
],
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:28:32.450Z"
+ "timestamp": "2026-09-12T03:34:01.941Z"
},
{
"browser": "webkit",
@@ -5433,7 +5469,7 @@
"nape-js arm (pure-JS peer): default single-step solver with default velocity/position iterations (10/10), sleeping and dynamic AABB broadphase at library defaults. Materials, body layouts, joints and perturbations come from the shared neutral scene descriptor. Contact count = active collision arbiters; ray queries use Space.rayCast with outer-surface semantics. These counters are engine-specific structural proxies, not a claim that every solver performs identical internal work."
],
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T02:40:41.625Z"
+ "timestamp": "2026-09-12T03:46:13.242Z"
}
],
"libraries": [
@@ -5471,19 +5507,19 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.480000000000018,
- "referenceP95Ms": 5.919999999999845,
+ "referenceMs": 5.139999999999873,
+ "referenceP95Ms": 6.019999999999982,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 10.339999999998327,
- "competitorP95Ms": 12.059999999997672,
+ "competitorMs": 11.139999999999418,
+ "competitorP95Ms": 12.099999999998545,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5299806576403197,
- "factor": 1.8868613138683015,
- "label": "ExoJS leads (1.89x)",
+ "ratio": 0.46140035906643995,
+ "factor": 2.1673151750972166,
+ "label": "ExoJS leads (2.17x)",
"structural": false
},
"mechanism": "ExoJS resolves fewer solved contacts (5501 vs 12297); the counters are not semantically identical across arms (see the run's caveats)",
@@ -5491,14 +5527,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.379999999999654,
- "maxMs": 5.5,
- "ratio": 1.0223048327138202
+ "minMs": 5.059999999999945,
+ "maxMs": 5.400000000000091,
+ "ratio": 1.0671936758893577
},
"competitor": {
- "minMs": 10.30000000000291,
- "maxMs": 10.399999999997817,
- "ratio": 1.0097087378635805
+ "minMs": 10.380000000001019,
+ "maxMs": 11.200000000000728,
+ "ratio": 1.0789980732176907
},
"stable": true,
"rungs": [
@@ -5510,19 +5546,19 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.480000000000018,
- "referenceP95Ms": 5.919999999999845,
+ "referenceMs": 5.139999999999873,
+ "referenceP95Ms": 6.019999999999982,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 10.020000000004075,
- "competitorP95Ms": 13.440000000002328,
+ "competitorMs": 9.639999999999418,
+ "competitorP95Ms": 12.660000000003492,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5469061876245299,
- "factor": 1.828467153285409,
- "label": "ExoJS leads (1.83x)",
+ "ratio": 0.533195020746907,
+ "factor": 1.8754863813228904,
+ "label": "ExoJS leads (1.88x)",
"structural": false
},
"mechanism": "identical scene (5501 bodies, 5501 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5530,14 +5566,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.379999999999654,
- "maxMs": 5.5,
- "ratio": 1.0223048327138202
+ "minMs": 5.059999999999945,
+ "maxMs": 5.400000000000091,
+ "ratio": 1.0671936758893577
},
"competitor": {
- "minMs": 9.610000000000582,
- "maxMs": 10.029999999998836,
- "ratio": 1.0437044745055388
+ "minMs": 9.540000000008149,
+ "maxMs": 10.020000000004075,
+ "ratio": 1.050314465408335
},
"stable": true,
"rungs": [
@@ -5549,19 +5585,19 @@
},
{
"competitor": "planck",
- "referenceMs": 5.480000000000018,
- "referenceP95Ms": 5.919999999999845,
+ "referenceMs": 5.139999999999873,
+ "referenceP95Ms": 6.019999999999982,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 29.979999999999563,
- "competitorP95Ms": 36.36000000000058,
+ "competitorMs": 29.5099999999984,
+ "competitorP95Ms": 36.61999999999534,
"competitorGpuMs": null,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.18278852568379247,
- "factor": 5.470802919707931,
- "label": "ExoJS leads clearly (5.47x)",
+ "ratio": 0.1741782446628313,
+ "factor": 5.741245136186601,
+ "label": "ExoJS leads clearly (5.74x)",
"structural": true
},
"mechanism": "ExoJS resolves fewer solved contacts (5501 vs 10677); the counters are not semantically identical across arms (see the run's caveats)",
@@ -5569,14 +5605,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.379999999999654,
- "maxMs": 5.5,
- "ratio": 1.0223048327138202
+ "minMs": 5.059999999999945,
+ "maxMs": 5.400000000000091,
+ "ratio": 1.0671936758893577
},
"competitor": {
- "minMs": 29.43000000000029,
- "maxMs": 30.4800000000032,
- "ratio": 1.0356778797146755
+ "minMs": 29.479999999999563,
+ "maxMs": 30.360000000000582,
+ "ratio": 1.0298507462686917
},
"stable": true,
"rungs": [
@@ -5588,19 +5624,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.480000000000018,
- "referenceP95Ms": 5.919999999999845,
+ "referenceMs": 5.139999999999873,
+ "referenceP95Ms": 6.019999999999982,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 4.060000000004948,
- "competitorP95Ms": 5.740000000005239,
+ "competitorMs": 4.290000000000873,
+ "competitorP95Ms": 5.360000000000582,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "competitor",
- "ratio": 1.3497536945796405,
- "factor": 1.3497536945796405,
- "label": "competitor leads (1.35x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "ExoJS resolves fewer solved contacts (5501 vs 10045); the counters are not semantically identical across arms (see the run's caveats)",
@@ -5608,19 +5644,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.379999999999654,
- "maxMs": 5.5,
- "ratio": 1.0223048327138202
+ "minMs": 5.059999999999945,
+ "maxMs": 5.400000000000091,
+ "ratio": 1.0671936758893577
},
"competitor": {
- "minMs": 4.060000000004948,
- "maxMs": 4.260000000002037,
- "ratio": 1.0492610837430656
+ "minMs": 4.05000000000291,
+ "maxMs": 4.310000000004948,
+ "ratio": 1.0641975308646545
},
- "stable": true,
+ "stable": false,
"rungs": [
- "competitor-leads",
- "competitor-leads",
+ "level",
+ "level",
"competitor-leads"
]
}
@@ -5637,17 +5673,17 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.420000000000073,
- "referenceP95Ms": 6.480000000000018,
+ "referenceMs": 5.440000000000509,
+ "referenceP95Ms": 6.460000000000036,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.3400000000001455,
- "competitorP95Ms": 6.080000000001746,
+ "competitorMs": 5.240000000001601,
+ "competitorP95Ms": 5.979999999999563,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.0149812734082257,
+ "ratio": 1.0381679389310778,
"factor": 1,
"label": "level",
"structural": false
@@ -5657,14 +5693,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.3400000000001455,
- "maxMs": 5.5600000000004,
- "ratio": 1.0411985018727057
+ "minMs": 5.380000000000109,
+ "maxMs": 5.479999999999563,
+ "ratio": 1.0185873605946938
},
"competitor": {
- "minMs": 5.279999999998836,
- "maxMs": 5.559999999999491,
- "ratio": 1.0530303030304387
+ "minMs": 5.220000000001164,
+ "maxMs": 5.299999999999272,
+ "ratio": 1.0153256704977185
},
"stable": true,
"rungs": [
@@ -5676,17 +5712,17 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.420000000000073,
- "referenceP95Ms": 6.480000000000018,
+ "referenceMs": 5.440000000000509,
+ "referenceP95Ms": 6.460000000000036,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.80000000000291,
- "competitorP95Ms": 6.80000000000291,
+ "competitorMs": 5.860000000000582,
+ "competitorP95Ms": 6.680000000007567,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9344827586202333,
+ "ratio": 0.9283276450511893,
"factor": 1,
"label": "level",
"structural": false
@@ -5696,14 +5732,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.3400000000001455,
- "maxMs": 5.5600000000004,
- "ratio": 1.0411985018727057
+ "minMs": 5.380000000000109,
+ "maxMs": 5.479999999999563,
+ "ratio": 1.0185873605946938
},
"competitor": {
- "minMs": 5.779999999998836,
- "maxMs": 5.820000000006985,
- "ratio": 1.0069204152263247
+ "minMs": 5.819999999992433,
+ "maxMs": 5.880000000004657,
+ "ratio": 1.010309278352629
},
"stable": true,
"rungs": [
@@ -5715,17 +5751,17 @@
},
{
"competitor": "planck",
- "referenceMs": 5.420000000000073,
- "referenceP95Ms": 6.480000000000018,
+ "referenceMs": 5.440000000000509,
+ "referenceP95Ms": 6.460000000000036,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.740000000005239,
- "competitorP95Ms": 6.459999999999127,
+ "competitorMs": 5.620000000002619,
+ "competitorP95Ms": 6.419999999998254,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9442508710792903,
+ "ratio": 0.9679715302487498,
"factor": 1,
"label": "level",
"structural": false
@@ -5735,14 +5771,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.3400000000001455,
- "maxMs": 5.5600000000004,
- "ratio": 1.0411985018727057
+ "minMs": 5.380000000000109,
+ "maxMs": 5.479999999999563,
+ "ratio": 1.0185873605946938
},
"competitor": {
- "minMs": 5.519999999996799,
- "maxMs": 6,
- "ratio": 1.0869565217397608
+ "minMs": 5.440000000002328,
+ "maxMs": 5.739999999997963,
+ "ratio": 1.0551470588227032
},
"stable": true,
"rungs": [
@@ -5754,19 +5790,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.420000000000073,
- "referenceP95Ms": 6.480000000000018,
+ "referenceMs": 5.440000000000509,
+ "referenceP95Ms": 6.460000000000036,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 1.3000000000029104,
- "competitorP95Ms": 1.360000000000582,
+ "competitorMs": 1.320000000006985,
+ "competitorP95Ms": 1.3800000000046566,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 4.169230769221492,
- "factor": 4.169230769221492,
- "label": "competitor leads (4.17x)",
+ "ratio": 4.121212121190699,
+ "factor": 4.121212121190699,
+ "label": "competitor leads (4.12x)",
"structural": false
},
"mechanism": "identical scene (1504 bodies, 4236 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5774,14 +5810,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.3400000000001455,
- "maxMs": 5.5600000000004,
- "ratio": 1.0411985018727057
+ "minMs": 5.380000000000109,
+ "maxMs": 5.479999999999563,
+ "ratio": 1.0185873605946938
},
"competitor": {
- "minMs": 1.2800000000061118,
- "maxMs": 1.3000000000029104,
- "ratio": 1.0156249999974243
+ "minMs": 1.3000000000029104,
+ "maxMs": 1.360000000000582,
+ "ratio": 1.0461538461519517
},
"stable": true,
"rungs": [
@@ -5804,18 +5840,18 @@
{
"competitor": "matter-js",
"referenceMs": 4.579999999999927,
- "referenceP95Ms": 5.059999999999491,
+ "referenceP95Ms": 5.020000000000437,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 2.2399999999979627,
- "competitorP95Ms": 2.599999999998545,
+ "competitorMs": 2.2000000000007276,
+ "competitorP95Ms": 2.359999999996944,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 2.044642857144684,
- "factor": 2.044642857144684,
- "label": "competitor leads (2.04x)",
+ "ratio": 2.0818181818174604,
+ "factor": 2.0818181818174604,
+ "label": "competitor leads (2.08x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5824,13 +5860,13 @@
"runs": 3,
"reference": {
"minMs": 4.539999999999964,
- "maxMs": 4.600000000000364,
- "ratio": 1.0132158590309253
+ "maxMs": 4.619999999999891,
+ "ratio": 1.0176211453744335
},
"competitor": {
- "minMs": 2.1700000000000728,
- "maxMs": 2.2999999999992724,
- "ratio": 1.0599078341010117
+ "minMs": 2.1200000000026193,
+ "maxMs": 2.220000000001164,
+ "ratio": 1.04716981132001
},
"stable": true,
"rungs": [
@@ -5843,11 +5879,11 @@
{
"competitor": "nape-js",
"referenceMs": 4.579999999999927,
- "referenceP95Ms": 5.059999999999491,
+ "referenceP95Ms": 5.020000000000437,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
"competitorMs": 5.019999999989523,
- "competitorP95Ms": 6.059999999997672,
+ "competitorP95Ms": 6.279999999998836,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
@@ -5863,13 +5899,13 @@
"runs": 3,
"reference": {
"minMs": 4.539999999999964,
- "maxMs": 4.600000000000364,
- "ratio": 1.0132158590309253
+ "maxMs": 4.619999999999891,
+ "ratio": 1.0176211453744335
},
"competitor": {
- "minMs": 4.959999999999127,
- "maxMs": 5.150000000001455,
- "ratio": 1.0383064516133793
+ "minMs": 4.990000000005239,
+ "maxMs": 5.099999999991269,
+ "ratio": 1.02204408817353
},
"stable": true,
"rungs": [
@@ -5882,18 +5918,18 @@
{
"competitor": "planck",
"referenceMs": 4.579999999999927,
- "referenceP95Ms": 5.059999999999491,
+ "referenceP95Ms": 5.020000000000437,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 7.860000000000582,
- "competitorP95Ms": 10.69999999999709,
+ "competitorMs": 7.779999999998836,
+ "competitorP95Ms": 11.040000000000873,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5826972010177593,
- "factor": 1.7161572052403289,
- "label": "ExoJS leads (1.72x)",
+ "ratio": 0.5886889460155029,
+ "factor": 1.6986899563316504,
+ "label": "ExoJS leads (1.70x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5902,13 +5938,13 @@
"runs": 3,
"reference": {
"minMs": 4.539999999999964,
- "maxMs": 4.600000000000364,
- "ratio": 1.0132158590309253
+ "maxMs": 4.619999999999891,
+ "ratio": 1.0176211453744335
},
"competitor": {
- "minMs": 7.769999999996799,
- "maxMs": 7.979999999999563,
- "ratio": 1.027027027027394
+ "minMs": 7.770000000000437,
+ "maxMs": 7.860000000000582,
+ "ratio": 1.0115830115830298
},
"stable": true,
"rungs": [
@@ -5921,18 +5957,18 @@
{
"competitor": "rapier",
"referenceMs": 4.579999999999927,
- "referenceP95Ms": 5.059999999999491,
+ "referenceP95Ms": 5.020000000000437,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 1.5800000000017462,
- "competitorP95Ms": 1.8399999999965075,
+ "competitorMs": 1.639999999999418,
+ "competitorP95Ms": 1.7799999999988358,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 2.89873417721194,
- "factor": 2.89873417721194,
- "label": "competitor leads (2.90x)",
+ "ratio": 2.792682926830215,
+ "factor": 2.792682926830215,
+ "label": "competitor leads (2.79x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5941,13 +5977,13 @@
"runs": 3,
"reference": {
"minMs": 4.539999999999964,
- "maxMs": 4.600000000000364,
- "ratio": 1.0132158590309253
+ "maxMs": 4.619999999999891,
+ "ratio": 1.0176211453744335
},
"competitor": {
- "minMs": 1.5799999999871943,
+ "minMs": 1.5800000000017462,
"maxMs": 1.639999999999418,
- "ratio": 1.037974683552348
+ "ratio": 1.0379746835427883
},
"stable": true,
"rungs": [
@@ -5969,17 +6005,17 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.720000000000255,
+ "referenceMs": 5.780000000000655,
"referenceP95Ms": 6.319999999999709,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 6.520000000000437,
- "competitorP95Ms": 8.020000000000437,
+ "competitorMs": 6.470000000001164,
+ "competitorP95Ms": 8.299999999999272,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.8773006134969128,
+ "ratio": 0.8933539412673284,
"factor": 1,
"label": "level",
"structural": false
@@ -5989,14 +6025,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.640000000001237,
- "maxMs": 5.739999999999782,
- "ratio": 1.0177304964536389
+ "minMs": 5.739999999999782,
+ "maxMs": 5.800000000001091,
+ "ratio": 1.0104529616727025
},
"competitor": {
- "minMs": 6.440000000000509,
- "maxMs": 6.550000000001091,
- "ratio": 1.017080745341704
+ "minMs": 6.430000000000291,
+ "maxMs": 6.479999999999563,
+ "ratio": 1.007776049766605
},
"stable": true,
"rungs": [
@@ -6008,19 +6044,19 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.720000000000255,
+ "referenceMs": 5.780000000000655,
"referenceP95Ms": 6.319999999999709,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 12.619999999995343,
- "competitorP95Ms": 14.059999999997672,
+ "competitorMs": 12.660000000003492,
+ "competitorP95Ms": 14.279999999998836,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.453248811410647,
- "factor": 2.206293706292794,
- "label": "ExoJS leads (2.21x)",
+ "ratio": 0.45655608214842497,
+ "factor": 2.1903114186854773,
+ "label": "ExoJS leads (2.19x)",
"structural": false
},
"mechanism": "competitor resolves fewer solved contacts (2195 vs 1461); the counters are not semantically identical across arms (see the run's caveats)",
@@ -6028,14 +6064,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.640000000001237,
- "maxMs": 5.739999999999782,
- "ratio": 1.0177304964536389
+ "minMs": 5.739999999999782,
+ "maxMs": 5.800000000001091,
+ "ratio": 1.0104529616727025
},
"competitor": {
- "minMs": 12.539999999993597,
- "maxMs": 12.69999999999709,
- "ratio": 1.0127591706541925
+ "minMs": 12.55000000000291,
+ "maxMs": 12.720000000001164,
+ "ratio": 1.0135458167329254
},
"stable": true,
"rungs": [
@@ -6047,19 +6083,19 @@
},
{
"competitor": "planck",
- "referenceMs": 5.720000000000255,
+ "referenceMs": 5.780000000000655,
"referenceP95Ms": 6.319999999999709,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 8.059999999997672,
- "competitorP95Ms": 10.339999999996508,
+ "competitorMs": 7.990000000001601,
+ "competitorP95Ms": 10.280000000006112,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.7096774193550753,
- "factor": 1.4090909090904393,
- "label": "ExoJS leads (1.41x)",
+ "ratio": 0.7234042553190859,
+ "factor": 1.382352941176591,
+ "label": "ExoJS leads (1.38x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms) with 34 vs 37 ray hits per step; the difference is query and solver cost",
@@ -6067,14 +6103,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.640000000001237,
- "maxMs": 5.739999999999782,
- "ratio": 1.0177304964536389
+ "minMs": 5.739999999999782,
+ "maxMs": 5.800000000001091,
+ "ratio": 1.0104529616727025
},
"competitor": {
- "minMs": 7.990000000001601,
- "maxMs": 8.100000000002183,
- "ratio": 1.013767209011334
+ "minMs": 7.9099999999962165,
+ "maxMs": 8.0099999999984,
+ "ratio": 1.0126422250318876
},
"stable": true,
"rungs": [
@@ -6086,19 +6122,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.720000000000255,
+ "referenceMs": 5.780000000000655,
"referenceP95Ms": 6.319999999999709,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 1.7000000000116415,
- "competitorP95Ms": 1.860000000000582,
+ "competitorMs": 1.679999999993015,
+ "competitorP95Ms": 1.8599999999860302,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 3.3647058823300497,
- "factor": 3.3647058823300497,
- "label": "competitor leads (3.36x)",
+ "ratio": 3.4404761904908847,
+ "factor": 3.4404761904908847,
+ "label": "competitor leads (3.44x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms) with 34 vs 39 ray hits per step; the difference is query and solver cost",
@@ -6106,14 +6142,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.640000000001237,
- "maxMs": 5.739999999999782,
- "ratio": 1.0177304964536389
+ "minMs": 5.739999999999782,
+ "maxMs": 5.800000000001091,
+ "ratio": 1.0104529616727025
},
"competitor": {
- "minMs": 1.6499999999941792,
- "maxMs": 1.7200000000011642,
- "ratio": 1.0424242424286254
+ "minMs": 1.639999999999418,
+ "maxMs": 1.7000000000116415,
+ "ratio": 1.036585365861125
},
"stable": true,
"rungs": [
@@ -6135,17 +6171,17 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.599999999999454,
- "referenceP95Ms": 6.399999999999636,
+ "referenceMs": 5.619999999998981,
+ "referenceP95Ms": 6.6200000000008,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.709999999999127,
- "competitorP95Ms": 6.700000000000728,
+ "competitorMs": 5.720000000001164,
+ "competitorP95Ms": 6.6599999999962165,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9807355516638022,
+ "ratio": 0.9825174825171045,
"factor": 1,
"label": "level",
"structural": false
@@ -6155,14 +6191,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.520000000000437,
- "maxMs": 5.6899999999996,
- "ratio": 1.0307971014491213
+ "minMs": 5.5,
+ "maxMs": 5.639999999999418,
+ "ratio": 1.0254545454544397
},
"competitor": {
- "minMs": 5.639999999999418,
- "maxMs": 5.739999999997963,
- "ratio": 1.0177304964536444
+ "minMs": 5.709999999999127,
+ "maxMs": 5.819999999999709,
+ "ratio": 1.019264448336357
},
"stable": true,
"rungs": [
@@ -6174,19 +6210,19 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.599999999999454,
- "referenceP95Ms": 6.399999999999636,
+ "referenceMs": 5.619999999998981,
+ "referenceP95Ms": 6.6200000000008,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 3.039999999993597,
- "competitorP95Ms": 3.5599999999976717,
+ "competitorMs": 2.9199999999982538,
+ "competitorP95Ms": 3.5200000000040745,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.842105263161595,
- "factor": 1.842105263161595,
- "label": "competitor leads (1.84x)",
+ "ratio": 1.9246575342473775,
+ "factor": 1.9246575342473775,
+ "label": "competitor leads (1.92x)",
"structural": false
},
"mechanism": "identical scene (1504 bodies, 1415 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6194,14 +6230,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.520000000000437,
- "maxMs": 5.6899999999996,
- "ratio": 1.0307971014491213
+ "minMs": 5.5,
+ "maxMs": 5.639999999999418,
+ "ratio": 1.0254545454544397
},
"competitor": {
- "minMs": 2.820000000006985,
- "maxMs": 3.1000000000058208,
- "ratio": 1.0992907801411853
+ "minMs": 2.720000000001164,
+ "maxMs": 3.0800000000017462,
+ "ratio": 1.132352941176628
},
"stable": true,
"rungs": [
@@ -6213,17 +6249,17 @@
},
{
"competitor": "planck",
- "referenceMs": 5.599999999999454,
- "referenceP95Ms": 6.399999999999636,
+ "referenceMs": 5.619999999998981,
+ "referenceP95Ms": 6.6200000000008,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.430000000000291,
- "competitorP95Ms": 7.180000000007567,
+ "competitorMs": 5.100000000005821,
+ "competitorP95Ms": 7.380000000004657,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.0313075506444114,
+ "ratio": 1.101960784312268,
"factor": 1,
"label": "level",
"structural": false
@@ -6233,14 +6269,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.520000000000437,
- "maxMs": 5.6899999999996,
- "ratio": 1.0307971014491213
+ "minMs": 5.5,
+ "maxMs": 5.639999999999418,
+ "ratio": 1.0254545454544397
},
"competitor": {
- "minMs": 5.280000000006112,
- "maxMs": 5.619999999995343,
- "ratio": 1.0643939393918254
+ "minMs": 5.070000000006985,
+ "maxMs": 5.4799999999959255,
+ "ratio": 1.0808678500963265
},
"stable": true,
"rungs": [
@@ -6252,19 +6288,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.599999999999454,
- "referenceP95Ms": 6.399999999999636,
+ "referenceMs": 5.619999999998981,
+ "referenceP95Ms": 6.6200000000008,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 0.7599999999947613,
- "competitorP95Ms": 0.7799999999988358,
+ "competitorMs": 0.7799999999988358,
+ "competitorP95Ms": 0.819999999992433,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 7.368421052681652,
- "factor": 7.368421052681652,
- "label": "competitor leads clearly (7.37x)",
+ "ratio": 7.205128205137653,
+ "factor": 7.205128205137653,
+ "label": "competitor leads clearly (7.21x)",
"structural": true
},
"mechanism": "identical scene (1504 bodies, 1415 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6272,14 +6308,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.520000000000437,
- "maxMs": 5.6899999999996,
- "ratio": 1.0307971014491213
+ "minMs": 5.5,
+ "maxMs": 5.639999999999418,
+ "ratio": 1.0254545454544397
},
"competitor": {
"minMs": 0.7599999999947613,
- "maxMs": 0.8000000000029104,
- "ratio": 1.0526315789584537
+ "maxMs": 0.7999999999883585,
+ "ratio": 1.0526315789393064
},
"stable": true,
"rungs": [
@@ -6301,19 +6337,19 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.240000000000691,
- "referenceP95Ms": 5.459999999999127,
+ "referenceMs": 5.289999999999964,
+ "referenceP95Ms": 5.519999999998618,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 4.819999999999709,
- "competitorP95Ms": 6.580000000001746,
+ "competitorMs": 5.169999999998254,
+ "competitorP95Ms": 7.119999999995343,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.08713692946079,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "competitor resolves fewer solved contacts (7875 vs 0); the counters are not semantically identical across arms (see the run's caveats)",
@@ -6321,18 +6357,18 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.980000000000473,
- "maxMs": 5.699999999998909,
- "ratio": 1.144578313252684
+ "minMs": 5.020000000000437,
+ "maxMs": 5.680000000000291,
+ "ratio": 1.1314741035856168
},
"competitor": {
- "minMs": 4.740000000001601,
- "maxMs": 5.879999999997381,
- "ratio": 1.2405063291129526
+ "minMs": 4.399999999997817,
+ "maxMs": 6.120000000002619,
+ "ratio": 1.3909090909103763
},
- "stable": true,
+ "stable": false,
"rungs": [
- "level",
+ "competitor-leads",
"level",
"level"
]
@@ -6340,12 +6376,12 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.240000000000691,
- "referenceP95Ms": 5.459999999999127,
+ "referenceMs": 5.289999999999964,
+ "referenceP95Ms": 5.519999999998618,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
"competitorMs": 0,
- "competitorP95Ms": 0,
+ "competitorP95Ms": 0.0020000000004074536,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
@@ -6360,9 +6396,9 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.980000000000473,
- "maxMs": 5.699999999998909,
- "ratio": 1.144578313252684
+ "minMs": 5.020000000000437,
+ "maxMs": 5.680000000000291,
+ "ratio": 1.1314741035856168
},
"competitor": {
"minMs": 0,
@@ -6379,19 +6415,19 @@
},
{
"competitor": "planck",
- "referenceMs": 5.240000000000691,
- "referenceP95Ms": 5.459999999999127,
+ "referenceMs": 5.289999999999964,
+ "referenceP95Ms": 5.519999999998618,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 0.39999999999417923,
- "competitorP95Ms": 0.40000000000873115,
+ "competitorMs": 0.37000000000261934,
+ "competitorP95Ms": 0.3800000000046566,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 13.100000000192358,
- "factor": 13.100000000192358,
- "label": "competitor leads clearly (13.10x)",
+ "ratio": 14.297297297195984,
+ "factor": 14.297297297195984,
+ "label": "competitor leads clearly (14.30x)",
"structural": true
},
"mechanism": "competitor resolves fewer solved contacts (7875 vs 0); the counters are not semantically identical across arms (see the run's caveats)",
@@ -6399,14 +6435,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.980000000000473,
- "maxMs": 5.699999999998909,
- "ratio": 1.144578313252684
+ "minMs": 5.020000000000437,
+ "maxMs": 5.680000000000291,
+ "ratio": 1.1314741035856168
},
"competitor": {
- "minMs": 0.36499999999796273,
- "maxMs": 0.41000000000349246,
- "ratio": 1.1232876712487148
+ "minMs": 0.37000000000261934,
+ "maxMs": 0.37999999999738066,
+ "ratio": 1.0270270270126771
},
"stable": true,
"rungs": [
@@ -6418,19 +6454,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.240000000000691,
- "referenceP95Ms": 5.459999999999127,
+ "referenceMs": 5.289999999999964,
+ "referenceP95Ms": 5.519999999998618,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 0.19999999999708962,
- "competitorP95Ms": 0.22000000000116415,
+ "competitorMs": 0.20000000001164153,
+ "competitorP95Ms": 0.23999999999068677,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 26.200000000384716,
- "factor": 26.200000000384716,
- "label": "competitor leads clearly (26.20x)",
+ "ratio": 26.449999998460225,
+ "factor": 26.449999998460225,
+ "label": "competitor leads clearly (26.45x)",
"structural": true
},
"mechanism": "competitor resolves fewer solved contacts (7875 vs 1125); the counters are not semantically identical across arms (see the run's caveats)",
@@ -6438,14 +6474,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.980000000000473,
- "maxMs": 5.699999999998909,
- "ratio": 1.144578313252684
+ "minMs": 5.020000000000437,
+ "maxMs": 5.680000000000291,
+ "ratio": 1.1314741035856168
},
"competitor": {
"minMs": 0.19999999999708962,
- "maxMs": 0.20000000001164153,
- "ratio": 1.0000000000727596
+ "maxMs": 0.21999999998661224,
+ "ratio": 1.0999999999490684
},
"stable": true,
"rungs": [
@@ -6467,19 +6503,19 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 3.7400000000016007,
- "referenceP95Ms": 4.440000000002328,
+ "referenceMs": 3.7399999999979627,
+ "referenceP95Ms": 4.5,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 10.640000000003056,
- "competitorP95Ms": 12.339999999996508,
+ "competitorMs": 10.680000000000291,
+ "competitorP95Ms": 12.340000000003783,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.3515037593985457,
- "factor": 2.8449197860958564,
- "label": "ExoJS leads (2.84x)",
+ "ratio": 0.3501872659174027,
+ "factor": 2.8556149732636658,
+ "label": "ExoJS leads (2.86x)",
"structural": false
},
"mechanism": "identical scene (3004 bodies, 6199 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6487,14 +6523,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.719999999997526,
- "maxMs": 3.7599999999983993,
- "ratio": 1.0107526881722848
+ "minMs": 3.7399999999979627,
+ "maxMs": 3.7400000000016007,
+ "ratio": 1.0000000000009728
},
"competitor": {
"minMs": 10.639999999999418,
- "maxMs": 10.680000000000291,
- "ratio": 1.003759398496323
+ "maxMs": 10.75,
+ "ratio": 1.0103383458647168
},
"stable": true,
"rungs": [
@@ -6506,19 +6542,19 @@
},
{
"competitor": "nape-js",
- "referenceMs": 3.7400000000016007,
- "referenceP95Ms": 4.440000000002328,
+ "referenceMs": 3.7399999999979627,
+ "referenceP95Ms": 4.5,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 11.059999999997672,
- "competitorP95Ms": 14.099999999991269,
+ "competitorMs": 11,
+ "competitorP95Ms": 13.820000000006985,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.33815551537092114,
- "factor": 2.9572192513350104,
- "label": "ExoJS leads (2.96x)",
+ "ratio": 0.3399999999998148,
+ "factor": 2.9411764705898373,
+ "label": "ExoJS leads (2.94x)",
"structural": false
},
"mechanism": "identical scene (3004 bodies, 6199 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6526,14 +6562,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.719999999997526,
- "maxMs": 3.7599999999983993,
- "ratio": 1.0107526881722848
+ "minMs": 3.7399999999979627,
+ "maxMs": 3.7400000000016007,
+ "ratio": 1.0000000000009728
},
"competitor": {
- "minMs": 11,
- "maxMs": 11.080000000001746,
- "ratio": 1.007272727272886
+ "minMs": 10.980000000010477,
+ "maxMs": 11,
+ "ratio": 1.0018214936238163
},
"stable": true,
"rungs": [
@@ -6545,19 +6581,19 @@
},
{
"competitor": "planck",
- "referenceMs": 3.7400000000016007,
- "referenceP95Ms": 4.440000000002328,
+ "referenceMs": 3.7399999999979627,
+ "referenceP95Ms": 4.5,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 13.299999999988358,
- "competitorP95Ms": 19.679999999993015,
+ "competitorMs": 13.080000000001746,
+ "competitorP95Ms": 19.54000000000815,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.2812030075191635,
- "factor": 3.556149732615686,
- "label": "ExoJS leads (3.56x)",
+ "ratio": 0.2859327217123443,
+ "factor": 3.4973262032109282,
+ "label": "ExoJS leads (3.50x)",
"structural": false
},
"mechanism": "identical scene (3004 bodies, 6199 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6565,14 +6601,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.719999999997526,
- "maxMs": 3.7599999999983993,
- "ratio": 1.0107526881722848
+ "minMs": 3.7399999999979627,
+ "maxMs": 3.7400000000016007,
+ "ratio": 1.0000000000009728
},
"competitor": {
- "minMs": 13.240000000005239,
- "maxMs": 13.330000000001746,
- "ratio": 1.0067975830813045
+ "minMs": 12.979999999995925,
+ "maxMs": 13.34000000001106,
+ "ratio": 1.0277349768886939
},
"stable": true,
"rungs": [
@@ -6584,19 +6620,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 3.7400000000016007,
- "referenceP95Ms": 4.440000000002328,
+ "referenceMs": 3.7399999999979627,
+ "referenceP95Ms": 4.5,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 2.099999999991269,
- "competitorP95Ms": 2.2599999999947613,
+ "competitorMs": 2.1199999999953434,
+ "competitorP95Ms": 2.220000000001164,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.7809523809605479,
- "factor": 1.7809523809605479,
- "label": "competitor leads (1.78x)",
+ "ratio": 1.7641509433991405,
+ "factor": 1.7641509433991405,
+ "label": "competitor leads (1.76x)",
"structural": false
},
"mechanism": "identical scene (3004 bodies, 6199 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6604,14 +6640,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.719999999997526,
- "maxMs": 3.7599999999983993,
- "ratio": 1.0107526881722848
+ "minMs": 3.7399999999979627,
+ "maxMs": 3.7400000000016007,
+ "ratio": 1.0000000000009728
},
"competitor": {
"minMs": 2.0800000000017462,
- "maxMs": 2.139999999999418,
- "ratio": 1.0288461538450102
+ "maxMs": 2.1600000000034925,
+ "ratio": 1.0384615384623457
},
"stable": true,
"rungs": [
@@ -6628,6 +6664,6 @@
},
"signature": {
"algorithm": "sha256",
- "value": "d251be16370d0abc9c51f386e8a873c328de964248aaaf83e80546a0ea754888"
+ "value": "74734d08514f28925d94d9550137e610aa03b9c692c53cf588b06b4e62d677ce"
}
}
From 51dd433e7610a04adc2726c0e797bd9ca8ff6101 Mon Sep 17 00:00:00 2001
From: Dima Giesler
Date: Sat, 12 Sep 2026 06:46:44 +0200
Subject: [PATCH 17/28] bench: re-measure the macOS reference run on the
current arms
---
.../results/m3-max-macos-27-beta-webkit.json | 3941 ++++++++---------
1 file changed, 1912 insertions(+), 2029 deletions(-)
diff --git a/packages/exojs-bench/results/m3-max-macos-27-beta-webkit.json b/packages/exojs-bench/results/m3-max-macos-27-beta-webkit.json
index cfb1cdc71..863e9a37b 100644
--- a/packages/exojs-bench/results/m3-max-macos-27-beta-webkit.json
+++ b/packages/exojs-bench/results/m3-max-macos-27-beta-webkit.json
@@ -12,7 +12,7 @@
"prerelease": true
},
"engineVersion": "0.17.0",
- "measuredAt": "2026-09-12T03:46:13.242Z",
+ "measuredAt": "2026-09-12T04:44:36.717Z",
"runs": 3
},
"rendering": {
@@ -43,7 +43,7 @@
"headless": true,
"software": false,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:11:55.632Z"
+ "timestamp": "2026-09-12T04:11:17.999Z"
},
{
"backend": "webgpu",
@@ -70,7 +70,7 @@
"software": false,
"slotTier": 16,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:19:13.432Z"
+ "timestamp": "2026-09-12T04:18:01.494Z"
}
]
},
@@ -100,7 +100,7 @@
"headless": true,
"software": false,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:24:03.163Z"
+ "timestamp": "2026-09-12T04:23:07.261Z"
},
{
"backend": "webgpu",
@@ -127,7 +127,7 @@
"software": false,
"slotTier": 16,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:31:20.194Z"
+ "timestamp": "2026-09-12T04:29:50.278Z"
}
]
},
@@ -157,7 +157,7 @@
"headless": true,
"software": false,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:36:09.267Z"
+ "timestamp": "2026-09-12T04:34:54.521Z"
},
{
"backend": "webgpu",
@@ -184,7 +184,7 @@
"software": false,
"slotTier": 16,
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:43:31.391Z"
+ "timestamp": "2026-09-12T04:41:40.647Z"
}
]
}
@@ -226,19 +226,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.20000000000004547,
- "referenceP95Ms": 0.42000000000007276,
+ "referenceMs": 0.2199999999997999,
+ "referenceP95Ms": 0.40000000000009095,
"referenceGpuMs": 16.660000000000082,
"referenceOverFrameBudget": false,
- "competitorMs": 2.240000000000009,
- "competitorP95Ms": 8.180000000000291,
+ "competitorMs": 2.339999999999975,
+ "competitorP95Ms": 9.620000000000118,
"competitorGpuMs": 16.660000000000082,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.08928571428573423,
- "factor": 11.199999999997498,
- "label": "ExoJS leads clearly (11.20x)",
+ "ratio": 0.09401709401700951,
+ "factor": 10.636363636373197,
+ "label": "ExoJS leads clearly (10.64x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -247,13 +247,13 @@
"runs": 3,
"reference": {
"minMs": 0.20000000000004547,
- "maxMs": 0.23999999999995225,
- "ratio": 1.1999999999994884
+ "maxMs": 0.2400000000000091,
+ "ratio": 1.1999999999997726
},
"competitor": {
- "minMs": 2.2199999999999704,
- "maxMs": 2.509999999999991,
- "ratio": 1.1306306306306415
+ "minMs": 2.2800000000000864,
+ "maxMs": 2.4500000000000455,
+ "ratio": 1.0745614035087512
},
"stable": true,
"rungs": [
@@ -265,19 +265,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.20000000000004547,
- "referenceP95Ms": 0.42000000000007276,
+ "referenceMs": 0.2199999999997999,
+ "referenceP95Ms": 0.40000000000009095,
"referenceGpuMs": 16.660000000000082,
"referenceOverFrameBudget": false,
- "competitorMs": 1.2700000000000955,
- "competitorP95Ms": 1.7200000000000273,
- "competitorGpuMs": 16.66000000000031,
+ "competitorMs": 1.2100000000000364,
+ "competitorP95Ms": 1.759999999999991,
+ "competitorGpuMs": 16.679999999999836,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.1574803149606539,
- "factor": 6.349999999999033,
- "label": "ExoJS leads clearly (6.35x)",
+ "ratio": 0.181818181818011,
+ "factor": 5.500000000005167,
+ "label": "ExoJS leads clearly (5.50x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -286,13 +286,13 @@
"runs": 3,
"reference": {
"minMs": 0.20000000000004547,
- "maxMs": 0.23999999999995225,
- "ratio": 1.1999999999994884
+ "maxMs": 0.2400000000000091,
+ "ratio": 1.1999999999997726
},
"competitor": {
- "minMs": 1.259999999999991,
- "maxMs": 1.2799999999999727,
- "ratio": 1.0158730158730016
+ "minMs": 1.2000000000001592,
+ "maxMs": 1.3199999999999363,
+ "ratio": 1.0999999999998011
},
"stable": true,
"rungs": [
@@ -304,13 +304,13 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.20000000000004547,
- "referenceP95Ms": 0.42000000000007276,
+ "referenceMs": 0.2199999999997999,
+ "referenceP95Ms": 0.40000000000009095,
"referenceGpuMs": 16.660000000000082,
"referenceOverFrameBudget": false,
- "competitorMs": 0.18000000000017735,
- "competitorP95Ms": 0.3999999999998636,
- "competitorGpuMs": 16.67999999999995,
+ "competitorMs": 0.1999999999998181,
+ "competitorP95Ms": 0.4399999999999409,
+ "competitorGpuMs": 16.660000000000082,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -325,13 +325,13 @@
"runs": 3,
"reference": {
"minMs": 0.20000000000004547,
- "maxMs": 0.23999999999995225,
- "ratio": 1.1999999999994884
+ "maxMs": 0.2400000000000091,
+ "ratio": 1.1999999999997726
},
"competitor": {
- "minMs": 0.1799999999998363,
- "maxMs": 0.1999999999998181,
- "ratio": 1.1111111111111112
+ "minMs": 0.18000000000006366,
+ "maxMs": 0.20000000000004547,
+ "ratio": 1.1111111111109708
},
"stable": false,
"rungs": [
@@ -354,18 +354,18 @@
{
"competitor": "excalibur",
"referenceMs": 0.13999999999987267,
- "referenceP95Ms": 0.25999999999976353,
+ "referenceP95Ms": 0.24000000000023647,
"referenceGpuMs": 16.66000000000031,
"referenceOverFrameBudget": false,
- "competitorMs": 19.84999999999991,
- "competitorP95Ms": 24.079999999999927,
- "competitorGpuMs": 20.960000000000036,
+ "competitorMs": 19.739999999999554,
+ "competitorP95Ms": 24.0600000000004,
+ "competitorGpuMs": 20.780000000000655,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.007052896725434424,
- "factor": 141.7857142858426,
- "label": "ExoJS leads clearly (141.79x)",
+ "ratio": 0.007092198581553993,
+ "factor": 141.00000000012506,
+ "label": "ExoJS leads clearly (141.00x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -374,13 +374,13 @@
"runs": 3,
"reference": {
"minMs": 0.13999999999987267,
- "maxMs": 0.17000000000007276,
- "ratio": 1.2142857142873384
+ "maxMs": 0.16000000000030923,
+ "ratio": 1.142857142860391
},
"competitor": {
- "minMs": 19.420000000000073,
- "maxMs": 19.98999999999978,
- "ratio": 1.02935118434602
+ "minMs": 19.439999999999827,
+ "maxMs": 20.24000000000001,
+ "ratio": 1.0411522633744954
},
"stable": true,
"rungs": [
@@ -393,12 +393,12 @@
{
"competitor": "phaser",
"referenceMs": 0.13999999999987267,
- "referenceP95Ms": 0.25999999999976353,
+ "referenceP95Ms": 0.24000000000023647,
"referenceGpuMs": 16.66000000000031,
"referenceOverFrameBudget": false,
"competitorMs": 3.0800000000001546,
- "competitorP95Ms": 9.159999999999854,
- "competitorGpuMs": 16.659999999999854,
+ "competitorP95Ms": 7.2400000000002365,
+ "competitorGpuMs": 16.66000000000031,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
@@ -413,13 +413,13 @@
"runs": 3,
"reference": {
"minMs": 0.13999999999987267,
- "maxMs": 0.17000000000007276,
- "ratio": 1.2142857142873384
+ "maxMs": 0.16000000000030923,
+ "ratio": 1.142857142860391
},
"competitor": {
- "minMs": 3.0799999999999272,
- "maxMs": 3.080000000000382,
- "ratio": 1.0000000000001477
+ "minMs": 3.0499999999999545,
+ "maxMs": 3.100000000000364,
+ "ratio": 1.0163934426230852
},
"stable": true,
"rungs": [
@@ -432,18 +432,18 @@
{
"competitor": "pixi",
"referenceMs": 0.13999999999987267,
- "referenceP95Ms": 0.25999999999976353,
+ "referenceP95Ms": 0.24000000000023647,
"referenceGpuMs": 16.66000000000031,
"referenceOverFrameBudget": false,
"competitorMs": 0.13999999999987267,
- "competitorP95Ms": 0.2600000000002183,
- "competitorGpuMs": 16.679999999999836,
+ "competitorP95Ms": 0.27999999999974534,
+ "competitorGpuMs": 16.66000000000031,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 1,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -452,17 +452,17 @@
"runs": 3,
"reference": {
"minMs": 0.13999999999987267,
- "maxMs": 0.17000000000007276,
- "ratio": 1.2142857142873384
+ "maxMs": 0.16000000000030923,
+ "ratio": 1.142857142860391
},
"competitor": {
"minMs": 0.13999999999987267,
"maxMs": 0.13999999999987267,
"ratio": 1
},
- "stable": false,
+ "stable": true,
"rungs": [
- "competitor-leads",
+ "level",
"level",
"level"
]
@@ -480,19 +480,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.06000000000040018,
- "referenceP95Ms": 0.2599999999993088,
- "referenceGpuMs": 16.67999999999938,
+ "referenceMs": 0.07000000000016371,
+ "referenceP95Ms": 0.2600000000002183,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 0.04999999999972715,
- "competitorP95Ms": 0.2600000000002183,
- "competitorGpuMs": 16.660000000000764,
+ "competitorMs": 0.03999999999996362,
+ "competitorP95Ms": 0.21999999999934516,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "competitor",
+ "ratio": 1.7500000000056843,
+ "factor": 1.7500000000056843,
+ "label": "competitor leads (1.75x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (25 vs 1 per frame)",
@@ -500,32 +500,32 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.05999999999949068,
- "maxMs": 0.06000000000040018,
- "ratio": 1.0000000000151583
+ "minMs": 0.06000000000040018,
+ "maxMs": 0.07999999999992724,
+ "ratio": 1.3333333333232278
},
"competitor": {
- "minMs": 0.03999999999996362,
- "maxMs": 0.06999999999970896,
- "ratio": 1.7499999999943157
+ "minMs": 0.020000000000436557,
+ "maxMs": 0.03999999999996362,
+ "ratio": 1.9999999999545253
},
- "stable": false,
+ "stable": true,
"rungs": [
"competitor-leads",
"competitor-leads",
- "level"
+ "competitor-leads"
]
}
},
{
"competitor": "phaser",
- "referenceMs": 0.06000000000040018,
- "referenceP95Ms": 0.2599999999993088,
- "referenceGpuMs": 16.67999999999938,
+ "referenceMs": 0.07500000000004547,
+ "referenceP95Ms": 0.24000000000023647,
+ "referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 16.88000000000011,
- "competitorP95Ms": 21.82000000000062,
- "competitorGpuMs": 18.05999999999949,
+ "competitorMs": 17.670000000000073,
+ "competitorP95Ms": 22.52999999999929,
+ "competitorGpuMs": 18.840000000000146,
"competitorOverFrameBudget": true,
"verdict": {
"side": "neither",
@@ -537,19 +537,20 @@
"mechanism": "competitor issues fewer draw calls (25 vs 7 per frame)",
"timer": "limited",
"aggregate": {
- "runs": 1,
+ "runs": 2,
"reference": {
- "minMs": 0.06000000000040018,
- "maxMs": 0.06000000000040018,
- "ratio": 1
+ "minMs": 0.07000000000016371,
+ "maxMs": 0.07999999999992724,
+ "ratio": 1.1428571428534307
},
"competitor": {
- "minMs": 16.88000000000011,
- "maxMs": 16.88000000000011,
- "ratio": 1
+ "minMs": 17.3100000000004,
+ "maxMs": 18.029999999999745,
+ "ratio": 1.0415944540727515
},
"stable": false,
"rungs": [
+ "exojs-leads-clearly",
"exojs-leads-clearly"
]
}
@@ -566,19 +567,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 1.7200000000002547,
- "referenceP95Ms": 2.480000000000473,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 1.7500000000004547,
+ "referenceP95Ms": 2.4399999999996,
+ "referenceGpuMs": 16.660000000000764,
"referenceOverFrameBudget": false,
- "competitorMs": 26.140000000001237,
- "competitorP95Ms": 35.37999999999738,
- "competitorGpuMs": 27.260000000002037,
+ "competitorMs": 25.170000000000073,
+ "competitorP95Ms": 29.780000000002474,
+ "competitorGpuMs": 26.7400000000016,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.06579954093344198,
- "factor": 15.19767441860312,
- "label": "ExoJS leads clearly (15.20x)",
+ "ratio": 0.06952721493843662,
+ "factor": 14.382857142853446,
+ "label": "ExoJS leads clearly (14.38x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -586,14 +587,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5399999999999636,
- "maxMs": 1.980000000000473,
- "ratio": 1.285714285714623
+ "minMs": 1.6399999999998727,
+ "maxMs": 1.819999999999709,
+ "ratio": 1.1097560975608842
},
"competitor": {
- "minMs": 25.790000000000873,
- "maxMs": 26.600000000002183,
- "ratio": 1.031407522295513
+ "minMs": 25.090000000000146,
+ "maxMs": 25.48999999999978,
+ "ratio": 1.0159426066161672
},
"stable": true,
"rungs": [
@@ -605,19 +606,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 1.7200000000002547,
- "referenceP95Ms": 2.480000000000473,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 1.7500000000004547,
+ "referenceP95Ms": 2.4399999999996,
+ "referenceGpuMs": 16.660000000000764,
"referenceOverFrameBudget": false,
- "competitorMs": 2.9900000000016007,
- "competitorP95Ms": 7.960000000000036,
- "competitorGpuMs": 16.660000000000082,
+ "competitorMs": 3.25,
+ "competitorP95Ms": 8.420000000000073,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5752508361201786,
- "factor": 1.738372093023929,
- "label": "ExoJS leads (1.74x)",
+ "ratio": 0.5384615384616784,
+ "factor": 1.8571428571423745,
+ "label": "ExoJS leads (1.86x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -625,14 +626,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5399999999999636,
- "maxMs": 1.980000000000473,
- "ratio": 1.285714285714623
+ "minMs": 1.6399999999998727,
+ "maxMs": 1.819999999999709,
+ "ratio": 1.1097560975608842
},
"competitor": {
- "minMs": 2.990000000000009,
- "maxMs": 3.259999999999991,
- "ratio": 1.0903010033444753
+ "minMs": 3.110000000000582,
+ "maxMs": 3.269999999999982,
+ "ratio": 1.051446945337418
},
"stable": true,
"rungs": [
@@ -644,19 +645,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.7200000000002547,
- "referenceP95Ms": 2.480000000000473,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 1.7500000000004547,
+ "referenceP95Ms": 2.4399999999996,
+ "referenceGpuMs": 16.660000000000764,
"referenceOverFrameBudget": false,
"competitorMs": 1.319999999999709,
- "competitorP95Ms": 1.9200000000000728,
- "competitorGpuMs": 16.659999999999854,
+ "competitorP95Ms": 1.8800000000001091,
+ "competitorGpuMs": 16.67999999999938,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.3030303030307833,
- "factor": 1.3030303030307833,
- "label": "competitor leads (1.30x)",
+ "ratio": 1.3257575757582125,
+ "factor": 1.3257575757582125,
+ "label": "competitor leads (1.33x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -664,14 +665,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5399999999999636,
- "maxMs": 1.980000000000473,
- "ratio": 1.285714285714623
+ "minMs": 1.6399999999998727,
+ "maxMs": 1.819999999999709,
+ "ratio": 1.1097560975608842
},
"competitor": {
- "minMs": 1.2599999999997635,
- "maxMs": 1.319999999999709,
- "ratio": 1.0476190476190133
+ "minMs": 1.2300000000000182,
+ "maxMs": 1.3399999999996908,
+ "ratio": 1.0894308943086757
},
"stable": true,
"rungs": [
@@ -693,19 +694,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 1.6599999999998545,
- "referenceP95Ms": 2.2200000000002547,
- "referenceGpuMs": 16.68000000000029,
+ "referenceMs": 1.550000000000182,
+ "referenceP95Ms": 2.160000000000764,
+ "referenceGpuMs": 16.67999999999938,
"referenceOverFrameBudget": false,
- "competitorMs": 3.4200000000000728,
- "competitorP95Ms": 6.600000000002183,
+ "competitorMs": 3.3299999999999272,
+ "competitorP95Ms": 8.5,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.48538011695901145,
- "factor": 2.0602409638556463,
- "label": "ExoJS leads (2.06x)",
+ "ratio": 0.46546546546553025,
+ "factor": 2.1483870967738947,
+ "label": "ExoJS leads (2.15x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -713,14 +714,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5600000000004002,
- "maxMs": 1.7600000000002183,
- "ratio": 1.1282051282049788
+ "minMs": 1.480000000000473,
+ "maxMs": 1.8599999999996726,
+ "ratio": 1.256756756756134
},
"competitor": {
- "minMs": 3.390000000001237,
- "maxMs": 3.4899999999997817,
- "ratio": 1.0294985250733062
+ "minMs": 3.2599999999983993,
+ "maxMs": 3.5,
+ "ratio": 1.0736196319023676
},
"stable": true,
"rungs": [
@@ -732,19 +733,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 1.6599999999998545,
- "referenceP95Ms": 2.2200000000002547,
- "referenceGpuMs": 16.68000000000029,
+ "referenceMs": 1.550000000000182,
+ "referenceP95Ms": 2.160000000000764,
+ "referenceGpuMs": 16.67999999999938,
"referenceOverFrameBudget": false,
- "competitorMs": 1.2100000000000364,
- "competitorP95Ms": 1.6599999999998545,
- "competitorGpuMs": 16.679999999999836,
+ "competitorMs": 1.0200000000040745,
+ "competitorP95Ms": 1.4000000000087311,
+ "competitorGpuMs": 16.66000000000031,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.3719008264461194,
- "factor": 1.3719008264461194,
- "label": "competitor leads (1.37x)",
+ "ratio": 1.5196078431313629,
+ "factor": 1.5196078431313629,
+ "label": "competitor leads (1.52x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -752,14 +753,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5600000000004002,
- "maxMs": 1.7600000000002183,
- "ratio": 1.1282051282049788
+ "minMs": 1.480000000000473,
+ "maxMs": 1.8599999999996726,
+ "ratio": 1.256756756756134
},
"competitor": {
- "minMs": 1.0399999999972351,
- "maxMs": 1.240000000000009,
- "ratio": 1.1923076923108709
+ "minMs": 0.9900000000052387,
+ "maxMs": 1.2399999999997817,
+ "ratio": 1.252525252518404
},
"stable": true,
"rungs": [
@@ -771,19 +772,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.6599999999998545,
- "referenceP95Ms": 2.2200000000002547,
- "referenceGpuMs": 16.68000000000029,
+ "referenceMs": 1.550000000000182,
+ "referenceP95Ms": 2.160000000000764,
+ "referenceGpuMs": 16.67999999999938,
"referenceOverFrameBudget": false,
- "competitorMs": 0.9800000000000182,
- "competitorP95Ms": 1.339999999999236,
- "competitorGpuMs": 16.660000000000764,
+ "competitorMs": 1,
+ "competitorP95Ms": 1.4400000000005093,
+ "competitorGpuMs": 16.67999999999938,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.6938775510202282,
- "factor": 1.6938775510202282,
- "label": "competitor leads (1.69x)",
+ "ratio": 1.550000000000182,
+ "factor": 1.550000000000182,
+ "label": "competitor leads (1.55x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -791,14 +792,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5600000000004002,
- "maxMs": 1.7600000000002183,
- "ratio": 1.1282051282049788
+ "minMs": 1.480000000000473,
+ "maxMs": 1.8599999999996726,
+ "ratio": 1.256756756756134
},
"competitor": {
- "minMs": 0.9699999999997999,
- "maxMs": 0.9900000000002365,
- "ratio": 1.0206185567014852
+ "minMs": 0.9600000000000364,
+ "maxMs": 1.0199999999999818,
+ "ratio": 1.0624999999999407
},
"stable": true,
"rungs": [
@@ -820,19 +821,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 4.059999999999491,
- "referenceP95Ms": 5.199999999998909,
+ "referenceMs": 3.8900000000003274,
+ "referenceP95Ms": 5.420000000000073,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 31.779999999998836,
- "competitorP95Ms": 35.45999999999913,
- "competitorGpuMs": 32.60000000000218,
+ "competitorMs": 30.55000000000109,
+ "competitorP95Ms": 35.55999999999767,
+ "competitorGpuMs": 31.81999999999971,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.12775330396474635,
- "factor": 7.827586206897248,
- "label": "ExoJS leads clearly (7.83x)",
+ "ratio": 0.12733224222586542,
+ "factor": 7.853470437017614,
+ "label": "ExoJS leads clearly (7.85x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -840,14 +841,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.019999999998618,
- "maxMs": 4.299999999999272,
- "ratio": 1.0696517412937192
+ "minMs": 3.8800000000010186,
+ "maxMs": 4.039999999999054,
+ "ratio": 1.0412371134015448
},
"competitor": {
- "minMs": 31.55999999999949,
- "maxMs": 32.25,
- "ratio": 1.021863117870739
+ "minMs": 29.919999999998254,
+ "maxMs": 32.72999999999956,
+ "ratio": 1.0939171122995146
},
"stable": true,
"rungs": [
@@ -859,19 +860,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 4.059999999999491,
- "referenceP95Ms": 5.199999999998909,
+ "referenceMs": 3.8900000000003274,
+ "referenceP95Ms": 5.420000000000073,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.930000000000291,
- "competitorP95Ms": 7.6599999999998545,
- "competitorGpuMs": 16.660000000000764,
+ "competitorMs": 3.0800000000017462,
+ "competitorP95Ms": 7.299999999999272,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.3856655290099273,
- "factor": 1.3856655290099273,
- "label": "competitor leads (1.39x)",
+ "ratio": 1.2629870129864031,
+ "factor": 1.2629870129864031,
+ "label": "competitor leads (1.26x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -879,14 +880,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.019999999998618,
- "maxMs": 4.299999999999272,
- "ratio": 1.0696517412937192
+ "minMs": 3.8800000000010186,
+ "maxMs": 4.039999999999054,
+ "ratio": 1.0412371134015448
},
"competitor": {
- "minMs": 2.8400000000001455,
- "maxMs": 2.9600000000000364,
- "ratio": 1.0422535211267199
+ "minMs": 2.869999999999891,
+ "maxMs": 3.2399999999979627,
+ "ratio": 1.1289198606265107
},
"stable": true,
"rungs": [
@@ -898,19 +899,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 4.059999999999491,
- "referenceP95Ms": 5.199999999998909,
+ "referenceMs": 3.8900000000003274,
+ "referenceP95Ms": 5.420000000000073,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.6700000000000728,
- "competitorP95Ms": 11.5,
+ "competitorMs": 2.6599999999998545,
+ "competitorP95Ms": 8.959999999999127,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.5205992509360975,
- "factor": 1.5205992509360975,
- "label": "competitor leads (1.52x)",
+ "ratio": 1.462406015037797,
+ "factor": 1.462406015037797,
+ "label": "competitor leads (1.46x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -918,14 +919,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.019999999998618,
- "maxMs": 4.299999999999272,
- "ratio": 1.0696517412937192
+ "minMs": 3.8800000000010186,
+ "maxMs": 4.039999999999054,
+ "ratio": 1.0412371134015448
},
"competitor": {
- "minMs": 2.5799999999999272,
- "maxMs": 2.839999999999236,
- "ratio": 1.1007751937981844
+ "minMs": 2.6500000000005457,
+ "maxMs": 2.6599999999998545,
+ "ratio": 1.0037735849053988
},
"stable": true,
"rungs": [
@@ -945,58 +946,21 @@
"unit": "sprites",
"primary": false,
"cells": [
- {
- "competitor": "phaser",
- "referenceMs": 37.57000000000062,
- "referenceP95Ms": 43.31999999999971,
- "referenceGpuMs": 38.70000000000073,
- "referenceOverFrameBudget": true,
- "competitorMs": 20.53999999999951,
- "competitorP95Ms": 25.23999999999978,
- "competitorGpuMs": 21.300000000000182,
- "competitorOverFrameBudget": true,
- "verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
- "structural": false
- },
- "mechanism": "competitor issues fewer draw calls (25 vs 7 per frame)",
- "timer": "resolved",
- "aggregate": {
- "runs": 1,
- "reference": {
- "minMs": 37.57000000000062,
- "maxMs": 37.57000000000062,
- "ratio": 1
- },
- "competitor": {
- "minMs": 20.53999999999951,
- "maxMs": 20.53999999999951,
- "ratio": 1
- },
- "stable": false,
- "rungs": [
- "competitor-leads"
- ]
- }
- },
{
"competitor": "pixi",
- "referenceMs": 38.100000000000364,
- "referenceP95Ms": 44.18000000000029,
- "referenceGpuMs": 40.23999999999978,
+ "referenceMs": 39.42000000000098,
+ "referenceP95Ms": 41.82000000000153,
+ "referenceGpuMs": 41.68000000000029,
"referenceOverFrameBudget": true,
- "competitorMs": 29.01000000000022,
- "competitorP95Ms": 32.13999999999942,
- "competitorGpuMs": 30.200000000000728,
+ "competitorMs": 28.31000000000131,
+ "competitorP95Ms": 31.780000000000655,
+ "competitorGpuMs": 29.479999999999563,
"competitorOverFrameBudget": true,
"verdict": {
"side": "competitor",
- "ratio": 1.3133402275077586,
- "factor": 1.3133402275077586,
- "label": "competitor leads (1.31x)",
+ "ratio": 1.3924408336276637,
+ "factor": 1.3924408336276637,
+ "label": "competitor leads (1.39x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (25 vs 1 per frame)",
@@ -1004,14 +968,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 37.57000000000062,
- "maxMs": 39.88999999999942,
- "ratio": 1.061751397391503
+ "minMs": 37.280000000000655,
+ "maxMs": 40.44999999999982,
+ "ratio": 1.0850321888411778
},
"competitor": {
- "minMs": 28.31999999999971,
- "maxMs": 29.159999999999854,
- "ratio": 1.029661016949158
+ "minMs": 27.109999999999673,
+ "maxMs": 28.360000000000582,
+ "ratio": 1.0461084470675368
},
"stable": true,
"rungs": [
@@ -1034,18 +998,18 @@
{
"competitor": "excalibur",
"referenceMs": 0.5599999999994907,
- "referenceP95Ms": 0.7800000000006548,
- "referenceGpuMs": 16.659999999999854,
+ "referenceP95Ms": 0.7799999999988358,
+ "referenceGpuMs": 16.679999999998472,
"referenceOverFrameBudget": false,
- "competitorMs": 28.299999999999272,
- "competitorP95Ms": 33.599999999998545,
- "competitorGpuMs": 29.659999999996217,
+ "competitorMs": 28.029999999998836,
+ "competitorP95Ms": 32.81999999999971,
+ "competitorGpuMs": 29.31999999999971,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.019787985865706893,
- "factor": 50.53571428575895,
- "label": "ExoJS leads clearly (50.54x)",
+ "ratio": 0.019978594363164966,
+ "factor": 50.053571428614866,
+ "label": "ExoJS leads clearly (50.05x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1053,14 +1017,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5500000000001819,
- "maxMs": 0.6199999999989814,
- "ratio": 1.1272727272705023
+ "minMs": 0.5599999999994907,
+ "maxMs": 0.5600000000013097,
+ "ratio": 1.0000000000032483
},
"competitor": {
- "minMs": 27.539999999997235,
- "maxMs": 28.80999999999767,
- "ratio": 1.046114742193194
+ "minMs": 27.57999999999811,
+ "maxMs": 33.38999999999942,
+ "ratio": 1.2106598984772192
},
"stable": true,
"rungs": [
@@ -1073,18 +1037,18 @@
{
"competitor": "phaser",
"referenceMs": 0.5599999999994907,
- "referenceP95Ms": 0.7800000000006548,
- "referenceGpuMs": 16.659999999999854,
+ "referenceP95Ms": 0.7799999999988358,
+ "referenceGpuMs": 16.679999999998472,
"referenceOverFrameBudget": false,
- "competitorMs": 3.0600000000000023,
- "competitorP95Ms": 10.060000000012224,
+ "competitorMs": 3.0299999999999727,
+ "competitorP95Ms": 9.700000000000045,
"competitorGpuMs": 16.660000000000082,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.18300653594754585,
- "factor": 5.464285714290688,
- "label": "ExoJS leads clearly (5.46x)",
+ "ratio": 0.18481848184801838,
+ "factor": 5.410714285719158,
+ "label": "ExoJS leads clearly (5.41x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1092,14 +1056,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5500000000001819,
- "maxMs": 0.6199999999989814,
- "ratio": 1.1272727272705023
+ "minMs": 0.5599999999994907,
+ "maxMs": 0.5600000000013097,
+ "ratio": 1.0000000000032483
},
"competitor": {
- "minMs": 3.0599999999999454,
- "maxMs": 3.109999999993306,
- "ratio": 1.0163398692788763
+ "minMs": 2.8400000000000887,
+ "maxMs": 3.150000000000034,
+ "ratio": 1.109154929577442
},
"stable": true,
"rungs": [
@@ -1112,16 +1076,16 @@
{
"competitor": "pixi",
"referenceMs": 0.5599999999994907,
- "referenceP95Ms": 0.7800000000006548,
- "referenceGpuMs": 16.659999999999854,
+ "referenceP95Ms": 0.7799999999988358,
+ "referenceGpuMs": 16.679999999998472,
"referenceOverFrameBudget": false,
- "competitorMs": 0.5599999999994907,
- "competitorP95Ms": 0.8000000000010914,
- "competitorGpuMs": 16.659999999999854,
+ "competitorMs": 0.5799999999999272,
+ "competitorP95Ms": 0.819999999999709,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1,
+ "ratio": 0.9655172413785533,
"factor": 1,
"label": "level",
"structural": false
@@ -1131,14 +1095,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5500000000001819,
- "maxMs": 0.6199999999989814,
- "ratio": 1.1272727272705023
+ "minMs": 0.5599999999994907,
+ "maxMs": 0.5600000000013097,
+ "ratio": 1.0000000000032483
},
"competitor": {
- "minMs": 0.5400000000008731,
- "maxMs": 0.5799999999999272,
- "ratio": 1.0740740740722028
+ "minMs": 0.5600000000004002,
+ "maxMs": 0.589999999999236,
+ "ratio": 1.0535714285693114
},
"stable": true,
"rungs": [
@@ -1160,19 +1124,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 2.889999999999418,
- "referenceP95Ms": 6.240000000001601,
+ "referenceMs": 2.4899999999997817,
+ "referenceP95Ms": 6.360000000000582,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 25.400000000001455,
- "competitorP95Ms": 31.079999999987194,
- "competitorGpuMs": 26.84000000001106,
+ "competitorMs": 24.619999999995343,
+ "competitorP95Ms": 28.220000000001164,
+ "competitorGpuMs": 25.860000000000582,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.11377952755902568,
- "factor": 8.788927335642413,
- "label": "ExoJS leads clearly (8.79x)",
+ "ratio": 0.101137286758743,
+ "factor": 9.88755020080221,
+ "label": "ExoJS leads clearly (9.89x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/4 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1180,14 +1144,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.8400000000001455,
- "maxMs": 2.9500000000025466,
- "ratio": 1.0387323943670406
+ "minMs": 2.4899999999997817,
+ "maxMs": 2.6199999999989814,
+ "ratio": 1.0522088353410486
},
"competitor": {
- "minMs": 25.360000000000582,
- "maxMs": 25.44000000000233,
- "ratio": 1.003154574132561
+ "minMs": 23.270000000004075,
+ "maxMs": 25.799999999995634,
+ "ratio": 1.108723678555699
},
"stable": true,
"rungs": [
@@ -1199,19 +1163,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 2.889999999999418,
- "referenceP95Ms": 6.240000000001601,
+ "referenceMs": 2.4899999999997817,
+ "referenceP95Ms": 6.360000000000582,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 10.860000000000582,
- "competitorP95Ms": 11.380000000001019,
+ "competitorMs": 10.659999999999854,
+ "competitorP95Ms": 11.260000000002037,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.2661141804787535,
- "factor": 3.757785467128986,
- "label": "ExoJS leads (3.76x)",
+ "ratio": 0.23358348968103337,
+ "factor": 4.281124497992285,
+ "label": "ExoJS leads (4.28x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/4 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1219,14 +1183,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.8400000000001455,
- "maxMs": 2.9500000000025466,
- "ratio": 1.0387323943670406
+ "minMs": 2.4899999999997817,
+ "maxMs": 2.6199999999989814,
+ "ratio": 1.0522088353410486
},
"competitor": {
- "minMs": 10.590000000000146,
- "maxMs": 10.880000000001019,
- "ratio": 1.0273843248348318
+ "minMs": 10.579999999999927,
+ "maxMs": 10.799999999999272,
+ "ratio": 1.0207939508505999
},
"stable": true,
"rungs": [
@@ -1238,19 +1202,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 2.889999999999418,
- "referenceP95Ms": 6.240000000001601,
+ "referenceMs": 2.4899999999997817,
+ "referenceP95Ms": 6.360000000000582,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.5100000000002183,
- "competitorP95Ms": 7.580000000001746,
+ "competitorMs": 2.4899999999997817,
+ "competitorP95Ms": 6.979999999999563,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 1,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/4 vs 1/0/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1258,20 +1222,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.8400000000001455,
- "maxMs": 2.9500000000025466,
- "ratio": 1.0387323943670406
+ "minMs": 2.4899999999997817,
+ "maxMs": 2.6199999999989814,
+ "ratio": 1.0522088353410486
},
"competitor": {
- "minMs": 2.3699999999989814,
- "maxMs": 2.6199999999989814,
- "ratio": 1.105485232067556
+ "minMs": 2.4799999999995634,
+ "maxMs": 2.5599999999994907,
+ "ratio": 1.0322580645161055
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
"level",
- "competitor-leads"
+ "level"
]
}
}
@@ -1293,18 +1257,18 @@
{
"competitor": "excalibur",
"referenceMs": 0.07999999999992724,
- "referenceP95Ms": 0.13999999999941792,
+ "referenceP95Ms": 0.12000000000080036,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 0.6200000000026193,
+ "competitorMs": 0.6600000000034925,
"competitorP95Ms": 0.8799999999973807,
- "competitorGpuMs": 16.660000000003492,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.12903225806385366,
- "factor": 7.7500000000397895,
- "label": "ExoJS leads clearly (7.75x)",
+ "ratio": 0.12121212121136957,
+ "factor": 8.250000000051159,
+ "label": "ExoJS leads clearly (8.25x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1317,9 +1281,9 @@
"ratio": 1
},
"competitor": {
- "minMs": 0.6199999999989814,
- "maxMs": 0.6599999999998545,
- "ratio": 1.0645161290337724
+ "minMs": 0.6399999999994179,
+ "maxMs": 0.680000000000291,
+ "ratio": 1.062500000001421
},
"stable": true,
"rungs": [
@@ -1332,11 +1296,11 @@
{
"competitor": "phaser",
"referenceMs": 0.07999999999992724,
- "referenceP95Ms": 0.13999999999941792,
+ "referenceP95Ms": 0.12000000000080036,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
"competitorMs": 0.2600000000002183,
- "competitorP95Ms": 0.4600000000000364,
+ "competitorP95Ms": 0.44000000000005457,
"competitorGpuMs": 16.679999999999836,
"competitorOverFrameBudget": false,
"verdict": {
@@ -1356,9 +1320,9 @@
"ratio": 1
},
"competitor": {
- "minMs": 0.20000000001164153,
- "maxMs": 0.27999999999974534,
- "ratio": 1.399999999917236
+ "minMs": 0.2600000000002183,
+ "maxMs": 0.2999999999999545,
+ "ratio": 1.1538461538450102
},
"stable": true,
"rungs": [
@@ -1371,18 +1335,18 @@
{
"competitor": "pixi",
"referenceMs": 0.07999999999992724,
- "referenceP95Ms": 0.13999999999941792,
+ "referenceP95Ms": 0.12000000000080036,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
"competitorMs": 0.1000000000003638,
- "competitorP95Ms": 0.21999999999934516,
+ "competitorP95Ms": 0.2000000000007276,
"competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "exojs",
- "ratio": 0.7999999999963621,
- "factor": 1.2500000000056843,
- "label": "ExoJS leads (1.25x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1395,15 +1359,15 @@
"ratio": 1
},
"competitor": {
- "minMs": 0.1000000000003638,
+ "minMs": 0.09999999999854481,
"maxMs": 0.1000000000003638,
- "ratio": 1
+ "ratio": 1.00000000001819
},
- "stable": true,
+ "stable": false,
"rungs": [
"exojs-leads",
"exojs-leads",
- "exojs-leads"
+ "level"
]
}
}
@@ -1420,18 +1384,18 @@
{
"competitor": "excalibur",
"referenceMs": 1.4000000000014552,
- "referenceP95Ms": 1.819999999999709,
+ "referenceP95Ms": 1.7400000000016007,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 16.159999999999854,
- "competitorP95Ms": 17.919999999998254,
- "competitorGpuMs": 26.89999999999418,
+ "competitorMs": 16.60000000000582,
+ "competitorP95Ms": 19.18000000000029,
+ "competitorGpuMs": 27.080000000001746,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.08663366336642746,
- "factor": 11.542857142845042,
- "label": "ExoJS leads clearly (11.54x)",
+ "ratio": 0.08433734939764845,
+ "factor": 11.85714285713469,
+ "label": "ExoJS leads clearly (11.86x)",
"structural": true
},
"mechanism": "ExoJS issues fewer buffer uploads (0 vs 313 per frame)",
@@ -1439,14 +1403,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.3799999999991996,
- "maxMs": 1.4099999999998545,
- "ratio": 1.0217391304352696
+ "minMs": 1.3700000000008004,
+ "maxMs": 1.4200000000000728,
+ "ratio": 1.0364963503644111
},
"competitor": {
- "minMs": 15.869999999998981,
- "maxMs": 19.55000000000291,
- "ratio": 1.2318840579712769
+ "minMs": 15.959999999999127,
+ "maxMs": 19.349999999998545,
+ "ratio": 1.212406015037569
},
"stable": true,
"rungs": [
@@ -1459,18 +1423,18 @@
{
"competitor": "phaser",
"referenceMs": 1.4000000000014552,
- "referenceP95Ms": 1.819999999999709,
+ "referenceP95Ms": 1.7400000000016007,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 2.8899999999998727,
- "competitorP95Ms": 6.819999999999709,
+ "competitorMs": 3.019999999999527,
+ "competitorP95Ms": 4.5600000000004,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.48442906574446953,
- "factor": 2.0642857142834776,
- "label": "ExoJS leads (2.06x)",
+ "ratio": 0.4635761589409518,
+ "factor": 2.1571428571402773,
+ "label": "ExoJS leads (2.16x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 313/5000/0 vs 313/5000/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1478,14 +1442,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.3799999999991996,
- "maxMs": 1.4099999999998545,
- "ratio": 1.0217391304352696
+ "minMs": 1.3700000000008004,
+ "maxMs": 1.4200000000000728,
+ "ratio": 1.0364963503644111
},
"competitor": {
- "minMs": 2.7800000000002,
- "maxMs": 3,
- "ratio": 1.0791366906474043
+ "minMs": 2.7799999999997453,
+ "maxMs": 3.0599999999994907,
+ "ratio": 1.1007194244603493
},
"stable": true,
"rungs": [
@@ -1498,18 +1462,18 @@
{
"competitor": "pixi",
"referenceMs": 1.4000000000014552,
- "referenceP95Ms": 1.819999999999709,
+ "referenceP95Ms": 1.7400000000016007,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 1.180000000000291,
- "competitorP95Ms": 2,
+ "competitorMs": 1.2599999999983993,
+ "competitorP95Ms": 2.0599999999994907,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 1.1111111111136776,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 313/5000/0 vs 313/5000/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1517,20 +1481,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.3799999999991996,
- "maxMs": 1.4099999999998545,
- "ratio": 1.0217391304352696
+ "minMs": 1.3700000000008004,
+ "maxMs": 1.4200000000000728,
+ "ratio": 1.0364963503644111
},
"competitor": {
- "minMs": 1.139999999999418,
- "maxMs": 1.4799999999995634,
- "ratio": 1.2982456140353678
+ "minMs": 1.1499999999996362,
+ "maxMs": 1.2799999999997453,
+ "ratio": 1.1130434782610001
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
"level",
- "competitor-leads"
+ "level"
]
}
}
@@ -1546,19 +1510,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.4599999999991269,
- "referenceP95Ms": 0.7399999999979627,
+ "referenceMs": 0.47000000000116415,
+ "referenceP95Ms": 0.7200000000011642,
"referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 9.779999999995198,
- "competitorP95Ms": 12.940000000002328,
+ "competitorMs": 9.659999999999854,
+ "competitorP95Ms": 13.940000000002328,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.04703476482610969,
- "factor": 21.260869565247308,
- "label": "ExoJS leads clearly (21.26x)",
+ "ratio": 0.04865424430653947,
+ "factor": 20.553191489310482,
+ "label": "ExoJS leads clearly (20.55x)",
"structural": true
},
"mechanism": "competitor issues fewer draw calls (120 vs 1 per frame)",
@@ -1566,14 +1530,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.38000000000101863,
- "maxMs": 0.5400000000008731,
- "ratio": 1.4210526315774357
+ "minMs": 0.4599999999991269,
+ "maxMs": 0.4900000000016007,
+ "ratio": 1.0652173913098495
},
"competitor": {
- "minMs": 9.590000000000146,
- "maxMs": 9.909999999996217,
- "ratio": 1.0333680917618422
+ "minMs": 9.600000000002183,
+ "maxMs": 9.860000000000582,
+ "ratio": 1.0270833333331604
},
"stable": true,
"rungs": [
@@ -1585,58 +1549,58 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.4599999999991269,
- "referenceP95Ms": 0.7399999999979627,
+ "referenceMs": 0.47000000000116415,
+ "referenceP95Ms": 0.7200000000011642,
"referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 2.6699999999982538,
- "competitorP95Ms": 4.859999999999673,
- "competitorGpuMs": 16.660000000003492,
+ "competitorMs": 2.5399999999999636,
+ "competitorP95Ms": 4.579999999999927,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
- "structural": false
+ "side": "exojs",
+ "ratio": 0.18503937007920113,
+ "factor": 5.404255319135473,
+ "label": "ExoJS leads clearly (5.40x)",
+ "structural": true
},
"mechanism": "competitor issues fewer draw calls (120 vs 1 per frame)",
"timer": "resolved",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.38000000000101863,
- "maxMs": 0.5400000000008731,
- "ratio": 1.4210526315774357
+ "minMs": 0.4599999999991269,
+ "maxMs": 0.4900000000016007,
+ "ratio": 1.0652173913098495
},
"competitor": {
- "minMs": 2.6299999999996544,
- "maxMs": 2.6700000000000728,
- "ratio": 1.0152091254754463
+ "minMs": 2.5399999999999636,
+ "maxMs": 2.6400000000003274,
+ "ratio": 1.0393700787403013
},
- "stable": false,
+ "stable": true,
"rungs": [
"exojs-leads-clearly",
"exojs-leads-clearly",
- "exojs-leads"
+ "exojs-leads-clearly"
]
}
},
{
"competitor": "pixi",
- "referenceMs": 0.4599999999991269,
- "referenceP95Ms": 0.7399999999979627,
+ "referenceMs": 0.47000000000116415,
+ "referenceP95Ms": 0.7200000000011642,
"referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
"competitorMs": 0.31999999999970896,
- "competitorP95Ms": 0.4400000000023283,
- "competitorGpuMs": 16.679999999996653,
+ "competitorP95Ms": 0.4399999999986903,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "competitor",
+ "ratio": 1.4687500000049738,
+ "factor": 1.4687500000049738,
+ "label": "competitor leads (1.47x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 120/0/0 vs 158/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1644,19 +1608,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.38000000000101863,
- "maxMs": 0.5400000000008731,
- "ratio": 1.4210526315774357
+ "minMs": 0.4599999999991269,
+ "maxMs": 0.4900000000016007,
+ "ratio": 1.0652173913098495
},
"competitor": {
- "minMs": 0.3000000000029104,
+ "minMs": 0.2999999999992724,
"maxMs": 0.31999999999970896,
- "ratio": 1.0666666666553486
+ "ratio": 1.0666666666682836
},
- "stable": false,
+ "stable": true,
"rungs": [
"competitor-leads",
- "level",
+ "competitor-leads",
"competitor-leads"
]
}
@@ -1680,17 +1644,17 @@
"competitor": "excalibur",
"referenceMs": 0.08000000000174623,
"referenceP95Ms": 0.12000000000261934,
- "referenceGpuMs": 16.679999999996653,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 9.659999999999854,
- "competitorP95Ms": 14.37999999999738,
+ "competitorMs": 10.299999999999272,
+ "competitorP95Ms": 14.340000000003783,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.008281573499145697,
- "factor": 120.74999999736247,
- "label": "ExoJS leads clearly (120.75x)",
+ "ratio": 0.007766990291432222,
+ "factor": 128.74999999718057,
+ "label": "ExoJS leads clearly (128.75x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 2/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1698,14 +1662,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.08000000000174623,
+ "minMs": 0.07999999999810825,
"maxMs": 0.08000000000174623,
- "ratio": 1
+ "ratio": 1.0000000000454747
},
"competitor": {
- "minMs": 9.650000000001455,
- "maxMs": 10.049999999999272,
- "ratio": 1.04145077720184
+ "minMs": 9.930000000003929,
+ "maxMs": 10.350000000002183,
+ "ratio": 1.0422960725073602
},
"stable": true,
"rungs": [
@@ -1719,17 +1683,17 @@
"competitor": "phaser",
"referenceMs": 0.08000000000174623,
"referenceP95Ms": 0.12000000000261934,
- "referenceGpuMs": 16.679999999996653,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 2.600000000000364,
- "competitorP95Ms": 4.059999999997672,
- "competitorGpuMs": 16.68000000000029,
+ "competitorMs": 2.7599999999997635,
+ "competitorP95Ms": 4.899999999999636,
+ "competitorGpuMs": 16.679999999998472,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.03076923076989809,
- "factor": 32.49999999929514,
- "label": "ExoJS leads clearly (32.50x)",
+ "ratio": 0.028985507247011988,
+ "factor": 34.49999999924398,
+ "label": "ExoJS leads clearly (34.50x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 2/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1737,14 +1701,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.08000000000174623,
+ "minMs": 0.07999999999810825,
"maxMs": 0.08000000000174623,
- "ratio": 1
+ "ratio": 1.0000000000454747
},
"competitor": {
- "minMs": 2.4399999999996,
- "maxMs": 2.889999999992142,
- "ratio": 1.1844262295051704
+ "minMs": 2.5799999999999272,
+ "maxMs": 2.889999999999418,
+ "ratio": 1.1201550387594958
},
"stable": true,
"rungs": [
@@ -1758,17 +1722,17 @@
"competitor": "pixi",
"referenceMs": 0.08000000000174623,
"referenceP95Ms": 0.12000000000261934,
- "referenceGpuMs": 16.679999999996653,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
"competitorMs": 0.09999999999854481,
- "competitorP95Ms": 0.18000000000029104,
- "competitorGpuMs": 16.68000000000029,
+ "competitorP95Ms": 0.19999999999708962,
+ "competitorGpuMs": 16.679999999996653,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.8000000000291039,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 2/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1776,18 +1740,18 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.08000000000174623,
+ "minMs": 0.07999999999810825,
"maxMs": 0.08000000000174623,
- "ratio": 1
+ "ratio": 1.0000000000454747
},
"competitor": {
"minMs": 0.08000000000174623,
"maxMs": 0.09999999999854481,
"ratio": 1.2499999999545253
},
- "stable": true,
+ "stable": false,
"rungs": [
- "level",
+ "exojs-leads",
"level",
"level"
]
@@ -1810,19 +1774,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.10000000000218279,
- "referenceP95Ms": 0.22000000000116415,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 0.09999999999854481,
+ "referenceP95Ms": 0.2000000000007276,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 6.619999999995343,
- "competitorP95Ms": 9.440000000002328,
+ "competitorMs": 6.540000000004511,
+ "competitorP95Ms": 8.700000000004366,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.015105740181609234,
- "factor": 66.19999999850843,
- "label": "ExoJS leads clearly (66.20x)",
+ "ratio": 0.015290519877442788,
+ "factor": 65.40000000099681,
+ "label": "ExoJS leads clearly (65.40x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1835,9 +1799,9 @@
"ratio": 1.0000000000363798
},
"competitor": {
- "minMs": 6.580000000001746,
- "maxMs": 6.700000000000728,
- "ratio": 1.0182370820667097
+ "minMs": 6.389999999999418,
+ "maxMs": 6.809999999997672,
+ "ratio": 1.0657276995302492
},
"stable": true,
"rungs": [
@@ -1849,19 +1813,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.10000000000218279,
- "referenceP95Ms": 0.22000000000116415,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 0.09999999999854481,
+ "referenceP95Ms": 0.2000000000007276,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 2.970000000001164,
- "competitorP95Ms": 4.220000000001164,
- "competitorGpuMs": 16.660000000003492,
+ "competitorMs": 2.899999999999636,
+ "competitorP95Ms": 4.040000000000873,
+ "competitorGpuMs": 16.660000000001673,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.03367003367075542,
- "factor": 29.699999999363353,
- "label": "ExoJS leads clearly (29.70x)",
+ "ratio": 0.03448275862019219,
+ "factor": 29.000000000418368,
+ "label": "ExoJS leads clearly (29.00x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1874,9 +1838,9 @@
"ratio": 1.0000000000363798
},
"competitor": {
- "minMs": 2.8599999999996726,
- "maxMs": 3.039999999999054,
- "ratio": 1.062937062936854
+ "minMs": 2.880000000000109,
+ "maxMs": 3.0599999999994907,
+ "ratio": 1.0624999999997828
},
"stable": true,
"rungs": [
@@ -1888,19 +1852,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.10000000000218279,
- "referenceP95Ms": 0.22000000000116415,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 0.09999999999854481,
+ "referenceP95Ms": 0.2000000000007276,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.09999999999854481,
- "competitorP95Ms": 0.21999999999752617,
- "competitorGpuMs": 16.68000000000029,
+ "competitorMs": 0.10000000000218279,
+ "competitorP95Ms": 0.2000000000007276,
+ "competitorGpuMs": 16.679999999996653,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.0000000000363798,
- "factor": 1,
- "label": "level",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1913,14 +1877,14 @@
"ratio": 1.0000000000363798
},
"competitor": {
- "minMs": 0.09999999999854481,
- "maxMs": 0.09999999999854481,
- "ratio": 1
+ "minMs": 0.08000000000174623,
+ "maxMs": 0.10000000000218279,
+ "ratio": 1.25
},
- "stable": true,
+ "stable": false,
"rungs": [
"level",
- "level",
+ "competitor-leads",
"level"
]
}
@@ -1937,19 +1901,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 0.08000000000174623,
- "referenceP95Ms": 0.15999999999985448,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 0.09000000000014552,
+ "referenceP95Ms": 0.18000000000029104,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 33.390000000003056,
- "competitorP95Ms": 38.18000000000029,
- "competitorGpuMs": 34.63999999999942,
+ "competitorMs": 33,
+ "competitorP95Ms": 36.900000000001455,
+ "competitorGpuMs": 34.62000000000262,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.0023959269242808897,
- "factor": 417.3749999909278,
- "label": "ExoJS leads clearly (417.37x)",
+ "ratio": 0.002727272727277137,
+ "factor": 366.6666666660738,
+ "label": "ExoJS leads clearly (366.67x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 3/4/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1957,14 +1921,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.08000000000174623,
+ "minMs": 0.09000000000014552,
"maxMs": 0.09999999999854481,
- "ratio": 1.2499999999545253
+ "ratio": 1.1111111110931458
},
"competitor": {
- "minMs": 32.85000000000218,
- "maxMs": 33.43000000000029,
- "ratio": 1.0176560121765013
+ "minMs": 32.11000000000058,
+ "maxMs": 33.44999999999709,
+ "ratio": 1.0417315478043128
},
"stable": true,
"rungs": [
@@ -1976,19 +1940,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 0.08000000000174623,
- "referenceP95Ms": 0.15999999999985448,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 0.09000000000014552,
+ "referenceP95Ms": 0.18000000000029104,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 6.8400000000037835,
- "competitorP95Ms": 7.959999999999127,
+ "competitorMs": 6.469999999999345,
+ "competitorP95Ms": 8,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.011695906432997366,
- "factor": 85.49999999818101,
- "label": "ExoJS leads clearly (85.50x)",
+ "ratio": 0.013910355486886341,
+ "factor": 71.88888888876538,
+ "label": "ExoJS leads clearly (71.89x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/0 vs 4/0/4, none of them large enough to account for the gap); the difference is CPU-side",
@@ -1996,14 +1960,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.08000000000174623,
+ "minMs": 0.09000000000014552,
"maxMs": 0.09999999999854481,
- "ratio": 1.2499999999545253
+ "ratio": 1.1111111110931458
},
"competitor": {
- "minMs": 6.5,
- "maxMs": 6.899999999999636,
- "ratio": 1.0615384615384056
+ "minMs": 6.440000000000509,
+ "maxMs": 6.619999999998981,
+ "ratio": 1.0279503105587668
},
"stable": true,
"rungs": [
@@ -2015,17 +1979,17 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.08000000000174623,
- "referenceP95Ms": 0.15999999999985448,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 0.09000000000014552,
+ "referenceP95Ms": 0.18000000000029104,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
"competitorMs": 0.09999999999854481,
"competitorP95Ms": 0.2000000000007276,
- "competitorGpuMs": 16.68000000000029,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.8000000000291039,
+ "ratio": 0.9000000000145519,
"factor": 1,
"label": "level",
"structural": false
@@ -2035,14 +1999,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.08000000000174623,
+ "minMs": 0.09000000000014552,
"maxMs": 0.09999999999854481,
- "ratio": 1.2499999999545253
+ "ratio": 1.1111111110931458
},
"competitor": {
"minMs": 0.09999999999854481,
- "maxMs": 0.10000000000218279,
- "ratio": 1.0000000000363798
+ "maxMs": 0.09999999999854481,
+ "ratio": 1
},
"stable": true,
"rungs": [
@@ -2064,19 +2028,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 2.5900000000019645,
- "referenceP95Ms": 6.400000000001455,
+ "referenceMs": 2.5799999999999272,
+ "referenceP95Ms": 5.259999999998399,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 7.130000000001019,
- "competitorP95Ms": 9.660000000003492,
+ "competitorMs": 6.729999999999563,
+ "competitorP95Ms": 9.159999999996217,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.3632538569427201,
- "factor": 2.7528957528940583,
- "label": "ExoJS leads (2.75x)",
+ "ratio": 0.38335809806836474,
+ "factor": 2.60852713178285,
+ "label": "ExoJS leads (2.61x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2084,14 +2048,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.460000000000946,
- "maxMs": 2.640000000001237,
- "ratio": 1.0731707317074073
+ "minMs": 2.5200000000004366,
+ "maxMs": 2.7000000000007276,
+ "ratio": 1.0714285714286746
},
"competitor": {
- "minMs": 7.120000000002619,
- "maxMs": 7.5900000000001455,
- "ratio": 1.0660112359546845
+ "minMs": 5.6599999999962165,
+ "maxMs": 7.030000000002474,
+ "ratio": 1.2420494699659317
},
"stable": true,
"rungs": [
@@ -2103,19 +2067,19 @@
},
{
"competitor": "phaser",
- "referenceMs": 2.5900000000019645,
- "referenceP95Ms": 6.400000000001455,
+ "referenceMs": 2.5799999999999272,
+ "referenceP95Ms": 5.259999999998399,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 3.0600000000004,
- "competitorP95Ms": 4.960000000006403,
- "competitorGpuMs": 16.659999999999854,
+ "competitorMs": 2.980000000000473,
+ "competitorP95Ms": 5.239999999999782,
+ "competitorGpuMs": 16.679999999998472,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 0.8657718120803751,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2123,18 +2087,18 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.460000000000946,
- "maxMs": 2.640000000001237,
- "ratio": 1.0731707317074073
+ "minMs": 2.5200000000004366,
+ "maxMs": 2.7000000000007276,
+ "ratio": 1.0714285714286746
},
"competitor": {
- "minMs": 3.030000000000655,
- "maxMs": 3.210000000006403,
- "ratio": 1.0594059405959435
+ "minMs": 2.9799999999995634,
+ "maxMs": 3.0100000000002183,
+ "ratio": 1.010067114094181
},
- "stable": false,
+ "stable": true,
"rungs": [
- "exojs-leads",
+ "level",
"level",
"level"
]
@@ -2142,19 +2106,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 2.5900000000019645,
- "referenceP95Ms": 6.400000000001455,
+ "referenceMs": 2.5799999999999272,
+ "referenceP95Ms": 5.259999999998399,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 4.450000000000728,
- "competitorP95Ms": 6,
+ "competitorMs": 4.259999999998399,
+ "competitorP95Ms": 5.899999999997817,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5820224719104586,
- "factor": 1.718146718145696,
- "label": "ExoJS leads (1.72x)",
+ "ratio": 0.6056338028171119,
+ "factor": 1.6511627906971007,
+ "label": "ExoJS leads (1.65x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 1/0/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2162,14 +2126,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.460000000000946,
- "maxMs": 2.640000000001237,
- "ratio": 1.0731707317074073
+ "minMs": 2.5200000000004366,
+ "maxMs": 2.7000000000007276,
+ "ratio": 1.0714285714286746
},
"competitor": {
- "minMs": 4.3700000000008,
- "maxMs": 4.459999999999127,
- "ratio": 1.0205949656746705
+ "minMs": 4.170000000000073,
+ "maxMs": 4.479999999999563,
+ "ratio": 1.0743405275778142
},
"stable": true,
"rungs": [
@@ -2191,19 +2155,19 @@
"cells": [
{
"competitor": "excalibur",
- "referenceMs": 7.4099999999980355,
- "referenceP95Ms": 8.840000000000146,
+ "referenceMs": 7.210000000000946,
+ "referenceP95Ms": 9.400000000001455,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 34.94999999999709,
- "competitorP95Ms": 39.4800000000032,
- "competitorGpuMs": 36.419999999998254,
+ "competitorMs": 32.25999999999476,
+ "competitorP95Ms": 39.5199999999968,
+ "competitorGpuMs": 33.76000000000931,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.21201716738193568,
- "factor": 4.716599190284259,
- "label": "ExoJS leads (4.72x)",
+ "ratio": 0.22349659020465334,
+ "factor": 4.474341192786481,
+ "label": "ExoJS leads (4.47x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 3/4/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2211,14 +2175,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 7.099999999998545,
- "maxMs": 7.469999999999345,
- "ratio": 1.0521126760564614
+ "minMs": 7.039999999999054,
+ "maxMs": 7.280000000000655,
+ "ratio": 1.034090909091141
},
"competitor": {
- "minMs": 34.22999999999956,
- "maxMs": 36.279999999998836,
- "ratio": 1.059888986269334
+ "minMs": 28.43000000000393,
+ "maxMs": 34.93000000000029,
+ "ratio": 1.2286317270487324
},
"stable": true,
"rungs": [
@@ -2230,17 +2194,17 @@
},
{
"competitor": "phaser",
- "referenceMs": 7.4099999999980355,
- "referenceP95Ms": 8.840000000000146,
+ "referenceMs": 7.210000000000946,
+ "referenceP95Ms": 9.400000000001455,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 6.9399999999996,
- "competitorP95Ms": 8.220000000001164,
+ "competitorMs": 6.579999999999927,
+ "competitorP95Ms": 8.1200000000008,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.0677233429392599,
+ "ratio": 1.0957446808512197,
"factor": 1,
"label": "level",
"structural": false
@@ -2250,14 +2214,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 7.099999999998545,
- "maxMs": 7.469999999999345,
- "ratio": 1.0521126760564614
+ "minMs": 7.039999999999054,
+ "maxMs": 7.280000000000655,
+ "ratio": 1.034090909091141
},
"competitor": {
- "minMs": 6.930000000007567,
- "maxMs": 7.050000000000182,
- "ratio": 1.0173160173149327
+ "minMs": 6.509999999999309,
+ "maxMs": 6.9099999999998545,
+ "ratio": 1.0614439324117646
},
"stable": true,
"rungs": [
@@ -2269,19 +2233,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 7.4099999999980355,
- "referenceP95Ms": 8.840000000000146,
+ "referenceMs": 7.210000000000946,
+ "referenceP95Ms": 9.400000000001455,
"referenceGpuMs": 16.659999999999854,
"referenceOverFrameBudget": false,
- "competitorMs": 18.779999999998836,
- "competitorP95Ms": 22.600000000002183,
- "competitorGpuMs": 20.860000000000582,
+ "competitorMs": 18.7400000000016,
+ "competitorP95Ms": 21.780000000002474,
+ "competitorGpuMs": 20.279999999998836,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.3945686900957665,
- "factor": 2.534412955466102,
- "label": "ExoJS leads (2.53x)",
+ "ratio": 0.384738527214532,
+ "factor": 2.5991678224686745,
+ "label": "ExoJS leads (2.60x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/3 vs 1/0/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2289,14 +2253,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 7.099999999998545,
- "maxMs": 7.469999999999345,
- "ratio": 1.0521126760564614
+ "minMs": 7.039999999999054,
+ "maxMs": 7.280000000000655,
+ "ratio": 1.034090909091141
},
"competitor": {
- "minMs": 18.770000000002256,
- "maxMs": 18.93999999999869,
- "ratio": 1.0090570058602246
+ "minMs": 18.530000000002474,
+ "maxMs": 18.920000000000073,
+ "ratio": 1.0210469508903155
},
"stable": true,
"rungs": [
@@ -2323,19 +2287,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.37999999999919964,
- "referenceP95Ms": 0.680000000000291,
- "referenceGpuMs": 16.659999999999854,
+ "referenceMs": 0.3999999999978172,
+ "referenceP95Ms": 0.6999999999970896,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 2.039999999999054,
- "competitorP95Ms": 3.959999999999127,
- "competitorGpuMs": 16.659999999999854,
+ "competitorMs": 2.2299999999977445,
+ "competitorP95Ms": 3.819999999999709,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.1862745098036156,
- "factor": 5.3684210526403975,
- "label": "ExoJS leads clearly (5.37x)",
+ "ratio": 0.17937219730861964,
+ "factor": 5.575000000024784,
+ "label": "ExoJS leads clearly (5.58x)",
"structural": true
},
"mechanism": "competitor issues fewer texture binds (9 vs 3 per frame)",
@@ -2343,14 +2307,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.36999999999898137,
- "maxMs": 0.38000000000101863,
- "ratio": 1.0270270270326076
+ "minMs": 0.3499999999985448,
+ "maxMs": 0.41999999999825377,
+ "ratio": 1.2
},
"competitor": {
- "minMs": 2.0100000000002183,
- "maxMs": 2.0900000000001455,
- "ratio": 1.039800995024835
+ "minMs": 2.210000000000946,
+ "maxMs": 2.25,
+ "ratio": 1.0180995475108765
},
"stable": true,
"rungs": [
@@ -2372,19 +2336,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.3100000000013097,
- "referenceP95Ms": 0.5,
- "referenceGpuMs": 16.68000000000029,
+ "referenceMs": 0.3000000000029104,
+ "referenceP95Ms": 0.5199999999967986,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 2.4099999999998545,
- "competitorP95Ms": 4.580000000001746,
- "competitorGpuMs": 16.660000000003492,
+ "competitorMs": 2.3400000000001455,
+ "competitorP95Ms": 4.639999999999418,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.12863070539474208,
- "factor": 7.774193548353782,
- "label": "ExoJS leads clearly (7.77x)",
+ "ratio": 0.12820512820636398,
+ "factor": 7.7999999999248155,
+ "label": "ExoJS leads clearly (7.80x)",
"structural": true
},
"mechanism": "competitor issues fewer texture binds (11 vs 3 per frame)",
@@ -2397,9 +2361,9 @@
"ratio": 1.0666666666553486
},
"competitor": {
- "minMs": 2.349999999998545,
- "maxMs": 2.640000000003056,
- "ratio": 1.123404255321145
+ "minMs": 2.2399999999997817,
+ "maxMs": 2.540000000002692,
+ "ratio": 1.1339285714298837
},
"stable": true,
"rungs": [
@@ -2421,19 +2385,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.2999999999992724,
+ "referenceMs": 0.2800000000061118,
"referenceP95Ms": 0.4599999999991269,
- "referenceGpuMs": 16.68000000000029,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 2.7600000000020373,
- "competitorP95Ms": 4.440000000002328,
- "competitorGpuMs": 16.660000000003492,
+ "competitorMs": 2.5099999999983993,
+ "competitorP95Ms": 4.540000000000873,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.10869565217356919,
- "factor": 9.200000000029103,
- "label": "ExoJS leads clearly (9.20x)",
+ "ratio": 0.11155378486306389,
+ "factor": 8.964285714084326,
+ "label": "ExoJS leads clearly (8.96x)",
"structural": true
},
"mechanism": "competitor issues fewer texture binds (15 vs 7 per frame)",
@@ -2441,14 +2405,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.26000000000203727,
- "maxMs": 0.31999999999970896,
- "ratio": 1.2307692307584674
+ "minMs": 0.2800000000024738,
+ "maxMs": 0.3100000000013097,
+ "ratio": 1.1071428571377528
},
"competitor": {
- "minMs": 2.399999999997817,
- "maxMs": 2.959999999999127,
- "ratio": 1.2333333333340912
+ "minMs": 2.4199999999982538,
+ "maxMs": 2.529999999998836,
+ "ratio": 1.0454545454548188
},
"stable": true,
"rungs": [
@@ -2470,19 +2434,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.3400000000037835,
- "referenceP95Ms": 0.5600000000049477,
- "referenceGpuMs": 16.660000000003492,
+ "referenceMs": 0.31999999999970896,
+ "referenceP95Ms": 0.5200000000040745,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 0.4599999999991269,
- "competitorP95Ms": 0.7600000000020373,
+ "competitorMs": 0.47000000000116415,
+ "competitorP95Ms": 0.6999999999970896,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "exojs",
+ "ratio": 0.6808510638274816,
+ "factor": 1.4687500000049738,
+ "label": "ExoJS leads (1.47x)",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (5 vs 8 per frame)",
@@ -2490,20 +2454,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.31999999999970896,
- "maxMs": 0.3599999999933061,
- "ratio": 1.1249999999801048
+ "minMs": 0.3099999999976717,
+ "maxMs": 0.3400000000001455,
+ "ratio": 1.096774193557094
},
"competitor": {
- "minMs": 0.42000000000552973,
- "maxMs": 0.5599999999976717,
- "ratio": 1.333333333310235
+ "minMs": 0.4400000000023283,
+ "maxMs": 0.47000000000116415,
+ "ratio": 1.0681818181788116
},
- "stable": false,
+ "stable": true,
"rungs": [
"exojs-leads",
"exojs-leads",
- "level"
+ "exojs-leads"
]
}
}
@@ -2519,19 +2483,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.2400000000052387,
- "referenceP95Ms": 0.43999999999505235,
+ "referenceMs": 0.2599999999983993,
+ "referenceP95Ms": 0.4400000000023283,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.16000000000349246,
- "competitorP95Ms": 0.26000000000203727,
+ "competitorMs": 0.13999999999941792,
+ "competitorP95Ms": 0.27999999999883585,
"competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.5,
- "factor": 1.5,
- "label": "competitor leads (1.50x)",
+ "ratio": 1.8571428571391448,
+ "factor": 1.8571428571391448,
+ "label": "competitor leads (1.86x)",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (4 vs 10 per frame)",
@@ -2539,14 +2503,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.23999999999796273,
- "maxMs": 0.25,
- "ratio": 1.041666666675509
+ "minMs": 0.22000000000116415,
+ "maxMs": 0.26000000000203727,
+ "ratio": 1.1818181818211884
},
"competitor": {
"minMs": 0.13999999999941792,
- "maxMs": 0.16000000000349246,
- "ratio": 1.1428571428868406
+ "maxMs": 0.1599999999962165,
+ "ratio": 1.1428571428348695
},
"stable": true,
"rungs": [
@@ -2558,6 +2522,56 @@
}
]
},
+ {
+ "archetype": "fx-blur",
+ "category": "Render targets",
+ "count": 720,
+ "loadId": "720",
+ "unit": "viewport",
+ "primary": true,
+ "label": "1280 x 720",
+ "cells": [
+ {
+ "competitor": "pixi",
+ "referenceMs": 0.2800000000061118,
+ "referenceP95Ms": 0.4800000000032014,
+ "referenceGpuMs": 16.68000000000029,
+ "referenceOverFrameBudget": false,
+ "competitorMs": 0.26000000000203727,
+ "competitorP95Ms": 0.4599999999991269,
+ "competitorGpuMs": 16.68000000000029,
+ "competitorOverFrameBudget": false,
+ "verdict": {
+ "side": "neither",
+ "ratio": 1.0769230769381455,
+ "factor": 1,
+ "label": "level",
+ "structural": false
+ },
+ "mechanism": "competitor issues fewer texture binds (11 vs 3 per frame)",
+ "timer": "resolved",
+ "aggregate": {
+ "runs": 3,
+ "reference": {
+ "minMs": 0.27999999999883585,
+ "maxMs": 0.2800000000061118,
+ "ratio": 1.0000000000259857
+ },
+ "competitor": {
+ "minMs": 0.26000000000203727,
+ "maxMs": 0.26000000000203727,
+ "ratio": 1
+ },
+ "stable": true,
+ "rungs": [
+ "level",
+ "level",
+ "level"
+ ]
+ }
+ }
+ ]
+ },
{
"archetype": "mask-clip-animated",
"category": "Render targets",
@@ -2568,19 +2582,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.26000000000203727,
- "referenceP95Ms": 0.4400000000023283,
+ "referenceMs": 0.2800000000024738,
+ "referenceP95Ms": 0.4800000000032014,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.4000000000014552,
+ "competitorMs": 0.38000000000101863,
"competitorP95Ms": 0.5800000000017462,
- "competitorGpuMs": 16.68000000000029,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.6500000000027285,
- "factor": 1.5384615384550804,
- "label": "ExoJS leads (1.54x)",
+ "ratio": 0.7368421052676928,
+ "factor": 1.3571428571345046,
+ "label": "ExoJS leads (1.36x)",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (4 vs 10 per frame)",
@@ -2588,14 +2602,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2400000000016007,
- "maxMs": 0.27999999999883585,
- "ratio": 1.1666666666540348
+ "minMs": 0.27000000000043656,
+ "maxMs": 0.2999999999956344,
+ "ratio": 1.1111111110931458
},
"competitor": {
- "minMs": 0.3900000000030559,
+ "minMs": 0.37999999999738066,
"maxMs": 0.4000000000014552,
- "ratio": 1.0256410256367203
+ "ratio": 1.0526315789584537
},
"stable": true,
"rungs": [
@@ -2623,12 +2637,12 @@
{
"competitor": "pixi",
"referenceMs": 0.18000000000029104,
- "referenceP95Ms": 1.6000000000021828,
- "referenceGpuMs": 16.679999999996653,
+ "referenceP95Ms": 1.4600000000027649,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
"competitorMs": 0.11000000000058208,
"competitorP95Ms": 0.22000000000116415,
- "competitorGpuMs": 16.679999999996653,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
@@ -2642,14 +2656,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.17999999999847205,
- "maxMs": 0.18000000000029104,
- "ratio": 1.0000000000101055
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.2000000000007276,
+ "ratio": 1.1111111111133567
},
"competitor": {
- "minMs": 0.10000000000218279,
+ "minMs": 0.1000000000003638,
"maxMs": 0.11999999999898137,
- "ratio": 1.1999999999636202
+ "ratio": 1.199999999985448
},
"stable": true,
"rungs": [
@@ -2674,54 +2688,15 @@
"unit": "tiles",
"primary": false,
"cells": [
- {
- "competitor": "excalibur",
- "referenceMs": 0.18000000000029104,
- "referenceP95Ms": 1.1600000000034925,
- "referenceGpuMs": 16.660000000003492,
- "referenceOverFrameBudget": false,
- "competitorMs": 20.810000000004948,
- "competitorP95Ms": 25.90000000000873,
- "competitorGpuMs": 22,
- "competitorOverFrameBudget": true,
- "verdict": {
- "side": "exojs",
- "ratio": 0.008649687650180118,
- "factor": 115.61111111095167,
- "label": "ExoJS leads clearly (115.61x)",
- "structural": true
- },
- "mechanism": "competitor issues fewer draw calls (90 vs 1 per frame)",
- "timer": "limited",
- "aggregate": {
- "runs": 3,
- "reference": {
- "minMs": 0.18000000000029104,
- "maxMs": 0.20000000000436557,
- "ratio": 1.1111111111335679
- },
- "competitor": {
- "minMs": 20.580000000001746,
- "maxMs": 21.060000000004948,
- "ratio": 1.0233236151605034
- },
- "stable": true,
- "rungs": [
- "exojs-leads-clearly",
- "exojs-leads-clearly",
- "exojs-leads-clearly"
- ]
- }
- },
{
"competitor": "phaser",
"referenceMs": 0.18000000000029104,
- "referenceP95Ms": 1.1600000000034925,
+ "referenceP95Ms": 1.1999999999970896,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
"competitorMs": 0.2000000000007276,
- "competitorP95Ms": 0.42000000000189175,
- "competitorGpuMs": 16.659999999999854,
+ "competitorP95Ms": 0.3999999999978172,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -2736,13 +2711,13 @@
"runs": 3,
"reference": {
"minMs": 0.18000000000029104,
- "maxMs": 0.20000000000436557,
- "ratio": 1.1111111111335679
+ "maxMs": 0.19999999999708962,
+ "ratio": 1.1111111110931458
},
"competitor": {
- "minMs": 0.1999999999989086,
- "maxMs": 0.20999999999912689,
- "ratio": 1.0500000000013643
+ "minMs": 0.2000000000007276,
+ "maxMs": 0.22000000000116415,
+ "ratio": 1.100000000001819
},
"stable": true,
"rungs": [
@@ -2755,12 +2730,12 @@
{
"competitor": "pixi",
"referenceMs": 0.18000000000029104,
- "referenceP95Ms": 1.1600000000034925,
+ "referenceP95Ms": 1.1999999999970896,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
"competitorMs": 0.22000000000116415,
"competitorP95Ms": 0.37999999999738066,
- "competitorGpuMs": 16.68000000000029,
+ "competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -2775,13 +2750,13 @@
"runs": 3,
"reference": {
"minMs": 0.18000000000029104,
- "maxMs": 0.20000000000436557,
- "ratio": 1.1111111111335679
+ "maxMs": 0.19999999999708962,
+ "ratio": 1.1111111110931458
},
"competitor": {
- "minMs": 0.20000000000436557,
- "maxMs": 0.22000000000116415,
- "ratio": 1.0999999999818102
+ "minMs": 0.19999999999708962,
+ "maxMs": 0.23999999999796273,
+ "ratio": 1.200000000007276
},
"stable": true,
"rungs": [
@@ -2801,60 +2776,21 @@
"unit": "tiles",
"primary": true,
"cells": [
- {
- "competitor": "excalibur",
- "referenceMs": 0.13999999999941792,
- "referenceP95Ms": 0.7799999999988358,
- "referenceGpuMs": 16.660000000003492,
- "referenceOverFrameBudget": false,
- "competitorMs": 180.13999999999942,
- "competitorP95Ms": 189.39999999999418,
- "competitorGpuMs": 183.11999999999534,
- "competitorOverFrameBudget": true,
- "verdict": {
- "side": "exojs",
- "ratio": 0.0007771733096448227,
- "factor": 1286.7142857196313,
- "label": "ExoJS leads clearly (1286.71x)",
- "structural": true
- },
- "mechanism": "competitor issues fewer draw calls (30 vs 5 per frame)",
- "timer": "limited",
- "aggregate": {
- "runs": 3,
- "reference": {
- "minMs": 0.11999999999898137,
- "maxMs": 0.18000000000029104,
- "ratio": 1.5000000000151583
- },
- "competitor": {
- "minMs": 178.79000000000087,
- "maxMs": 182.29000000000087,
- "ratio": 1.0195760389283517
- },
- "stable": true,
- "rungs": [
- "exojs-leads-clearly",
- "exojs-leads-clearly",
- "exojs-leads-clearly"
- ]
- }
- },
{
"competitor": "phaser",
"referenceMs": 0.13999999999941792,
- "referenceP95Ms": 0.7799999999988358,
+ "referenceP95Ms": 0.819999999999709,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.16000000000349246,
- "competitorP95Ms": 0.38000000000101863,
- "competitorGpuMs": 16.700000000000728,
+ "competitorMs": 0.18000000000029104,
+ "competitorP95Ms": 0.2999999999992724,
+ "competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "exojs",
+ "ratio": 0.7777777777732865,
+ "factor": 1.28571428572171,
+ "label": "ExoJS leads (1.29x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (30 vs 1 per frame)",
@@ -2862,38 +2798,38 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.11999999999898137,
- "maxMs": 0.18000000000029104,
- "ratio": 1.5000000000151583
+ "minMs": 0.11999999999534339,
+ "maxMs": 0.13999999999941792,
+ "ratio": 1.1666666667070886
},
"competitor": {
- "minMs": 0.15999999999985448,
- "maxMs": 0.17000000000189175,
- "ratio": 1.0625000000127898
+ "minMs": 0.1499999999996362,
+ "maxMs": 0.18000000000029104,
+ "ratio": 1.2000000000048507
},
- "stable": false,
+ "stable": true,
"rungs": [
- "level",
"exojs-leads",
- "level"
+ "exojs-leads",
+ "exojs-leads"
]
}
},
{
"competitor": "pixi",
"referenceMs": 0.13999999999941792,
- "referenceP95Ms": 0.7799999999988358,
+ "referenceP95Ms": 0.819999999999709,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.22000000000116415,
+ "competitorMs": 0.18000000000029104,
"competitorP95Ms": 0.3600000000005821,
- "competitorGpuMs": 16.659999999996217,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "exojs",
+ "ratio": 0.7777777777732865,
+ "factor": 1.28571428572171,
+ "label": "ExoJS leads (1.29x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (30 vs 2 per frame)",
@@ -2901,20 +2837,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.11999999999898137,
- "maxMs": 0.18000000000029104,
- "ratio": 1.5000000000151583
+ "minMs": 0.11999999999534339,
+ "maxMs": 0.13999999999941792,
+ "ratio": 1.1666666667070886
},
"competitor": {
"minMs": 0.18000000000029104,
- "maxMs": 0.22000000000116415,
- "ratio": 1.2222222222267136
+ "maxMs": 0.21999999999752617,
+ "ratio": 1.2222222222065025
},
- "stable": false,
+ "stable": true,
"rungs": [
"exojs-leads",
"exojs-leads",
- "level"
+ "exojs-leads"
]
}
}
@@ -2930,19 +2866,19 @@
"cells": [
{
"competitor": "phaser",
- "referenceMs": 0.750000000003638,
+ "referenceMs": 0.6699999999982538,
"referenceP95Ms": 1.319999999999709,
- "referenceGpuMs": 16.659999999996217,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 1.8000000000010914,
- "competitorP95Ms": 6,
+ "competitorMs": 1.9600000000009459,
+ "competitorP95Ms": 6.520000000000437,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.4166666666684351,
- "factor": 2.399999999989814,
- "label": "ExoJS leads (2.40x)",
+ "ratio": 0.34183673469282166,
+ "factor": 2.925373134337394,
+ "label": "ExoJS leads (2.93x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/3/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2950,14 +2886,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.7000000000007276,
- "maxMs": 0.8100000000013097,
- "ratio": 1.1571428571435254
+ "minMs": 0.63999999999578,
+ "maxMs": 0.6899999999986903,
+ "ratio": 1.0781250000050626
},
"competitor": {
- "minMs": 1.68000000000211,
- "maxMs": 2.400000000001455,
- "ratio": 1.4285714285705005
+ "minMs": 1.3800000000010186,
+ "maxMs": 2.600000000000364,
+ "ratio": 1.8840579710133656
},
"stable": true,
"rungs": [
@@ -2969,19 +2905,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.750000000003638,
+ "referenceMs": 0.6699999999982538,
"referenceP95Ms": 1.319999999999709,
- "referenceGpuMs": 16.659999999996217,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 1.1299999999973807,
+ "competitorMs": 1.0100000000020373,
"competitorP95Ms": 1.9000000000014552,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "exojs",
- "ratio": 0.6637168141640499,
- "factor": 1.5066666666558661,
- "label": "ExoJS leads (1.51x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 2/0/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -2989,18 +2925,18 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.7000000000007276,
- "maxMs": 0.8100000000013097,
- "ratio": 1.1571428571435254
+ "minMs": 0.63999999999578,
+ "maxMs": 0.6899999999986903,
+ "ratio": 1.0781250000050626
},
"competitor": {
- "minMs": 1.110000000000582,
- "maxMs": 1.2600000000020373,
- "ratio": 1.1351351351363752
+ "minMs": 0.7400000000016007,
+ "maxMs": 1.0600000000013097,
+ "ratio": 1.4324324324311037
},
- "stable": true,
+ "stable": false,
"rungs": [
- "exojs-leads",
+ "level",
"exojs-leads",
"exojs-leads"
]
@@ -3021,60 +2957,21 @@
"unit": "particles",
"primary": false,
"cells": [
- {
- "competitor": "excalibur",
- "referenceMs": 0.26000000000203727,
- "referenceP95Ms": 0.41999999999825377,
- "referenceGpuMs": 16.660000000003492,
- "referenceOverFrameBudget": false,
- "competitorMs": 2.390000000006694,
- "competitorP95Ms": 7.419999999998254,
- "competitorGpuMs": 16.660000000003492,
- "competitorOverFrameBudget": false,
- "verdict": {
- "side": "exojs",
- "ratio": 0.10878661087920881,
- "factor": 9.19230769226141,
- "label": "ExoJS leads clearly (9.19x)",
- "structural": true
- },
- "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
- "timer": "resolved",
- "aggregate": {
- "runs": 3,
- "reference": {
- "minMs": 0.26000000000203727,
- "maxMs": 0.27999999999883585,
- "ratio": 1.076923076910161
- },
- "competitor": {
- "minMs": 2.389999999992142,
- "maxMs": 2.4199999999982538,
- "ratio": 1.0125523012578286
- },
- "stable": true,
- "rungs": [
- "exojs-leads-clearly",
- "exojs-leads-clearly",
- "exojs-leads-clearly"
- ]
- }
- },
{
"competitor": "phaser",
"referenceMs": 0.26000000000203727,
"referenceP95Ms": 0.41999999999825377,
- "referenceGpuMs": 16.660000000003492,
+ "referenceGpuMs": 16.679999999993015,
"referenceOverFrameBudget": false,
- "competitorMs": 0.8400000000001455,
+ "competitorMs": 0.8500000000003638,
"competitorP95Ms": 1.0800000000017462,
"competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.30952380952618125,
- "factor": 3.230769230744475,
- "label": "ExoJS leads (3.23x)",
+ "ratio": 0.30588235294344235,
+ "factor": 3.2692307692065516,
+ "label": "ExoJS leads (3.27x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3087,9 +2984,9 @@
"ratio": 1.076923076910161
},
"competitor": {
- "minMs": 0.8400000000001455,
- "maxMs": 0.8799999999901047,
- "ratio": 1.047619047607086
+ "minMs": 0.819999999999709,
+ "maxMs": 0.8600000000005821,
+ "ratio": 1.0487804878059601
},
"stable": true,
"rungs": [
@@ -3103,11 +3000,11 @@
"competitor": "pixi",
"referenceMs": 0.26000000000203727,
"referenceP95Ms": 0.41999999999825377,
- "referenceGpuMs": 16.660000000003492,
+ "referenceGpuMs": 16.679999999993015,
"referenceOverFrameBudget": false,
"competitorMs": 0.13999999999941792,
- "competitorP95Ms": 0.27999999999883585,
- "competitorGpuMs": 16.660000000003492,
+ "competitorP95Ms": 0.2800000000061118,
+ "competitorGpuMs": 16.68000000000029,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
@@ -3148,60 +3045,21 @@
"unit": "particles",
"primary": true,
"cells": [
- {
- "competitor": "excalibur",
- "referenceMs": 0.46000000000276486,
- "referenceP95Ms": 0.5800000000017462,
- "referenceGpuMs": 16.68000000000029,
- "referenceOverFrameBudget": false,
- "competitorMs": 24.489999999997963,
- "competitorP95Ms": 26.979999999995925,
- "competitorGpuMs": 25.460000000006403,
- "competitorOverFrameBudget": true,
- "verdict": {
- "side": "exojs",
- "ratio": 0.018783176806974403,
- "factor": 53.23913043445818,
- "label": "ExoJS leads clearly (53.24x)",
- "structural": true
- },
- "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
- "timer": "resolved",
- "aggregate": {
- "runs": 3,
- "reference": {
- "minMs": 0.4500000000007276,
- "maxMs": 0.47999999999956344,
- "ratio": 1.066666666663972
- },
- "competitor": {
- "minMs": 14.69999999999709,
- "maxMs": 25.69000000000233,
- "ratio": 1.7476190476195521
- },
- "stable": true,
- "rungs": [
- "exojs-leads-clearly",
- "exojs-leads-clearly",
- "exojs-leads-clearly"
- ]
- }
- },
{
"competitor": "phaser",
- "referenceMs": 0.46000000000276486,
+ "referenceMs": 0.47999999999592546,
"referenceP95Ms": 0.5800000000017462,
- "referenceGpuMs": 16.68000000000029,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 2.9800000000032014,
- "competitorP95Ms": 3.779999999998836,
- "competitorGpuMs": 16.659999999999854,
+ "competitorMs": 2.680000000000291,
+ "competitorP95Ms": 3.7599999999983993,
+ "competitorGpuMs": 16.679999999996653,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.15436241610814452,
- "factor": 6.478260869533239,
- "label": "ExoJS leads clearly (6.48x)",
+ "ratio": 0.1791044776104005,
+ "factor": 5.583333333381335,
+ "label": "ExoJS leads clearly (5.58x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3209,14 +3067,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.4500000000007276,
- "maxMs": 0.47999999999956344,
- "ratio": 1.066666666663972
+ "minMs": 0.46000000000276486,
+ "maxMs": 0.47999999999592546,
+ "ratio": 1.0434782608544357
},
"competitor": {
- "minMs": 2.7999999999992724,
- "maxMs": 3.2000000000007276,
- "ratio": 1.1428571428576997
+ "minMs": 2.5500000000010914,
+ "maxMs": 3.0799999999999272,
+ "ratio": 1.2078431372543565
},
"stable": true,
"rungs": [
@@ -3228,19 +3086,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 0.46000000000276486,
+ "referenceMs": 0.47999999999592546,
"referenceP95Ms": 0.5800000000017462,
- "referenceGpuMs": 16.68000000000029,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.11999999999898137,
+ "competitorMs": 0.12000000000261934,
"competitorP95Ms": 0.2400000000052387,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 3.8333333333889135,
- "factor": 3.8333333333889135,
- "label": "competitor leads (3.83x)",
+ "ratio": 3.999999999878734,
+ "factor": 3.999999999878734,
+ "label": "competitor leads (4.00x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3248,14 +3106,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.4500000000007276,
- "maxMs": 0.47999999999956344,
- "ratio": 1.066666666663972
+ "minMs": 0.46000000000276486,
+ "maxMs": 0.47999999999592546,
+ "ratio": 1.0434782608544357
},
"competitor": {
- "minMs": 0.11999999999534339,
+ "minMs": 0.12000000000261934,
"maxMs": 0.12000000000261934,
- "ratio": 1.000000000060633
+ "ratio": 1
},
"stable": true,
"rungs": [
@@ -3277,19 +3135,19 @@
"cells": [
{
"competitor": "phaser",
- "referenceMs": 1.6699999999982538,
- "referenceP95Ms": 3.1000000000058208,
+ "referenceMs": 1.7900000000008731,
+ "referenceP95Ms": 2.6199999999953434,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 9.510000000002037,
- "competitorP95Ms": 10.659999999999854,
+ "competitorMs": 9.460000000000946,
+ "competitorP95Ms": 10.020000000000437,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.1756046267085064,
- "factor": 5.694610778450288,
- "label": "ExoJS leads clearly (5.69x)",
+ "ratio": 0.1892177589852742,
+ "factor": 5.284916201115269,
+ "label": "ExoJS leads clearly (5.28x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 7/0/7, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3297,14 +3155,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5800000000017462,
- "maxMs": 1.8799999999973807,
- "ratio": 1.1898734177185462
+ "minMs": 1.7899999999972351,
+ "maxMs": 1.860000000000582,
+ "ratio": 1.0391061452533268
},
"competitor": {
- "minMs": 9.449999999998909,
- "maxMs": 9.6299999999992,
- "ratio": 1.019047619047652
+ "minMs": 9.459999999999127,
+ "maxMs": 9.570000000001528,
+ "ratio": 1.0116279069769991
},
"stable": true,
"rungs": [
@@ -3316,18 +3174,18 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.6699999999982538,
- "referenceP95Ms": 3.1000000000058208,
+ "referenceMs": 1.7900000000008731,
+ "referenceP95Ms": 2.6199999999953434,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.13999999999941792,
- "competitorP95Ms": 0.27999999999883585,
+ "competitorMs": 0.1499999999978172,
+ "competitorP95Ms": 0.2999999999956344,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 11.928571428608551,
- "factor": 11.928571428608551,
+ "ratio": 11.933333333512808,
+ "factor": 11.933333333512808,
"label": "competitor leads clearly (11.93x)",
"structural": true
},
@@ -3336,14 +3194,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.5800000000017462,
- "maxMs": 1.8799999999973807,
- "ratio": 1.1898734177185462
+ "minMs": 1.7899999999972351,
+ "maxMs": 1.860000000000582,
+ "ratio": 1.0391061452533268
},
"competitor": {
- "minMs": 0.13999999999941792,
- "maxMs": 0.1499999999978172,
- "ratio": 1.0714285714174347
+ "minMs": 0.11000000000058208,
+ "maxMs": 0.1500000000014552,
+ "ratio": 1.3636363636423767
},
"stable": true,
"rungs": [
@@ -3352,43 +3210,6 @@
"competitor-leads-clearly"
]
}
- },
- {
- "competitor": "excalibur",
- "referenceMs": 1.8799999999973807,
- "referenceP95Ms": 3.1599999999962165,
- "referenceGpuMs": 16.660000000003492,
- "referenceOverFrameBudget": false,
- "competitorMs": 191.07000000000698,
- "competitorP95Ms": 195.77999999999884,
- "competitorGpuMs": 196.6600000000035,
- "competitorOverFrameBudget": true,
- "verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
- "structural": false
- },
- "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 5/6/5, none of them large enough to account for the gap); the difference is CPU-side",
- "timer": "resolved",
- "aggregate": {
- "runs": 1,
- "reference": {
- "minMs": 1.8799999999973807,
- "maxMs": 1.8799999999973807,
- "ratio": 1
- },
- "competitor": {
- "minMs": 191.07000000000698,
- "maxMs": 191.07000000000698,
- "ratio": 1
- },
- "stable": false,
- "rungs": [
- "exojs-leads-clearly"
- ]
- }
}
]
},
@@ -3400,60 +3221,21 @@
"unit": "particles",
"primary": true,
"cells": [
- {
- "competitor": "excalibur",
- "referenceMs": 1.360000000000582,
- "referenceP95Ms": 2.279999999998836,
- "referenceGpuMs": 16.660000000003492,
- "referenceOverFrameBudget": false,
- "competitorMs": 24.959999999999127,
- "competitorP95Ms": 27.360000000000582,
- "competitorGpuMs": 26.05999999999767,
- "competitorOverFrameBudget": true,
- "verdict": {
- "side": "exojs",
- "ratio": 0.05448717948720471,
- "factor": 18.352941176462092,
- "label": "ExoJS leads clearly (18.35x)",
- "structural": true
- },
- "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
- "timer": "resolved",
- "aggregate": {
- "runs": 3,
- "reference": {
- "minMs": 1.3400000000001455,
- "maxMs": 1.6599999999962165,
- "ratio": 1.2388059701462957
- },
- "competitor": {
- "minMs": 23.999999999992724,
- "maxMs": 25.179999999993015,
- "ratio": 1.0491666666666937
- },
- "stable": true,
- "rungs": [
- "exojs-leads-clearly",
- "exojs-leads-clearly",
- "exojs-leads-clearly"
- ]
- }
- },
{
"competitor": "phaser",
- "referenceMs": 1.360000000000582,
- "referenceP95Ms": 2.279999999998836,
+ "referenceMs": 1.3000000000029104,
+ "referenceP95Ms": 2.2399999999979627,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 3.1600000000034925,
- "competitorP95Ms": 6.139999999999418,
+ "competitorMs": 3.2299999999995634,
+ "competitorP95Ms": 5.780000000002474,
"competitorGpuMs": 16.659999999999854,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.43037974683515157,
- "factor": 2.3235294117662795,
- "label": "ExoJS leads (2.32x)",
+ "ratio": 0.40247678018671396,
+ "factor": 2.4846153846094863,
+ "label": "ExoJS leads (2.48x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3461,14 +3243,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.3400000000001455,
- "maxMs": 1.6599999999962165,
- "ratio": 1.2388059701462957
+ "minMs": 1.2300000000032014,
+ "maxMs": 1.6500000000014552,
+ "ratio": 1.3414634146318378
},
"competitor": {
- "minMs": 3.1199999999989814,
- "maxMs": 3.360000000000582,
- "ratio": 1.076923076923615
+ "minMs": 3.0600000000013097,
+ "maxMs": 3.2699999999986176,
+ "ratio": 1.068627450979483
},
"stable": true,
"rungs": [
@@ -3480,19 +3262,19 @@
},
{
"competitor": "pixi",
- "referenceMs": 1.360000000000582,
- "referenceP95Ms": 2.279999999998836,
+ "referenceMs": 1.3000000000029104,
+ "referenceP95Ms": 2.2399999999979627,
"referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 0.9000000000014552,
- "competitorP95Ms": 1.139999999999418,
+ "competitorMs": 1,
+ "competitorP95Ms": 1.2800000000061118,
"competitorGpuMs": 16.660000000003492,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.5111111111093145,
- "factor": 1.5111111111093145,
- "label": "competitor leads (1.51x)",
+ "ratio": 1.3000000000029104,
+ "factor": 1.3000000000029104,
+ "label": "competitor leads (1.30x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/0/1 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3500,14 +3282,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.3400000000001455,
- "maxMs": 1.6599999999962165,
- "ratio": 1.2388059701462957
+ "minMs": 1.2300000000032014,
+ "maxMs": 1.6500000000014552,
+ "ratio": 1.3414634146318378
},
"competitor": {
- "minMs": 0.8900000000030559,
- "maxMs": 0.9199999999982538,
- "ratio": 1.033707865163028
+ "minMs": 0.9000000000014552,
+ "maxMs": 1.0199999999967986,
+ "ratio": 1.1333333333279438
},
"stable": true,
"rungs": [
@@ -3533,35 +3315,35 @@
"primary": true,
"cells": [
{
- "competitor": "excalibur",
- "referenceMs": 0.569999999999709,
- "referenceP95Ms": 0.9400000000023283,
- "referenceGpuMs": 16.679999999993015,
+ "competitor": "phaser",
+ "referenceMs": 0.5600000000049477,
+ "referenceP95Ms": 0.8799999999973807,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 24.62999999999738,
- "competitorP95Ms": 27.920000000012806,
- "competitorGpuMs": 25.720000000001164,
+ "competitorMs": 32.44000000000233,
+ "competitorP95Ms": 35.44000000000233,
+ "competitorGpuMs": 33.31999999999971,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.02314250913519162,
- "factor": 43.21052631580694,
- "label": "ExoJS leads clearly (43.21x)",
+ "ratio": 0.01726263871778383,
+ "factor": 57.92857142806378,
+ "label": "ExoJS leads clearly (57.93x)",
"structural": true
},
- "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
+ "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
"timer": "resolved",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5400000000008731,
- "maxMs": 0.5799999999944703,
- "ratio": 1.074074074062097
+ "minMs": 0.5600000000013097,
+ "maxMs": 0.5999999999985448,
+ "ratio": 1.071428571423467
},
"competitor": {
- "minMs": 24.510000000002037,
- "maxMs": 25.810000000004948,
- "ratio": 1.053039575683509
+ "minMs": 32.279999999998836,
+ "maxMs": 32.61999999999898,
+ "ratio": 1.010532837670389
},
"stable": true,
"rungs": [
@@ -3572,35 +3354,35 @@
}
},
{
- "competitor": "phaser",
- "referenceMs": 0.569999999999709,
- "referenceP95Ms": 0.9400000000023283,
- "referenceGpuMs": 16.679999999993015,
+ "competitor": "pixi",
+ "referenceMs": 0.5600000000049477,
+ "referenceP95Ms": 0.8799999999973807,
+ "referenceGpuMs": 16.68000000000029,
"referenceOverFrameBudget": false,
- "competitorMs": 32.67000000000007,
- "competitorP95Ms": 35.43999999999869,
- "competitorGpuMs": 33.5199999999968,
- "competitorOverFrameBudget": true,
+ "competitorMs": 16.5,
+ "competitorP95Ms": 21.5,
+ "competitorGpuMs": 17.0199999999968,
+ "competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.017447199265372137,
- "factor": 57.3157894737136,
- "label": "ExoJS leads clearly (57.32x)",
+ "ratio": 0.0339393939396938,
+ "factor": 29.46428571402539,
+ "label": "ExoJS leads clearly (29.46x)",
"structural": true
},
- "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/1, none of them large enough to account for the gap); the difference is CPU-side",
+ "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
"timer": "resolved",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5400000000008731,
- "maxMs": 0.5799999999944703,
- "ratio": 1.074074074062097
+ "minMs": 0.5600000000013097,
+ "maxMs": 0.5999999999985448,
+ "ratio": 1.071428571423467
},
"competitor": {
- "minMs": 32.51000000000022,
- "maxMs": 32.90000000000873,
- "ratio": 1.0119963088283146
+ "minMs": 16.270000000000437,
+ "maxMs": 17.31000000000131,
+ "ratio": 1.063921327596856
},
"stable": true,
"rungs": [
@@ -3609,43 +3391,53 @@
"exojs-leads-clearly"
]
}
- },
+ }
+ ]
+ },
+ {
+ "archetype": "ui-layout-update",
+ "category": "Interaction",
+ "count": 1000,
+ "loadId": "1k",
+ "unit": "widgets",
+ "primary": true,
+ "cells": [
{
"competitor": "pixi",
- "referenceMs": 0.569999999999709,
- "referenceP95Ms": 0.9400000000023283,
- "referenceGpuMs": 16.679999999993015,
+ "referenceMs": 10.25,
+ "referenceP95Ms": 10.720000000001164,
+ "referenceGpuMs": 16.660000000003492,
"referenceOverFrameBudget": false,
- "competitorMs": 17.169999999998254,
- "competitorP95Ms": 21.87999999999738,
- "competitorGpuMs": 17.839999999996508,
+ "competitorMs": 48.460000000002765,
+ "competitorP95Ms": 52.75999999999476,
+ "competitorGpuMs": 49.140000000006694,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.03319743739078433,
- "factor": 30.122807017556173,
- "label": "ExoJS leads clearly (30.12x)",
- "structural": true
+ "ratio": 0.21151465125875804,
+ "factor": 4.72780487804905,
+ "label": "ExoJS leads (4.73x)",
+ "structural": false
},
- "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/0/0 vs 1/0/0, none of them large enough to account for the gap); the difference is CPU-side",
+ "mechanism": "neither arm submits anything for this scene (draw/bind/upload per frame: 0/0/0 vs 0/0/0); the whole difference is the per-frame work itself",
"timer": "resolved",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5400000000008731,
- "maxMs": 0.5799999999944703,
- "ratio": 1.074074074062097
+ "minMs": 10.220000000001164,
+ "maxMs": 10.340000000003783,
+ "ratio": 1.0117416829748147
},
"competitor": {
- "minMs": 16.56999999999971,
- "maxMs": 17.5,
- "ratio": 1.0561255280627826
+ "minMs": 47.99999999999636,
+ "maxMs": 49.04999999999927,
+ "ratio": 1.0218750000000623
},
"stable": true,
"rungs": [
- "exojs-leads-clearly",
- "exojs-leads-clearly",
- "exojs-leads-clearly"
+ "exojs-leads",
+ "exojs-leads",
+ "exojs-leads"
]
}
}
@@ -3682,10 +3474,6 @@
{
"archetype": "mixed-material-atlased",
"reason": "ExoJS-internal structural probe: a competitor arm renders a different scene here, so a wall-clock comparison would not be like for like"
- },
- {
- "archetype": "fx-blur",
- "reason": "ExoJS-internal structural probe: a competitor arm renders a different scene here, so a wall-clock comparison would not be like for like"
}
],
"webgl1": []
@@ -3711,18 +3499,18 @@
{
"competitor": "pixi",
"referenceMs": 0.2999999999999545,
- "referenceP95Ms": 0.5799999999999272,
- "referenceGpuMs": 0.072688,
+ "referenceP95Ms": 0.5599999999999454,
+ "referenceGpuMs": 0.072937,
"referenceOverFrameBudget": false,
- "competitorMs": 0.2999999999999545,
- "competitorP95Ms": 0.5800000000000409,
- "competitorGpuMs": 0.07325,
+ "competitorMs": 0.3000000000001819,
+ "competitorP95Ms": 0.6000000000001364,
+ "competitorGpuMs": 0.073125,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 0.999999999999242,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3730,19 +3518,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2599999999998772,
- "maxMs": 0.32000000000010687,
- "ratio": 1.230769230770223
+ "minMs": 0.2800000000001148,
+ "maxMs": 0.3000000000000682,
+ "ratio": 1.0714285714283758
},
"competitor": {
- "minMs": 0.27999999999985903,
- "maxMs": 0.4600000000000364,
- "ratio": 1.6428571428580998
+ "minMs": 0.29999999999998295,
+ "maxMs": 0.31999999999993634,
+ "ratio": 1.066666666666515
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
- "exojs-leads",
+ "level",
"level"
]
}
@@ -3759,40 +3547,40 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.20000000000004547,
- "referenceP95Ms": 0.36000000000012733,
- "referenceGpuMs": 0.2054165,
+ "referenceMs": 0.20000000000027285,
+ "referenceP95Ms": 0.38000000000010914,
+ "referenceGpuMs": 0.206729,
"referenceOverFrameBudget": false,
"competitorMs": 0.23999999999978172,
- "competitorP95Ms": 0.4600000000000364,
- "competitorGpuMs": 0.18993749999999998,
+ "competitorP95Ms": 0.42000000000007276,
+ "competitorGpuMs": 0.19004149999999997,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 0.8333333333352281,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
- "timer": "limited",
+ "timer": "resolved",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.14000000000032742,
- "maxMs": 0.21000000000003638,
- "ratio": 1.4999999999967517
+ "minMs": 0.1999999999998181,
+ "maxMs": 0.20000000000027285,
+ "ratio": 1.0000000000022737
},
"competitor": {
- "minMs": 0.19000000000005457,
- "maxMs": 0.2800000000002001,
- "ratio": 1.4736842105269456
+ "minMs": 0.22000000000025466,
+ "maxMs": 0.23999999999978172,
+ "ratio": 1.090909090906836
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
- "exojs-leads",
- "exojs-leads"
+ "level",
+ "level"
]
}
}
@@ -3808,13 +3596,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.15000000000009095,
- "referenceP95Ms": 0.3000000000001819,
- "referenceGpuMs": 0.429021,
+ "referenceMs": 0.11000000000012733,
+ "referenceP95Ms": 0.27999999999974534,
+ "referenceGpuMs": 0.30341700000000005,
"referenceOverFrameBudget": false,
- "competitorMs": 0.13000000000010914,
- "competitorP95Ms": 0.5,
- "competitorGpuMs": 0.274937,
+ "competitorMs": 0.08000000000038199,
+ "competitorP95Ms": 0.38000000000010914,
+ "competitorGpuMs": 0.241354,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -3828,19 +3616,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.05999999999994543,
- "maxMs": 0.15999999999985448,
- "ratio": 2.6666666666666665
+ "minMs": 0.06000000000040018,
+ "maxMs": 0.169999999999618,
+ "ratio": 2.8333333333080697
},
"competitor": {
- "minMs": 0.09000000000014552,
- "maxMs": 0.3599999999996726,
- "ratio": 3.9999999999898943
+ "minMs": 0.07999999999992724,
+ "maxMs": 0.15999999999985448,
+ "ratio": 2
},
"stable": false,
"rungs": [
- "competitor-leads",
"exojs-leads",
+ "competitor-leads",
"exojs-leads"
]
}
@@ -3857,19 +3645,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 1.8900000000003274,
- "referenceP95Ms": 2.4600000000000364,
- "referenceGpuMs": 0.2075835,
+ "referenceMs": 1.9299999999998363,
+ "referenceP95Ms": 2.399999999999636,
+ "referenceGpuMs": 0.206667,
"referenceOverFrameBudget": false,
- "competitorMs": 1.300000000000182,
- "competitorP95Ms": 1.8400000000001455,
- "competitorGpuMs": 0.1915835,
+ "competitorMs": 1.2699999999999818,
+ "competitorP95Ms": 1.9600000000000364,
+ "competitorGpuMs": 0.192,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.4538461538462022,
- "factor": 1.4538461538462022,
- "label": "competitor leads (1.45x)",
+ "ratio": 1.5196850393699717,
+ "factor": 1.5196850393699717,
+ "label": "competitor leads (1.52x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/2 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3877,14 +3665,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.8599999999996726,
- "maxMs": 1.900000000000091,
- "ratio": 1.0215053763443147
+ "minMs": 1.7999999999997272,
+ "maxMs": 2,
+ "ratio": 1.1111111111112795
},
"competitor": {
- "minMs": 1.0899999999996908,
- "maxMs": 1.4200000000000728,
- "ratio": 1.302752293578418
+ "minMs": 1.2399999999997817,
+ "maxMs": 1.2799999999997453,
+ "ratio": 1.0322580645161055
},
"stable": true,
"rungs": [
@@ -3906,19 +3694,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 1.7199999999993452,
- "referenceP95Ms": 2.199999999999818,
- "referenceGpuMs": 0.073708,
+ "referenceMs": 1.6599999999998545,
+ "referenceP95Ms": 2.240000000000691,
+ "referenceGpuMs": 0.073459,
"referenceOverFrameBudget": false,
- "competitorMs": 0.9799999999995634,
- "competitorP95Ms": 1.319999999999709,
- "competitorGpuMs": 0.0729795,
+ "competitorMs": 0.9800000000004729,
+ "competitorP95Ms": 1.3599999999996726,
+ "competitorGpuMs": 0.0719585,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.7551020408164402,
- "factor": 1.7551020408164402,
- "label": "competitor leads (1.76x)",
+ "ratio": 1.6938775510194422,
+ "factor": 1.6938775510194422,
+ "label": "competitor leads (1.69x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/1 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -3926,14 +3714,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 1.7100000000000364,
- "maxMs": 1.7499999999995453,
- "ratio": 1.0233918128652093
+ "minMs": 1.6400000000003274,
+ "maxMs": 1.7100000000000364,
+ "ratio": 1.0426829268290823
},
"competitor": {
- "minMs": 0.9399999999995998,
- "maxMs": 1.2300000000000182,
- "ratio": 1.3085106382984488
+ "minMs": 0.9800000000000182,
+ "maxMs": 0.9900000000002365,
+ "ratio": 1.0102040816328757
},
"stable": true,
"rungs": [
@@ -3955,18 +3743,18 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 4.220000000001164,
- "referenceP95Ms": 10.44000000000051,
- "referenceGpuMs": 0.211333,
+ "referenceMs": 4.229999999999563,
+ "referenceP95Ms": 5.8400000000001455,
+ "referenceGpuMs": 0.2107915,
"referenceOverFrameBudget": false,
"competitorMs": 2.7600000000002183,
- "competitorP95Ms": 9.219999999999345,
- "competitorGpuMs": 0.1934165,
+ "competitorP95Ms": 10.05999999999949,
+ "competitorGpuMs": 0.1925625,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.5289855072466776,
- "factor": 1.5289855072466776,
+ "ratio": 1.5326086956518945,
+ "factor": 1.5326086956518945,
"label": "competitor leads (1.53x)",
"structural": false
},
@@ -3975,14 +3763,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.7399999999997817,
- "maxMs": 4.400000000000546,
- "ratio": 1.1764705882355087
+ "minMs": 3.860000000000582,
+ "maxMs": 4.230000000000473,
+ "ratio": 1.09585492227975
},
"competitor": {
- "minMs": 2.7100000000000364,
- "maxMs": 2.780000000000655,
- "ratio": 1.025830258302811
+ "minMs": 2.550000000000182,
+ "maxMs": 2.769999999999527,
+ "ratio": 1.0862745098036586
},
"stable": true,
"rungs": [
@@ -4004,19 +3792,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 38.039999999999964,
- "referenceP95Ms": 41.659999999999854,
- "referenceGpuMs": 0.970521,
+ "referenceMs": 38,
+ "referenceP95Ms": 44.02000000000044,
+ "referenceGpuMs": 0.976,
"referenceOverFrameBudget": true,
- "competitorMs": 28.61999999999898,
- "competitorP95Ms": 31.81999999999971,
- "competitorGpuMs": 0.7028755,
+ "competitorMs": 27.970000000000255,
+ "competitorP95Ms": 32,
+ "competitorGpuMs": 0.6748544999999999,
"competitorOverFrameBudget": true,
"verdict": {
"side": "competitor",
- "ratio": 1.329140461215979,
- "factor": 1.329140461215979,
- "label": "competitor leads (1.33x)",
+ "ratio": 1.358598498391121,
+ "factor": 1.358598498391121,
+ "label": "competitor leads (1.36x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/1 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4024,14 +3812,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 37,
- "maxMs": 39.590000000000146,
- "ratio": 1.0700000000000038
+ "minMs": 37.01000000000022,
+ "maxMs": 40.13999999999942,
+ "ratio": 1.0845717373682566
},
"competitor": {
- "minMs": 28.220000000000255,
- "maxMs": 28.789999999999964,
- "ratio": 1.0201984408221014
+ "minMs": 27.639999999999418,
+ "maxMs": 28.100000000000364,
+ "ratio": 1.0166425470333196
},
"stable": true,
"rungs": [
@@ -4053,19 +3841,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.47000000000025466,
- "referenceP95Ms": 0.6599999999998545,
- "referenceGpuMs": 0.13700050000000003,
+ "referenceMs": 0.5,
+ "referenceP95Ms": 0.7199999999993452,
+ "referenceGpuMs": 0.2287705,
"referenceOverFrameBudget": false,
- "competitorMs": 0.5,
- "competitorP95Ms": 0.7400000000016007,
- "competitorGpuMs": 0.1317705,
+ "competitorMs": 0.5199999999995271,
+ "competitorP95Ms": 0.7599999999983993,
+ "competitorGpuMs": 0.130792,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 0.9615384615393361,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/1 vs 1/2/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4073,19 +3861,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.42000000000007276,
- "maxMs": 0.47999999999956344,
- "ratio": 1.1428571428559053
+ "minMs": 0.4600000000009459,
+ "maxMs": 0.5599999999994907,
+ "ratio": 1.2173913043442157
},
"competitor": {
- "minMs": 0.4400000000005093,
- "maxMs": 0.7399999999997817,
- "ratio": 1.681818181815739
+ "minMs": 0.5099999999993088,
+ "maxMs": 0.5399999999990541,
+ "ratio": 1.058823529411345
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
- "exojs-leads",
+ "level",
"level"
]
}
@@ -4102,17 +3890,17 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 2.680000000000291,
- "referenceP95Ms": 6.479999999999563,
- "referenceGpuMs": 0.142021,
+ "referenceMs": 2.540000000000873,
+ "referenceP95Ms": 6.919999999998254,
+ "referenceGpuMs": 0.1434375,
"referenceOverFrameBudget": false,
- "competitorMs": 2.5799999999981083,
- "competitorP95Ms": 7.440000000002328,
- "competitorGpuMs": 0.1590205,
+ "competitorMs": 2.390000000001237,
+ "competitorP95Ms": 6.979999999999563,
+ "competitorGpuMs": 0.15862500000000002,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.038759689923355,
+ "ratio": 1.0627615062759659,
"factor": 1,
"label": "level",
"structural": false
@@ -4122,14 +3910,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.5099999999983993,
- "maxMs": 2.7300000000013824,
- "ratio": 1.0876494023916827
+ "minMs": 2.4799999999995634,
+ "maxMs": 2.680000000000291,
+ "ratio": 1.0806451612906303
},
"competitor": {
- "minMs": 2.539999999999054,
- "maxMs": 2.5899999999983265,
- "ratio": 1.0196850393697996
+ "minMs": 2.3699999999971624,
+ "maxMs": 2.5,
+ "ratio": 1.0548523206763685
},
"stable": true,
"rungs": [
@@ -4157,18 +3945,18 @@
{
"competitor": "pixi",
"referenceMs": 0.13999999999941792,
- "referenceP95Ms": 0.23999999999978172,
- "referenceGpuMs": 0.589167,
+ "referenceP95Ms": 0.27999999999883585,
+ "referenceGpuMs": 0.58875,
"referenceOverFrameBudget": false,
- "competitorMs": 0.2000000000007276,
- "competitorP95Ms": 0.3999999999996362,
- "competitorGpuMs": 0.6553745,
+ "competitorMs": 0.18000000000029104,
+ "competitorP95Ms": 0.3600000000005821,
+ "competitorGpuMs": 0.634937,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "exojs",
- "ratio": 0.699999999994543,
- "factor": 1.4285714285825653,
- "label": "ExoJS leads (1.43x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4176,19 +3964,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.1000000000003638,
- "maxMs": 0.1400000000012369,
- "ratio": 1.4000000000072759
+ "minMs": 0.13999999999941792,
+ "maxMs": 0.15999999999985448,
+ "ratio": 1.1428571428608552
},
"competitor": {
- "minMs": 0.15999999999985448,
- "maxMs": 0.38000000000101863,
- "ratio": 2.3750000000085265
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.1999999999989086,
+ "ratio": 1.1111111111032512
},
- "stable": true,
+ "stable": false,
"rungs": [
"exojs-leads",
- "exojs-leads",
+ "level",
"exojs-leads"
]
}
@@ -4205,19 +3993,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.570000000001528,
- "referenceP95Ms": 1,
- "referenceGpuMs": 0.22197899999999998,
+ "referenceMs": 0.6399999999994179,
+ "referenceP95Ms": 1.4799999999995634,
+ "referenceGpuMs": 0.2210625,
"referenceOverFrameBudget": false,
- "competitorMs": 0.7600000000011278,
- "competitorP95Ms": 1.0799999999999272,
- "competitorGpuMs": 0.1250205,
+ "competitorMs": 0.680000000000291,
+ "competitorP95Ms": 1.0200000000004366,
+ "competitorGpuMs": 0.1242705,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "exojs",
- "ratio": 0.7500000000008975,
- "factor": 1.3333333333317379,
- "label": "ExoJS leads (1.33x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "competitor issues fewer texture binds (626 vs 314 per frame)",
@@ -4225,20 +4013,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5400000000008731,
- "maxMs": 0.5799999999999272,
- "ratio": 1.0740740740722028
+ "minMs": 0.5200000000004366,
+ "maxMs": 0.7999999999992724,
+ "ratio": 1.5384615384588476
},
"competitor": {
- "minMs": 0.7399999999979627,
- "maxMs": 0.7999999999992724,
- "ratio": 1.0810810810830742
+ "minMs": 0.5399999999999636,
+ "maxMs": 0.7000000000007276,
+ "ratio": 1.2962962962977311
},
- "stable": true,
+ "stable": false,
"rungs": [
"exojs-leads",
- "exojs-leads",
- "exojs-leads"
+ "level",
+ "level"
]
}
}
@@ -4254,19 +4042,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.42000000000189175,
- "referenceP95Ms": 0.5199999999967986,
- "referenceGpuMs": 0.11856249999999999,
+ "referenceMs": 0.4099999999998545,
+ "referenceP95Ms": 0.5399999999972351,
+ "referenceGpuMs": 0.11906249999999999,
"referenceOverFrameBudget": false,
- "competitorMs": 0.5499999999992724,
- "competitorP95Ms": 0.7600000000020373,
- "competitorGpuMs": 0.119646,
+ "competitorMs": 0.5599999999976717,
+ "competitorP95Ms": 0.680000000000291,
+ "competitorGpuMs": 0.072354,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "exojs",
- "ratio": 0.7636363636408134,
- "factor": 1.3095238095161787,
- "label": "ExoJS leads (1.31x)",
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
"structural": false
},
"mechanism": "competitor issues fewer texture binds (240 vs 159 per frame)",
@@ -4274,20 +4062,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.41999999999825377,
- "maxMs": 0.42000000000189175,
- "ratio": 1.000000000008662
+ "minMs": 0.37999999999919964,
+ "maxMs": 0.4399999999986903,
+ "ratio": 1.1578947368410974
},
"competitor": {
- "minMs": 0.5400000000008731,
- "maxMs": 0.7200000000011642,
- "ratio": 1.3333333333333333
+ "minMs": 0.3599999999969441,
+ "maxMs": 0.5600000000013097,
+ "ratio": 1.555555555572398
},
- "stable": true,
+ "stable": false,
"rungs": [
"exojs-leads",
"exojs-leads",
- "exojs-leads"
+ "level"
]
}
}
@@ -4309,12 +4097,12 @@
{
"competitor": "pixi",
"referenceMs": 0.11999999999898137,
- "referenceP95Ms": 0.2000000000007276,
- "referenceGpuMs": 0.12593749999999998,
+ "referenceP95Ms": 0.15999999999985448,
+ "referenceGpuMs": 0.125917,
"referenceOverFrameBudget": false,
"competitorMs": 0.18000000000029104,
- "competitorP95Ms": 0.3600000000005821,
- "competitorGpuMs": 0.1145,
+ "competitorP95Ms": 0.31999999999970896,
+ "competitorGpuMs": 0.11552100000000001,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
@@ -4328,14 +4116,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.11999999999898137,
+ "minMs": 0.10000000000218279,
"maxMs": 0.11999999999898137,
- "ratio": 1
+ "ratio": 1.1999999999636202
},
"competitor": {
- "minMs": 0.15999999999985448,
- "maxMs": 0.3999999999978172,
- "ratio": 2.4999999999886313
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.18000000000029104,
+ "ratio": 1
},
"stable": true,
"rungs": [
@@ -4363,18 +4151,18 @@
{
"competitor": "pixi",
"referenceMs": 0.18000000000029104,
- "referenceP95Ms": 0.2999999999992724,
- "referenceGpuMs": 1.414479,
+ "referenceP95Ms": 0.2800000000024738,
+ "referenceGpuMs": 0.6382915,
"referenceOverFrameBudget": false,
- "competitorMs": 0.18000000000029104,
- "competitorP95Ms": 0.31999999999970896,
- "competitorGpuMs": 0.2457295,
+ "competitorMs": 0.2000000000007276,
+ "competitorP95Ms": 0.3400000000001455,
+ "competitorGpuMs": 0.245938,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 0.899999999998181,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4382,19 +4170,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.13999999999941792,
- "maxMs": 0.19999999999708962,
- "ratio": 1.4285714285565796
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.2000000000007276,
+ "ratio": 1.1111111111133567
},
"competitor": {
- "minMs": 0.17000000000007276,
- "maxMs": 0.37999999999738066,
- "ratio": 2.235294117630694
+ "minMs": 0.2000000000007276,
+ "maxMs": 0.2000000000007276,
+ "ratio": 1
},
- "stable": false,
+ "stable": true,
"rungs": [
"level",
- "exojs-leads",
+ "level",
"level"
]
}
@@ -4411,13 +4199,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.1500000000014552,
- "referenceP95Ms": 0.27999999999883585,
- "referenceGpuMs": 3.4957295000000004,
+ "referenceMs": 0.15999999999985448,
+ "referenceP95Ms": 0.2800000000024738,
+ "referenceGpuMs": 3.4241455,
"referenceOverFrameBudget": false,
"competitorMs": 0.18000000000029104,
- "competitorP95Ms": 0.3400000000001455,
- "competitorGpuMs": 0.366375,
+ "competitorP95Ms": 0.37999999999738066,
+ "competitorGpuMs": 0.36543749999999997,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -4431,19 +4219,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.11000000000058208,
- "maxMs": 0.15999999999985448,
- "ratio": 1.4545454545364347
+ "minMs": 0.1400000000030559,
+ "maxMs": 0.17000000000007276,
+ "ratio": 1.2142857142597288
},
"competitor": {
- "minMs": 0.13999999999941792,
- "maxMs": 0.3400000000001455,
- "ratio": 2.4285714285825653
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.19999999999708962,
+ "ratio": 1.1111111110931458
},
"stable": false,
"rungs": [
"level",
- "exojs-leads",
+ "level",
"exojs-leads"
]
}
@@ -4460,19 +4248,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 2.7000000000007276,
- "referenceP95Ms": 7.3400000000001455,
- "referenceGpuMs": 1.49175,
+ "referenceMs": 2.8800000000010186,
+ "referenceP95Ms": 7.140000000003056,
+ "referenceGpuMs": 1.4768125,
"referenceOverFrameBudget": false,
- "competitorMs": 4.319999999999709,
- "competitorP95Ms": 5.919999999998254,
- "competitorGpuMs": 0.29112499999999997,
+ "competitorMs": 4.309999999999491,
+ "competitorP95Ms": 5.819999999999709,
+ "competitorGpuMs": 0.29060450000000004,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.6250000000002105,
- "factor": 1.5999999999994612,
- "label": "ExoJS leads (1.60x)",
+ "ratio": 0.6682134570768814,
+ "factor": 1.4965277777770716,
+ "label": "ExoJS leads (1.50x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/3 vs 1/2/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4480,14 +4268,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.6700000000000728,
- "maxMs": 3.1300000000010186,
- "ratio": 1.172284644195106
+ "minMs": 2.75,
+ "maxMs": 2.9899999999997817,
+ "ratio": 1.087272727272648
},
"competitor": {
- "minMs": 4.249999999998181,
- "maxMs": 4.700000000000728,
- "ratio": 1.105882352941821
+ "minMs": 4.200000000000728,
+ "maxMs": 4.479999999999563,
+ "ratio": 1.066666666666378
},
"stable": true,
"rungs": [
@@ -4509,19 +4297,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 7.290000000000873,
- "referenceP95Ms": 9.399999999997817,
- "referenceGpuMs": 3.8783125,
+ "referenceMs": 7.920000000000073,
+ "referenceP95Ms": 9.299999999999272,
+ "referenceGpuMs": 3.80725,
"referenceOverFrameBudget": false,
- "competitorMs": 19.57999999999811,
- "competitorP95Ms": 24.42000000000189,
- "competitorGpuMs": 0.800354,
+ "competitorMs": 19.170000000000073,
+ "competitorP95Ms": 23.399999999997817,
+ "competitorGpuMs": 0.45458350000000003,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.3723186925434922,
- "factor": 2.6858710562408454,
- "label": "ExoJS leads (2.69x)",
+ "ratio": 0.41314553990610553,
+ "factor": 2.420454545454532,
+ "label": "ExoJS leads (2.42x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/3 vs 1/2/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4529,14 +4317,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 7.240000000001601,
- "maxMs": 8.089999999998327,
- "ratio": 1.117403314916649
+ "minMs": 7.1599999999998545,
+ "maxMs": 8.079999999999927,
+ "ratio": 1.1284916201117445
},
"competitor": {
- "minMs": 19,
- "maxMs": 19.7599999999984,
- "ratio": 1.0399999999999157
+ "minMs": 18.959999999999127,
+ "maxMs": 19.289999999999054,
+ "ratio": 1.0174050632911362
},
"stable": true,
"rungs": [
@@ -4563,19 +4351,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.5400000000008731,
- "referenceP95Ms": 0.8000000000029104,
- "referenceGpuMs": 0.223082,
+ "referenceMs": 0.5,
+ "referenceP95Ms": 0.9000000000014552,
+ "referenceGpuMs": 0.20479199999999997,
"referenceOverFrameBudget": false,
- "competitorMs": 1.8999999999996362,
- "competitorP95Ms": 2.680000000000291,
- "competitorGpuMs": 0.2800835,
+ "competitorMs": 2.0900000000019645,
+ "competitorP95Ms": 3.900000000001455,
+ "competitorGpuMs": 0.2813745,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.28421052631630345,
- "factor": 3.5185185185121557,
- "label": "ExoJS leads (3.52x)",
+ "ratio": 0.23923444976054067,
+ "factor": 4.180000000003929,
+ "label": "ExoJS leads (4.18x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 3/6/3 vs 2/4/2, none of them large enough to account for the gap); the difference is CPU-side",
@@ -4583,14 +4371,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.41999999999825377,
+ "minMs": 0.46000000000276486,
"maxMs": 0.5400000000008731,
- "ratio": 1.28571428572171
+ "ratio": 1.173913043473103
},
"competitor": {
- "minMs": 1.8400000000001455,
- "maxMs": 2.3799999999991996,
- "ratio": 1.2934782608690278
+ "minMs": 2.0600000000013097,
+ "maxMs": 2.349999999998545,
+ "ratio": 1.1407766990276946
},
"stable": true,
"rungs": [
@@ -4612,38 +4400,38 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.4400000000023283,
- "referenceP95Ms": 0.680000000000291,
- "referenceGpuMs": 0.235958,
+ "referenceMs": 0.4599999999991269,
+ "referenceP95Ms": 0.6000000000058208,
+ "referenceGpuMs": 0.234937,
"referenceOverFrameBudget": false,
- "competitorMs": 2.1700000000018917,
- "competitorP95Ms": 3.779999999998836,
- "competitorGpuMs": 0.449771,
+ "competitorMs": 2.360000000000582,
+ "competitorP95Ms": 3.4799999999959255,
+ "competitorGpuMs": 0.451791,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
- "structural": false
+ "side": "exojs",
+ "ratio": 0.1949152542368701,
+ "factor": 5.130434782619699,
+ "label": "ExoJS leads clearly (5.13x)",
+ "structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 4/8/3 vs 3/6/3, none of them large enough to account for the gap); the difference is CPU-side",
"timer": "resolved",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.3600000000005821,
- "maxMs": 0.4500000000007276,
- "ratio": 1.25
+ "minMs": 0.4399999999986903,
+ "maxMs": 0.4599999999991269,
+ "ratio": 1.045454545455673
},
"competitor": {
- "minMs": 2,
- "maxMs": 2.400000000001455,
- "ratio": 1.2000000000007276
+ "minMs": 2.1999999999970896,
+ "maxMs": 2.7400000000016007,
+ "ratio": 1.2454545454569206
},
- "stable": false,
+ "stable": true,
"rungs": [
- "exojs-leads",
+ "exojs-leads-clearly",
"exojs-leads-clearly",
"exojs-leads-clearly"
]
@@ -4661,13 +4449,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.42000000000189175,
- "referenceP95Ms": 0.6200000000026193,
- "referenceGpuMs": 0.30972900000000003,
+ "referenceMs": 0.4400000000023283,
+ "referenceP95Ms": 0.6599999999962165,
+ "referenceGpuMs": 0.3148955,
"referenceOverFrameBudget": false,
- "competitorMs": 2.1699999999982538,
- "competitorP95Ms": 3.720000000001164,
- "competitorGpuMs": 0.8490215,
+ "competitorMs": 2.1999999999970896,
+ "competitorP95Ms": 3.819999999999709,
+ "competitorGpuMs": 0.7915205,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -4681,20 +4469,20 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.3600000000005821,
- "maxMs": 0.4400000000023283,
- "ratio": 1.2222222222267136
+ "minMs": 0.4400000000023283,
+ "maxMs": 0.4599999999991269,
+ "ratio": 1.045454545447029
},
"competitor": {
- "minMs": 1.9199999999982538,
- "maxMs": 2.9099999999998545,
- "ratio": 1.5156250000013027
+ "minMs": 2.100000000002183,
+ "maxMs": 2.4099999999998545,
+ "ratio": 1.1476190476177854
},
"stable": false,
"rungs": [
- "exojs-leads",
"exojs-leads-clearly",
- "exojs-leads-clearly"
+ "exojs-leads",
+ "exojs-leads"
]
}
}
@@ -4710,19 +4498,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.4599999999991269,
- "referenceP95Ms": 0.6999999999970896,
- "referenceGpuMs": 0.3076675,
+ "referenceMs": 0.4500000000007276,
+ "referenceP95Ms": 0.7199999999938882,
+ "referenceGpuMs": 0.3193745,
"referenceOverFrameBudget": false,
- "competitorMs": 0.75,
- "competitorP95Ms": 1.180000000000291,
- "competitorGpuMs": 0.47770799999999997,
+ "competitorMs": 0.7599999999983993,
+ "competitorP95Ms": 1.2200000000011642,
+ "competitorGpuMs": 0.42333350000000003,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.6133333333321692,
- "factor": 1.6304347826117902,
- "label": "ExoJS leads (1.63x)",
+ "ratio": 0.5921052631600991,
+ "factor": 1.6888888888826012,
+ "label": "ExoJS leads (1.69x)",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (5 vs 8 per frame)",
@@ -4730,14 +4518,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.4500000000007276,
- "maxMs": 0.5199999999967986,
- "ratio": 1.1555555555465729
+ "minMs": 0.42000000000189175,
+ "maxMs": 0.5600000000013097,
+ "ratio": 1.333333333330446
},
"competitor": {
- "minMs": 0.6999999999970896,
- "maxMs": 1.3699999999989814,
- "ratio": 1.957142857149539
+ "minMs": 0.7299999999995634,
+ "maxMs": 0.9199999999982538,
+ "ratio": 1.2602739726011014
},
"stable": true,
"rungs": [
@@ -4760,12 +4548,12 @@
{
"competitor": "pixi",
"referenceMs": 0.3600000000005821,
- "referenceP95Ms": 0.5200000000040745,
- "referenceGpuMs": 0.3171875,
+ "referenceP95Ms": 0.5999999999985448,
+ "referenceGpuMs": 0.30210349999999997,
"referenceOverFrameBudget": false,
- "competitorMs": 0.3000000000029104,
- "competitorP95Ms": 0.5199999999967986,
- "competitorGpuMs": 0.153042,
+ "competitorMs": 0.31999999999970896,
+ "competitorP95Ms": 0.5,
+ "competitorGpuMs": 0.1531245,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -4779,20 +4567,70 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.3000000000029104,
- "maxMs": 0.3899999999994179,
- "ratio": 1.2999999999854481
+ "minMs": 0.3499999999985448,
+ "maxMs": 0.3999999999978172,
+ "ratio": 1.142857142855658
},
"competitor": {
- "minMs": 0.2400000000016007,
- "maxMs": 0.5200000000004366,
- "ratio": 2.166666666654035
+ "minMs": 0.2800000000024738,
+ "maxMs": 0.41999999999825377,
+ "ratio": 1.499999999980511
},
"stable": false,
"rungs": [
+ "level",
"competitor-leads",
- "exojs-leads",
- "competitor-leads"
+ "level"
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "archetype": "fx-blur",
+ "category": "Render targets",
+ "count": 720,
+ "loadId": "720",
+ "unit": "viewport",
+ "primary": true,
+ "label": "1280 x 720",
+ "cells": [
+ {
+ "competitor": "pixi",
+ "referenceMs": 0.42000000000552973,
+ "referenceP95Ms": 0.5800000000017462,
+ "referenceGpuMs": 0.313563,
+ "referenceOverFrameBudget": false,
+ "competitorMs": 0.47999999999592546,
+ "competitorP95Ms": 0.7399999999979627,
+ "competitorGpuMs": 0.33620700000000003,
+ "competitorOverFrameBudget": false,
+ "verdict": {
+ "side": "neither",
+ "ratio": null,
+ "factor": null,
+ "label": "unstable across runs",
+ "structural": false
+ },
+ "mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 4/8/5 vs 3/6/3, none of them large enough to account for the gap); the difference is CPU-side",
+ "timer": "resolved",
+ "aggregate": {
+ "runs": 3,
+ "reference": {
+ "minMs": 0.3800000000046566,
+ "maxMs": 0.43999999999505235,
+ "ratio": 1.157894736814896
+ },
+ "competitor": {
+ "minMs": 0.4599999999991269,
+ "maxMs": 0.47999999999956344,
+ "ratio": 1.0434782608705968
+ },
+ "stable": false,
+ "rungs": [
+ "level",
+ "level",
+ "exojs-leads"
]
}
}
@@ -4808,19 +4646,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.3500000000021828,
- "referenceP95Ms": 0.5,
- "referenceGpuMs": 0.32100049999999997,
+ "referenceMs": 0.37999999999738066,
+ "referenceP95Ms": 0.6199999999953434,
+ "referenceGpuMs": 0.26908299999999996,
"referenceOverFrameBudget": false,
- "competitorMs": 0.4599999999991269,
- "competitorP95Ms": 0.7599999999947613,
- "competitorGpuMs": 0.121666,
+ "competitorMs": 0.42000000000552973,
+ "competitorP95Ms": 0.7199999999938882,
+ "competitorGpuMs": 0.0922915,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 0.9047619047437561,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "ExoJS issues fewer draw calls (4 vs 10 per frame)",
@@ -4828,19 +4666,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.33999999999650754,
- "maxMs": 0.3600000000005821,
- "ratio": 1.0588235294243529
+ "minMs": 0.36999999999898137,
+ "maxMs": 0.4000000000014552,
+ "ratio": 1.0810810810879903
},
"competitor": {
- "minMs": 0.3400000000001455,
- "maxMs": 0.6300000000010186,
- "ratio": 1.8529411764727912
+ "minMs": 0.42000000000189175,
+ "maxMs": 0.4400000000023283,
+ "ratio": 1.0476190476198726
},
- "stable": false,
+ "stable": true,
"rungs": [
- "exojs-leads",
- "exojs-leads",
+ "level",
+ "level",
"level"
]
}
@@ -4862,13 +4700,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.23999999999978172,
- "referenceP95Ms": 1.4600000000027649,
- "referenceGpuMs": 0.101021,
+ "referenceMs": 0.25,
+ "referenceP95Ms": 1.5600000000013097,
+ "referenceGpuMs": 0.100583,
"referenceOverFrameBudget": false,
- "competitorMs": 0.19999999999708962,
- "competitorP95Ms": 0.3600000000005821,
- "competitorGpuMs": 0.097458,
+ "competitorMs": 0.2000000000007276,
+ "competitorP95Ms": 0.3400000000001455,
+ "competitorGpuMs": 0.097875,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -4878,23 +4716,23 @@
"structural": false
},
"mechanism": "competitor issues fewer draw calls (90 vs 1 per frame)",
- "timer": "limited",
+ "timer": "resolved",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.18000000000029104,
- "maxMs": 0.2400000000016007,
- "ratio": 1.3333333333400703
+ "minMs": 0.23999999999978172,
+ "maxMs": 0.2800000000024738,
+ "ratio": 1.1666666666780354
},
"competitor": {
- "minMs": 0.17000000000189175,
- "maxMs": 0.36999999999898137,
- "ratio": 2.1764705882050825
+ "minMs": 0.2000000000007276,
+ "maxMs": 0.21999999999752617,
+ "ratio": 1.0999999999836292
},
"stable": false,
"rungs": [
"competitor-leads",
- "exojs-leads",
+ "competitor-leads",
"level"
]
}
@@ -4916,18 +4754,18 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.2599999999983993,
- "referenceP95Ms": 1.4799999999959255,
- "referenceGpuMs": 0.067771,
+ "referenceMs": 0.26000000000203727,
+ "referenceP95Ms": 1.4400000000023283,
+ "referenceGpuMs": 0.0677085,
"referenceOverFrameBudget": false,
- "competitorMs": 0.41999999999825377,
- "competitorP95Ms": 0.8399999999965075,
- "competitorGpuMs": 0.076708,
+ "competitorMs": 0.42000000000189175,
+ "competitorP95Ms": 0.7000000000043656,
+ "competitorGpuMs": 0.079042,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.6190476190463816,
- "factor": 1.6153846153878444,
+ "ratio": 0.6190476190496814,
+ "factor": 1.6153846153792337,
"label": "ExoJS leads (1.62x)",
"structural": false
},
@@ -4936,14 +4774,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.22000000000116415,
- "maxMs": 0.26000000000203727,
- "ratio": 1.1818181818211884
+ "minMs": 0.26000000000203727,
+ "maxMs": 0.27999999999883585,
+ "ratio": 1.076923076910161
},
"competitor": {
- "minMs": 0.37999999999738066,
- "maxMs": 0.6399999999994179,
- "ratio": 1.6842105263258669
+ "minMs": 0.4000000000014552,
+ "maxMs": 0.5300000000024738,
+ "ratio": 1.3250000000013642
},
"stable": true,
"rungs": [
@@ -4965,34 +4803,34 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.20999999999912689,
+ "referenceMs": 0.18000000000029104,
"referenceP95Ms": 0.8400000000037835,
- "referenceGpuMs": 0.06789600000000001,
+ "referenceGpuMs": 0.066458,
"referenceOverFrameBudget": false,
- "competitorMs": 0.4400000000023283,
- "competitorP95Ms": 0.6999999999970896,
- "competitorGpuMs": 0.0767505,
+ "competitorMs": 0.42999999999665306,
+ "competitorP95Ms": 0.6399999999994179,
+ "competitorGpuMs": 0.0762915,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.4772727272682174,
- "factor": 2.0952380952578937,
- "label": "ExoJS leads (2.10x)",
+ "ratio": 0.4186046511667258,
+ "factor": 2.388888888866432,
+ "label": "ExoJS leads (2.39x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (60 vs 2 per frame)",
- "timer": "resolved",
+ "timer": "limited",
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2000000000007276,
- "maxMs": 0.22999999999956344,
- "ratio": 1.1499999999936334
+ "minMs": 0.18000000000029104,
+ "maxMs": 0.26000000000203727,
+ "ratio": 1.444444444453427
},
"competitor": {
- "minMs": 0.31999999999970896,
- "maxMs": 0.48999999999796273,
- "ratio": 1.5312499999950262
+ "minMs": 0.42000000000189175,
+ "maxMs": 0.4599999999991269,
+ "ratio": 1.0952380952310832
},
"stable": true,
"rungs": [
@@ -5014,19 +4852,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.6899999999986903,
- "referenceP95Ms": 1.319999999999709,
- "referenceGpuMs": 0.0669585,
+ "referenceMs": 0.8600000000005821,
+ "referenceP95Ms": 1.3800000000046566,
+ "referenceGpuMs": 0.06756200000000001,
"referenceOverFrameBudget": false,
- "competitorMs": 2.3300000000017462,
- "competitorP95Ms": 3.3800000000046566,
- "competitorGpuMs": 0.069917,
+ "competitorMs": 1.8699999999989814,
+ "competitorP95Ms": 3.1200000000026193,
+ "competitorGpuMs": 0.06975,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.29613733905500994,
- "factor": 3.376811594211839,
- "label": "ExoJS leads (3.38x)",
+ "ratio": 0.459893048128904,
+ "factor": 2.1744186046485066,
+ "label": "ExoJS leads (2.17x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 2/4/2 vs 2/4/3, none of them large enough to account for the gap); the difference is CPU-side",
@@ -5034,14 +4872,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.6699999999982538,
- "maxMs": 0.9099999999998545,
- "ratio": 1.3582089552272034
+ "minMs": 0.8599999999969441,
+ "maxMs": 1.0400000000008731,
+ "ratio": 1.2093023255867077
},
"competitor": {
- "minMs": 1.7000000000007276,
- "maxMs": 2.390000000003056,
- "ratio": 1.4058823529423723
+ "minMs": 1.2000000000043656,
+ "maxMs": 2.2699999999967986,
+ "ratio": 1.891666666657117
},
"stable": true,
"rungs": [
@@ -5068,13 +4906,13 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.2800000000024738,
- "referenceP95Ms": 0.4400000000023283,
- "referenceGpuMs": 0.07079150000000001,
+ "referenceMs": 0.27999999999883585,
+ "referenceP95Ms": 0.41999999999825377,
+ "referenceGpuMs": 0.070042,
"referenceOverFrameBudget": false,
- "competitorMs": 0.26000000000203727,
- "competitorP95Ms": 0.5,
- "competitorGpuMs": 0.0683335,
+ "competitorMs": 0.27999999999883585,
+ "competitorP95Ms": 0.4400000000023283,
+ "competitorGpuMs": 0.06852050000000001,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
@@ -5088,19 +4926,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.2599999999947613,
- "maxMs": 0.3000000000029104,
- "ratio": 1.1538461538805962
+ "minMs": 0.27999999999883585,
+ "maxMs": 0.2999999999956344,
+ "ratio": 1.0714285714174347
},
"competitor": {
- "minMs": 0.22999999999956344,
- "maxMs": 0.4400000000023283,
- "ratio": 1.9130434782746237
+ "minMs": 0.26000000000203727,
+ "maxMs": 0.3600000000005821,
+ "ratio": 1.384615384606774
},
"stable": false,
"rungs": [
- "level",
"exojs-leads",
+ "level",
"level"
]
}
@@ -5117,19 +4955,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.4599999999991269,
- "referenceP95Ms": 0.5799999999944703,
- "referenceGpuMs": 0.146333,
+ "referenceMs": 0.4400000000023283,
+ "referenceP95Ms": 0.5800000000017462,
+ "referenceGpuMs": 0.1442495,
"referenceOverFrameBudget": false,
- "competitorMs": 0.23999999999796273,
- "competitorP95Ms": 0.41999999999825377,
- "competitorGpuMs": 0.232042,
+ "competitorMs": 0.25,
+ "competitorP95Ms": 0.4599999999991269,
+ "competitorGpuMs": 0.23293750000000002,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "competitor",
+ "ratio": 1.7600000000093132,
+ "factor": 1.7600000000093132,
+ "label": "competitor leads (1.76x)",
"structural": false
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/2 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -5138,18 +4976,18 @@
"runs": 3,
"reference": {
"minMs": 0.43999999999505235,
- "maxMs": 0.47999999999592546,
- "ratio": 1.0909090909120975
+ "maxMs": 0.4599999999991269,
+ "ratio": 1.045454545464317
},
"competitor": {
- "minMs": 0.22000000000116415,
- "maxMs": 0.4599999999991269,
- "ratio": 2.090909090894058
+ "minMs": 0.23999999999796273,
+ "maxMs": 0.27999999999883585,
+ "ratio": 1.1666666666717194
},
- "stable": false,
+ "stable": true,
"rungs": [
"competitor-leads",
- "level",
+ "competitor-leads",
"competitor-leads"
]
}
@@ -5166,19 +5004,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 2.109999999996944,
- "referenceP95Ms": 2.5199999999967986,
- "referenceGpuMs": 0.38845850000000004,
+ "referenceMs": 2.030000000002474,
+ "referenceP95Ms": 2.959999999999127,
+ "referenceGpuMs": 0.623188,
"referenceOverFrameBudget": false,
- "competitorMs": 0.26000000000203727,
- "competitorP95Ms": 0.4000000000014552,
- "competitorGpuMs": 0.261021,
+ "competitorMs": 0.3099999999976717,
+ "competitorP95Ms": 0.47999999999592546,
+ "competitorGpuMs": 0.2931875,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 8.115384615309273,
- "factor": 8.115384615309273,
- "label": "competitor leads clearly (8.12x)",
+ "ratio": 6.548387096831356,
+ "factor": 6.548387096831356,
+ "label": "competitor leads clearly (6.55x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/2 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -5186,14 +5024,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 2.0200000000004366,
- "maxMs": 2.179999999996653,
- "ratio": 1.079207920790189
+ "minMs": 1.9099999999998545,
+ "maxMs": 2.139999999999418,
+ "ratio": 1.1204188481673198
},
"competitor": {
- "minMs": 0.20999999999912689,
- "maxMs": 0.37999999999738066,
- "ratio": 1.80952380951886
+ "minMs": 0.27999999999883585,
+ "maxMs": 0.32999999999810825,
+ "ratio": 1.1785714285695725
},
"stable": true,
"rungs": [
@@ -5215,19 +5053,19 @@
"cells": [
{
"competitor": "pixi",
- "referenceMs": 0.680000000000291,
- "referenceP95Ms": 0.8600000000005821,
- "referenceGpuMs": 0.22912500000000002,
+ "referenceMs": 0.6999999999970896,
+ "referenceP95Ms": 0.8400000000037835,
+ "referenceGpuMs": 0.229396,
"referenceOverFrameBudget": false,
- "competitorMs": 0.9200000000018917,
- "competitorP95Ms": 1.180000000000291,
- "competitorGpuMs": 0.138229,
+ "competitorMs": 0.9599999999991269,
+ "competitorP95Ms": 1.2000000000043656,
+ "competitorGpuMs": 0.1384795,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.7391304347814052,
- "factor": 1.3529411764727912,
- "label": "ExoJS leads (1.35x)",
+ "ratio": 0.7291666666642982,
+ "factor": 1.371428571433026,
+ "label": "ExoJS leads (1.37x)",
"structural": false
},
"mechanism": "competitor issues fewer draw calls (90 vs 1 per frame)",
@@ -5235,14 +5073,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.6600000000034925,
- "maxMs": 0.6999999999970896,
- "ratio": 1.0606060605960386
+ "minMs": 0.6900000000023283,
+ "maxMs": 0.7099999999991269,
+ "ratio": 1.0289855072416392
},
"competitor": {
- "minMs": 0.9199999999982538,
- "maxMs": 1.0799999999981083,
- "ratio": 1.1739130434784328
+ "minMs": 0.9399999999986903,
+ "maxMs": 1.0400000000008731,
+ "ratio": 1.1063829787258745
},
"stable": true,
"rungs": [
@@ -5270,18 +5108,18 @@
{
"competitor": "pixi",
"referenceMs": 0.6100000000005821,
- "referenceP95Ms": 0.8600000000005821,
- "referenceGpuMs": 0.30239649999999996,
+ "referenceP95Ms": 0.9199999999982538,
+ "referenceGpuMs": 0.175959,
"referenceOverFrameBudget": false,
- "competitorMs": 16.660000000003492,
- "competitorP95Ms": 21,
- "competitorGpuMs": 0.294688,
- "competitorOverFrameBudget": false,
+ "competitorMs": 17.63000000000102,
+ "competitorP95Ms": 22.099999999998545,
+ "competitorGpuMs": 0.293354,
+ "competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.0366146458583706,
- "factor": 27.31147540981573,
- "label": "ExoJS leads clearly (27.31x)",
+ "ratio": 0.03460011344302591,
+ "factor": 28.90163934423639,
+ "label": "ExoJS leads clearly (28.90x)",
"structural": true
},
"mechanism": "structurally equivalent at this scale (draw/bind/upload per frame: 1/2/0 vs 1/2/1, none of them large enough to account for the gap); the difference is CPU-side",
@@ -5289,14 +5127,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 0.5,
- "maxMs": 0.6200000000026193,
- "ratio": 1.2400000000052387
+ "minMs": 0.5599999999976717,
+ "maxMs": 0.6100000000005821,
+ "ratio": 1.0892857142912826
},
"competitor": {
- "minMs": 16.280000000002474,
- "maxMs": 17.74000000000524,
- "ratio": 1.089680589680746
+ "minMs": 16.61999999999898,
+ "maxMs": 17.68000000000029,
+ "ratio": 1.0637785800241502
},
"stable": true,
"rungs": [
@@ -5307,6 +5145,55 @@
}
}
]
+ },
+ {
+ "archetype": "ui-layout-update",
+ "category": "Interaction",
+ "count": 1000,
+ "loadId": "1k",
+ "unit": "widgets",
+ "primary": true,
+ "cells": [
+ {
+ "competitor": "pixi",
+ "referenceMs": 10.2599999999984,
+ "referenceP95Ms": 10.780000000006112,
+ "referenceGpuMs": 0.0336665,
+ "referenceOverFrameBudget": false,
+ "competitorMs": 48.62000000000262,
+ "competitorP95Ms": 52.599999999998545,
+ "competitorGpuMs": 0.033708,
+ "competitorOverFrameBudget": true,
+ "verdict": {
+ "side": "exojs",
+ "ratio": 0.21102426984775496,
+ "factor": 4.738791423002944,
+ "label": "ExoJS leads (4.74x)",
+ "structural": false
+ },
+ "mechanism": "neither arm submits anything for this scene (draw/bind/upload per frame: 0/0/0 vs 0/0/1); the whole difference is the per-frame work itself",
+ "timer": "resolved",
+ "aggregate": {
+ "runs": 3,
+ "reference": {
+ "minMs": 10.220000000001164,
+ "maxMs": 10.400000000001455,
+ "ratio": 1.017612524461866
+ },
+ "competitor": {
+ "minMs": 48.36000000000058,
+ "maxMs": 48.70000000000073,
+ "ratio": 1.0070306038048003
+ },
+ "stable": true,
+ "rungs": [
+ "exojs-leads",
+ "exojs-leads",
+ "exojs-leads"
+ ]
+ }
+ }
+ ]
}
]
}
@@ -5339,10 +5226,6 @@
{
"archetype": "mixed-material-atlased",
"reason": "ExoJS-internal structural probe: a competitor arm renders a different scene here, so a wall-clock comparison would not be like for like"
- },
- {
- "archetype": "fx-blur",
- "reason": "ExoJS-internal structural probe: a competitor arm renders a different scene here, so a wall-clock comparison would not be like for like"
}
],
"webgl1": []
@@ -5372,7 +5255,7 @@
},
"fixedDelta": 0.016666666666666666,
"clock": {
- "resolutionMs": 0.01999999999999602,
+ "resolutionMs": 0.019999999999999574,
"crossOriginIsolated": true
},
"caveats": [
@@ -5389,7 +5272,7 @@
"nape-js arm (pure-JS peer): default single-step solver with default velocity/position iterations (10/10), sleeping and dynamic AABB broadphase at library defaults. Materials, body layouts, joints and perturbations come from the shared neutral scene descriptor. Contact count = active collision arbiters; ray queries use Space.rayCast with outer-surface semantics. These counters are engine-specific structural proxies, not a claim that every solver performs identical internal work."
],
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:21:55.258Z"
+ "timestamp": "2026-09-12T04:20:58.243Z"
},
{
"browser": "webkit",
@@ -5412,7 +5295,7 @@
},
"fixedDelta": 0.016666666666666666,
"clock": {
- "resolutionMs": 0.01999999999999602,
+ "resolutionMs": 0.019999999999999574,
"crossOriginIsolated": true
},
"caveats": [
@@ -5429,7 +5312,7 @@
"nape-js arm (pure-JS peer): default single-step solver with default velocity/position iterations (10/10), sleeping and dynamic AABB broadphase at library defaults. Materials, body layouts, joints and perturbations come from the shared neutral scene descriptor. Contact count = active collision arbiters; ray queries use Space.rayCast with outer-surface semantics. These counters are engine-specific structural proxies, not a claim that every solver performs identical internal work."
],
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:34:01.941Z"
+ "timestamp": "2026-09-12T04:32:46.548Z"
},
{
"browser": "webkit",
@@ -5452,7 +5335,7 @@
},
"fixedDelta": 0.016666666666666666,
"clock": {
- "resolutionMs": 0.01999999999999602,
+ "resolutionMs": 0.019999999999999574,
"crossOriginIsolated": true
},
"caveats": [
@@ -5469,7 +5352,7 @@
"nape-js arm (pure-JS peer): default single-step solver with default velocity/position iterations (10/10), sleeping and dynamic AABB broadphase at library defaults. Materials, body layouts, joints and perturbations come from the shared neutral scene descriptor. Contact count = active collision arbiters; ray queries use Space.rayCast with outer-surface semantics. These counters are engine-specific structural proxies, not a claim that every solver performs identical internal work."
],
"engineVersion": "0.17.0",
- "timestamp": "2026-09-12T03:46:13.242Z"
+ "timestamp": "2026-09-12T04:44:36.717Z"
}
],
"libraries": [
@@ -5507,19 +5390,19 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.139999999999873,
- "referenceP95Ms": 6.019999999999982,
+ "referenceMs": 5.350000000000136,
+ "referenceP95Ms": 6.120000000000118,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 11.139999999999418,
- "competitorP95Ms": 12.099999999998545,
+ "competitorMs": 10.290000000000873,
+ "competitorP95Ms": 12.119999999998981,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.46140035906643995,
- "factor": 2.1673151750972166,
- "label": "ExoJS leads (2.17x)",
+ "ratio": 0.5199222546161013,
+ "factor": 1.9233644859814225,
+ "label": "ExoJS leads (1.92x)",
"structural": false
},
"mechanism": "ExoJS resolves fewer solved contacts (5501 vs 12297); the counters are not semantically identical across arms (see the run's caveats)",
@@ -5527,14 +5410,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.059999999999945,
- "maxMs": 5.400000000000091,
- "ratio": 1.0671936758893577
+ "minMs": 5.3400000000001455,
+ "maxMs": 5.460000000000036,
+ "ratio": 1.0224719101123385
},
"competitor": {
- "minMs": 10.380000000001019,
- "maxMs": 11.200000000000728,
- "ratio": 1.0789980732176907
+ "minMs": 10.180000000000291,
+ "maxMs": 11.140000000001237,
+ "ratio": 1.094302554027595
},
"stable": true,
"rungs": [
@@ -5546,18 +5429,18 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.139999999999873,
- "referenceP95Ms": 6.019999999999982,
+ "referenceMs": 5.350000000000136,
+ "referenceP95Ms": 6.120000000000118,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 9.639999999999418,
- "competitorP95Ms": 12.660000000003492,
+ "competitorMs": 10.080000000001746,
+ "competitorP95Ms": 12.15999999998894,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.533195020746907,
- "factor": 1.8754863813228904,
+ "ratio": 0.5307539682538899,
+ "factor": 1.8841121495329884,
"label": "ExoJS leads (1.88x)",
"structural": false
},
@@ -5566,14 +5449,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.059999999999945,
- "maxMs": 5.400000000000091,
- "ratio": 1.0671936758893577
+ "minMs": 5.3400000000001455,
+ "maxMs": 5.460000000000036,
+ "ratio": 1.0224719101123385
},
"competitor": {
- "minMs": 9.540000000008149,
- "maxMs": 10.020000000004075,
- "ratio": 1.050314465408335
+ "minMs": 10.009999999994761,
+ "maxMs": 10.220000000001164,
+ "ratio": 1.0209790209796716
},
"stable": true,
"rungs": [
@@ -5585,19 +5468,19 @@
},
{
"competitor": "planck",
- "referenceMs": 5.139999999999873,
- "referenceP95Ms": 6.019999999999982,
+ "referenceMs": 5.350000000000136,
+ "referenceP95Ms": 6.120000000000118,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 29.5099999999984,
- "competitorP95Ms": 36.61999999999534,
+ "competitorMs": 29.81999999999971,
+ "competitorP95Ms": 36.4800000000032,
"competitorGpuMs": null,
"competitorOverFrameBudget": true,
"verdict": {
"side": "exojs",
- "ratio": 0.1741782446628313,
- "factor": 5.741245136186601,
- "label": "ExoJS leads clearly (5.74x)",
+ "ratio": 0.17940979208585475,
+ "factor": 5.573831775700738,
+ "label": "ExoJS leads clearly (5.57x)",
"structural": true
},
"mechanism": "ExoJS resolves fewer solved contacts (5501 vs 10677); the counters are not semantically identical across arms (see the run's caveats)",
@@ -5605,14 +5488,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.059999999999945,
- "maxMs": 5.400000000000091,
- "ratio": 1.0671936758893577
+ "minMs": 5.3400000000001455,
+ "maxMs": 5.460000000000036,
+ "ratio": 1.0224719101123385
},
"competitor": {
- "minMs": 29.479999999999563,
- "maxMs": 30.360000000000582,
- "ratio": 1.0298507462686917
+ "minMs": 29.450000000000728,
+ "maxMs": 30.470000000004802,
+ "ratio": 1.0346349745332444
},
"stable": true,
"rungs": [
@@ -5624,19 +5507,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.139999999999873,
- "referenceP95Ms": 6.019999999999982,
+ "referenceMs": 5.350000000000136,
+ "referenceP95Ms": 6.120000000000118,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 4.290000000000873,
- "competitorP95Ms": 5.360000000000582,
+ "competitorMs": 4.080000000001746,
+ "competitorP95Ms": 5.320000000006985,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
- "side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "side": "competitor",
+ "ratio": 1.3112745098033938,
+ "factor": 1.3112745098033938,
+ "label": "competitor leads (1.31x)",
"structural": false
},
"mechanism": "ExoJS resolves fewer solved contacts (5501 vs 10045); the counters are not semantically identical across arms (see the run's caveats)",
@@ -5644,19 +5527,19 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.059999999999945,
- "maxMs": 5.400000000000091,
- "ratio": 1.0671936758893577
+ "minMs": 5.3400000000001455,
+ "maxMs": 5.460000000000036,
+ "ratio": 1.0224719101123385
},
"competitor": {
- "minMs": 4.05000000000291,
- "maxMs": 4.310000000004948,
- "ratio": 1.0641975308646545
+ "minMs": 4.059999999997672,
+ "maxMs": 4.0899999999965075,
+ "ratio": 1.0073891625612938
},
- "stable": false,
+ "stable": true,
"rungs": [
- "level",
- "level",
+ "competitor-leads",
+ "competitor-leads",
"competitor-leads"
]
}
@@ -5673,17 +5556,17 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.440000000000509,
- "referenceP95Ms": 6.460000000000036,
+ "referenceMs": 5.460000000000036,
+ "referenceP95Ms": 6.5,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
"competitorMs": 5.240000000001601,
- "competitorP95Ms": 5.979999999999563,
+ "competitorP95Ms": 6.219999999997526,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.0381679389310778,
+ "ratio": 1.041984732824116,
"factor": 1,
"label": "level",
"structural": false
@@ -5693,14 +5576,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.380000000000109,
- "maxMs": 5.479999999999563,
- "ratio": 1.0185873605946938
+ "minMs": 5.4399999999996,
+ "maxMs": 5.559999999999945,
+ "ratio": 1.022058823529477
},
"competitor": {
- "minMs": 5.220000000001164,
- "maxMs": 5.299999999999272,
- "ratio": 1.0153256704977185
+ "minMs": 5.240000000001601,
+ "maxMs": 5.400000000001455,
+ "ratio": 1.0305343511450011
},
"stable": true,
"rungs": [
@@ -5712,17 +5595,17 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.440000000000509,
- "referenceP95Ms": 6.460000000000036,
+ "referenceMs": 5.460000000000036,
+ "referenceP95Ms": 6.5,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.860000000000582,
- "competitorP95Ms": 6.680000000007567,
+ "competitorMs": 5.8399999999965075,
+ "competitorP95Ms": 6.69999999999709,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9283276450511893,
+ "ratio": 0.9349315068498804,
"factor": 1,
"label": "level",
"structural": false
@@ -5732,14 +5615,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.380000000000109,
- "maxMs": 5.479999999999563,
- "ratio": 1.0185873605946938
+ "minMs": 5.4399999999996,
+ "maxMs": 5.559999999999945,
+ "ratio": 1.022058823529477
},
"competitor": {
"minMs": 5.819999999992433,
- "maxMs": 5.880000000004657,
- "ratio": 1.010309278352629
+ "maxMs": 5.899999999994179,
+ "ratio": 1.0137457044676719
},
"stable": true,
"rungs": [
@@ -5751,17 +5634,17 @@
},
{
"competitor": "planck",
- "referenceMs": 5.440000000000509,
- "referenceP95Ms": 6.460000000000036,
+ "referenceMs": 5.460000000000036,
+ "referenceP95Ms": 6.5,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.620000000002619,
- "competitorP95Ms": 6.419999999998254,
+ "competitorMs": 5.819999999999709,
+ "competitorP95Ms": 6.619999999995343,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9679715302487498,
+ "ratio": 0.9381443298969604,
"factor": 1,
"label": "level",
"structural": false
@@ -5771,14 +5654,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.380000000000109,
- "maxMs": 5.479999999999563,
- "ratio": 1.0185873605946938
+ "minMs": 5.4399999999996,
+ "maxMs": 5.559999999999945,
+ "ratio": 1.022058823529477
},
"competitor": {
- "minMs": 5.440000000002328,
- "maxMs": 5.739999999997963,
- "ratio": 1.0551470588227032
+ "minMs": 5.580000000001746,
+ "maxMs": 5.999999999996362,
+ "ratio": 1.0752688172033127
},
"stable": true,
"rungs": [
@@ -5790,8 +5673,8 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.440000000000509,
- "referenceP95Ms": 6.460000000000036,
+ "referenceMs": 5.460000000000036,
+ "referenceP95Ms": 6.5,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
"competitorMs": 1.320000000006985,
@@ -5800,9 +5683,9 @@
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 4.121212121190699,
- "factor": 4.121212121190699,
- "label": "competitor leads (4.12x)",
+ "ratio": 4.136363636341776,
+ "factor": 4.136363636341776,
+ "label": "competitor leads (4.14x)",
"structural": false
},
"mechanism": "identical scene (1504 bodies, 4236 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5810,14 +5693,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.380000000000109,
- "maxMs": 5.479999999999563,
- "ratio": 1.0185873605946938
+ "minMs": 5.4399999999996,
+ "maxMs": 5.559999999999945,
+ "ratio": 1.022058823529477
},
"competitor": {
- "minMs": 1.3000000000029104,
- "maxMs": 1.360000000000582,
- "ratio": 1.0461538461519517
+ "minMs": 1.319999999999709,
+ "maxMs": 1.3399999999965075,
+ "ratio": 1.015151515149093
},
"stable": true,
"rungs": [
@@ -5839,19 +5722,19 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 4.579999999999927,
- "referenceP95Ms": 5.020000000000437,
+ "referenceMs": 4.539999999999964,
+ "referenceP95Ms": 4.839999999999236,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 2.2000000000007276,
- "competitorP95Ms": 2.359999999996944,
+ "competitorMs": 2.1199999999989814,
+ "competitorP95Ms": 2.319999999999709,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 2.0818181818174604,
- "factor": 2.0818181818174604,
- "label": "competitor leads (2.08x)",
+ "ratio": 2.141509433963276,
+ "factor": 2.141509433963276,
+ "label": "competitor leads (2.14x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5859,14 +5742,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.539999999999964,
- "maxMs": 4.619999999999891,
- "ratio": 1.0176211453744335
+ "minMs": 4.520000000000437,
+ "maxMs": 4.579999999999927,
+ "ratio": 1.0132743362830718
},
"competitor": {
- "minMs": 2.1200000000026193,
- "maxMs": 2.220000000001164,
- "ratio": 1.04716981132001
+ "minMs": 2.1199999999989814,
+ "maxMs": 2.2400000000016007,
+ "ratio": 1.0566037735861684
},
"stable": true,
"rungs": [
@@ -5878,17 +5761,17 @@
},
{
"competitor": "nape-js",
- "referenceMs": 4.579999999999927,
- "referenceP95Ms": 5.020000000000437,
+ "referenceMs": 4.539999999999964,
+ "referenceP95Ms": 4.839999999999236,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.019999999989523,
- "competitorP95Ms": 6.279999999998836,
+ "competitorMs": 4.899999999994179,
+ "competitorP95Ms": 6.039999999993597,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9123505976114514,
+ "ratio": 0.9265306122459912,
"factor": 1,
"label": "level",
"structural": false
@@ -5898,14 +5781,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.539999999999964,
- "maxMs": 4.619999999999891,
- "ratio": 1.0176211453744335
+ "minMs": 4.520000000000437,
+ "maxMs": 4.579999999999927,
+ "ratio": 1.0132743362830718
},
"competitor": {
- "minMs": 4.990000000005239,
- "maxMs": 5.099999999991269,
- "ratio": 1.02204408817353
+ "minMs": 4.879999999997381,
+ "maxMs": 5.059999999997672,
+ "ratio": 1.0368852459017188
},
"stable": true,
"rungs": [
@@ -5917,19 +5800,19 @@
},
{
"competitor": "planck",
- "referenceMs": 4.579999999999927,
- "referenceP95Ms": 5.020000000000437,
+ "referenceMs": 4.539999999999964,
+ "referenceP95Ms": 4.839999999999236,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 7.779999999998836,
- "competitorP95Ms": 11.040000000000873,
+ "competitorMs": 7.770000000000437,
+ "competitorP95Ms": 10.540000000000873,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.5886889460155029,
- "factor": 1.6986899563316504,
- "label": "ExoJS leads (1.70x)",
+ "ratio": 0.5842985842985468,
+ "factor": 1.711453744493502,
+ "label": "ExoJS leads (1.71x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5937,14 +5820,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.539999999999964,
- "maxMs": 4.619999999999891,
- "ratio": 1.0176211453744335
+ "minMs": 4.520000000000437,
+ "maxMs": 4.579999999999927,
+ "ratio": 1.0132743362830718
},
"competitor": {
- "minMs": 7.770000000000437,
- "maxMs": 7.860000000000582,
- "ratio": 1.0115830115830298
+ "minMs": 7.710000000002765,
+ "maxMs": 7.959999999999127,
+ "ratio": 1.0324254215299964
},
"stable": true,
"rungs": [
@@ -5956,19 +5839,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 4.579999999999927,
- "referenceP95Ms": 5.020000000000437,
+ "referenceMs": 4.539999999999964,
+ "referenceP95Ms": 4.839999999999236,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
"competitorMs": 1.639999999999418,
- "competitorP95Ms": 1.7799999999988358,
+ "competitorP95Ms": 1.8000000000029104,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 2.792682926830215,
- "factor": 2.792682926830215,
- "label": "competitor leads (2.79x)",
+ "ratio": 2.7682926829277896,
+ "factor": 2.7682926829277896,
+ "label": "competitor leads (2.77x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms); the difference is solver cost",
@@ -5976,14 +5859,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 4.539999999999964,
- "maxMs": 4.619999999999891,
- "ratio": 1.0176211453744335
+ "minMs": 4.520000000000437,
+ "maxMs": 4.579999999999927,
+ "ratio": 1.0132743362830718
},
"competitor": {
- "minMs": 1.5800000000017462,
- "maxMs": 1.639999999999418,
- "ratio": 1.0379746835427883
+ "minMs": 1.639999999999418,
+ "maxMs": 1.6600000000034925,
+ "ratio": 1.0121951219537084
},
"stable": true,
"rungs": [
@@ -6005,17 +5888,17 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.780000000000655,
- "referenceP95Ms": 6.319999999999709,
+ "referenceMs": 5.779999999998836,
+ "referenceP95Ms": 6.260000000000218,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 6.470000000001164,
- "competitorP95Ms": 8.299999999999272,
+ "competitorMs": 6.529999999998836,
+ "competitorP95Ms": 8.159999999999854,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.8933539412673284,
+ "ratio": 0.8851454823889535,
"factor": 1,
"label": "level",
"structural": false
@@ -6025,14 +5908,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.739999999999782,
- "maxMs": 5.800000000001091,
- "ratio": 1.0104529616727025
+ "minMs": 5.700000000000728,
+ "maxMs": 5.800000000000182,
+ "ratio": 1.017543859649025
},
"competitor": {
- "minMs": 6.430000000000291,
- "maxMs": 6.479999999999563,
- "ratio": 1.007776049766605
+ "minMs": 6.489999999999782,
+ "maxMs": 6.579999999999927,
+ "ratio": 1.0138674884437826
},
"stable": true,
"rungs": [
@@ -6044,18 +5927,18 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.780000000000655,
- "referenceP95Ms": 6.319999999999709,
+ "referenceMs": 5.779999999998836,
+ "referenceP95Ms": 6.260000000000218,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 12.660000000003492,
- "competitorP95Ms": 14.279999999998836,
+ "competitorMs": 12.680000000007567,
+ "competitorP95Ms": 14.280000000013388,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.45655608214842497,
- "factor": 2.1903114186854773,
+ "ratio": 0.4558359621447466,
+ "factor": 2.1937716262993288,
"label": "ExoJS leads (2.19x)",
"structural": false
},
@@ -6064,14 +5947,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.739999999999782,
- "maxMs": 5.800000000001091,
- "ratio": 1.0104529616727025
+ "minMs": 5.700000000000728,
+ "maxMs": 5.800000000000182,
+ "ratio": 1.017543859649025
},
"competitor": {
- "minMs": 12.55000000000291,
- "maxMs": 12.720000000001164,
- "ratio": 1.0135458167329254
+ "minMs": 12.660000000003492,
+ "maxMs": 12.760000000009313,
+ "ratio": 1.007898894155276
},
"stable": true,
"rungs": [
@@ -6083,19 +5966,19 @@
},
{
"competitor": "planck",
- "referenceMs": 5.780000000000655,
- "referenceP95Ms": 6.319999999999709,
+ "referenceMs": 5.779999999998836,
+ "referenceP95Ms": 6.260000000000218,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 7.990000000001601,
- "competitorP95Ms": 10.280000000006112,
+ "competitorMs": 8.209999999999127,
+ "competitorP95Ms": 10.339999999996508,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.7234042553190859,
- "factor": 1.382352941176591,
- "label": "ExoJS leads (1.38x)",
+ "ratio": 0.7040194884286785,
+ "factor": 1.42041522491363,
+ "label": "ExoJS leads (1.42x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms) with 34 vs 37 ray hits per step; the difference is query and solver cost",
@@ -6103,14 +5986,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.739999999999782,
- "maxMs": 5.800000000001091,
- "ratio": 1.0104529616727025
+ "minMs": 5.700000000000728,
+ "maxMs": 5.800000000000182,
+ "ratio": 1.017543859649025
},
"competitor": {
- "minMs": 7.9099999999962165,
- "maxMs": 8.0099999999984,
- "ratio": 1.0126422250318876
+ "minMs": 8.139999999999418,
+ "maxMs": 8.210000000002765,
+ "ratio": 1.0085995085999204
},
"stable": true,
"rungs": [
@@ -6122,19 +6005,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.780000000000655,
- "referenceP95Ms": 6.319999999999709,
+ "referenceMs": 5.779999999998836,
+ "referenceP95Ms": 6.260000000000218,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 1.679999999993015,
- "competitorP95Ms": 1.8599999999860302,
+ "competitorMs": 1.7200000000011642,
+ "competitorP95Ms": 1.8399999999965075,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 3.4404761904908847,
- "factor": 3.4404761904908847,
- "label": "competitor leads (3.44x)",
+ "ratio": 3.3604651162761185,
+ "factor": 3.3604651162761185,
+ "label": "competitor leads (3.36x)",
"structural": false
},
"mechanism": "identical scene (1783 bodies, 2195 contacts, 0 joints on both arms) with 34 vs 39 ray hits per step; the difference is query and solver cost",
@@ -6142,14 +6025,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.739999999999782,
- "maxMs": 5.800000000001091,
- "ratio": 1.0104529616727025
+ "minMs": 5.700000000000728,
+ "maxMs": 5.800000000000182,
+ "ratio": 1.017543859649025
},
"competitor": {
- "minMs": 1.639999999999418,
- "maxMs": 1.7000000000116415,
- "ratio": 1.036585365861125
+ "minMs": 1.6999999999970896,
+ "maxMs": 1.7200000000011642,
+ "ratio": 1.0117647058847699
},
"stable": true,
"rungs": [
@@ -6171,17 +6054,17 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.619999999998981,
- "referenceP95Ms": 6.6200000000008,
+ "referenceMs": 5.639999999999418,
+ "referenceP95Ms": 6.819999999999709,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.720000000001164,
- "competitorP95Ms": 6.6599999999962165,
+ "competitorMs": 5.740000000005239,
+ "competitorP95Ms": 6.759999999994761,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 0.9825174825171045,
+ "ratio": 0.9825783972115454,
"factor": 1,
"label": "level",
"structural": false
@@ -6191,14 +6074,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.5,
- "maxMs": 5.639999999999418,
- "ratio": 1.0254545454544397
+ "minMs": 5.6200000000008,
+ "maxMs": 5.650000000000546,
+ "ratio": 1.005338078291769
},
"competitor": {
- "minMs": 5.709999999999127,
- "maxMs": 5.819999999999709,
- "ratio": 1.019264448336357
+ "minMs": 5.680000000000291,
+ "maxMs": 5.880000000001019,
+ "ratio": 1.03521126760576
},
"stable": true,
"rungs": [
@@ -6210,19 +6093,19 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.619999999998981,
- "referenceP95Ms": 6.6200000000008,
+ "referenceMs": 5.639999999999418,
+ "referenceP95Ms": 6.819999999999709,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 2.9199999999982538,
- "competitorP95Ms": 3.5200000000040745,
+ "competitorMs": 3,
+ "competitorP95Ms": 3.7400000000052387,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.9246575342473775,
- "factor": 1.9246575342473775,
- "label": "competitor leads (1.92x)",
+ "ratio": 1.879999999999806,
+ "factor": 1.879999999999806,
+ "label": "competitor leads (1.88x)",
"structural": false
},
"mechanism": "identical scene (1504 bodies, 1415 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6230,14 +6113,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.5,
- "maxMs": 5.639999999999418,
- "ratio": 1.0254545454544397
+ "minMs": 5.6200000000008,
+ "maxMs": 5.650000000000546,
+ "ratio": 1.005338078291769
},
"competitor": {
- "minMs": 2.720000000001164,
- "maxMs": 3.0800000000017462,
- "ratio": 1.132352941176628
+ "minMs": 2.860000000000582,
+ "maxMs": 3.460000000006403,
+ "ratio": 1.2097902097922024
},
"stable": true,
"rungs": [
@@ -6249,17 +6132,17 @@
},
{
"competitor": "planck",
- "referenceMs": 5.619999999998981,
- "referenceP95Ms": 6.6200000000008,
+ "referenceMs": 5.639999999999418,
+ "referenceP95Ms": 6.819999999999709,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.100000000005821,
- "competitorP95Ms": 7.380000000004657,
+ "competitorMs": 5.120000000009895,
+ "competitorP95Ms": 7.580000000001746,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": 1.101960784312268,
+ "ratio": 1.1015624999977573,
"factor": 1,
"label": "level",
"structural": false
@@ -6269,14 +6152,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.5,
- "maxMs": 5.639999999999418,
- "ratio": 1.0254545454544397
+ "minMs": 5.6200000000008,
+ "maxMs": 5.650000000000546,
+ "ratio": 1.005338078291769
},
"competitor": {
- "minMs": 5.070000000006985,
- "maxMs": 5.4799999999959255,
- "ratio": 1.0808678500963265
+ "minMs": 5.07999999999447,
+ "maxMs": 5.180000000000291,
+ "ratio": 1.019685039371246
},
"stable": true,
"rungs": [
@@ -6288,19 +6171,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.619999999998981,
- "referenceP95Ms": 6.6200000000008,
+ "referenceMs": 5.639999999999418,
+ "referenceP95Ms": 6.819999999999709,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 0.7799999999988358,
- "competitorP95Ms": 0.819999999992433,
+ "competitorMs": 0.7599999999947613,
+ "competitorP95Ms": 0.7799999999988358,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 7.205128205137653,
- "factor": 7.205128205137653,
- "label": "competitor leads clearly (7.21x)",
+ "ratio": 7.421052631629335,
+ "factor": 7.421052631629335,
+ "label": "competitor leads clearly (7.42x)",
"structural": true
},
"mechanism": "identical scene (1504 bodies, 1415 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6308,14 +6191,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.5,
- "maxMs": 5.639999999999418,
- "ratio": 1.0254545454544397
+ "minMs": 5.6200000000008,
+ "maxMs": 5.650000000000546,
+ "ratio": 1.005338078291769
},
"competitor": {
"minMs": 0.7599999999947613,
- "maxMs": 0.7999999999883585,
- "ratio": 1.0526315789393064
+ "maxMs": 0.7599999999947613,
+ "ratio": 1
},
"stable": true,
"rungs": [
@@ -6337,19 +6220,19 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 5.289999999999964,
- "referenceP95Ms": 5.519999999998618,
+ "referenceMs": 4.959999999999127,
+ "referenceP95Ms": 5.3400000000001455,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 5.169999999998254,
- "competitorP95Ms": 7.119999999995343,
+ "competitorMs": 4.860000000000582,
+ "competitorP95Ms": 7.519999999996799,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "neither",
- "ratio": null,
- "factor": null,
- "label": "unstable across runs",
+ "ratio": 1.0205761316869408,
+ "factor": 1,
+ "label": "level",
"structural": false
},
"mechanism": "competitor resolves fewer solved contacts (7875 vs 0); the counters are not semantically identical across arms (see the run's caveats)",
@@ -6357,18 +6240,18 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.020000000000437,
- "maxMs": 5.680000000000291,
- "ratio": 1.1314741035856168
+ "minMs": 4.940000000000509,
+ "maxMs": 5.6200000000008,
+ "ratio": 1.137651821862393
},
"competitor": {
- "minMs": 4.399999999997817,
- "maxMs": 6.120000000002619,
- "ratio": 1.3909090909103763
+ "minMs": 4.779999999998836,
+ "maxMs": 6.25,
+ "ratio": 1.3075313807534565
},
- "stable": false,
+ "stable": true,
"rungs": [
- "competitor-leads",
+ "level",
"level",
"level"
]
@@ -6376,8 +6259,8 @@
},
{
"competitor": "nape-js",
- "referenceMs": 5.289999999999964,
- "referenceP95Ms": 5.519999999998618,
+ "referenceMs": 4.959999999999127,
+ "referenceP95Ms": 5.3400000000001455,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
"competitorMs": 0,
@@ -6396,9 +6279,9 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.020000000000437,
- "maxMs": 5.680000000000291,
- "ratio": 1.1314741035856168
+ "minMs": 4.940000000000509,
+ "maxMs": 5.6200000000008,
+ "ratio": 1.137651821862393
},
"competitor": {
"minMs": 0,
@@ -6415,19 +6298,19 @@
},
{
"competitor": "planck",
- "referenceMs": 5.289999999999964,
- "referenceP95Ms": 5.519999999998618,
+ "referenceMs": 4.959999999999127,
+ "referenceP95Ms": 5.3400000000001455,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
"competitorMs": 0.37000000000261934,
- "competitorP95Ms": 0.3800000000046566,
+ "competitorP95Ms": 0.4599999999991269,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 14.297297297195984,
- "factor": 14.297297297195984,
- "label": "competitor leads clearly (14.30x)",
+ "ratio": 13.405405405308144,
+ "factor": 13.405405405308144,
+ "label": "competitor leads clearly (13.41x)",
"structural": true
},
"mechanism": "competitor resolves fewer solved contacts (7875 vs 0); the counters are not semantically identical across arms (see the run's caveats)",
@@ -6435,14 +6318,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.020000000000437,
- "maxMs": 5.680000000000291,
- "ratio": 1.1314741035856168
+ "minMs": 4.940000000000509,
+ "maxMs": 5.6200000000008,
+ "ratio": 1.137651821862393
},
"competitor": {
- "minMs": 0.37000000000261934,
- "maxMs": 0.37999999999738066,
- "ratio": 1.0270270270126771
+ "minMs": 0.3699999999953434,
+ "maxMs": 0.3799999999901047,
+ "ratio": 1.0270270270132085
},
"stable": true,
"rungs": [
@@ -6454,19 +6337,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 5.289999999999964,
- "referenceP95Ms": 5.519999999998618,
+ "referenceMs": 4.959999999999127,
+ "referenceP95Ms": 5.3400000000001455,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 0.20000000001164153,
- "competitorP95Ms": 0.23999999999068677,
+ "competitorMs": 0.19999999999708962,
+ "competitorP95Ms": 0.22000000000116415,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 26.449999998460225,
- "factor": 26.449999998460225,
- "label": "competitor leads clearly (26.45x)",
+ "ratio": 24.800000000356523,
+ "factor": 24.800000000356523,
+ "label": "competitor leads clearly (24.80x)",
"structural": true
},
"mechanism": "competitor resolves fewer solved contacts (7875 vs 1125); the counters are not semantically identical across arms (see the run's caveats)",
@@ -6474,14 +6357,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 5.020000000000437,
- "maxMs": 5.680000000000291,
- "ratio": 1.1314741035856168
+ "minMs": 4.940000000000509,
+ "maxMs": 5.6200000000008,
+ "ratio": 1.137651821862393
},
"competitor": {
"minMs": 0.19999999999708962,
- "maxMs": 0.21999999998661224,
- "ratio": 1.0999999999490684
+ "maxMs": 0.19999999999708962,
+ "ratio": 1
},
"stable": true,
"rungs": [
@@ -6503,19 +6386,19 @@
"cells": [
{
"competitor": "matter-js",
- "referenceMs": 3.7399999999979627,
- "referenceP95Ms": 4.5,
+ "referenceMs": 3.7400000000016007,
+ "referenceP95Ms": 4.479999999999563,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 10.680000000000291,
- "competitorP95Ms": 12.340000000003783,
+ "competitorMs": 10.760000000002037,
+ "competitorP95Ms": 12.540000000000873,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.3501872659174027,
- "factor": 2.8556149732636658,
- "label": "ExoJS leads (2.86x)",
+ "ratio": 0.3475836431227595,
+ "factor": 2.8770053475928963,
+ "label": "ExoJS leads (2.88x)",
"structural": false
},
"mechanism": "identical scene (3004 bodies, 6199 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6523,14 +6406,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.7399999999979627,
+ "minMs": 3.719999999997526,
"maxMs": 3.7400000000016007,
- "ratio": 1.0000000000009728
+ "ratio": 1.0053763440871204
},
"competitor": {
- "minMs": 10.639999999999418,
- "maxMs": 10.75,
- "ratio": 1.0103383458647168
+ "minMs": 10.660000000003492,
+ "maxMs": 10.909999999999854,
+ "ratio": 1.0234521575981501
},
"stable": true,
"rungs": [
@@ -6542,19 +6425,19 @@
},
{
"competitor": "nape-js",
- "referenceMs": 3.7399999999979627,
- "referenceP95Ms": 4.5,
+ "referenceMs": 3.7400000000016007,
+ "referenceP95Ms": 4.479999999999563,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 11,
- "competitorP95Ms": 13.820000000006985,
+ "competitorMs": 11.07999999999447,
+ "competitorP95Ms": 14.200000000011642,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.3399999999998148,
- "factor": 2.9411764705898373,
- "label": "ExoJS leads (2.94x)",
+ "ratio": 0.33754512635410355,
+ "factor": 2.9625668449170397,
+ "label": "ExoJS leads (2.96x)",
"structural": false
},
"mechanism": "identical scene (3004 bodies, 6199 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6562,14 +6445,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.7399999999979627,
+ "minMs": 3.719999999997526,
"maxMs": 3.7400000000016007,
- "ratio": 1.0000000000009728
+ "ratio": 1.0053763440871204
},
"competitor": {
- "minMs": 10.980000000010477,
- "maxMs": 11,
- "ratio": 1.0018214936238163
+ "minMs": 11.059999999997672,
+ "maxMs": 11.19999999999709,
+ "ratio": 1.0126582278480514
},
"stable": true,
"rungs": [
@@ -6581,19 +6464,19 @@
},
{
"competitor": "planck",
- "referenceMs": 3.7399999999979627,
- "referenceP95Ms": 4.5,
+ "referenceMs": 3.7400000000016007,
+ "referenceP95Ms": 4.479999999999563,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 13.080000000001746,
- "competitorP95Ms": 19.54000000000815,
+ "competitorMs": 13.220000000001164,
+ "competitorP95Ms": 19.860000000000582,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "exojs",
- "ratio": 0.2859327217123443,
- "factor": 3.4973262032109282,
- "label": "ExoJS leads (3.50x)",
+ "ratio": 0.28290468986393885,
+ "factor": 3.5347593582875683,
+ "label": "ExoJS leads (3.53x)",
"structural": false
},
"mechanism": "identical scene (3004 bodies, 6199 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6601,14 +6484,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.7399999999979627,
+ "minMs": 3.719999999997526,
"maxMs": 3.7400000000016007,
- "ratio": 1.0000000000009728
+ "ratio": 1.0053763440871204
},
"competitor": {
- "minMs": 12.979999999995925,
- "maxMs": 13.34000000001106,
- "ratio": 1.0277349768886939
+ "minMs": 13.200000000004366,
+ "maxMs": 13.319999999992433,
+ "ratio": 1.0090909090900022
},
"stable": true,
"rungs": [
@@ -6620,19 +6503,19 @@
},
{
"competitor": "rapier",
- "referenceMs": 3.7399999999979627,
- "referenceP95Ms": 4.5,
+ "referenceMs": 3.7400000000016007,
+ "referenceP95Ms": 4.479999999999563,
"referenceGpuMs": null,
"referenceOverFrameBudget": false,
- "competitorMs": 2.1199999999953434,
+ "competitorMs": 2.099999999991269,
"competitorP95Ms": 2.220000000001164,
"competitorGpuMs": null,
"competitorOverFrameBudget": false,
"verdict": {
"side": "competitor",
- "ratio": 1.7641509433991405,
- "factor": 1.7641509433991405,
- "label": "competitor leads (1.76x)",
+ "ratio": 1.7809523809605479,
+ "factor": 1.7809523809605479,
+ "label": "competitor leads (1.78x)",
"structural": false
},
"mechanism": "identical scene (3004 bodies, 6199 contacts, 0 joints on both arms); the difference is solver cost",
@@ -6640,14 +6523,14 @@
"aggregate": {
"runs": 3,
"reference": {
- "minMs": 3.7399999999979627,
+ "minMs": 3.719999999997526,
"maxMs": 3.7400000000016007,
- "ratio": 1.0000000000009728
+ "ratio": 1.0053763440871204
},
"competitor": {
"minMs": 2.0800000000017462,
- "maxMs": 2.1600000000034925,
- "ratio": 1.0384615384623457
+ "maxMs": 2.099999999991269,
+ "ratio": 1.0096153846103393
},
"stable": true,
"rungs": [
@@ -6664,6 +6547,6 @@
},
"signature": {
"algorithm": "sha256",
- "value": "74734d08514f28925d94d9550137e610aa03b9c692c53cf588b06b4e62d677ce"
+ "value": "fbd97ee33f914a4f55e761c15fd321fa6d41a7d1c57d5618fffdd7495d9c049a"
}
}
From 866883bc2bd86673eacb83f4d9b6cdf3e003d1c8 Mon Sep 17 00:00:00 2001
From: Exoridus
Date: Sat, 12 Sep 2026 06:23:50 +0200
Subject: [PATCH 18/28] docs(changelog): render the 0.17.0 section one line per
entry
---
CHANGELOG.md | 531 +++------------------------------------------------
1 file changed, 22 insertions(+), 509 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9f9e5b00..bc6a97e8c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,529 +11,42 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
### Changed
- **BREAKING: Retain filtered and clipped scopes, coalesce WebGPU row patches, add hitArea and move culling to RenderNode.** ([#681](https://github.com/Exoridus/ExoJS/pull/681))
- Two per-frame costs that scaled with the scene rather than with the
- change.
-
- **A filter or a clip was a retention floor.** A barrier-bearing node
- collected through the effect path and never reached the plan builder's
- group branch, so it never got the automatic persistent render
- representation. Everything below a filter chain or a rect clip was
- walked out of the scene graph, transform-derived and material-resolved
- on every single frame, however static it was. The barrier's content now
- climbs the same ladder a render root does, while the effect itself stays
- live in the barrier entry and the effect executor: a changed filter
- chain, clip rect or target size still takes effect on the frame it
- changes.
-
- A 5 000-sprite scene under a colour-matrix chain drops from 3.8 ms to
- 0.25 ms per frame on WebGL2 and from 2.7 ms to 0.35 ms on WebGPU, with
- the per-frame instance re-upload gone (7 -> 1). Three nested rectangle
- masks over the same scene drop from 3.9 ms to 2.2 ms (WebGL2) and 3.1 ms
- to 1.9 ms (WebGPU). Draw calls are unchanged everywhere.
-
- **A moving node cost a GPU upload of its own on WebGPU.** The retained
- group bundle wrote each patched transform row with its own
- `queue.writeBuffer`, so the per-frame upload count followed the number
- of moving nodes: 375 moved sprites were 375 calls, against one on
- WebGL2, whose row store is a texture whose dirty rect is unioned and
- committed once. The bundle now mirrors its rows, marks the blocks a
- patch touches and uploads them at the end of the patch pass: tight runs
- while the moves cluster, one span once they scatter. Uploads per frame
- on `dynamic-heavy` at 5 000 nodes: 369 -> 1.
-
- Text nodes get the same treatment as sprites: a moved text node no
- longer costs a `queue.writeBuffer` of its own, since the retained
- node-data store is now block-mirrored and uploaded per dirty region
- through the shared `DirtyRowTracker`. A WGSL filter pass writes its
- resolution and user uniform blocks only when they actually change, which
- makes the per-frame upload count on `filter-chain-1/2/4` flat in chain
- depth (11 -> 3 at depth four) instead of growing by two per link.
-
- The benchmark's structural baseline is re-recorded in the same change:
- the immediate arm's filter-chain and mask-clip cells now submit what the
- retained arm already did.
-
- Measured but not changed here: `lifecycle-churn` is not object
- construction cost (1.2 us per sprite create/add/destroy) but a full
- immediate collect after every structural change, which needs an
- incremental structural delta in the retained source; `mask-clip` keeps
- ~1.9 ms of entry replay behind nested clips because a recorded fragment
- cannot carry a barrier, which needs a splice-contract change;
- `scrolling-world` already renders in one draw call (the earlier "120
- draws" read raw totals over 120 frames).
-
- **Also in this change: `hitArea`, and `cullable`/`cullArea` move to
- `RenderNode`.** A bare `SceneNode` is structural and never rendered, and
- the cull test is evaluated over render items, so the two culling
- properties now live on `RenderNode`; semantics unchanged (read live,
- caller-owned rectangle, default `cullable = true`). `RenderNode.hitArea`
- accepts a `Rectangle`, `Circle`, `Ellipse` or `Polygon` in the node's
- own space (default `null`): when set, `contains()` maps the world point
- through the inverse world transform and tests the shape instead of the
- bounds, so a round button, a hex cell or a province outline picks
- exactly, rotated or not. Picking only; bounds, culling and rendering
- ignore it. Widgets inherit it.
-
- **Breaking changes**
- - `cullable` / `cullArea` no longer exist on a bare `SceneNode`; every
- renderable class keeps them through `RenderNode`.
-
- ***
-
- **BREAKING: Multi-stop gradients, caps and slant variants, decorations, line clamping, case mapping and tab stops.** ([#682](https://github.com/Exoridus/ExoJS/pull/682))
- A sweep across `TextStyle` and `LayoutOptions` that closes the gap
- between what the text stack can lay out and what display typography
- actually needs, plus two DX fixes.
-
- **Multi-stop gradients with an angle.** `gradient: { stops, angle }`
- replaces `gradientColors` + `gradientAxis`. Up to eight stops, offsets
- clamped and sorted on the way in, and an angle in degrees following the
- CSS `linear-gradient` convention (0 = to top, 90 = to right, default
- 180). The ramp spans the ink box corner to corner, so the first and last
- stops land on the box edges at every angle. Evaluated per fragment from
- the node's own packed style row, still a `'tint'` change that never
- touches the atlas. The stop type is reused from the existing
- `GradientStop`.
-
- **Caps and slant variants.** `fontStyle` gains `'oblique'`;
- `fontVariant: 'small-caps'` is new. Both go into the CSS `font`
- shorthand the rasterizer hands to Canvas 2D, and both are part of a
- glyph atlas's identity, so a small-cap `a` never shares a cache entry
- with an ordinary one.
-
- **Underline and strikethrough.** `underline`, `strikethrough`,
- `decorationColor`, `decorationThickness`, `decorationOffset`. Rules are
- quads the layout emits per line, so they follow alignment, wrapping and
- letter spacing. Their position comes from the font's own ascent, descent
- and x-height rather than from a fraction of the font size. A rule takes
- the fill, gradient included, unless `decorationColor` overrides it.
- `BitmapText` renders no rules: an offline atlas has no opaque block to
- sample.
-
- **Line clamping.** `maxLines` caps the laid-out line count after
- wrapping and clips on its own; pair it with `overflow: 'ellipsis'` for a
- marker. `ellipsis` configures that marker (`'...'`, `''`, anything).
- Under a cap the marker also reaches a line that no wrap could shorten,
- such as `maxLines: 1` on a single unbreakable word.
-
- **Case mapping.** `textTransform: 'none' | 'uppercase' | 'lowercase' |
-'capitalize'`, applied at layout time per grapheme cluster and under the
- layout locale. The node's `text` is untouched, and a cluster that
- changes length under the mapping still traces back to the character it
- came from, so a caret lands where the reader clicked.
-
- **Tab stops.** `tabSize` (default 8, the CSS `tab-size` initial value)
- advances a preserved tab to the next stop from the line origin, so
- tab-separated values line up as columns. Only reachable under
- `whiteSpace: 'pre'`; the collapsing modes turn a tab into one space
- before layout, as CSS does.
-
- **DX.** `AbstractText.update()` is gone; `syncDirty()` is the name.
- Stale references to a distance-field package the engine never depended
- on are replaced with a description of the in-house rasterizer. Glyph
- caches are keyed by one named `FontVariantKey` instead of four
- positional strings.
-
- New guide sections (case, variants, decorations, line clamping, tab
- stops) and the example `text-fonts/typographic-styling`. Verified on
- both backends in the browser, including new pixel-probing tests that
- prove a rule reaches the frame and that `decorationColor` reaches only
- the rule.
-
- **Breaking changes**
- - `TextStyleOptions.gradientColors` / `gradientAxis` -> `gradient`; the
- `GradientAxis` type is gone. Serialized text styles carry `gradient`
- instead of the two old keys.
- - `AbstractText.update()` is removed. `syncDirty()` is the name; the
- renderer and every extent read already resolve a pending pass on their
- own, so most callers need nothing.
- - `GlyphAtlasPool.getAtlas` / `getMetrics` / `getShapedMetrics` /
- `clearVariant`, and the `GlyphAtlas` / `GlyphMetrics` /
- `ShapedTextMetrics` constructors, take one named `FontVariantKey` (`{
-family, fontStyle?, fontWeight?, fontVariant? }`, each optional field
- defaulting to `'normal'`) instead of positional strings. `clearVariant`
- takes the narrower `FontTypefaceKey`. `ShapedTextSourceOptions` nests
- its font fields under `font`.
- - `TextPageQuads` gains `decorations`; the packed per-vertex node index
- narrows from 24 to 23 bits to make room for the decoration flag.
-
- ***
-
-- **`ShaderSource.glsl.vertex` is optional.** A sprite material and a shader
- filter never compiled the author's vertex stage (the sprite vertex program is
- engine-owned, the filter draws a fullscreen quad), yet the source required a
- non-empty string, so callers passed a dummy. `glsl: { fragment }` is now
- enough for both; `ShaderSource.glsl.vertex` reads `null` in that case, and a
- mesh or particle material without a vertex stage fails with a named error.
-
-- **The extension seams that survived the `@internal` strip lost their
- underscore prefix.** A member an official package (or any extension author)
- has to call is API, and now reads like it: `SceneNode._setLocalBounds` is
- `setLocalBounds`, `RenderNode._collect` is `collect`, `Material._onDispose` is
- `onDispose`, `AudioBus._getInputNode`/`_getOutputNode` are
- `getInputNode`/`getOutputNode`, and `Playable._createVoice` is `createVoice`
- (with `Sound`, `AudioStream` and `AudioGenerator` following). On the renderer
- SDK, `WebGl2Backend._stageViewportUniform` is `stageViewportUniform`,
- `_pushTransform` and `_recordRetainedBatch` are `pushTransform` and
- `recordRetainedBatch` on both backends, `WebGpuBackend._transformStorageWouldGrow`
- and `_textureUploadWouldMutate` are `transformStorageWouldGrow` and
- `textureUploadWouldMutate`, the retained replayer contracts
- (`_scanRetainedNodeIndexRange`, `_rebaseRetainedNodeIndices`,
- `_configureRetainedVao`, `_validateRetainedBatch`, `_replayRetainedBatch`) and
- `RetainedGroupBundle`'s `_patchTransformRow`/`_patchTintRow` drop the prefix
- the same way. Rename the call sites; there are no compatibility aliases. Every
- remaining underscore member is engine-private and no longer reaches the
- published `.d.ts` at all.
-
-- **Punctuation keys are named after their `code` on both input surfaces.**
- `Keyboard.Colon`, `Equals`, `Dash`, `QuestionMark`, `Tilde`, `OpenBracket`,
- `BackwardSlash`, `ClosedBracket` and `Quotes` are now `Semicolon`, `Equal`,
- `Minus`, `Slash`, `Backquote`, `BracketLeft`, `Backslash`, `BracketRight` and
- `Quote`, matching the pattern tokens (`keyboard.semicolon`, ...) and
- `KeyboardEvent.code`. Channel values, bindings and actions are unchanged.
-
-- **`ShaderFilter` sources get a `uOrientation` auto-bind, so one shader offsets
- along `v` the same way on both backends.** A WebGL2 render texture stores the
- effect domain bottom-up and a WebGPU one top-down, which used to make a
- directional `v` offset move the image up on one backend and down on the other.
- `uOrientation` is `+1` where `v` grows along the domain's y axis and `-1`
- where it grows against it (GLSL `uniform float uOrientation`, WGSL
- `@group(0) @binding(3) var uOrientation: f32`); multiply the v
- component of a directional offset by it. Existing sources that only sample
- their own texel need no change.
-
-- **Every remaining public duration input takes branded `Seconds` instead of a
- plain millisecond `number`.** `AudioBus.fadeIn`/`fadeOut`, `Voice.fade`/`stop`
- (and `crossFade`'s duration), `InputVoice.record`, `Envelope`'s
- `attack`/`decay`/`release`/`totalDuration` (renamed from the `*Ms` fields,
- with `trigger`'s `elapsed` following) and its `releaseAt` method (renamed
- from `release`, which now names the duration field instead),
- `View.shake`'s duration, `AnimatedSprite`'s `frameDuration`/`frameDurations`,
- and `PhasedSceneTransition`/`CrossFadeSceneTransition`'s `duration` all match
- the `Seconds` unit the rest of the engine already uses. Wrap existing
- millisecond literals with `Time.seconds(ms / 1000)` (or write the value
- directly in seconds); `Envelope.releaseAt` replaces `envelope.release(...)`
- now that `release` names the duration property.
-
-- **The published `.d.ts` no longer carries `@internal` members.** The
- declaration emit now strips them, so consumer autocomplete on `Loader`,
- `AssetRef`, `Text`, `Tween`, `AudioBus` and the rest shows the API instead of
- the engine's internals, and the published types finally agree with the
- published API reference. Types that a public or renderer-SDK signature
- genuinely exposes became part of the surface rather than disappearing with
- the tag: `CheckableWidget`, `TextEditWidget`, `UIBackgroundNode`, `Ticker`,
- `InputVoice`, `ShapeLike`, `PointerChannel`, `GamepadButtonChannel`,
- `GamepadAxisChannel`, `CatalogResourceLeaf`, `CatalogValueLeaf`,
- `OwnedNetworkHintSource` and `BmFontAdapter` on the root barrel;
- `RenderPlanBuilder`, `DrawCommand`, `MaterialKey`, `InstanceDataView`,
- `InstanceAttributeBinding`, `ShaderProgram`, `RenderPassCoordinator`,
- `RenderPassDescriptor`, `RenderPassLoad`, `StencilAttachmentMode`, the
- retained-group payload/replayer types and `WebGpuActiveRenderPass` on
- `@codexo/exojs/renderer-sdk`. Going the other way, `SpriteFlags` and
- `ViewFlags` - internal dirty-flag bitmasks that were exported by accident -
- are gone from the root barrel, `ObservableVector`'s owner constructor is
- internal (construct a plain vector with `new ObservableVector()`), and
- `onAudioContextReady` is typed as the `Signal<[AudioContext]>` it always
- was.
-
-- **`AnimatedSprite.defineClip` is now `addClip`, `Sound.defineSprite` is now
- `addSprite`, and `Spritesheet.addFrame`/`removeFrame` return `this`.** One
- verb pair, `add`/`remove`, for every named-registration mutator, and every
- one of them chainable. Rename the calls; the `clips`/`sprites` constructor
- options and `setClips`/`setSprites` are unchanged.
-
-- **`Assets.from` rejects a bare path whose suffix no asset type claims, at the
- literal.** `'hero.pgn'` used to type-check and hand back `unknown`; it now
- fails to compile with a message naming the path and the way out. Paths that
- only exist at runtime (`string`, not a literal) are unaffected.
-
-- **`BurstSpawn`'s `loop: boolean` is replaced by `interval: number`, the
- period in seconds between two runs of the schedule.** `loop: true` restarted
- the schedule in the same `apply()` call that exhausted it and zeroed the
- clock, so a schedule with nothing after its final burst re-fired every frame
- and the emitted count followed the frame rate rather than elapsed time. The
- period is now declared, the clock wraps by subtracting it so overshoot
- carries into the next cycle, and a long frame fires every period it covered.
- Replace `loop: true` with `interval: `; a schedule that used a
- trailing `{ time: period, count: 0 }` entry to fake a period can drop it.
-
-- **`TileSet._setDefinitions` is now `setDefinitions`.** The tilemap SDK
- contract for extension packages that build tilesets programmatically loses
- the leading underscore now that the method is the only cross-package member
- in the extension packages that isn't `@internal`; the other 25
- package-private members across `@codexo/exojs-physics` and
- `@codexo/exojs-tilemap` are now tagged `@internal` and no longer appear in
- the published `.d.ts`. Rename the call.
+- **BREAKING: Name the renderer and audio SDK seams, tag the rest @internal.** ([#672](https://github.com/Exoridus/ExoJS/pull/672))
+- **BREAKING: Name punctuation keys after their code on both surfaces.** ([#667](https://github.com/Exoridus/ExoJS/pull/667))
+- **BREAKING: Strip internals from the declaration emit.** ([#668](https://github.com/Exoridus/ExoJS/pull/668))
+- **BREAKING: Take every public duration input in seconds.** ([#666](https://github.com/Exoridus/ExoJS/pull/666))
+- **BREAKING: Unify add/remove mutator verbs and reject unknown asset suffixes at the literal.** ([#661](https://github.com/Exoridus/ExoJS/pull/661))
+- **Tag package-private members @internal.** ([#673](https://github.com/Exoridus/ExoJS/pull/673))
### Added
- **Show examples without guide markers and with one-line imports.** ([#683](https://github.com/Exoridus/ExoJS/pull/683))
- The playground and guide code blocks showed example sources verbatim,
- including the `// #region guide:...` markers that exist only for snippet
- extraction and the import lists Prettier had wrapped one specifier per
- line. The display source now drops the markers (with the blank line they
- would leave) and joins each wrapped import back onto one line. Execution
- source and files on disk are unchanged, so snippet extraction,
- typechecking and formatting keep working on the originals.
-
- **Add JobScheduler for frame-budgeted generator jobs.** ([#679](https://github.com/Exoridus/ExoJS/pull/679))
- Heavy work (world generation, batch pathfinding, visibility rebuilds) no
- longer has to choose between blocking a frame and an `async` update that
- resumes in a later microtask.
-
- - `JobScheduler` advances generator jobs one `yield` at a time inside a
- per-frame time budget (default 2 ms; at least one step per update so a
- job always progresses), in strict priority order with round-robin inside
- a priority. Instantiable with its own budget and order, so a scene can
- own one via `scene.systems.add(new JobScheduler())`.
- - `Job` handle: frame code polls `status` / `result` / `error`, async
- code awaits `done` (created lazily, so an unawaited failure never raises
- an unhandled rejection; cancellation rejects with an `AbortError`).
- `cancel()` stops the generator at its `yield` and runs `finally` blocks;
- `{ scope }` lets a `DestroyScope` own the job only while it runs.
- - `app.jobs` is the application-owned instance, ticked in the `update`
- phase at the new `SystemOrder.CoreJobs`.
- - Guide section "Spreading work over frames" in the Application chapter;
- API docs generated; export snapshot updated.
-
- Worker-backed jobs are deliberately not part of this: the handle is
- designed so a `WorkerPool` can hand out the same `Job` later.
-
- ***
-
-- **`@codexo/exojs-pathfinding`, the official pathfinding extension.** One
- search core - A\* over integer node handles - serving pluggable navigation
- spaces. `GridSpace` is a finite window of weighted cells with diagonal
- policies, `setCost`/`revision` for runtime edits, brushfire clearance for
- agents wider than one cell, and string-pulling smoothing; `WaypointGraph` is a
- directed graph whose edges carry a `kind` and a typed payload, which is what a
- platformer's jump and fall links need and what a grid cannot express, and
- which degrades to plain Dijkstra when its nodes have no positions.
- `Pathfinder.findPath`/`findPathBetween` return a `PathResult` whose `status`
- distinguishes `found`, `unreachable` and `budget-exceeded` instead of throwing
- or returning `null`, and `floodFrom` answers "everything reachable within this
- cost". Jump-point search self-enables on a uniform-cost grid and returns the
- same optimal path from a fraction of the expanded nodes. Paths are
- reproducible across runs and machines, and a search allocates nothing that
- scales with the nodes it visits. The package depends on `@codexo/exojs` alone:
- a tilemap reaches it through the cost callback `GridSpace.from` takes, not
- through a package edge.
-
-- **Browser-native shaping for bidirectional and contextual text.**
- `LayoutOptions.shaping` selects how a glyph's appearance is resolved:
- `'auto'` (the default) keeps ordinary content on the shared glyph atlas and
- hands text that needs its surroundings - a right-to-left base direction, an
- explicit bidi control, or any script outside a proven-safe allow-list - to
- the browser's canvas text engine one complete line at a time, which resolves
- the bidirectional order and the contextual forms. `'simple'` and `'browser'`
- force either path; `Text.shapingMode` reports which one settled. Shaped
- lines are rasterized into pages the node owns and released with it, so no
- process-wide cache of whole strings accumulates. No runtime dependency is
- added: the platform provides the segmentation, the shaping and the raster.
-
-- **`LayoutOptions.locale`.** The language tag Unicode segmentation runs
- under - which clusters count as one character, and where a line may break.
- It selects no font and loads nothing.
-
-- **`GlyphPlacement.sourceStart` / `sourceEnd` and the same pair on
- `TextLineMetrics`.** Every laid-out glyph and every laid-out line now carries
- the UTF-16 range of the string it came from. Nothing in a string marks a soft
- wrap, so this is what maps a caret, a selection or a hit test onto wrapped
- text; a glyph that stands for no source character (the ellipsis an overflow
- appended) reports an empty range at the point it replaced.
-
-- **`TextArea` wraps and scrolls.** A line too long for the field breaks at a
- word boundary instead of scrolling sideways, and a vertical scrollbar appears
- along the right edge once the value outgrows the field and drives the scroll
- position. `wrap: false` restores horizontal scrolling for content whose own
- line breaks are what matters; `scrollbar: false` and `scrollbarThickness`
- control the bar, and `TextArea.verticalScrollbar` exposes it. Caret motion,
- `Home`/`End`, `PageUp`/`PageDown`, hit testing and selection rectangles
- follow the laid-out lines, so a wrapped line behaves like the two lines it
- looks like while the value keeps exactly the line breaks the user typed.
-
-- **`when` on `SceneInteraction.observe()` and `scope()`.** Interaction
- registrations take the same `SceneAvailability` policy the input, tween and
- audio facades have. The default stays `'always'`, so a pause menu drawn by
- the paused scene keeps receiving pointer events; `'active'` detaches a
- registration while the scene is paused and `'paused'` attaches it only then.
-
-- **`DisplacementFilter`.** Warps the filtered node by a direction read out of a
- map texture - heat haze, water refraction, glass, shockwaves. `map`'s red and
- green channels are decoded to `[-1, 1]` and scaled by `scale` (one number or
- `[x, y]`, logical units, default `20`); `offsetU`/`offsetV` move where the map
- is sampled, so animating them scrolls the distortion. The reach is declared
- through `getOutputBounds`, and a fragment displaced past the effect domain
- comes out transparent rather than smearing the border.
-
-- **`PhasedSceneTransition.destroyPhaseState(state)`.** The release half of
- `createPhaseState()`, called exactly once per session on every exit path -
- normal completion, an abort before the commit, or the application being
- destroyed mid-transition. Override it when the phase state owns GPU-backed
- resources; plain scratch needs no override. A `{ enter, exit }` pair holds
- one state per side and each side is released through its own phase's hook.
-
-- **A guide chapter and a playground example for writing your own scene
- transition.** The **Writing your own transition** chapter spells out the
- lifecycle contract `SceneTransitionLifecycleError` enforces - the
- definition/session split, what the director guarantees per frame, why
- `commit()` does not switch the scene in the same call, and what an abort and
- a `destroy()` have to leave behind - and builds a complete bar-wipe
- transition against it, both as a full `SceneTransition` and as a
- `PhasedSceneTransition`. The matching `application-scenes/custom-transition`
- example runs that transition between two scenes. No API change.
-
-- **`DropShadowFilter`.** A soft, offset silhouette of the filtered node drawn
- behind it: `offsetX`/`offsetY`, `blur`, `quality`, `color` (alpha is the
- shadow opacity) and `shadowOnly` for glows and detached shadows. Composed from
- the stock colour-matrix and blur passes, so it runs on both backends and
- declares the extra reach it needs through `getOutputBounds`.
-
-- **`@codexo/exojs-lighting`, forward normal-mapped point lighting for
- sprites.** Lighting happens inside the sprite fragment stage, so a lit scene
- costs no extra render pass and no extra draw call - sprites sharing one
- `LitSpriteMaterial` stay in one batch. `PointLight` is plain mutable
- world-space data (`x`, `y`, `radius`, `color`, `intensity`, `height`);
- `LightingSystem` collects lights and packs them, together with the active
- count and the ambient term, into one `rgba32f` data texture per frame, and
- registers on any `SystemRegistry` like every other system. The light list
- being a texture rather than a uniform array is what makes the light count a
- shader loop bound instead of a compiled-in constant: a material user uniform
- is one `vec4` per name, which would have capped a scene at a handful of
- lights and needed a recompile to change. `LitSpriteMaterial` samples a
- tangent-space normal map next to the albedo and rotates the normal by the
- instance's local-to-world basis, so spinning and mirrored sprites keep their
- bumps facing the right way. One normal map per material (= per atlas) is the
- v1 contract; there is no deferred path yet. Two examples ship with it:
- `lighting/normal-mapped-sprites` and `lighting/many-lights`, which walks from
- 1 to 48 lights over a normal-mapped floor without leaving a single draw call.
-
-- **Custom sprite materials receive the fragment's world position and the
- instance's local-to-world basis.** `v_worldPosition` / `v_basis` (GLSL) and
- `worldPosition` / `basis` on `VertexOutput` (WGSL) let a fragment shade
- against world-space lights and rotate a tangent-space normal with the
- sprite, which is what a lighting effect needs and what the varyings did not
- carry before. The `lighting/normal-mapped-sprites` example lights a batch of
- spinning and mirrored sprites through one material and four point lights.
-
-- **`Scene.animations`, a scene-bound animation facade with the same `when`
- policy the tween and audio facades already have.** An `AnimatedSprite`
- attached to a scene tree kept advancing through `SceneDirector.pause()` and
- through retention, so a pause menu drawn over a "frozen" world still had
- moving sprites and a suspended scene kept burning frames.
- `this.animations.add(sprite, { when: 'active' })` binds playback to the
- scene: frozen while it is paused, frozen while it is retained, stopped when
- it ends. `when` takes the same `SceneAvailability` values with the same
- `'always'` default, so an untracked sprite behaves exactly as before.
-
-- **`TrailParticles`, a particle render mode that draws a motion trail behind
- every particle.** Where `RibbonParticles` connects the particles of one
- system into a single band, this gives each particle its own strip through the
- positions it recently occupied, kept in a per-particle ring buffer and drawn
- in one non-instanced draw. Positions are recorded on each particle's own
- clock (`interval`), so a trail covers the same travel at any frame rate;
- `points` sets how far back it reaches, `width` its thickness and `fade` how
- its alpha falls off towards the tail. CPU-only, like `RibbonParticles`.
+- **Unicode-safe layout, browser-native shaping, and soft-wrapping TextArea.** ([#677](https://github.com/Exoridus/ExoJS/pull/677))
+- **Add the @codexo/exojs-pathfinding extension package.** ([#676](https://github.com/Exoridus/ExoJS/pull/676))
+- **When policy for SceneInteraction, optional GLSL vertex stage, DropShadowFilter guide.** ([#671](https://github.com/Exoridus/ExoJS/pull/671))
+- **Transition authoring kit, and release phase state when a session ends.** ([#670](https://github.com/Exoridus/ExoJS/pull/670))
+- **V-axis orientation uniform for shader filters, and DisplacementFilter.** ([#669](https://github.com/Exoridus/ExoJS/pull/669))
+- **Add the @codexo/exojs-lighting extension package.** ([#664](https://github.com/Exoridus/ExoJS/pull/664))
+- **Expose world position and basis to custom sprite materials.** ([#659](https://github.com/Exoridus/ExoJS/pull/659))
+- **Add DropShadowFilter and fix the vertical mirror in WebGPU shader filter passes.** ([#660](https://github.com/Exoridus/ExoJS/pull/660))
+- **Periodic BurstSpawn and TrailParticles render mode.** ([#656](https://github.com/Exoridus/ExoJS/pull/656))
+- **Frame budgets, GPU frame timing and asset cache inspection.** ([#658](https://github.com/Exoridus/ExoJS/pull/658))
+- **DPR watcher, hit-ordered scroll wheel, pointer lock, animated widget backgrounds.** ([#657](https://github.com/Exoridus/ExoJS/pull/657))
### Fixed
- **Raise the contact push-out cap to its pixel-scale value and sleep settled piles.** ([#680](https://github.com/Exoridus/ExoJS/pull/680))
- The soft-constraint push-out was capped at 4 px/s. Box2D-v3's analogue
- is 3 m/s, which at the pixel scales ExoJS targets is 60-300 px/s, so the
- cap stood an order of magnitude below the speed it was meant to express.
- A gravity-driven pile rearranges faster than such a push-out can work:
- overlap accumulated instead of resolving, and 1000 dynamic circles
- settled at 4.7 px mean penetration across 4939 touching pairs where the
- geometry has about 2800. The cap is now 60 px/s, the low end of the
- honest conversion band and the point where measurement shows the scene
- stops fighting it.
-
- The sleep gate compounded the problem: it reset both bodies' timers
- while a contact's penetration exceeded the sleep tolerance, but a loaded
- contact rests at the depth its own soft-constraint deflection holds it
- at, which in a pile is several times a lone body's, so islands never
- slept and a fully settled scene kept being solved in full. The gate now
- reads push-out progress instead of depth: a contact deeper than the
- tolerance blocks sleep only while the last step actually moved its
- overlap, or while the point has no history at all, so geometry appearing
- inside a sleeping body still reopens the decision.
-
- Numbers (median ms/step, touching pairs): `many-dynamic` 1000 bodies
- 35.5 ms / 4875 pairs -> 16.1 ms / 2766; 4000 bodies 235.9 ms / 34 423 ->
- 99.1 ms / 10 894. A settling pile now sleeps completely at 2.4 ms/step
- instead of never at 5.2. `box-stack` 4000: 16.5 -> 9.7 ms with identical
- contact counts, which is the sleep gate alone. Three tests whose
- literals pinned the old cap were retuned deliberately and one was added:
- a contact resting deeper than the tolerance must still sleep once its
- push-out has stalled.
-
- Bench package, same change set:
- - planck.js joins the physics matrix as a second pure-JS peer
- (`lengthUnitsPerMeter = 30`; its default of 1 double-counts contacts in
- pixel coordinates), Rapier is labelled as the WASM reference rather than
- a peer, and `--engine` filters the physics domain. Contact counts now
- agree across exojs, matter-js, planck and rapier, which they previously
- did not.
- - New `composite` rendering archetype: scene into an offscreen render
- texture, blur sweeps, additive composite over the direct draw. ExoJS
- through the public `RenderPipeline`, Pixi hand-rolled with
- `RenderTexture` and filters. Structural baseline re-recorded for the two
- new cells; no other counter moved.
-
- ***
-
-- **Text no longer splits a grapheme cluster.** Layout counted code points, so
- a combining sequence, an emoji with a skin-tone modifier, a ZWJ sequence and
- a regional-indicator flag were each placed as several glyphs, could be broken
- in half by `breakWords` or `maxWidth`, and could be truncated to a dangling
- mark or a lone regional indicator by `overflow: 'ellipsis'`. The unit of
- layout is now the grapheme cluster throughout - placement, wrapping,
- truncation and the caret granularity of the editing widgets - resolved
- through `Intl.Segmenter`. Where a browser does not provide it, clusters
- degrade to code points and word boundaries to blank runs; no polyfill ships.
-
-- **Word wrapping is locale-aware rather than a split on spaces.** Text in a
- script written without inter-word spaces used to overflow as one unbreakable
- token; it now wraps at its own word boundaries. A run of blanks is one break
- candidate, and a run that stays inside a line is preserved verbatim.
-
-- **`FadeSceneTransition` no longer leaks a `QuadGeometry` per navigation.**
- Its per-session phase state allocates one, and nothing released it, so every
- faded scene change left a backend vertex/index buffer pair behind for the
- lifetime of the context. It now releases the quad through the new
- `destroyPhaseState` hook.
-
-- **WebGPU shader filters no longer mirror their input vertically.** The
- fullscreen pass sampled v = 0 at the bottom of the quad, which is texel row
- 0 on WebGL2 but the last row on WebGPU, so every `ShaderFilter` pass on
- WebGPU wrote its input upside down. Invisible while the effect domain equals
- the content bounds; wrong for a filter with asymmetric reach or one that
- samples away from its own texel.
-
-- **`Application.destroy()` now aborts the lifecycle signal of a navigation
- still inside `load()`.** Teardown already waited for an in-flight navigation
- to settle, but nothing told the incoming scene to stop: a `load()` awaiting
- `Scene.lifecycleSignal` never resolved, so the wait ran out the full
- five-second grace period and the backend went down while the scene was still
- preparing. The signal is aborted at the same point the navigation's
- generation is invalidated, so a cooperative `load()` returns immediately and
- the incoming scope's teardown completes before anything it depends on is
- released.
+- **Let the package policy accept Core's sideEffects allowlist.** ([#665](https://github.com/Exoridus/ExoJS/pull/665))
+- **Typed renderer bindings, buffered SceneAudio fades, Color.fromCss, LDtk enum fields.** ([#655](https://github.com/Exoridus/ExoJS/pull/655))
+- **Pause-aware scene animations and abortable in-flight navigation.** ([#654](https://github.com/Exoridus/ExoJS/pull/654))
### Documentation
- **Bring the README up to the 0.17 surface.** ([#684](https://github.com/Exoridus/ExoJS/pull/684))
- Package table and install list gain lighting, pathfinding and
- tilemap-physics, each package linked to its directory. The feature list
- covers custom sprite materials, the lighting package, the Unicode text
- stack with its new style properties, exact picking with `hitArea`, the
- frame-budgeted job scheduler, the transition authoring kit and the
- pathfinding package. The quickstart compiles again against the current
- API (`Seconds` instead of the removed `Time` type, a mounted canvas, a
- colour that still exists; verified with tsc against `src/`), and the
- roadmap names the 0.18 themes instead of items that have shipped.
-
- ***
+- **Show the brand mark and the companion.** ([#663](https://github.com/Exoridus/ExoJS/pull/663))
+- **Add the which-call-when table to the loading guide.** ([#662](https://github.com/Exoridus/ExoJS/pull/662))
## [0.16.2] - 2026-09-03
From 93599251297d85a6b155328d58312a8a8986b333 Mon Sep 17 00:00:00 2001
From: Exoridus
Date: Sat, 12 Sep 2026 06:27:25 +0200
Subject: [PATCH 19/28] docs(changelog): render the 0.16.x sections one line
per entry
---
CHANGELOG.md | 2634 +++++---------------------------------------------
1 file changed, 249 insertions(+), 2385 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bc6a97e8c..a6bef6c92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -52,2498 +52,362 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
### Added
-- **`Spritesheet.removeFrame(name)` and `Stack.removeItem(item)`.** Both
- mirror their existing `add`-side methods, completing the add/remove pair
- every other mutator on these classes already has.
+- **`Spritesheet.removeFrame(name)` and `Stack.removeItem(item)`.**
### Fixed
-- **Two class doc comments no longer erase their class from the published
- declarations under `stripInternal`.** `SceneNode` and `Loader` mentioned
- `@internal` in prose, which TypeScript reads as a real tag on the class; the
- wording changed. The 22 backend, scene-graph, material, audio, asset-type and
- tile-set members that official extension packages reach through the SDK entry
- points are now documented as that SDK contract instead of being tagged
- `@internal`. The flag itself stays off: 41 internal types still appear in
- public signatures and must be made public first.
-- **A material drawn into a multi-attachment target now gets a dev-build
- warning when its fragment shader under-declares outputs.** The guard that
- refuses a drawable without a material never checked whether a material's
- own shader actually writes every attachment; a shader with fewer declared
- outputs than the target's attachment count silently left the extra
- attachments at their previous contents on WebGL2 (WebGPU already refuses
- pipeline creation for this). `ShaderSource.countFragmentOutputs` reflects
- the declared `@location`/`layout(location = n) out` count from the active
- backend's language and warns once per shader/attachment-count pairing when
- it falls short.
+- **Two class doc comments no longer erase their class from the published declarations under `stripInternal`.**
+- **A material drawn into a multi-attachment target now gets a dev-build warning when its fragment shader under-declares outputs.**
- **`RenderTexturePool` keys pooled textures by format as well as size.**
- `acquire()` matched on `width x height` alone, so a pool holding an
- `Rgba8` entry could hand it back for a request in a different format.
- Latent today (every caller acquires the default format), but silent
- the moment an HDR intermediate requests `Rgba16F`/`Rgba32F`. `acquire()`
- now takes an optional `format` parameter (defaulting to `Rgba8`) and
- matches on it too.
-- **`SharedAbort` dropped its unused multi-holder API.** `retain()`, `holders`
- and `aborted` had no caller anywhere in the tree - cancellation is actually
- decided by the claim refcount elsewhere - and the class documented an
- N-holder contract that was never wired up. Removed, along with the doc
- paragraph describing it.
+- **`SharedAbort` dropped its unused multi-holder API.**
- **A press that hits no interactive node now clears keyboard focus.**
- Nothing blurred the focused node on a click or tap that resolved to empty
- canvas, so an open `Dropdown` stayed open and a `TextInput` kept its caret
- and DOM transport after the user clicked away from it.
-- **An infinitely repeating `Tween` releases its target once that target is
- destroyed.** A tween had no link to its target's lifetime, so
- `repeat(-1)` kept interpolating and writing to a destroyed `SceneNode`
- forever, pinning it in memory. `Tween.update` now stops itself (and is
- released from `TweenSystem`) the frame after its target reports
- `destroyed === true`.
+- **An infinitely repeating `Tween` releases its target once that target is destroyed.**
- **The fixed-timestep spiral-of-death guard now scales with `fixedTimeStep`.**
- The catch-up cap was a constant 5 steps regardless of the configured step
- size, so a step smaller than the default silently ran the simulation slower
- than wall time once the frame rate dropped enough to hit the clamp - with no
- warning. The cap is now derived from the existing frame-delta clamp and the
- configured step, so a smaller step gets proportionally more catch-up steps.
-- **A `Sprite` whose frame was set before its texture finished loading gets the
- right UVs.** Texture coordinates are the frame divided by the texture's
- dimensions, so a frame chosen against a still-loading handle - what
- `Spritesheet` does on an atlas that has not arrived - was computed against
- 0x0 and never recomputed: the sprite sampled a single texel, and a retained
- product recorded around it kept the non-finite coordinates for the life of
- the root. The sprite now recomputes its coordinates and announces the change
- when the payload lands.
-- **Tile layers on WebGL2 sample their own tileset again when a sprite is drawn
- between them.** `@codexo/exojs-tilemap`'s WebGL2 chunk renderer skipped its
- texture bind and blend call whenever its private memo matched, but the memo
- outlived the batch it described - and a sprite drawn between two tile layers
- binds its own texture to the very unit the tile shader samples. The layer
- after it drew the sprite's pixels, with the sprite's blend mode. The WebGPU
- chunk renderer was never affected, so the backends visibly disagreed.
-- **`Text` and `BitmapText` honour `blendMode` on both backends.** The setter
- is public on every drawable and already broke the render batch, but neither
- text renderer applied it: WebGPU baked `Normal` into its pipeline, and WebGL2
- drew with whatever blend state the previously flushed renderer had left, so
- the same run could composite differently from frame to frame. A text batch
- now breaks on a blend change and draws with the mode it declares.
-- **Sprites and meshes on WebGL2 draw with the blend mode they declare, even
- when another renderer type is interleaved.** The WebGL2 blend state is one
- global the backend owns, but the sprite and mesh renderers kept a private
- copy and skipped the backend call whenever a batch declared the mode that
- copy already held. A `Graphics` or nine-slice drawn in between had changed
- the real state in the meantime, so the next batch composited with a foreign
- blend mode - visibly disagreeing with WebGPU, which resolves blend per
- pipeline. Each batch now establishes its blend mode at its own draw call.
-- **Nine-slice sprites on WebGL2 pick up a texture whose payload changed under
- a stable identity, and keep their own blend mode.** The renderer bound the
- batch texture only when the identity differed from the last one it had seen,
- and the bind is what carries the upload - so a skin repainted through
- `Texture.setSource()` / `updateSource()`, a canvas or `ImageBitmap` texture
- refreshed per frame, and a `RenderTexture` re-rendered into went on drawing
- the pixels of their first upload forever. The same memo skipped the live
- check that rejects a destroyed texture, and its blend counterpart let another
- renderer's blend mode through. Texture and blend state are now established at
- the batch's own draw call.
-- **Particle systems on WebGL2 pick up a texture whose payload arrives after
- the first draw.** `WebGl2ParticleRenderer` bound the system's texture only
- when its identity changed, which for a single-system scene meant exactly
- once - while the handle from `loader.get(...)` was still empty. The image
- landed a few frames later and never reached the GPU, so the system simulated
- and drew its quads against blank pixels for the rest of its life. The same
- memo could hold a stale blend mode after another renderer changed it. Both
- are now offered to the backend on every system, which already collapses a
- redundant bind and is the only holder of the live GL state.
-- **A payload of one to three bytes is sniffed as `text/plain` instead of
- throwing.** The MP4 magic-byte check read a 32-bit box size without checking
- that the buffer holds one, so a truncated or near-empty response surfaced as
- `Offset is outside the bounds of the DataView` wrapped in a load failure,
- rather than as the documented fallback.
-- **`WebStorageStore.set()` rejects on a full quota instead of throwing
- synchronously.** Web Storage is synchronous, so a `QuotaExceededError`
- escaped the returned promise and never reached the `.catch()` that is the
- only handler a write has - unlike the serialization failure two lines above
- it, which did reject.
+- **A `Sprite` whose frame was set before its texture finished loading gets the right UVs.**
+- **Tile layers on WebGL2 sample their own tileset again when a sprite is drawn between them.**
+- **`Text` and `BitmapText` honour `blendMode` on both backends.**
+- **Sprites and meshes on WebGL2 draw with the blend mode they declare, even when another renderer type is interleaved.**
+- **Nine-slice sprites on WebGL2 pick up a texture whose payload changed under a stable identity, and keep their own blend mode.**
+- **Particle systems on WebGL2 pick up a texture whose payload arrives after the first draw.**
+- **A payload of one to three bytes is sniffed as `text/plain` instead of throwing.**
+- **`WebStorageStore.set()` rejects on a full quota instead of throwing synchronously.**
- **A blocked IndexedDB open no longer leaks the connection it later gets.**
- The `blocked` event rejected the open, but the request still completed once
- the blocking connection went away, handing over an `IDBDatabase` nobody was
- waiting for and nothing closed - which then blocked every future upgrade in
- its turn. A connection arriving after a rejected open is closed.
- **A container that packs one source twice is rejected instead of unpacked.**
- Both entries resolved to a single asset identity, so the second payload
- replaced the first - and for a texture, video or music entry the replaced one
- owned a GPU upload or a media element that no owner could release.
-- **Two sources that differ only in a `|` are two assets again.** Resource and
- source keys joined their fields with an unescaped separator, so a URL
- carrying an unencoded `|` in its query could compose the very key another
- request composes from a source plus a discriminator - and the two then shared
- one residency entry, one fetch and one claim set. The fields are now escaped
- the way persisted cache record keys already were. Because the source key is
- part of a persisted record's identity, the default cache layout version is
- raised: records written by an earlier version are no longer found and are
- acquired again rather than read under the old spelling.
-- **`awaitBackground()` settles for every caller, and for a queue an eviction
- emptied.** The residency kept a single resolver slot, so a second concurrent
- call overwrote the first and that promise never settled - a loading screen
- and a scene preloader awaiting one drain deadlocked one of them, with no
- error. Dropping a queued entry because its last claim went away (a scene
- teardown, a cancelled load) also left the queue counted as unfinished
- forever, so a lone awaiting caller hung and `onProgress` stayed below its
- total. Both now settle.
-- **A `get()` or `load()` reaching a source while its container is unpacking
- joins the unpack.** An unpack registered no in-flight identity, so for the
- whole window between parsing the index and storing a payload the key looked
- unknown to the loader and a concurrent acquisition of the same source started
- a second, competing fetch whose payload overwrote the container's. Which one
- a consumer saw was timing-dependent, and the loser - a texture upload, a
- media element - was never released.
+- **Two sources that differ only in a `|` are two assets again.**
+- **`awaitBackground()` settles for every caller, and for a queue an eviction emptied.**
+- **A `get()` or `load()` reaching a source while its container is unpacking joins the unpack.**
- **A container that fails while unpacking releases what it already claimed.**
- `Loader.loadContainer` claims every entry up front and only then builds them,
- but a failure rejected without ever handing the caller the scope holding
- those claims, so every entry of a failed container stayed resident for the
- loader's lifetime with no owner able to free it.
-- **A destroyed `LoaderScope` refuses to claim.** `get`, `load` and
- `loadContainer` still registered claims after `destroy()`, and since destroy
- is idempotent by contract there was no way to release them: an async
- continuation that outlived a scene teardown pinned its assets for the
- application's lifetime, and `Loader.inspect()` listed a destroyed scope as an
- owner. They now throw instead.
-- **Releasing a font or an image frees what it owns.** Neither factory
- implemented the per-resource teardown its resources need: a released font
- stayed registered on `document.fonts` (so CSS and Canvas went on resolving
- its family) and pinned for the loader's lifetime, and a released image never
- closed the `ImageBitmap` it had decoded. Only a bitmap the engine decoded
- itself is closed.
-- **An asset unloaded mid-fetch frees the resource its factory had already
- built.** The store was skipped, as it must be, but the finished resource -
- which for a video or a music stream owns a media element - was handed back
- undisposed and stayed alive until the loader was torn down.
-- **A failed or cancelled `music`/`video` load cleans up after itself.** The
- element was registered with the factory before the source was attached, and a
- failure left it there with its object URL unrevoked - and since no resource
- was built, nothing would ever release it. A repeatedly retried blob-backed
- load accumulated one element and one live blob per attempt.
-- **A `fetchOptions.signal` set on the loader aborts asset loads too.** Every
- asset load replaced it with the loader's own cancellation signal, so an
- application-wide abort signal worked for `.exoa` containers and silently did
- nothing for every other asset. The two are composed now: either one aborts
- the request, and neither disables the other.
-- **Options a later `get()` loses are diagnosed in development.** `Loader.get`
- documents that the same source yields the same instance and that conflicting
- options on a later call are ignored with a one-time dev warning - but no such
- warning existed, so a second `get('x.png', { textureOptions })` dropped its
- sampler request with nothing to diagnose it. The warning now exists (once per
- source, stripped in production). Options that take part in asset identity are
- unaffected: they resolve to their own instance and lose nothing.
-- **A `stop()` made while `start()` is still loading is no longer overwritten
- when the startup run settles.** The startup continuation promoted the state
- to `Running` unconditionally, so a `stop()` that landed inside the loading
- window - where the frame loop is live but the state is still `Loading` - was
- undone the moment `start()` resolved. The application then advertised
- `Running` for a halted loop, and because both `start()` and `stop()`
- early-return on that state, the instance was permanently unusable. The
- promotion now happens only if the loop the run started is still the live one.
-- **A destroyed `Application` stays destroyed.** A `start()` that failed while
- `destroy()` was running reset the state to `Stopped` from its own catch, and
- because that continuation resumes after the teardown chain has finished,
- `Stopped` was the last value written. `state` then lied about a destroyed
- instance and `start()` accepted it, reinitializing an already-destroyed
- backend and restarting the frame loop over released subsystems. `Destroying`
- and `Destroyed` are now terminal - the only transition out of them is
- `Destroying` to `Destroyed` - so a late startup failure cannot resurrect the
- application and `start()` rejects as documented.
-- **`Application.destroy()` waits for a scene navigation that is still in
- flight.** `destroy()` documents that `scenes` is fully disposed before the
- Loader, rendering context, audio system and backend are released, but a
- `change()`/`restore()` (or the initial `start(Target)` navigation) still
- inside `load()` was tracked by nothing the disposal awaited: aborting it only
- invalidated its generation, so the incoming scene went on to run `init()`,
- `unload()` and `destroy()` after teardown had finished, against subsystems
- that no longer existed. The disposal now awaits the run it just aborted, the
- same way it already awaits a preload. A scene whose `load()` never settles is
- bounded by `destroy()`'s existing teardown grace period.
+- **A destroyed `LoaderScope` refuses to claim.**
+- **Releasing a font or an image frees what it owns.**
+- **An asset unloaded mid-fetch frees the resource its factory had already built.**
+- **A failed or cancelled `music`/`video` load cleans up after itself.**
+- **A `fetchOptions.signal` set on the loader aborts asset loads too.**
+- **Options a later `get()` loses are diagnosed in development.**
+- **A `stop()` made while `start()` is still loading is no longer overwritten when the startup run settles.**
+- **A destroyed `Application` stays destroyed.**
+- **`Application.destroy()` waits for a scene navigation that is still in flight.**
- **A destroyed scene graph is no longer pinned by the changed-record index.**
- The process-wide dirty index recycled a generation by resetting its logical
- length only, leaving every entry above it in place - and a `SceneNode` links
- to its parent while a `Container` links to its children, so one retired entry
- kept a whole destroyed scene alive for the life of the process, long after
- the index itself reported those marks as outside its window. A recycled
- generation now drops its references, and a node releases its entry when it is
- destroyed, which is what leaves nothing pinned once `Application.destroy()`
- has stopped advancing the index.
- **A system removed and added back inside the same frame stays registered.**
- `remove()` marks a registration inactive and queues the structural delete for
- the frame boundary, but left it in the registry - so the `add()` that
- followed hit the duplicate-registration no-op, and the queued removal then
- deleted the system at the end of the frame with no error anywhere. The
- pattern is what a system re-registering itself to change its order or phase
- does, and it silently lost the system. `add()` now cancels a pending removal
- and re-registers with the options that call asks for.
-- **`SystemRegistry.remove()` reports the truth for a buffered add.** Removing
- a system added earlier in the same frame - one that never became a
- registration, and for which `has()` answers `false` - returned `true`,
- contradicting the method's own "true if it was registered". The add is still
- cancelled; the return value now agrees with `has()`.
-- **Loader claims are released last on both scene teardown paths.** A scope
- torn down after a failed `load()`/`init()` released its loader claims before
- calling `scene.destroy()`, while the ordinary teardown - whose documentation
- names "release loader claims last" as the normative order - released them
- after it. A `Scene.destroy()` override reaching for `this.loader` therefore
- saw a live claim scope or a destroyed one depending on whether activation had
- succeeded, and a claim taken on the failed path was never released. Both
- paths now release last.
-- **A manual `Application.update()` no longer forks the frame loop.** The
- public tick rescheduled the next animation frame unconditionally, so calling
- it while the loop was live - from `onFrame`, from an external fixed-rate
- host, from a test harness that also lets the loop run - started a second
- chain alongside the first and silently doubled the frame rate. Scheduling now
- belongs to the loop's own callback: `update()` runs exactly one frame.
-- **`SceneNode.destroy()` and `RenderNode.destroy()` are idempotent.** Only
- `Container` guarded re-entry, while the two layers beneath it documented
- releasing state a second pass must not touch again - so a double `destroy()`
- on a leaf node took its transform, bounds and flags through a second
- teardown, and on a `RenderNode` re-ran the filter and signal release as well.
- A second call is now a no-op at every layer.
-- **Audio objects created while the context is locked again are set up on the
- next unlock.** `onAudioContextReady` latched after its very first dispatch,
- so a bus, listener, stream voice, worklet or effect constructed while the
- context sat suspended - after an iOS audio-session interruption or a bfcache
- restore - subscribed to a signal that could never fire and stayed silent for
- the rest of the session. The signal now dispatches once per run of the
- context, to whoever is subscribed at that moment.
-- **An effect that never finishes its setup no longer silences the bus it is
- attached to.** `AudioBus` rebuilt its effect chain by disconnecting the bus
- input first and only then reading each effect's nodes, so an effect still
- unready on the retry pass threw with the graph half torn down - inside a
- microtask, where no caller could see it - and the bus stayed cut from its pan
- stage for good. The chain is now resolved before anything is disconnected,
- and an unready effect is bypassed with one diagnostic naming it.
+- **`SystemRegistry.remove()` reports the truth for a buffered add.**
+- **Loader claims are released last on both scene teardown paths.**
+- **A manual `Application.update()` no longer forks the frame loop.**
+- **`SceneNode.destroy()` and `RenderNode.destroy()` are idempotent.**
+- **Audio objects created while the context is locked again are set up on the next unlock.**
+- **An effect that never finishes its setup no longer silences the bus it is attached to.**
- **A worklet effect whose module fails to load degrades to a passthrough.**
- `WorkletEffect.ready` rejected with nobody attached, so a blocked
- `addModule` - a Content-Security-Policy forbidding `blob:` worker sources is
- the realistic case - surfaced as an unhandled rejection. The failure is
- logged instead and `ready` resolves; the effect keeps passing dry signal.
-- **A rejected `AudioContext.resume()` is logged instead of surfacing as an
- unhandled rejection.** The autoplay-unlock gesture handler attached no
- rejection handler, so a context the browser refused to resume produced a bare
- rejection with no hint of where it came from.
-- **Audio zones only colour spatial voices.** `SpatialZones` documented that it
- reconciles the live set of spatial voices, but `AudioSystem` handed it every
- voice - so a reverb zone opened a send on UI blips and music beds that have no
- position in the world at all. A voice that stops being positional now has its
- zone sends closed instead of keeping them open untouched.
-- **`AudioZone.height` is documented as the half-band it is.** The option and
- the field described it two different ways; `height: 100` covers `z` from
- `-100` to `100`, which both now say.
-- **A per-call `repeat` on `AnimatedSprite.play()` no longer leaks into the next
- clip.** The override was written on every `play()` and never cleared, so
- `play('attack', { repeat: 2 })` followed by `play('idle')` stopped the
- indefinitely-looping idle clip after two cycles. An override now belongs to
- the playback run that set it.
-- **A single-frame `AnimatedSprite` clip completes.** `update()` returned before
- any timing ran for a clip with one frame - the shape an Aseprite frame tag
- covering a single frame exports - so `onComplete` never fired, the sprite
- stayed `playing`, and its `AnimationSystem` registration was never released.
- The frame is now held for its own duration and then takes the normal
- completion path.
-- **`TweenSystem.clear()` and `destroy()` stop the tickers they drop.** Tweens
- were stopped but registered tickers were only dropped, so a `TweenSequencer`
- kept reporting `Active` after an application teardown with nothing left to
- advance it.
+- **A rejected `AudioContext.resume()` is logged instead of surfacing as an unhandled rejection.**
+- **Audio zones only colour spatial voices.**
+- **`AudioZone.height` is documented as the half-band it is.**
+- **A per-call `repeat` on `AnimatedSprite.play()` no longer leaks into the next clip.**
+- **A single-frame `AnimatedSprite` clip completes.**
+- **`TweenSystem.clear()` and `destroy()` stop the tickers they drop.**
- **A `TweenSequencer` delay stage carries its overshoot into the next stage.**
- The time past a `wait()` stage's own duration was dropped, so a chain of
- waits drifted by up to one frame per stage and a repeated sequence
- accumulated the error - `Tween.update` already carries the same remainder
- into its next repeat cycle.
- **A rebuilt particle GPU state no longer delivers garbage death contexts.**
- `@codexo/exojs-particles` kept the queue of deaths still awaiting a readback
- when the GPU state was torn down - after a device loss, a backend change or a
- transition back to CPU modules - so the next state staged that many records
- out of a freshly zeroed device buffer and every death module saw a
- zero-valued context, firing `SpawnOnDeath` sub-emitters at the origin.
-- **`RateSpawn` recovers from a negative rate sample.** A distribution that can
- return a value below zero drove the accumulator down without bound, and the
- emitter never spawned again. The sampled rate is clamped at zero.
+- **`RateSpawn` recovers from a negative rate sample.**
- **An out-of-range `ParticleWriter.frame` no longer wraps onto a valid frame.**
- The frame channel is a `Uint16Array`, so `-1` became `65535` and `70000`
- became `4464` - both of which can be a frame the system declares, instead of
- the documented frame-0 fallback. Development builds throw with the offending
- index; production clamps.
-- **A particle system is no longer culled by the size of one particle.** A
- `ParticleSystem`'s local bounds cover one texture frame at its local origin -
- a single pixel for the default white texture - while its particles travel
- arbitrarily far from there, so the viewport check removed the whole cloud as
- soon as the emitter's origin scrolled out of view. Systems opt out of culling
- by default; `cullArea` is the documented way back in for a system whose reach
- is known.
+- **A particle system is no longer culled by the size of one particle.**
- **The WebGPU compute path samples the texture frame the CPU path does.**
- `@codexo/exojs-particles` baked a particle system's frame UVs into a uniform
- block once, when the GPU state was built, and assumed the whole texture
- whenever no atlas was declared - so `system.textureFrame` was ignored
- outright, and a texture swapped in later left the UVs divided by the previous
- texture's dimensions. The same scene drew a sub-rect on WebGL2 and the whole
- atlas on WebGPU. Both setters now re-bake the block.
-- **Two update modules of the same class are reported by name instead of
- breaking WebGPU only.** A module's WGSL `key` names one struct and one member
- of the composite compute shader's uniform block, so a second module under the
- same key made the codegen declare each twice - invalid WGSL that failed
- pipeline creation at the first `update()`, while WebGL2 ran the same scene.
- `@codexo/exojs-particles` now throws `ParticleModuleKeyCollisionError` naming
- both modules and the key, before the device is asked to build anything.
+- **Two update modules of the same class are reported by name instead of breaking WebGPU only.**
- **A focused text field no longer blanks the keyboard and wheel pipeline.**
- Focusing a field hands host focus to the platform's own text transport, which
- blurs the canvas - and keyboard and wheel input were gated on the canvas
- element holding focus alone. Every editing key the widget owns (caret motion,
- Home/End, selection extension, `Escape`, `Ctrl+A`, `Ctrl+Z`/`Y`, `Enter` in a
- single-line field) and all wheel scrolling were dead for as long as any field
- was focused, and the held keys of a running game were released. The gate now
- treats an engine-owned transport holding host focus as the application
- holding it, and closes again when focus really leaves - including to a
- foreign element of the embedding page. Leaving a field hands host focus back
- to the surface rather than dropping it on the document. A transport that
- reports an edit for a keystroke the widget also handles (Backspace, Delete,
- and `Enter` in a multi-line field) now applies it once instead of twice.
- `app.input.canvasFocused` and `onCanvasFocusChange` mean "this application
- holds keyboard focus"; a press on a surface the host refuses focus for
- reports the change instead of flipping the flag silently.
-- **Text input works again in browsers that ship `EditContext`.** The backend
- attached its context with `EditContext.attachToElement()`, a draft method no
- browser implements, and hung it on a `
)}
- {/* The view already names its domain and its unit, so the block carries only what the tab cannot say: the size the rows were measured at. */}
+ {/*
+ * No global load note. Every row states its own load in its own column,
+ * because the rows are not measured at one: a scenario carries its own
+ * ladder, and a sentence claiming one figure for the table was wrong for
+ * most of the rows under it and unwritable for the rest.
+ */}
{isRendering && renderingTable.rows.length > 0 && (
-
{renderingCountNote}, chosen from the archetype ladders before any timing was read.
)}
diff --git a/site/src/components/BenchResultCard.astro b/site/src/components/BenchResultCard.astro
index 110a704b1..837aeff73 100644
--- a/site/src/components/BenchResultCard.astro
+++ b/site/src/components/BenchResultCard.astro
@@ -7,14 +7,31 @@
* is the time it shows and two bars can be read against each other directly.
* There is no log scale and no ratio axis: both require the reader to learn the
* axis before they can read the result, and both make a small difference look
- * like a large one.
+ * like a large one. Where one arm is two orders of magnitude slower, the short
+ * bars stop separating and the printed figures carry the row instead - which is
+ * why the time column is the card's strongest text and not a caption beside the
+ * bar.
*
* A card compares the arms WITHIN one load. It never compares two loads or two
* cards against each other - those are different scenes, and the harness makes
* no claim about them.
+ *
+ * A bar here is a DURATION and not a comparison, which is what decides when one
+ * is drawn: any figure the profile published gets one, including a figure whose
+ * pair the clock could not separate, because how long that arm took is not in
+ * doubt - only whether the two times may be divided by one another is. What
+ * such a pair loses is the factor and the winner, and that is stated once under
+ * the row rather than stamped on each arm of it: the check is a property of the
+ * pair, so tagging four arms says the same thing four times about a comparison
+ * only some of them are in.
+ *
+ * The detail each load opens is rendered from that load's own comparisons, so
+ * the load, the backend and the profile a reader is looking at cannot come
+ * apart from the ones the numbers were read out of.
*/
-import { archetypeDescription, archetypeTitle, formatMs, OUTCOME_LABELS } from '../lib/bench-profiles';
+import BenchMeasurementDetail from './BenchMeasurementDetail.astro';
+import { archetypeDescription, archetypeTitle, FRAME_BUDGET_NOTE, formatMs, OUTCOME_NOTES, OUTCOME_STATUS } from '../lib/bench-profiles';
import type { BenchCard } from '../lib/bench-cards';
import { openingLoad } from '../lib/bench-cards';
@@ -27,25 +44,27 @@ interface Props {
const { card, domain } = Astro.props;
const opening = openingLoad(card);
const description = archetypeDescription(card.id);
+const anchor = `${domain}-${card.id}${card.backend === undefined ? '' : `-${card.backend}`}`;
/**
- * Bar width for one figure, as a percentage of the card's slowest arm.
+ * Bar width for one figure, as a percentage of the card's slowest plotted arm.
*
* A measured figure always gets at least a sliver, so a very fast arm stays
* visible - but the sliver is deliberately narrow enough that nobody reads it as
- * a quantity. An absent figure gets no bar at all rather than a zero-length one:
- * zero would say the arm took no time, which is the opposite of what happened.
+ * a quantity, and the figure beside it is what the row is read from. A row with
+ * no plottable figure gets no bar at all rather than a zero-length one: zero
+ * would say the arm took no time, which is the opposite of what happened.
*/
const widthOf = (ms: number | null, maxMs: number): number | null => (ms === null || !Number.isFinite(ms) || maxMs <= 0 ? null : Math.max(1.5, (ms / maxMs) * 100));
---
-
+
))}
@@ -111,7 +162,7 @@ const widthOf = (ms: number | null, maxMs: number): number | null => (ms === nul
.load {
font: inherit;
font-size: 0.76rem;
- padding: 0.2rem 0.5rem;
+ padding: 0.2rem 0.55rem;
border-radius: 999px;
border: 1px solid var(--color-border);
background: transparent;
@@ -119,25 +170,34 @@ const widthOf = (ms: number | null, maxMs: number): number | null => (ms === nul
cursor: pointer;
}
+ /* Weight and a filled ground as well as hue: the selected load has to be readable without separating the two colours. */
.load[aria-pressed='true'] {
border-color: var(--color-accent);
- color: var(--color-accent);
- font-weight: 600;
+ background: color-mix(in srgb, var(--color-accent) 14%, transparent);
+ color: var(--color-text);
+ font-weight: 650;
}
.at {
- margin: 0 0 0.5rem;
+ margin: 0;
font-size: 0.78rem;
color: var(--color-text-muted);
}
+ .coverage {
+ margin: 0 0 0.4rem;
+ font-size: 0.76rem;
+ color: var(--color-text-muted);
+ }
+
+ /* No frame of its own: the card is already a box, and a second border around the bars only narrows them. */
.arms {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
- gap: 0.35rem;
+ gap: 0.4rem;
}
.arm {
@@ -159,7 +219,7 @@ const widthOf = (ms: number | null, maxMs: number): number | null => (ms === nul
}
.track {
- height: 0.55rem;
+ height: 0.5rem;
border-radius: 999px;
background: color-mix(in srgb, var(--color-border) 55%, transparent);
overflow: hidden;
@@ -172,30 +232,98 @@ const widthOf = (ms: number | null, maxMs: number): number | null => (ms === nul
background: color-mix(in srgb, var(--color-text-muted) 65%, transparent);
}
+ /* ExoJS keeps the brand hue across every card. It marks which row is the reference and never which row won. */
.arm.reference .bar {
background: var(--color-accent);
}
+ /* Where two bars are a few pixels apart the figure is the comparison, so it carries the weight the bar cannot. */
.time {
font-variant-numeric: tabular-nums;
white-space: nowrap;
+ font-size: 0.92rem;
+ display: inline-flex;
+ align-items: baseline;
+ gap: 0.15rem;
+ }
+
+ .time b {
+ font-weight: 650;
+ color: var(--color-text);
}
.arm.absent .time {
+ font-size: 0.78rem;
+ }
+
+ .state {
color: var(--color-text-muted);
- font-size: 0.76rem;
+ border-bottom: 1px dotted var(--color-border);
+ cursor: help;
}
.unit {
color: var(--color-text-muted);
- margin-left: 0.15rem;
font-size: 0.76rem;
}
- .over {
- color: var(--color-warning, #b45309);
- margin-left: 0.3rem;
+ /* A button rather than a glyph with a title: a touch reader and a keyboard reader both have to be able to reach what the mark means. */
+ .mark {
+ font: inherit;
+ font-size: 0.68rem;
+ line-height: 1;
+ margin-left: 0.25rem;
+ padding: 0.15rem 0.3rem;
+ border-radius: 0.3rem;
+ border: 1px solid currentcolor;
+ background: transparent;
+ cursor: help;
+ }
+
+ .mark.over {
+ color: var(--amber);
font-weight: 700;
+ padding: 0.15rem 0.35rem;
+ }
+
+ .mark.limited {
+ color: var(--color-text-muted);
+ flex: 0 0 auto;
+ }
+
+ .limited {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: baseline;
+ gap: 0.35rem;
+ margin: 0.5rem 0 0;
+ font-size: 0.76rem;
+ color: var(--color-text-muted);
+ }
+
+ .limited span {
+ flex: 1 1 12rem;
+ }
+
+ .more {
+ margin-top: 0.2rem;
+ font-size: 0.82rem;
+ }
+
+ .more > summary {
+ cursor: pointer;
+ color: var(--color-text-muted);
+ width: fit-content;
+ }
+
+ .more[open] > summary {
+ margin-bottom: 0.5rem;
+ }
+
+ .context {
+ margin: 0 0 0.5rem;
+ font-size: 0.78rem;
+ color: var(--color-text-muted);
}
@media (max-width: 34rem) {
@@ -203,6 +331,10 @@ const widthOf = (ms: number | null, maxMs: number): number | null => (ms === nul
grid-template-columns: 4.5rem 1fr auto;
font-size: 0.78rem;
}
+
+ .time {
+ font-size: 0.86rem;
+ }
}
@@ -210,7 +342,8 @@ const widthOf = (ms: number | null, maxMs: number): number | null => (ms === nul
// Load switching is per card and nothing else on the page depends on it, so
// it stays a listener on the card rather than shared state. Without
// JavaScript every panel but the opening one is `hidden`, which is the same
- // thing the buttons toggle - so the card still shows a real measured load.
+ // thing the buttons toggle - so the card still shows a real measured load,
+ // with the detail of that same load inside it.
for (const card of document.querySelectorAll('.card')) {
const buttons = card.querySelectorAll('.load');
const panels = card.querySelectorAll('.panel');
diff --git a/site/src/components/pages/BenchFullResultsPage.astro b/site/src/components/pages/BenchFullResultsPage.astro
new file mode 100644
index 000000000..27f0dd745
--- /dev/null
+++ b/site/src/components/pages/BenchFullResultsPage.astro
@@ -0,0 +1,192 @@
+---
+/**
+ * BenchFullResultsPage - every measured row of one machine, with its spread,
+ * its p95, the mechanism behind each difference and the rows the harness kept
+ * out.
+ *
+ * It is a page of its own rather than the foot of the results page: the reader
+ * who wants it is checking a specific row, and the reader who does not was
+ * scrolling past it. Nothing here is authored - a re-measurement rewrites it
+ * together with the cards.
+ *
+ * Machines are picked rather than stacked. A second profile appended under the
+ * first reads as more evidence about the first; it is a different machine, in a
+ * different browser, sharing no comparison with it.
+ */
+
+import BenchProfileReport from '../BenchProfileReport.astro';
+import DocsLayout from '../../layouts/DocsLayout.astro';
+import EnglishFallbackNotice from '../EnglishFallbackNotice.astro';
+import { benchProfiles, coversDomain, formatDay, machineName, olderThanReference, platformName } from '../../lib/bench-profiles';
+
+interface Props {
+ locale: 'en' | 'de';
+}
+
+const { locale } = Astro.props;
+const base = import.meta.env.BASE_URL;
+---
+
+
+
+ {locale === 'de' && }
+
+
+
Full results
+
Every measured row, with the spread its runs observed and the rows the harness left out.
+
+
+
+
+
diff --git a/site/src/components/pages/BenchMethodologyPage.astro b/site/src/components/pages/BenchMethodologyPage.astro
new file mode 100644
index 000000000..2939c949d
--- /dev/null
+++ b/site/src/components/pages/BenchMethodologyPage.astro
@@ -0,0 +1,47 @@
+---
+/**
+ * BenchMethodologyPage - the terms every published benchmark number is read
+ * under, on a page of its own.
+ *
+ * The results page links here rather than carrying it: a reader consults these
+ * once a row surprises them, and several screens of prose above the cards
+ * answered a question nobody had asked yet.
+ */
+
+import BenchMethodology from '../BenchMethodology.astro';
+import DocsLayout from '../../layouts/DocsLayout.astro';
+import EnglishFallbackNotice from '../EnglishFallbackNotice.astro';
+
+interface Props {
+ locale: 'en' | 'de';
+}
+
+const { locale } = Astro.props;
+const base = import.meta.env.BASE_URL;
+---
+
+
+
+ {locale === 'de' && }
+
+
How these numbers are made
+
The terms the published measurements are read under, and what it takes to reproduce one.
+
+
+
diff --git a/site/src/components/pages/BenchmarksPage.astro b/site/src/components/pages/BenchmarksPage.astro
index db57d0e84..8666508ef 100644
--- a/site/src/components/pages/BenchmarksPage.astro
+++ b/site/src/components/pages/BenchmarksPage.astro
@@ -1,22 +1,27 @@
---
/**
* BenchmarksPage - the published cross-library measurements, rendering and
- * physics on one page.
+ * physics on one page of scenario cards.
*
* The page is generated at build time from the machine profiles under
* `packages/exojs-bench/results/` and from nothing else, so it cannot drift from
- * the harness: a re-measurement rewrites the cards, the tables and the
- * provenance together. Losses are published on the same terms as wins, nothing
- * is aggregated into a score or an overall winner, and the rows the harness left
- * out of a comparison are listed with their reasons.
+ * the harness: a re-measurement rewrites the cards and the provenance together.
+ * Losses are published on the same terms as wins, nothing is aggregated into a
+ * score or an overall winner, and which scenarios open each section is fixed in
+ * `bench-cards.ts` before any run happens, so the top of the page cannot become
+ * a selection of whatever ExoJS won.
*
- * Results lead and the practices behind them follow. Which scenarios open each
- * section is fixed in `bench-cards.ts` before any run happens, so the top of the
- * page cannot become a selection of whatever ExoJS won; the rest stay one
- * disclosure away in the same section.
+ * The page carries cards and nothing else. Every row's own terms are one
+ * disclosure inside that row's card, and the full per-row report, the
+ * methodology and the raw profiles are their own pages: carrying them here made
+ * a reader scroll past several screens of prose that say the same thing
+ * whichever card raised the question.
+ *
+ * Machines are picked, never stacked. Two profiles are two machines measured in
+ * two browsers and share no comparison, so a second one appended under the
+ * first would read as more evidence about the first.
*/
-import BenchProfileReport from '../BenchProfileReport.astro';
import BenchResultCard from '../BenchResultCard.astro';
import BenchLocalProbe from '../BenchLocalProbe.astro';
import DocsLayout from '../../layouts/DocsLayout.astro';
@@ -25,13 +30,12 @@ import { appInfo } from '../../lib/app-info';
import { PHYSICS_HEADLINE_SCENARIOS, physicsCards, RENDERING_HEADLINE_SCENARIOS, renderingCards, selectCards } from '../../lib/bench-cards';
import {
BACKEND_LABELS,
- coversDomain,
+ benchProfiles,
formatDay,
- FRAME_BUDGET_MS,
- furtherProfiles,
- olderThanReference,
+ machineName,
+ platformName,
+ type BenchProfileDocument,
type ProfileBackendName,
- referenceProfile,
} from '../../lib/bench-profiles';
interface Props {
@@ -39,30 +43,28 @@ interface Props {
}
const { locale } = Astro.props;
+const base = import.meta.env.BASE_URL;
/**
- * Runs the reproduction below pools. A published profile states the number it
- * was actually built from; until one exists the page can only quote the count
- * its own reproduction steps prescribe.
+ * Runs a reference profile is built from. A published profile states the number
+ * it was actually built from; until one exists the page can only quote the
+ * count its own reproduction steps prescribe.
*/
const REPRODUCTION_RUNS = 3;
-const pooledRuns = referenceProfile?.profile.runs ?? REPRODUCTION_RUNS;
-const machine = referenceProfile?.profile;
-
-/** Cards per rendering backend, so the section switches without a second request. */
const backends: readonly ProfileBackendName[] = ['webgl2', 'webgpu'];
-const rendering = backends
- .map(backend => ({
- backend,
- ...selectCards(referenceProfile === undefined ? [] : renderingCards(referenceProfile, backend), RENDERING_HEADLINE_SCENARIOS, 6),
- }))
- .filter(entry => entry.headline.length > 0);
-
-const physics = selectCards(referenceProfile === undefined ? [] : physicsCards(referenceProfile), PHYSICS_HEADLINE_SCENARIOS, 4);
-/** Only the further machines that measured something, so no disclosure opens onto nothing. */
-const furtherMachines = furtherProfiles.filter(document => coversDomain(document, 'rendering') || coversDomain(document, 'physics'));
+/** Everything one machine contributes to the page, assembled once per profile. */
+const viewOf = (document: BenchProfileDocument) => ({
+ document,
+ rendering: backends
+ .map(backend => ({ backend, ...selectCards(renderingCards(document, backend), RENDERING_HEADLINE_SCENARIOS, 6) }))
+ .filter(entry => entry.headline.length > 0),
+ physics: selectCards(physicsCards(document), PHYSICS_HEADLINE_SCENARIOS, 4),
+});
+
+const machines = benchProfiles.map(viewOf);
+const leading = machines[0];
---
@@ -71,354 +73,183 @@ const furtherMachines = furtherProfiles.filter(document => coversDomain(document
Benchmarks
-
- How long one frame of rendering, and one fixed step of physics, costs on the CPU. Lower is better, and every published value is the median
- of {pooledRuns} independent runs.
-
No measurements are published yet. The reference measurement is {REPRODUCTION_RUNS} separate runs on one machine after a release is tagged,
- pooled into a single profile file in the repository; until then there is nothing here to read. The practices below already apply.
+ pooled into a single profile file in the repository; until then there is nothing here to read.{' '}
+ The terms they will be published under already apply.
+ {machines.length === 1 && {machineName(profile)}}
+ {platformName(profile)}
+ ExoJS {profile.engineVersion}
+ measured {formatDay(profile.measuredAt)}
+ {/* Stated once, here, rather than again inside the opening sentence: it is a fact about the run, not about the result. */}
+ median of {profile.runs} pooled runs
+
- Every measured row with its spread, its p95, the mechanism behind each difference and the rows the harness left out - the same
- numbers the cards above are drawn from, in full.
-
- Measured with ExoJS {document.profile.engineVersion}; the newest published profile is {newer}. Compare it against the
- reference profile with that in mind.
-
- The terms the tables above are published under. They are here rather than in front of the numbers because they are what a reader consults
- once a row surprises them.
-
+ {/* Four destinations and no explanatory paragraphs: what each one is is what its name says. */}
+
-
- Methodology: pooling, medians, ranges, the ladder, the frame budget
-
-
- A published profile pools {pooledRuns} separate runs of the same matrix. One run cannot support a ratio: the same
- code measured twice on one idle machine moves a cell's median far enough to reverse which library a cell favours - a reversal this
- harness has produced in practice, which is why a single run is not published as a reference measurement.
-
-
- The published value is the median of the per-run medians - each run's own median over its timed window, then the
- median across the runs - so one unlucky run cannot set a number. Nothing is ever a mean, and nothing is aggregated across archetypes.
-
-
- Every number carries the spread its runs observed, printed under it as the factor between the slowest and the
- fastest run; the two millisecond values behind it are on the cell itself. A spread of 1.2 or more is marked: the measurement's own
- noise then reaches as wide as the band the ladder treats as no difference at all, which is something to know before reading the
- number, not after.
-
-
- Every median is published with the p95 of the same timed window beside it. The median is the amortised cost and the
- number every verdict is computed from - it is also what independent published comparisons state - while the p95 is the step or frame
- a player feels as a hitch. A pair far apart describes work that is periodically expensive, which a median alone would report as
- cheap. There is no p99: the largest cells time 120 steps, so a p99 there is the second-worst sample, an outlier rather than a
- percentile.
-
-
- A published median past {FRAME_BUDGET_MS} ms - a whole 60 fps frame - is marked. The line is the entire frame and
- not a fraction of it on purpose: how much of a frame you may spend on physics, or on the CPU side of rendering, depends on everything
- else your frame does and is your decision, while a single step or frame that costs more than the frame it has to fit in is unplayable
- whatever you decide. Nothing is derived from the mark - there is no "how many bodies at N ms" capacity figure, because that would
- interpolate between the ladder's rungs rather than report something measured.
-
-
- A verdict is published only when all {pooledRuns} runs independently reach it. Each run is placed on the ladder on
- its own, and the pooled medians have to land on the same rung as well. A cell whose runs disagreed publishes no verdict, and
- it is counted nowhere - not as a win, not as a loss, and not as a level row. That the pair cannot be separated on this machine is the
- finding. It still shows what was measured: the factor its two pooled medians work out to, printed with a tilde and plotted without a
- side. That factor is the one figure the page derives rather than reads, and it is never a verdict - the tilde, the hollow mark and
- the scoreboard all keep it out of the outcome counts.
-
-
- A ratio between 0.8 and 1.2 is reported as level: inside that band the difference is not
- distinguishable from machine mood.
-
-
- A gap of 5x or more is reported as leads clearly rather than leads. Below that factor a driver
- state or an unlucky window could still explain the result; at or above it, the difference is attributable to how the two libraries
- are built.
-
-
- Each comparison names the mechanism behind its difference, drawn from structural counters the harness collects -
- draw calls, texture binds, buffer uploads, solved contacts - and they are listed under the tables. A row whose difference could not
- be evidenced that way is not published as a comparison; it appears among the omissions instead.
-
-
- One profile describes one machine measured in one browser. Numbers from different machines are never mixed into one
- table or averaged together, and neither are numbers from different browsers - including for physics, which touches no GPU but whose
- per-step times depend on which JavaScript engine executed the steps.
-
-
- Physics is measured in the browser, not in the process that drives the harness. Nobody runs ExoJS physics in Node,
- and the runtime is part of the measurement: heap limits, garbage collection and WebAssembly compilation are the browser's. The
- fastest cells step in microseconds, close to the browser's clock resolution, so a step too fast to time on its own is timed in
- batches large enough to clear that resolution, with the timed-step budget unchanged.
-
-
- Phaser renders through a WebGL1 context, so its rows sit in their own block, compare CPU time only, and carry no
- mechanism - the structural probe cannot attach to that context to say whether the backend generation or the engine caused the gap.
-
-
- Rapier is a Rust/WASM reference ceiling, not a pure-JS peer. It measures what leaving JavaScript buys; matter.js and
- planck are the peers ExoJS is compared against.
-
-
Culling is configured to match across arms, so no arm wins a row by drawing less of the same scene.
-
- A row's node or body count is chosen from the archetype ladders before any timing is read - the largest rung at
- which every arm produced a valid cell - so it can never be picked to suit the outcome. A rendering backend goes further and uses one
- node count for all of its rows, because its archetypes share their ladders. An arm that produced no comparable cell at that count -
- because it sits the archetype out, or because it exceeded the runaway step budget - is shown as not comparable rather than
- omitted.
-
-
- Each physics archetype has its own body-count ladder, placed so its rungs straddle the frame budget: two inside the
- frame and one past it, so you can see both the slope and where the archetype stops being viable. They reach a frame at sizes that
- differ by nearly an order of magnitude, so one shared count would put most rows at a size chosen to suit a different scene. Every
- physics row therefore states its own count, and physics rows are not comparable with one another - only the arms
- within one row are, which is what the table was ever for.
-
-
-
-
-
- Reproduce: run the harness yourself and publish a profile for your machine
-
- The harness is in the repository, and so are the adapters. A reference profile is {REPRODUCTION_RUNS} separate runs, not
- one run repeated inside itself: repeating a matrix in one process shares JIT and heap state between the repetitions and measures the same
- warm state {REPRODUCTION_RUNS} times, which is the very effect the repetition exists to expose. Each run is its own invocation with its
- own output directory, and bench:compare pools them by taking each input flag once per run.
-
- The harness lives in packages/exojs-bench and its scripts are run from there; the root pnpm bench is the
- engine's own micro-benchmark suite and not this one. The -- separates the harness's flags from pnpm's own. Output
- directories are relative to the package. pnpm bootstrap installs the competitor libraries alongside the workspace, each
- pnpm bench runs one matrix into its own directory, and bench:compare --profile pools them into a profile named
- after your machine under packages/exojs-bench/results/. Repeating an input flag is what pools: a profile built from fewer
- than {REPRODUCTION_RUNS} runs is rejected by the repository's own check on this directory. Pooling is refused outright for runs that do
- not repeat one measurement - a different engine version, different library arms, a different matrix - because a spread over those would
- describe the difference between two runs rather than the noise of one. Measure on an otherwise idle machine: these are wall-clock
- comparisons and background load moves them.
-
-
- pnpm bench -- --browser=webkit measures in WebKit instead of the default Chromium, for both domains - a physics run takes
- the flag too, and the two domains of one profile have to agree on it. The browser is part of the profile's name, so the same machine
- measured in both publishes two files rather than overwriting one with the other, and the harness refuses to pool runs taken in different
- browsers. A backend the browser does not expose is published as not measured, never as a number: WebKit reaches WebGPU on macOS alone. A
- physics arm the browser cannot load is published the same way, with the reason it failed. WebKit also reports a constant in place of the
- GPU, so a WebKit profile is named after the machine's CPU model and needs a physics measurement of the same machine alongside the
- rendering one.
-
-
- On macOS and Linux, add --platform=26 to every run - or --platform=26-beta on a pre-release build. The profile's
- name carries the operating system's major version, so a beta measurement and the shipping platform's later one do not overwrite each
- other, and neither the version nor the beta status is readable at runtime there: os.release() reports the kernel version.
- Windows reports its own version and needs no flag. Every stamp records whether the version was read or declared, and whether the platform
- was pre-release and how that was established.
-
-
- A profile for a machine that is not published yet is welcome as a pull request containing that one file. Nothing else needs to change -
- this page picks it up from the directory.
-
-
-
-
- Fairness: how the arms are configured and what is never derived
-
- The adapter for every competitor is in the repository next to the ExoJS one, and each is configured at that library's own defaults with
- the deviations disclosed in the run's caveats. If a maintainer of one of these libraries thinks an adapter misrepresents it, an issue
- about that adapter is the right place to say so, and a fix changes the published numbers the next time the harness runs.
-
-
- Nothing here is aggregated into a score and nothing is declared an overall winner. The scoreboard counts outcomes per arm and never sums
- them across arms, because the arms answer different questions. Every cell where ExoJS trails is published with the same weight as one
- where it leads, with the same mechanism evidence attached, and the rows the harness could not compare are listed with the reason it could
- not.
-
-
-
+
+ >
+ )}
@@ -427,17 +258,17 @@ pnpm bench:compare -- \
max-width: none;
}
- /* The docs reading measure belongs to prose pages; here it would wrap short notes beside full-width tables. */
+ /* The docs reading measure belongs to prose pages; here it would wrap short notes beside full-width cards. */
.bench-prose :where(p, li) {
max-width: none;
}
.bench-head {
- margin-bottom: var(--s-5);
+ margin-bottom: var(--s-4);
}
.bench-head h1 {
- margin: 0 0 var(--s-3);
+ margin: 0 0 var(--s-2);
}
.lede {
@@ -446,147 +277,68 @@ pnpm bench:compare -- \
line-height: 1.6;
}
- .stamp {
+ .profile-head {
display: flex;
- flex-wrap: wrap;
- gap: 0.15rem var(--s-4);
- margin: var(--s-3) 0 0 !important;
- font-family: var(--f-mono);
- font-size: 0.74rem;
- color: var(--fg-faint);
- }
-
- .stamp b {
- font-weight: 600;
- color: var(--fg-muted);
+ flex-direction: column;
+ gap: var(--s-3);
+ margin-top: var(--s-4);
}
- /*
- * The page is long and its sections are far apart, so the jump list stays
- * reachable. Horizontal scrolling is fine for navigation - it is exactly
- * what the measurements below must never need.
- */
- /* Drawn as tabs, but two ordinary links: each view is its own page, so there is nothing here to select, focus or arrow between. */
- .views {
+ .machines {
display: flex;
- gap: var(--s-4);
- margin: var(--s-5) 0 var(--s-4);
- border-bottom: 1px solid var(--line-soft);
+ flex-wrap: wrap;
+ gap: 0.3rem;
}
- .views a {
- padding: 0.35rem 0.1rem;
- margin-bottom: -1px;
- border-bottom: 2px solid transparent;
- font-size: 0.95rem;
- font-weight: 600;
+ .machines .machine {
+ font: inherit;
+ font-size: 0.85rem;
+ padding: 0.3rem 0.8rem;
+ border-radius: 999px;
+ border: 1px solid var(--border);
+ background: transparent;
color: var(--fg-muted);
- text-decoration: none;
+ cursor: pointer;
}
- .views a:hover {
+ /* Weight and a filled ground as well as hue, so the selected machine is legible without separating the two colours. */
+ .machines .machine[aria-pressed='true'] {
+ border-color: var(--accent);
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
color: var(--fg);
+ font-weight: 650;
}
- /* The rule's presence, not its hue, is what marks the current view; `aria-current` carries the same fact where the rule is not seen. */
- .views a[aria-current='page'] {
- color: var(--fg);
- border-bottom-color: var(--accent);
+ /* A flex box outranks the user-agent rule the `hidden` attribute relies on, so the stamp of an unselected machine would stay on screen under the selected machine's own. */
+ .stamp[hidden] {
+ display: none;
}
- .empty {
- margin: 0;
- padding: var(--s-4);
- border: 1px solid var(--line-soft);
- border-left: 3px solid var(--accent);
- border-radius: var(--r-3);
- background: var(--bg-elevated);
- color: var(--fg-muted);
- }
-
- .section-note {
- margin: 0 0 var(--s-3);
- color: var(--fg-muted);
- font-size: 0.85rem;
- }
-
- #further,
- #practices {
- margin-top: var(--s-8);
- }
-
- .machine {
- margin-top: var(--s-3);
- border: 1px solid var(--line-soft);
- border-radius: var(--r-3);
- padding: var(--s-3) var(--s-4);
- }
-
- .machine summary {
- cursor: pointer;
+ .stamp {
display: flex;
flex-wrap: wrap;
- align-items: baseline;
- gap: var(--s-3);
- }
-
- .machine-name {
- font-weight: 600;
- }
-
- .machine-meta {
- color: var(--fg-faint);
+ gap: 0.15rem var(--s-4);
+ margin: 0 !important;
font-family: var(--f-mono);
- font-size: 0.75rem;
+ font-size: 0.74rem;
+ color: var(--fg-faint);
}
- .stale {
- margin: var(--s-3) 0 0;
- padding: var(--s-2) var(--s-3);
- border-left: 3px solid var(--amber);
+ .stamp b {
+ font-weight: 600;
color: var(--fg-muted);
- font-size: 0.85rem;
}
- .practice {
- margin-top: var(--s-3);
+ .empty {
+ margin: 0;
+ padding: var(--s-4);
border: 1px solid var(--line-soft);
+ border-left: 3px solid var(--accent);
border-radius: var(--r-3);
- padding: var(--s-3) var(--s-4);
- }
-
- .practice summary {
- cursor: pointer;
- font-weight: 600;
- }
-
- .practice p,
- .method {
+ background: var(--bg-elevated);
color: var(--fg-muted);
- line-height: 1.6;
- font-size: 0.88rem;
- }
-
- .method {
- margin: var(--s-3) 0 0;
- padding-left: 1.15rem;
- }
-
- .method li {
- margin-bottom: 0.5rem;
}
- .method strong {
- color: var(--fg);
- }
-
- .practice pre {
- overflow-x: auto;
- max-width: 100%;
- }
-
-
-
@@ -284,13 +303,13 @@ const leading = machines[0];
margin-top: var(--s-4);
}
- .machines {
+ .browsers {
display: flex;
flex-wrap: wrap;
gap: 0.3rem;
}
- .machines .machine {
+ .browsers .browser {
font: inherit;
font-size: 0.85rem;
padding: 0.3rem 0.8rem;
@@ -301,8 +320,8 @@ const leading = machines[0];
cursor: pointer;
}
- /* Weight and a filled ground as well as hue, so the selected machine is legible without separating the two colours. */
- .machines .machine[aria-pressed='true'] {
+ /* Weight and a filled ground as well as hue, so the selected profile is legible without separating the two colours. */
+ .browsers .browser[aria-pressed='true'] {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 14%, transparent);
color: var(--fg);
@@ -329,6 +348,10 @@ const leading = machines[0];
color: var(--fg-muted);
}
+ .stamp a {
+ color: var(--fg-muted);
+ }
+
.empty {
margin: 0;
padding: var(--s-4);
diff --git a/site/src/lib/bench-profiles.ts b/site/src/lib/bench-profiles.ts
index d6521adad..aba86336a 100644
--- a/site/src/lib/bench-profiles.ts
+++ b/site/src/lib/bench-profiles.ts
@@ -256,8 +256,8 @@ export interface ProfileHost {
/** What the measuring page's clock could resolve, which decides how finely a step is timed. */
export interface PhysicsClock {
- /** Smallest non-zero `performance.now()` difference the page observed, in milliseconds. */
- readonly resolutionMs: number;
+ /** Smallest non-zero `performance.now()` difference the page observed, in milliseconds, or `null` where it observed none. */
+ readonly resolutionMs: number | null;
/** Whether the page reached a cross-origin-isolated context, which lifts the coarse clamp. */
readonly crossOriginIsolated: boolean;
}
@@ -402,12 +402,60 @@ export const referenceProfile: BenchProfileDocument | undefined = loaded[0];
/** Every profile except the reference one, in the same order. Empty until a second machine is contributed. */
export const furtherProfiles: readonly BenchProfileDocument[] = loaded.slice(1);
+/**
+ * Browsers in the order the page offers them, most practically relevant first.
+ *
+ * An editorial choice, fixed before any run and never derived from the results.
+ * Chromium leads because it is the broadest reference point a reader shipping a
+ * web game actually has; a browser with no published profile simply does not
+ * appear.
+ */
+const BROWSER_ORDER: readonly string[] = ['chromium', 'webkit', 'firefox'];
+
+/** One browser's published profiles: the one the page leads with, and the rest measured in the same browser. */
+export interface BrowserProfiles {
+ readonly browser: string;
+ /** The profile this browser is shown through - newest engine version, widest coverage; see `byRecency`. */
+ readonly reference: BenchProfileDocument;
+ /** Further machines measured in the same browser, in the same order. Usually empty. */
+ readonly others: readonly BenchProfileDocument[];
+}
+
+/**
+ * The published profiles grouped by the browser they were measured in.
+ *
+ * The page's primary axis, and deliberately not the machine. Switching machines
+ * changes the CPU, the GPU, the operating system, the driver stack AND the
+ * browser engine at once, so it is not an A/B of anything a reader can name;
+ * the browser at least names one dimension.
+ *
+ * It is still not a browser benchmark while each browser is measured on its own
+ * machine, which is why the page presents these as separate reference profiles
+ * and prints the machine beside every set of numbers rather than inviting a
+ * reader to divide one browser's figures by another's.
+ */
+export const profilesByBrowser: readonly BrowserProfiles[] = [...new Set(loaded.map(document => document.profile.browser))]
+ .sort((a, b) => {
+ const left = BROWSER_ORDER.indexOf(a);
+ const right = BROWSER_ORDER.indexOf(b);
+
+ return (left === -1 ? BROWSER_ORDER.length : left) - (right === -1 ? BROWSER_ORDER.length : right) || a.localeCompare(b);
+ })
+ .flatMap(browser => {
+ const [reference, ...others] = loaded.filter(document => document.profile.browser === browser);
+
+ return reference === undefined ? [] : [{ browser, reference, others }];
+ });
+
/** Display name for a rendering backend. */
export const BACKEND_LABELS: Readonly> = { webgl2: 'WebGL2', webgpu: 'WebGPU' };
/** Browser engines as they are written, keyed by the slug the harness stores. */
const BROWSER_LABELS: Readonly> = { chromium: 'Chromium', webkit: 'WebKit', firefox: 'Firefox' };
+/** A browser engine's published name, or its slug written out where none is known. */
+export const browserLabel = (browser: string): string => BROWSER_LABELS[browser] ?? deviceName(browser);
+
/** Operating systems as they are written, keyed by the normalized platform name. */
const OS_LABELS: Readonly> = { windows: 'Windows', macos: 'macOS', linux: 'Linux' };
@@ -438,6 +486,15 @@ const deviceName = (slug: string): string =>
*/
export const machineName = (profile: BenchProfile): string => `${deviceName(profile.gpu)} · ${BROWSER_LABELS[profile.browser] ?? deviceName(profile.browser)}`;
+/**
+ * Just the hardware, for a place that already names the browser.
+ *
+ * The benchmarks page picks a browser and then states the machine that browser
+ * was measured on, so repeating the engine inside the machine's own name says
+ * it twice on one line.
+ */
+export const deviceLabel = (profile: BenchProfile): string => deviceName(profile.gpu);
+
/**
* The platform a profile was measured on, spelled out: `macOS 27 beta`.
*
From 252b1faee86865bf3bf95c8113bcda1bb85b2666 Mon Sep 17 00:00:00 2001
From: Exoridus
Date: Sat, 12 Sep 2026 09:04:03 +0200
Subject: [PATCH 22/28] feat(site): read the benchmark scenarios as one card
per domain on a phone
---
site/src/components/BenchMethodology.astro | 8 ++
site/src/components/BenchResultCard.astro | 88 ++++++++++++++++++-
.../src/components/pages/BenchmarksPage.astro | 24 +++--
3 files changed, 114 insertions(+), 6 deletions(-)
diff --git a/site/src/components/BenchMethodology.astro b/site/src/components/BenchMethodology.astro
index a853d25a6..d9af6c65c 100644
--- a/site/src/components/BenchMethodology.astro
+++ b/site/src/components/BenchMethodology.astro
@@ -186,4 +186,12 @@ pnpm bench:compare -- \
where it leads, with the same mechanism evidence attached, and the rows the harness could not compare are listed with the reason it could
not.
+
+ One scenario currently carries an open equivalence question. In the joint-chain scenario the links are pinned at the edge they
+ share, so whether two jointed links also register a contact comes down to each engine's own contact margin and its default for connected
+ bodies - and the arms do not agree: ExoJS reports one contact for every jointed pair, Rapier one per chain, and matter.js, planck and Nape-JS
+ none. Its per-arm times are published like every other row, but what the scenario loads is not the same work in every arm, so the cross-arm
+ comparison there is not settled and is not read as one. What the neutral scene should require of every arm is a decision the harness owes
+ before that row is treated as a result.
+
diff --git a/site/src/components/BenchResultCard.astro b/site/src/components/BenchResultCard.astro
index e654a22fd..27929111e 100644
--- a/site/src/components/BenchResultCard.astro
+++ b/site/src/components/BenchResultCard.astro
@@ -28,6 +28,15 @@
* The detail each load opens is rendered from that load's own comparisons, so
* the load, the backend and the profile a reader is looking at cannot come
* apart from the ones the numbers were read out of.
+ *
+ * Below the width at which the grid becomes one column, the card gives up its
+ * own frame and becomes a SECTION of the domain's single card, separated from
+ * its neighbours by a rule. Six framed cards in a column is six visual restarts
+ * of the same structure - border, padding, title block, gap - where the frame
+ * has nothing left to separate horizontally, and the section headings carry the
+ * grouping on their own. The chrome is only dropped, not the structure: the
+ * rows, the load control and the per-scenario detail are identical at both
+ * widths, and nothing here becomes a table.
*/
import BenchMeasurementDetail from './BenchMeasurementDetail.astro';
@@ -35,6 +44,13 @@ import { archetypeDescription, archetypeTitle, type CellOutcome, FRAME_BUDGET_NO
import type { BenchCard } from '../lib/bench-cards';
import { openingLoad } from '../lib/bench-cards';
+/** A scenario description split into what the scene is and what it loads, at the semicolon the descriptions carry. */
+const splitAtClause = (text: string): readonly [string, string | undefined] => {
+ const at = text.indexOf('; ');
+
+ return at === -1 ? [text, undefined] : [`${text.slice(0, at)}.`, text.slice(at + 2)];
+};
+
interface Props {
card: BenchCard;
/** Anchor prefix, so a rendering and a physics card of one name stay distinct. */
@@ -44,6 +60,16 @@ interface Props {
const { card, domain } = Astro.props;
const opening = openingLoad(card);
const description = archetypeDescription(card.id);
+const [lead, descriptionRest] = description === undefined ? [undefined, undefined] : splitAtClause(description);
+
+/**
+ * The lead clause, unless it only repeats the title.
+ *
+ * `Changing labels; stresses per-frame text invalidation and layout.` reduces to
+ * `Changing labels.` under a heading that already says `Changing labels`, which
+ * on a phone spends a line saying nothing.
+ */
+const descriptionLead = lead !== undefined && lead.replace(/\.$/, '').toLowerCase() === archetypeTitle(card.id).toLowerCase() ? undefined : lead;
const anchor = `${domain}-${card.id}${card.backend === undefined ? '' : `-${card.backend}`}`;
/**
@@ -111,7 +137,24 @@ const statesOf = (load: BenchCard['loads'][number]): readonly CellOutcome[] => [
{archetypeTitle(card.id)}
- {description !== undefined &&
{description}
}
+ {/*
+ * Split at the semicolon the descriptions already carry: the clause
+ * before it says what the scene is, the clause after it says which
+ * part of the renderer it loads. Narrow, only the first is worth two
+ * lines of a phone screen, and the second is one tap away - so nothing
+ * is rewritten and nothing is lost.
+ */}
+ {description !== undefined && (
+
+ )}
{card.loads.length > 1 ? (
@@ -474,6 +517,49 @@ const statesOf = (load: BenchCard['loads'][number]): readonly CellOutcome[] => [
gap: 0.1rem;
}
}
+
+ /*
+ * One card per domain, scenarios as sections inside it. The breakpoint is
+ * the one at which the grid collapses to a single column: above it the
+ * frames separate cards that sit side by side, below it they separate
+ * nothing and only cost height.
+ */
+ @media (max-width: 52rem) {
+ .card {
+ border: 0;
+ border-radius: 0;
+ padding: 0.9rem 0 0;
+ background: none;
+ box-shadow: none;
+ }
+
+ /* The rule belongs between sections, so the first one does not open with one. */
+ .card + .card {
+ border-top: 1px solid var(--color-border);
+ }
+
+ .what-rest {
+ display: none;
+ }
+
+ /* Nothing left to print once the lead clause was only the title again. */
+ .what.lead-only {
+ display: none;
+ }
+
+ .what {
+ margin-top: 0.15rem;
+ }
+
+ .load {
+ font-size: 0.72rem;
+ padding: 0.15rem 0.45rem;
+ }
+
+ .more > summary {
+ font-size: 0.78rem;
+ }
+ }