Skip to content

Splat: full-stack team paintball shooter sample, with fog, PBR, shadows and post processing in every GPU backend - #6188

Merged
shai-almog merged 45 commits into
masterfrom
splat-paintball-sample
Nov 11, 2026
Merged

shai-almog merged 45 commits into
masterfrom
splat-paintball-sample

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Splat: a full-stack team paintball shooter

Splat is a first-person 3D team shooter, written in Codename One from the field to the server. Four against four in a self-storage yard or a suburban cul-de-sac, in Team Paint, Capture the Flag or Hold the Snack Bar. Every match opens with a grim mission briefing, every hit lands a big red PAINTED stamp, and a player who is out can try to wipe the paint off before the referee notices.

Practice match Briefing Scoreboard

Desktop match

The sample (scripts/splat)

  • rules/: a deterministic simulation in fixed point at 30 Hz. It covers movement, cover, slow visible paintballs, markers, grenades, aiming down the sights, wiping and the referee, plus bots. A golden replay corpus pins it.
  • backend/: accounts, parties and lobby codes, skill-banded matchmaking, and a match loop the server authorizes over WebSocket. Shots are lag-compensated against a capped rewind. It also has anti-cheat flags, results, XP, rating, replays, leaderboards, store receipts checked with Apple and Google, and an admin console with moderation. The database runs on SQLite, PostgreSQL or MySQL.
  • common/: the client. It has client prediction and reconciliation, a 3D field built from CC0 models, a HUD with a minimap, killfeed, hit markers and damage arcs, and touch, keyboard and mouse controls. There is a desktop layout, a replay viewer, WebRTC party voice, and synthesized sound effects, music and ambience, with no audio files shipped.
  • Initializr template, an implementor's guide, a website page, and end-to-end tests on the phone and desktop simulator, including a recorded walkthrough (record-demo.sh).

Engine features it needed (com.codename1.gpu, every backend)

  • Environment: exponential fog with height falloff, hemisphere ambient, exposure and tone mapping, and a procedural sky.
  • Material.Type.PBR: metallic and roughness, emissive, and vertex colour, filled from glTF.
  • Directional shadow maps, set up with Light.setShadows and setShadowMap, filtered with 3x3 PCF.
  • PostProcess on GameView: bloom, colour grade, vignette and grain.

They are implemented for JavaSE GL, Android, HTML5/WebGL, iOS Metal, Windows D3D11 and Linux GL, with the JavaSE software rasterizer covering fog, ambient, tone mapping and sky. A device that lacks shadows or offscreen rendering reports it through GpuCapabilities, and the scene is drawn directly.

🤖 Generated with Claude Code

shai-almog and others added 17 commits November 5, 2026 06:06
Fixed-point 30 Hz simulation shared by client, server and replay viewer:
projectile paintballs with drop, one-hit eliminations with a judged
wipe-off, three markers, grenades, Team Paint / Capture the Flag / Hold
the Snack Bar on two mirrored fields, bots inside the rules, snapshots,
lag-compensated shots and a golden replay corpus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server-stepped matches with snapshot acks for client prediction, flood and
flick flags, bot fill, demo history played by the rules' bots, and a shop of
side-grade markers and paint. The client is still being ported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Operators, markers and props are CC0 glTF packed by tools/pack-art.py; the
menus, loadout, operations playlist, lobby, briefing and HUD follow a
military-shooter look with Rajdhani type. Docs, site page and a draft blog
post describe the new UI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core gpu: Environment.setSky (procedural gradient, clouds, sun) in the GLSL
generator and JavaSE GL device; shadow pass culls non-casters and far models;
VirtualButton label colour. Splat: nature props, sky dome, compact HUD on
phones, comms folded behind a button, HUD hidden behind briefing/results,
menus fixed for phones; backend Rooms.join leaves a still-running match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ocs and template

