Repository navigation
feat: show the Pocket3D title card at launch on PS Vita, PSP and 3DS - #35
Merged
Merged
Conversation
vendor/pocketjs moves from 1c2002a2 to 757e90ec: a Vita GXP alignment fix, the 3d.pocket.nexus site, the pocket3d-title crate, and the Pocket3D License 1.0 for pocket3d/, devices/ and engine/pocket3d/. That license makes the title card a condition of distributing a game that draws with Pocket3D, so the three console builds play it first at every launch, before the renderer starts: the mark and the wordmark, 144 ticks at 60 Hz. - vita: pocket3d_title::vita::play() in wired::run, before graphics::init_with_pool. main() has no other path into the game. - psp: title() in main.rs draws into the uncached mirror of video memory in 8888, before host::init_graphics. It zeroes those bytes afterwards: the card ends on [0, 0, 0, 255] pixels, which the GE's 16-bit display buffer would show as 0x0000/0xff00 columns until the first frame is drawn. - 3ds: host.patch includes <pocket3d_title.h> and calls pocket3d_title_play() after gfxInitDefault(), before C3D_Init. The Makefile adds the crate's include directory. No build flag or boot switch skips the card: capture and benchmark builds play it too. The desktop, iPod touch 4 and Nokia E7 builds and the static map viewer have no call and do not show it. OpenStrike's own LICENSE is unchanged. Verified on the host, not on a console: - release builds of the PSP EBOOT, the Vita VPK and the 3DS .3dsx, and the 3DS capture configuration; - the cargo and bun suites the workflows run. test/3ds-device-lease.test.ts takes the 3ds:wire lease and is left to CI; - under PPSSPPHeadless the capture EBOOT dumps every frame of the four e2e cases, those frames equal the frames of a build without the call byte for byte, and video memory at tick 60 hashes to the PSP frame pocket3d-title records (0x6605dcb9c1790b74). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…memory zeroed vendor/pocketjs moves from 757e90ec to 223be88d on PocketJS main. It carries the title card with its name in plain white (pocketjs#531) and the fix this integration prompted (pocketjs#532): after its last frame the card sets its surface to zero bytes, so the GE's 16-bit display buffer on the same video memory is black until the first frame. The PSP host drops its own fill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
doodlewind
marked this pull request as ready for review
October 5, 2026 02:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
OpenStrike moves to the current PocketJS and plays the Pocket3D title card when it starts on PS Vita, PSP and Nintendo 3DS: the mark and the wordmark on the plum ground, 144 ticks at 60 Hz (2.4 s), drawn by the CPU into the display frame buffer before the renderer is initialized.
What changed
vendor/pocketjsmoves1c2002a2→757e90ec(five commits: a Vita GXP alignment fix, the 3d.pocket.nexus site, thepocket3d-titlecrate, the Pocket3D License). None of them changes a file underhosts/;crates/openstrike-3ds/host.patchapplies to the same host sources as before.pocket3d_title::vita::play()crates/openstrike-vita/src/wired.rs, first statement ofrun(), beforegraphics::init_with_poolmain()only callswired::run(), so this is the one launch path. Dependency added under the Vita target.title()crates/openstrike-psp/src/main.rs, inrun()after the clock is set and beforehost::init_graphicssceGeEdramGetAddr() | 0x4000_0000), 480 x 272, stride 512. Zeroes those bytes when the card has ended (see below).pocket3d_title_play()crates/openstrike-3ds/host.patch, aftergfxInitDefault()and beforeC3D_Init#include <pocket3d_title.h>;crates/openstrike-3ds/Makefileadds the crate'sinclude/directory. The vendored host stays unmodified.README.mdgains a "Pocket3D title card" section: the credit with a link to https://3d.pocket.nexus, the three call sites, and the rule that the card is not skipped, shortened, recoloured or redrawn here. The repository has noAGENTS.mdorCLAUDE.md, so the rule lives there.PSP hand-over. The card ends on black pixels whose fourth byte is 255. With the default 16-bit frame buffer the GE's display buffer occupies the same bytes and is shown from
sceGuDisplay(true)until the first frame is drawn, so it would read them as alternating0x0000/0xff00columns.title()therefore fills the bytes it used with zero before it returns.No skip switch. None of the three hosts reads a development boot switch before graphics start, so every build plays the card, capture and benchmark builds included. Capture frame indices are counted in the host loop and are not shifted by it (checked on PSP, below).
Platforms without the card
These builds have no drawer in
pocket3d-titlefor their display path and do not show the card yet. This PR adds none.crates/openstrike, wgpu)crates/openstrike-ipod)crates/openstrike-symbian)site/map-viewer).pocket3d-titleships a browserplayTitle(); the viewer does not call it here.domain/crates/gu-demoand thepocket3d-vitafullscreen_skyexample are renderer bring-up utilities and are unchanged.License
The pinned PocketJS puts Pocket3D (
pocket3d/,devices/,engine/pocket3d/invendor/pocketjs) under the Pocket3D License 1.0: MIT's grant plus the condition that a distributed product drawing 3D scenes with Pocket3D shows the title card at each start. OpenStrike's ownLICENSE(MIT) is unchanged. For a platform without a drawer the license asks for the mark and wordmark from the artwork for at least two seconds (condition 2b); the four builds listed above do not do that yet.Verification
Everything below ran on a macOS host. Nothing was run on a console.
Cooked maps (
<maps>: the eight classic maps andwwdc24-parkour.p3d) were supplied from a local directory; each build verified them withpocket3d-cook --verify-cooked.Host builds
bun scripts/psp.ts --release --cooked-maps <maps> --packageEBOOT.PBP, 5,263,106 bytesOPENSTRIKE_COOKED_MAPS=<maps> bun scripts/vita.ts --releasedist/vita/OpenStrike.vpk, 26,949,949 bytes (USB debugging on, the default);pocket3d_title::draw,sceDisplaySetFrameBufandsceKernelAllocMemBlockare in the ELFOPENSTRIKE_COOKED_MAPS=<maps> bun run build:3dsdist/3ds/openstrike.3dsx, 3,636,052 bytes;pocket3d_title_drawandpocket3d_title_art_halfare in the link mapOPENSTRIKE_COOKED_MAPS=<maps> bun scripts/3ds.ts --capturebun run build:3ds --pocket-onlyTests the workflows run (Rust stable 1.98.0)
CI on this PR (commit
518d186): all seven jobs pass, includingbun run test:3dswith the lease test and the iPodcargo miri testjob. The table is the local run.cargo test --locked -p openstrike-core -p openstrike-character -p openstrike-mods -p openstrike-companioncargo check --locked -p openstrike-core --no-default-features --features libmcargo check --locked --manifest-path crates/openstrike-symbian/Cargo.toml --libcargo test --locked --manifest-path crates/openstrike-vita/Cargo.toml --libbun test test/strike-sdk.test.ts test/openstrike-vita-artwork.test.tscargo test --locked --manifest-path domain/Cargo.tomlcargo check --locked --manifest-path domain/Cargo.toml -p pocket3d-bsp --no-default-features --features libmcargo test --locked --manifest-path domain/crates/pocket3d-vita/Cargo.tomlcargo test --locked --manifest-path domain/crates/pocket3d-gles2/Cargo.tomlcargo check --locked -p openstrikebun test test/cook-map.test.ts test/symbian-tooling.test.ts test/psp-toolchain.test.tsbun run test:ipodcargo check --locked --manifest-path crates/openstrike-ipod/Cargo.toml --features native-checkbun run check:platforms(includesbun run typecheck)bun run test:3dstest/3ds-device-lease.test.tsreportedDevice busy: 3ds:wire, because that lease was held by another process on the machine. It was not retried locally; it passes in CI.test:3ds, run separately:python3 -B -m unittest discover -s test -p test_3ds_deploy.py;bun test test/3ds-tooling.test.ts test/tactical-touch.test.ts;cargo test --locked --manifest-path crates/openstrike-3ds/Cargo.tomlbun test test/psp-map-read.test.ts test/psp-memory.test.tstest/3ds-tooling.test.tsapplieshost.patchto the pinned host, so it covers the extended patch.Emulator: PPSSPPHeadless, software renderer, at the commit in
test/goldens-psp/PPSSPP-COMMIT.txtOPENSTRIKE_COOKED_MAPS=<maps> bun scripts/e2e-psp.ts, livenessscripts/psp.tshas defaulted to the 16-bit buffer since4b528d5(2026-09-20). A captured frame has 611 colours, its golden 12,247.title();call removed--framebuffer32build. The 32-bit frames are within 2 to 405 of 130,560 pixels of the goldens in both.0x6605dcb9c1790b74, the PSP frame hash recorded inpocket3d-title's tests. The display frame buffer reads back as0x44000000, width 512, format 8888, and the present closure ran 144 times.Not done
bun scripts/e2e-vita.ts(Vita3K) andbun run test:e2e:3ds(Azahar) were not run; both open an emulator window. Their capture builds now play the card before frame 0.cargo miri testjob of the iPod workflow was not run locally (it passes in CI).🤖 Generated with Claude Code