Back to Pickle Rustlers
SOURCE / PINNED RELEASE

Made of little things.

Pickle Rustlers

Release
039e51f55e34…
Author-recorded commit
40608586a8a1…
License
LICENSE
Author’s source reference
nostr://npub12lm3rxsva8kfempyjkxupt09e02n3fezurkyadyqfejdc5e0r2kscqty6r/wss%3A%2F%2Fgit.napplet.soy%2F/n-bad44e7ab35

Archive hash verified: f38e99afa0992052…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

docs/engine-performance.md
# Engine performance changes

The optimization keeps the existing triangle geometry, flat shading, materials,
lighting, shadow settings, resolution policy, particle budget and animation pivots.
No graphics quality setting was reduced.

## Implementation

- Cache immutable model templates and clone their object hierarchies. Repeated
  pickles, onions, tanks, sauce bottles and kings share geometry and materials,
  while positions and animation state stay independent. These bounded shared
  resources live for the game session and must not be disposed when one actor leaves.
- Merge opaque rigid sibling meshes that share a material and shadow behavior.
  Animated wheels and muzzle flashes, transparent surfaces and animation groups
  remain separate. Cacti and mesas use the same merge step during world creation.
- Batch the 360 pooled particles into tetrahedron and box InstancedMeshes with
  dynamic matrix/color buffers. Physics, rotation, color and pool overwrite order
  are unchanged. Upload only when particle state changes. Disable batch frustum
  culling because particle bounds change continuously across the arena.
- Dispose the unique geometry/materials of retired shells, warning rings and lassos.
- Freeze local transforms of rigid model parts and world transforms of static
  scenery; keep lighting, tumbleweeds and animated parents updating normally.
- Reuse rope/sun scratch vectors, count live pickles without an intermediate array,
  cache camera orientation on resize and reject non-overlapping circles with squared
  distances before calculating their separation. Collision processing order stays intact.

## Measurements

Compared with commit `1f80fe3` using Chromium 153 / SwiftShader, a fixed 900x600
render buffer, fixed camera and lighting, 10 live pickles, 36 jar floaters,
14 onions and 360 particles. Counts include the shadow pass.

| Measurement | Original | Optimized |
| --- | ---: | ---: |
| Draw calls | 2,428 | 957 |
| Resident GPU geometries | 1,238 | 160 |
| Pickle meshes / triangles | 11 / 262 | 5 / 262 |
| Onion meshes / triangles | 19 / 370 | 10 / 370 |
| Rider meshes / triangles | 38 / 570 | 27 / 570 |
| Enemy tank meshes / triangles | 45 / 926 | 29 / 926 |
| Particle draw calls at capacity | Up to 360 | At most 2 |

This scene uses about 61% fewer draw calls. Geometry count is a resource count,
not a VRAM byte measurement. Rendering may submit more offscreen triangles because
merged meshes and particle batches have coarser culling. No model triangles were
removed. Physical low-end GPU performance and phone hardware remain unmeasured.

With actor transforms explicitly aligned between builds (Three.js UUID generation
consumes randomness), 246 of 540,000 framebuffer pixels differed by more than two
8-bit channel levels. Mean absolute channel error was 0.016 out of 255; screenshots
were also inspected. The result is visually preserved, rather than byte-identical
rasterization after baking transforms into geometry.

A separate hosted stress test rendered and retired ten pickles, ten onions and ten
shells per cycle. After warmup, GPU geometry count stayed constant across 20 cycles.
That test used a different scene from the comparison above.

## Verification

`pnpm verify` includes six guidance tests, ten engine regression tests, type-checking
and the single-file build. Engine tests cover triangle counts, mesh reductions,
independent animation references, shared resources, particle transforms/colors,
expiration/pool reuse, transient disposal and static/dynamic world transforms.

Hosted tests used `soyli dev` at its printed URL and covered iframe boot, injected
domains, movement, shooting, lasso input, and a user-triggered game-over progress save
through the real storage SDK. Explicit test-only iframe sizing verified 200x160,
320x560, 900x600 and 1400x900. Touch emulation checked outer viewports 390x844,
360x640 and 844x390 (actual app frames 390x709, 360x505 and 844x300), including
reachable shoot/lasso controls. The app palette stayed unchanged in light/dark
color schemes, and removing optional theme/config/storage domains caused no crash.
The temporary game inspection hook was removed from the final source.

`pnpm test:conformance` passed five checks and skipped five: the three manifest
checks lacked a signed manifest, wire checks observed no messages, and lifecycle
teardown was not measured. These skips do not establish coverage. An initial run
raced the preview build watcher and returned a 404; the stable-build rerun passed.
The owned hosted preview was stopped and its listener closure checked.

The final `soyli check --json` passed with playback profile `space-playback-6`
and browser `153.0.8010.12`. No NAP requirements, SDK calls, or relay behavior
were added or changed.