Environment (fog, hemisphere, tone map, sky), PBR/emissive, shadow maps and
the post chain on Android, HTML5, Linux (core generator replaces the copy),
iOS Metal and Windows D3D; the JavaSE software rasterizer applies the
atmosphere. Mac and embedded Linux stubs for the new natives. Core unit tests
for the generator and the new API. Splat: dusk atmosphere on the menu
backdrop, guide sections and screenshots, Initializr template and fixtures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…race

Backend (JVM mode): a websocket read and write that overlapped could leave
the channel non-blocking, so the next read returned 0 and was taken as EOF;
matches dropped mid-stream about half the e2e runs. Deadlines now counts
non-blocking entries per fd and restores the owner's original mode, reads
branch on that logical mode, and a no-deadline read waits on the selector.
ConcurrentReadWriteBlockingModeTest reproduces it.

Splat: opaque player handles on the wire, leavers never place first,
per-seat input FIFO, kick closes every socket, mid-match reconnect (tests
assert none happen), stale END ignored; desktop: theme font floor, toolbar
title-bar mode, centred list column, compact home menu, sized back arrow,
DesktopTourTest. Core gpu: shadow map validity per camera, D3D post
viewport restore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ot only while alive

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every sound is rendered at start-up by a small synthesizer (no audio files):
positional shots, splats, whistles, grenades, footsteps, countdown and horn,
a menu march and field ambience, with a Music toggle in settings.
DemoVideoTest and record-demo.sh film a phone and a desktop walkthrough with
the app's audio, keeping preferences in memory so the developer's simulator
settings are untouched. SimulatorRecorder's doc now says app audio is captured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java
#	scripts/initializr/common/src/test/java/com/codename1/initializr/model/GeneratorModelMatrixTest.java
#	scripts/initializr/e2e-shipped.sh
#	scripts/sync-initializr-template.py
#	scripts/tests/GenerateInitializr.java
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 3D guide's atmosphere example moves into the demos tree, the Splat
guide's ArenaView region gets back its end tag, and the validator accepts
Splat's theme.css as it does Dash's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server: a suspension closes every socket the account has, a removed player
cannot resume the seat, inputs renumber after a resume, chat and emotes are
throttled before the profile read, Apple receipts must name the app's bundle
(splat.iap.apple.bundle), Play tokens are checked before they reach the URL,
and a crew's member count is recounted rather than incremented.
Client: looping music releases each finished player, a failed music build
can be retried, and an unused sound pool is released.
Engine: HTML5 falls back to no shadows or post processing when a browser
rejects the shaders, Linux zeroes unused uniform slots, iOS caches its
sampler states, and the shadow/post pass order is documented.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…able touch controls

Button labels in SpriteRenderer are scaled to fit the disc instead of
clipped; TouchControls gets separate x/y anchor margins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…layer-built fields

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

Cloudflare Preview

…), narrative demo

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Blog prose gate

✅ No net-new prose findings introduced by this PR.

…ecals and footwork

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@shai-almog

shai-almog commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 12 screenshots: 12 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

shai-almog and others added 2 commits November 7, 2026 22:26
…ose, embedded stubs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… job

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ✅ ByteCodeTranslator: 0 findings (no issues)
    • ✅ android: 0 findings (no issues)
    • ✅ android-compat: 0 findings (no issues)
    • ✅ android-res-compiler: 0 findings (no issues)
    • ✅ backend: 0 findings (no issues)
    • ✅ backend-test: 0 findings (no issues)
    • ✅ build-engine: 0 findings (no issues)
    • ✅ build-hint-catalog: 0 findings (no issues)
    • ✅ build-hint-tools: 0 findings (no issues)
    • ✅ codenameone-gradle-plugin: 0 findings (no issues)
    • ✅ codenameone-maven-plugin: 0 findings (no issues)
    • ✅ compose-compat: 0 findings (no issues)
    • ✅ core-unittests: 0 findings (no issues)
    • ✅ desktop-compat-runtime: 0 findings (no issues)
    • ✅ fxml-compiler: 0 findings (no issues)
    • ✅ ios: 0 findings (no issues)
    • ✅ javac: 0 findings (no issues)
    • ✅ javafx-compat: 0 findings (no issues)
    • ✅ project-model: 0 findings (no issues)
    • ✅ python-runtime: 0 findings (no issues)
    • ✅ python-transpiler: 0 findings (no issues)
    • ✅ swing-compat: 0 findings (no issues)
  • ✅ PMD: 0 findings (no issues) [Report archive]
  • ✅ Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

