Repository navigation
Splat: full-stack team paintball shooter sample, with fog, PBR, shadows and post processing in every GPU backend - #6188
Conversation
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>
Cloudflare Preview
|
…), narrative demo Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
|
Compared 12 screenshots: 12 matched. |
…ose, embedded stubs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… job Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e project Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 195 screenshots: 195 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
… it draws with 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>
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>
|
Compared 192 screenshots: 192 matched. Benchmark Results
Detailed Performance Metrics
|
|
Compared 193 screenshots: 193 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 193 screenshots: 193 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 253 screenshots: 253 matched. |
|
Compared 188 screenshots: 188 matched. |
…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>
|
Compared 210 screenshots: 210 matched. ParparVM vs HotSpot (JDK 25): Linux x64Runner CPU: AMD EPYC 7763 64-Core Processor (baseline 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
Result: no regression |
|
Compared 210 screenshots: 210 matched. ParparVM vs HotSpot (JDK 25): Linux arm64Runner CPU: Neoverse-N2 (baseline 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
Result: no regression |
…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>
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.
The sample (
scripts/splat)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.Light.setShadowsandsetShadowMap, filtered with 3x3 PCF.PostProcessonGameView: 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