shai-almog and others added 2 commits November 8, 2026 00:47
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e project

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

shai-almog commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 195 screenshots: 195 matched.

Native Android coverage

  • 📊 Line coverage: 19.18% (56169/292885 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 18.13% (270599/1492353), branch 12.38% (19676/158943), complexity 10.36% (15846/153017), method 15.74% (11411/72518), class 27.93% (2247/8045)
    • Lowest covered classes
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2396 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • androidx.compose.runtime.androidx.compose.runtime.LinkComposer – 0.00% (0/1430 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlinx.coroutines.channels.kotlinx.coroutines.channels.BufferedChannel – 0.00% (0/863 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/744 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/630 lines covered)
      • com.codename1.androidcompat.rt.com.codename1.androidcompat.rt.TextXmlPullParser – 0.00% (0/623 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 19.18% (56169/292885 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 18.13% (270599/1492353), branch 12.38% (19676/158943), complexity 10.36% (15846/153017), method 15.74% (11411/72518), class 27.93% (2247/8045)
    • Lowest covered classes
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2396 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • androidx.compose.runtime.androidx.compose.runtime.LinkComposer – 0.00% (0/1430 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlinx.coroutines.channels.kotlinx.coroutines.channels.BufferedChannel – 0.00% (0/863 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/744 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/630 lines covered)
      • com.codename1.androidcompat.rt.com.codename1.androidcompat.rt.TextXmlPullParser – 0.00% (0/623 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 166ms / native 80ms = 2.0x speedup
SIMD float-mul (64K x300) java 73ms / native 122ms = 0.5x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 77.000 ms
Base64 CN1 decode 67.000 ms
Base64 native encode 353.000 ms
Base64 encode ratio (CN1/native) 0.218x (78.2% faster)
Base64 native decode 233.000 ms
Base64 decode ratio (CN1/native) 0.288x (71.2% faster)
Image encode benchmark status skipped (SIMD unsupported)

… it draws with

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shai-almog and others added 3 commits November 8, 2026 06:15
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A GameView's update runs on the render thread, which in the simulator is
AWT's; creating a Media there waited for the EDT while the EDT waited on AWT
to blit, and the first match of every CI e2e test froze.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

shai-almog commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 192 screenshots: 192 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 888 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 63ms / native 7ms = 9.0x speedup
SIMD float-mul (64K x300) java 55ms / native 3ms = 18.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 59.000 ms
Base64 CN1 decode 53.000 ms
Base64 native encode 766.000 ms
Base64 encode ratio (CN1/native) 0.077x (92.3% faster)
Base64 native decode 328.000 ms
Base64 decode ratio (CN1/native) 0.162x (83.8% faster)
Base64 SIMD encode 50.000 ms
Base64 encode ratio (SIMD/CN1) 0.847x (15.3% faster)
Base64 SIMD decode 46.000 ms
Base64 decode ratio (SIMD/CN1) 0.868x (13.2% faster)
Base64 encode ratio (SIMD/native) 0.065x (93.5% faster)
Base64 decode ratio (SIMD/native) 0.140x (86.0% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 3.000 ms
Image createMask ratio (SIMD on/off) 0.429x (57.1% faster)
Image applyMask (SIMD off) 67.000 ms
Image applyMask (SIMD on) 64.000 ms
Image applyMask ratio (SIMD on/off) 0.955x (4.5% faster)
Image modifyAlpha (SIMD off) 94.000 ms
Image modifyAlpha (SIMD on) 67.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.713x (28.7% faster)
Image modifyAlpha removeColor (SIMD off) 83.000 ms
Image modifyAlpha removeColor (SIMD on) 47.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.566x (43.4% faster)

@shai-almog

shai-almog commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 193 screenshots: 193 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 3584 seconds

Build and Run Timing

Metric Duration
Simulator Boot 131000 ms
Simulator Boot (Run) 1000 ms
App Install 19000 ms
App Launch 17000 ms
Test Execution 573000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 64ms / native 3ms = 21.3x speedup
SIMD float-mul (64K x300) java 74ms / native 4ms = 18.5x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 139.000 ms
Base64 CN1 decode 85.000 ms
Base64 native encode 2567.000 ms
Base64 encode ratio (CN1/native) 0.054x (94.6% faster)
Base64 native decode 1506.000 ms
Base64 decode ratio (CN1/native) 0.056x (94.4% faster)
Base64 SIMD encode 127.000 ms
Base64 encode ratio (SIMD/CN1) 0.914x (8.6% faster)
Base64 SIMD decode 177.000 ms
Base64 decode ratio (SIMD/CN1) 2.082x (108.2% slower)
Base64 encode ratio (SIMD/native) 0.049x (95.1% faster)
Base64 decode ratio (SIMD/native) 0.118x (88.2% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 12.000 ms
Image createMask (SIMD on) 8.000 ms
Image createMask ratio (SIMD on/off) 0.667x (33.3% faster)
Image applyMask (SIMD off) 214.000 ms
Image applyMask (SIMD on) 51.000 ms
Image applyMask ratio (SIMD on/off) 0.238x (76.2% faster)
Image modifyAlpha (SIMD off) 120.000 ms
Image modifyAlpha (SIMD on) 156.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.300x (30.0% slower)
Image modifyAlpha removeColor (SIMD off) 192.000 ms
Image modifyAlpha removeColor (SIMD on) 152.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.792x (20.8% faster)

@shai-almog

shai-almog commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 193 screenshots: 193 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 2819 seconds

Build and Run Timing

Metric Duration
Simulator Boot 53000 ms
Simulator Boot (Run) 2000 ms
App Install 23000 ms
App Launch 3000 ms
Test Execution 483000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 376ms / native 4ms = 94.0x speedup
SIMD float-mul (64K x300) java 165ms / native 8ms = 20.6x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 171.000 ms
Base64 CN1 decode 107.000 ms
Base64 native encode 1814.000 ms
Base64 encode ratio (CN1/native) 0.094x (90.6% faster)
Base64 native decode 2368.000 ms
Base64 decode ratio (CN1/native) 0.045x (95.5% faster)
Base64 SIMD encode 69.000 ms
Base64 encode ratio (SIMD/CN1) 0.404x (59.6% faster)
Base64 SIMD decode 72.000 ms
Base64 decode ratio (SIMD/CN1) 0.673x (32.7% faster)
Base64 encode ratio (SIMD/native) 0.038x (96.2% faster)
Base64 decode ratio (SIMD/native) 0.030x (97.0% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 6.000 ms
Image createMask ratio (SIMD on/off) 0.857x (14.3% faster)
Image applyMask (SIMD off) 231.000 ms
Image applyMask (SIMD on) 351.000 ms
Image applyMask ratio (SIMD on/off) 1.519x (51.9% slower)
Image modifyAlpha (SIMD off) 67.000 ms
Image modifyAlpha (SIMD on) 92.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.373x (37.3% slower)
Image modifyAlpha removeColor (SIMD off) 512.000 ms
Image modifyAlpha removeColor (SIMD on) 442.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.863x (13.7% faster)

@shai-almog

shai-almog commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 253 screenshots: 253 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

@shai-almog

shai-almog commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 188 screenshots: 188 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

shai-almog and others added 8 commits November 8, 2026 19:38
…ide shots

Operators get welded smooth normals (pack-art.py --smooth). The instant
replay records every tick, keeps twelve seconds and blends across ticks an
online driver never received, so it reaches the hit. HUD events go to the
EDT. The e2e captures wait until the player is in play and facing open
field, and add the overhead view, the instant replay and the mission
editor; the implementor's guide shows them and describes the real art.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… test that plays

A splat near an edge is shrunk and moved inward so none hangs in the air.
The replay camera eases after the shooter's look instead of every tick's
twitch, and pulls in when a prop is between it and the shooter. The
mission tour's play test drives the player instead of standing still.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	scripts/developer-guide/validate-guide-snippets.py
On a machine with no native mixer Sfx.load leaves every clip unset, and a
splat or a footstep then indexed a null array on the render thread every
frame. The random picks now answer null and play() skips them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An unlit textured shader declares no a_normal, but its buffer may carry
normals; the texcoord offset was counted from the shader, so it sampled
the normal (Gpu3DTexturedCube, Media360Panorama, UnityCompat* goldens).

The embedded GPU renderer's entry points now share a recursive lock with
cn1GpuShutdown, which atexit ran while the EDT was still inside a draw
and freed the mask atlas under its memcpy (demo SIGSEGV after the bench).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
callSerially runs inline once Display is down, so fireReady's hop to the
EDT recursed on the CEF thread until StackOverflowError, and the
simulator test run then died with signal 6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

shai-almog commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 210 screenshots: 210 matched.
Native Linux port (x64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub x64 runner. Baseline: scripts/linux/screenshots.

ParparVM vs HotSpot (JDK 25): Linux x64

Runner CPU: AMD EPYC 7763 64-Core Processor (baseline linux-x64@amd-epyc-7763-64-core-processor)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (LinuxHelloMain) 4 1.07x (base 0.85x, +26.2%) 0.74x (base 0.83x, -11.6%) ok
translator (self) 4 0.54x (base 0.64x, -15.0%) 0.51x (base 0.52x, -2.5%) ok
intArithmetic 4 1.10x (base 1.12x, -1.2%) 0.04x (base 0.06x, -30.1%) ok
longArithmetic 4 1.08x (base 1.08x, +0.0%) 0.04x (base 0.05x, -30.0%) ok
mathTranscendental 4 1.09x (base 1.08x, +0.1%) 0.04x (base 0.07x, -45.7%) ok
arraySequential 4 2.21x (base 2.00x, +10.2%) 0.36x (base 0.36x, +0.3%) ok
arrayRandom 4 1.03x (base 0.91x, +13.4%) 0.20x (base 0.21x, -3.3%) ok
objectAllocation 4 1.56x (base 1.65x, -5.5%) 0.26x (base 0.35x, -26.6%) ok
valueEscape 4 0.10x (base 0.10x, -0.3%) 0.03x (base 0.04x, -27.2%) ok
hashMapChurn 4 1.42x (base 1.48x, -4.2%) 0.11x (base 0.09x, +13.7%) ok
stringBuilding 4 1.28x (base 1.39x, -8.0%) 0.26x (base 0.31x, -16.8%) ok
recursion 4 1.38x (base 1.25x, +10.3%) 0.04x (base 0.08x, -48.4%) ok
quicksort 4 1.08x (base 1.07x, +1.1%) 0.10x (base 0.11x, -12.6%) ok

Result: no regression

@shai-almog

shai-almog commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 210 screenshots: 210 matched.
Native Linux port (arm64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub arm64 runner. Baseline: scripts/linux/screenshots-arm.

ParparVM vs HotSpot (JDK 25): Linux arm64

Runner CPU: Neoverse-N2 (baseline linux-arm64@neoverse-n2)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (LinuxHelloMain) 4 1.11x (base 1.02x, +9.1%) 0.78x (base 0.66x, +17.7%) ok
translator (self) 4 0.77x (base 0.70x, +10.5%) 0.46x (base 0.43x, +7.8%) ok
intArithmetic 4 1.05x (base 1.04x, +0.0%) 0.04x (base 0.03x, +7.3%) ok
longArithmetic 4 0.79x (base 0.79x, -0.3%) 0.03x (base 0.03x, +5.1%) ok
mathTranscendental 4 1.09x (base 1.10x, -0.3%) 0.04x (base 0.03x, +9.6%) ok
arraySequential 4 0.38x (base 0.36x, +3.7%) 0.37x (base 0.37x, +0.2%) ok
arrayRandom 4 0.93x (base 0.94x, -0.6%) 0.20x (base 0.20x, +0.6%) ok
objectAllocation 4 1.99x (base 1.77x, +12.5%) 0.36x (base 0.37x, -3.2%) ok
valueEscape 4 0.51x (base 0.51x, -0.1%) 0.03x (base 0.03x, +6.1%) ok
hashMapChurn 4 0.85x (base 0.84x, +1.0%) 0.12x (base 0.12x, -2.8%) ok
stringBuilding 4 1.39x (base 1.57x, -11.2%) 0.32x (base 0.26x, +20.6%) ok
recursion 4 1.55x (base 1.43x, +8.1%) 0.04x (base 0.04x, +3.2%) ok
quicksort 4 1.00x (base 0.99x, +0.4%) 0.10x (base 0.09x, +2.7%) ok

Result: no regression

shai-almog and others added 10 commits November 9, 2026 17:38
…ktop layout

Three-angle slow-motion instant replay with a paint burst on every hit, victims
who make a scene with speech bubbles, winners who celebrate at game over, a
proper carried flag, faces on the operators, Toon Shooter markers in gunmetal
held at the grip, mm-floored desktop sizing, bot nav around props, slower
pacing, a new icon and the promo video on the website page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
First person shows your own operator (head hidden, the eye at its head) with
the marker in its hand instead of an armless gun floating in the view. Every
held marker sits at a fixed carry point of the gun-up poses and aims along the
look, so it neither floats beside a hand nor bounces with the stride. Players
are solid to each other in the rules (rules 5, goldens regenerated), winners
wave and jump apart instead of punching through teammates, and the orbit
rises over props. Shots get a bigger muzzle flash at the real barrel, a gas
puff and a paint trail behind every ball. The website shows the desktop tour
and the phone video.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sktop editor

The marker follows the right wrist (turn and position), calibrated so it
points ahead in the shooting pose: the arm and the marker move as one, and
a painted player goes down still holding it. The winners wave on the spot
instead of being lifted up and down. On a wide window the mission editor
lays the field on its side and puts the tools in a side panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The operators are now MakeHuman characters (CC0 assets only) built in
Blender by tools/make-operators.py, with Quaternius' Universal Animation
Library retargeted onto them: faces, hair, clothes, modelled paintball
goggles and 21 clips, decimated to ~11k triangles and JPEG textures.

AnimatedModel.setLayer mixes a clip into one bone's subtree at a weight;
Splat uses it to pitch the aim pose up and down from the spine by the look.
Grip places the marker on the hand bone for the match and the menu stage,
recalibrated for the new rig. First person holds the marker low and right
at the hip and keeps its stock clear of the near plane. The menu stage
poses before its first frame. pack-art.py no longer packs operators.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a streams

On a runner without FFmpeg every Media is a CEF browser reading a registered
stream. The stream had no length and could not be re-read, so Chromium failed
it at once; Music took that completion for the end of the loop and built a new
player several times a second until libcef crashed (SIGILL) mid-suite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A suite of 3D tests ran out of heap by its last test: every test's class
loader, and with it the whole application, stayed alive.
- JavaSEJoglSurface's 16ms repaint timer was never stopped, and the surface
  map kept every 3D view ever shown (its value held its key). The surface now
  lives on its peer, pauses off screen, and is disposed with the port.
- Sound pools' mixer threads never ended; the port's deinitialize() now runs
  pending deinitialize hooks and the pool registers one.
- Classes were defined with each loader's default protection domain, which
  every thread a test started captured; one shared domain names no loader.
- JOGL and JavaCPP load once in the parent, JavaCPP's deallocator starts
  before any test, and survivors' context class loaders are reset.
Also: header exclusion for the CEF-derived InputStreamSchemeHandler, and the
splat e2e heap to 3072m.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog
shai-almog merged commit 005769b into master Nov 11, 2026
111 of 121 checks passed
@shai-almog
shai-almog deleted the splat-paintball-sample branch November 11, 2026 05:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant