{"id":47765048,"url":"https://github.com/bloom-engine/jump","last_synced_at":"2026-06-10T06:01:40.406Z","repository":{"id":347923789,"uuid":"1192547207","full_name":"Bloom-Engine/jump","owner":"Bloom-Engine","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-07T10:47:24.000Z","size":15811,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-07T12:23:13.581Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Bloom-Engine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-26T10:22:13.000Z","updated_at":"2026-06-07T02:01:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"2539ba24-f6d4-4076-a736-149bca58a03b","html_url":"https://github.com/Bloom-Engine/jump","commit_stats":null,"previous_names":["bloom-engine/jump"],"tags_count":106,"template":false,"template_full_name":null,"purl":"pkg:github/Bloom-Engine/jump","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bloom-Engine%2Fjump","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bloom-Engine%2Fjump/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bloom-Engine%2Fjump/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bloom-Engine%2Fjump/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Bloom-Engine","download_url":"https://codeload.github.com/Bloom-Engine/jump/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bloom-Engine%2Fjump/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34139182,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-03T06:05:58.221Z","updated_at":"2026-06-10T06:01:40.396Z","avatar_url":"https://github.com/Bloom-Engine.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# 🍄 Bloom Jump\n\n**A classic 2D side-scrolling pixel-art platformer — written in pure TypeScript, compiled to native machine code.**\n\nNo VM. No interpreter. No garbage collector. One TypeScript file becomes a real native binary on macOS, Windows, Linux, iOS, tvOS, watchOS, Android, and the Web.\n\n![Bloom Jump title screen](docs/screenshots/01-title.png)\n\n\u003c/div\u003e\n\n---\n\n## ✨ What is this?\n\nBloom Jump is a complete, shippable platformer game built on two pieces of technology:\n\n- **[Bloom Engine](https://www.npmjs.com/package/@bloomengine/engine)** — a native game engine for TypeScript with a Rust + `wgpu` rendering layer (sprites, audio, input, windowing).\n- **[Perry](https://github.com/PerryTS/perry)** — a TypeScript-to-native compiler. It lowers TypeScript straight to machine code, so the game ships as a standalone native executable on every target.\n\nThe result is a full game — 5 levels, multiple enemy types, collectibles, a pixel-art renderer, sound and music, a title/menu flow, and a standalone level editor — that runs at a fixed 60 FPS with no runtime overhead.\n\n---\n\n## 📸 Screenshots\n\n| Gameplay | Level Select |\n|---|---|\n| ![Gameplay](docs/screenshots/03-gameplay.png) | ![Level select](docs/screenshots/02-level-select.png) |\n\n| Pause | Level Editor |\n|---|---|\n| ![Pause](docs/screenshots/04-pause.png) | ![Editor](docs/screenshots/05-editor.png) |\n\n---\n\n## 🎮 Features\n\n- **5 hand-designed levels** — *Green Meadows*, *Rocky Cliffs*, *Sky Gardens*, *Dark Caves*, *Final Heights*.\n- **Pixel-art rendering** — a single sprite atlas drawn at 2× (16×16 → 32×32) with nearest-neighbour filtering for crisp pixels, plus parallax mountain/hill/cloud backgrounds.\n- **Platformer physics** — separated-axis AABB collision, gravity, springs, one-way platforms, and coyote-friendly jumping at a fixed 60 FPS timestep.\n- **Enemies \u0026 hazards** — walkers, flyers, chasers, and spikes. Stomp enemies from above or take damage.\n- **Collectibles** — coins, gems, and a flag goal per level. Three lives, three hearts.\n- **Audio** — generated sound effects and two music tracks (menu + gameplay).\n- **Truly cross-platform input** — keyboard/mouse on desktop, touch controls on mobile, gamepad/Siri Remote on tvOS, and the Digital Crown on watchOS.\n- **Standalone level editor** — paint tiles and entities, undo/redo, grid snap, save/load — see [Level Editor](#-level-editor).\n- **Fullscreen** — press **F11** on any desktop platform.\n\n---\n\n## 🧠 How it works\n\n### The compile pipeline\n\n```\nsrc/main.ts ──► Perry compiler ──► native object code ──► linked with ──► standalone\n(TypeScript)     (TS → machine code)                       Bloom Engine      executable\n                                                           (Rust + wgpu)\n```\n\n`src/main.ts` is the **entire game** in a single file. Perry compiles it to native object code and links it against the Bloom Engine's per-platform native library (`@bloomengine/engine/native/\u003cplatform\u003e`). There is no JavaScript runtime in the output — the TypeScript *is* the program.\n\n### Single-file, Perry-safe architecture\n\nBoth the game (`src/main.ts`) and the editor (`src/editor.ts`) are deliberately **single-file**. This avoids cross-module edge cases in the compiler and keeps the whole game in one translation unit. A few conventions make the TypeScript compile cleanly and run identically on every backend:\n\n- **State lives in `const` arrays**, not module-level `let`. Player state is `const P = [...]`, game state is `const GS = [...]`, etc. Reading/writing array slots is stable across every Perry backend; module-level `let` mutation is not.\n- **Float literals are explicit** (`0.0`, not `0`) so arithmetic stays in floating point.\n- **Engine values are inlined** where a backend can't resolve imported `const`-object property access (e.g. key codes `K_SPACE = 32`), keeping the Web target working.\n- **Index-based loops** (`for (let i = 0; ...)`) rather than `for…of`.\n\nSee [`CLAUDE.md`](CLAUDE.md) for the full list of compiler conventions.\n\n### Game loop \u0026 state machine\n\nThe game is driven by `runGame(dt =\u003e { … })`, which the engine dispatches per platform (a `requestAnimationFrame` loop on Web, a native game loop elsewhere). Every frame:\n\n1. Query screen size and compute a UI scale factor (so the HUD scales from phone to TV).\n2. Update music stream and read platform input (touch / gamepad / crown).\n3. Dispatch on the current state: **Menu → Level Select → Playing → Paused → Game Over → Level Complete → Credits**.\n\nGameplay updates run in fixed order each frame: `updatePlayer → updateEnemies → updateCollectibles → updateParticles → updateCamera`, then the world is drawn inside a 2D camera transform, followed by the HUD and any on-screen controls.\n\n### Rendering\n\nThe game uses the engine's **Direct-2D mode** (`setDirect2DMode(true)`), which renders straight to the swapchain and skips the deferred 3D pipeline entirely — on mobile GPUs (e.g. Adreno) this is the difference between ~15 FPS and a locked 60. All sprites come from one atlas texture, so there are zero texture switches per frame. Several hot draw calls bypass the TypeScript wrapper objects and call the engine's FFI directly (`bloom_draw_texture_pro`, `bloom_draw_rect`, …) to avoid per-call allocations.\n\n### Cross-platform input\n\n| Platform | Input |\n|---|---|\n| **Desktop** (macOS/Windows/Linux) | Arrow keys / WASD + Space; **mouse** for menus; **F11** fullscreen |\n| **iOS / Android** | Virtual joystick (left), jump button (right), pause (top-right) |\n| **tvOS** | Gamepad / Siri Remote d-pad + button A; Menu to pause |\n| **watchOS** | Digital Crown to move, tap to jump |\n\nPlatform detection comes from `isMobile()` / `isTV()` / `isWatch()`; touch state lives in a `TCH[]` array and gamepad state in `GP[]`, both refreshed each frame.\n\n---\n\n## 📁 Project structure\n\n```\njump/\n├── src/\n│   ├── main.ts            # The entire game (single-file, Perry-safe)\n│   └── editor.ts          # Standalone level editor (desktop-only)\n├── assets/\n│   ├── sprites/           # PNG sprite atlas + parallax backgrounds\n│   ├── sounds/            # WAV sound effects + music\n│   ├── levels/            # Level data (.txt) — level1…level5\n│   └── icons/             # Per-platform app icons\n├── tools/\n│   ├── generate-assets.js # Regenerates ALL sprites + sounds (Node, no deps)\n│   └── generate-icon.js   # Regenerates app icons\n├── android/               # Android Gradle project (BloomActivity + JNI bridge)\n├── build-android.sh       # Android: compile → APK → install\n├── build-linux.sh         # Linux: build native crate → bundle Jolt → compile\n├── build-web.sh           # Web: wasm-pack bundle\n├── build-windows.bat      # Windows: vcvars + perry compile\n├── .github/workflows/\n│   └── release.yml         # CI: builds \u0026 ships every platform on a GitHub release\n├── perry.toml             # Perry build + per-platform publish config\n└── docs/screenshots/      # Images used in this README\n```\n\n---\n\n## 🚀 Getting started\n\n### Prerequisites\n\n- **[Perry](https://github.com/PerryTS/perry)** compiler on your `PATH` (`perry --version`)\n- **Node.js** (only to regenerate assets)\n- Platform toolchains as needed (Xcode for Apple targets, Android SDK/NDK for Android, MSVC or LLVM for Windows)\n\n### 1. Install dependencies\n\n```bash\nnpm install\n```\n\n### 2. Generate assets (first run only)\n\n```bash\nnode tools/generate-assets.js\n```\n\nThis writes every sprite sheet and sound effect into `assets/` using only built-in Node modules — no image/audio libraries required.\n\n### 3. Build \u0026 run\n\n**macOS (desktop):**\n```bash\nperry compile src/main.ts -o jump \u0026\u0026 ./jump\n```\n\n**Level editor (desktop only):**\n```bash\nperry compile src/editor.ts -o editor \u0026\u0026 ./editor\n```\n\n**iOS Simulator:**\n```bash\nperry compile --target ios-simulator --features ios-game-loop src/main.ts -o bloom_jump\n/usr/libexec/PlistBuddy -c \"Delete :UIApplicationSceneManifest\" bloom_jump.app/Info.plist\nxcrun simctl install booted bloom_jump.app\nxcrun simctl launch booted com.bloom.jump\n```\n\n**tvOS:**\n```bash\nperry compile --target tvos --features ios-game-loop src/main.ts -o bloom_jump_tv\n```\n\n**Android (build + install + run):**\n```bash\n./build-android.sh --run\n```\n\n**Linux:**\n```bash\n./build-linux.sh --run\n```\n\n**Windows** (from a Developer Command Prompt):\n```bat\nbuild-windows.bat\n```\n\u003e The Windows build links with the **GUI subsystem** (`[windows] subsystem = \"windows\"` in `perry.toml`) so no console window opens alongside the game.\n\n**Web:**\n```bash\n./build-web.sh\n```\n\n---\n\n## 🗺️ Level format\n\nLevels are plain-text files in `assets/levels/`:\n\n```\nname:Green Meadows\nwidth:60\nheight:15\nbg:0\nspawn:3,12\ntiles:0,0,0,1,1,1,...      # row-major grid, width × height entries\nentities:1,20,12;10,30,12;20,95,12   # type,x,y separated by ;\n```\n\n**Tile types**\n\n| ID | Tile | ID | Tile |\n|---|---|---|---|\n| 0 | air | 4 | stone |\n| 1 | grass | 5 | spike-up |\n| 2 | dirt | 6 | spike-down |\n| 3 | brick | 7 | platform (one-way) |\n\n**Entity types**\n\n| ID | Entity | ID | Entity |\n|---|---|---|---|\n| 1 | walker | 11 | gem |\n| 2 | flyer | 12 | spring |\n| 3 | chaser | 20 | flag (goal) |\n| 10 | coin | | |\n\n---\n\n## ✏️ Level Editor\n\n`src/editor.ts` is a standalone desktop tool for authoring levels:\n\n- **Tile \u0026 entity palette** (right panel) — pick grass/dirt/brick/stone/spikes/platforms and walker/flyer/chaser/coin/gem/spring/flag/spawn.\n- **Paint** by clicking/dragging on the grid; **erase** with the air tile.\n- **Undo / redo** (`Ctrl+Z` / `Ctrl+Y`), **grid toggle** (`G`), and **zoom**.\n- **New / Open / Save / Save As** toolbar buttons read and write the same `.txt` format the game loads.\n\n```bash\nperry compile src/editor.ts -o editor \u0026\u0026 ./editor\n```\n\n---\n\n## 🎨 Asset pipeline\n\nAll art and audio are **generated procedurally** by `tools/generate-assets.js` (pure Node — `fs`, `path`, `zlib` only):\n\n- `assets/sprites/atlas.png` — the single 16×16 tile/sprite atlas (rendered at 2×).\n- `assets/sprites/bg_*.png` — parallax mountain / hill / cloud layers.\n- `assets/sounds/*.wav` — coin, gem, jump, stomp, hurt, death, spring, complete, select.\n- `assets/sounds/music_*.wav` — menu and gameplay music.\n\nRe-run `node tools/generate-assets.js` after editing the generator to refresh everything.\n\n---\n\n## 📦 Releasing (going live)\n\nShipping is driven by **`.github/workflows/release.yml`**, triggered when a **GitHub Release is published**. Each platform builds in parallel and ships to its store/channel via `perry publish`:\n\n| Job | Target | Destination |\n|---|---|---|\n| iOS | `perry publish ios` | TestFlight → App Store |\n| tvOS | `perry publish tvos` | TestFlight → App Store |\n| watchOS | `perry publish watchos` | TestFlight → App Store |\n| macOS | `perry publish macos` | App Store + notarized DMG (attached to the release) |\n| Android | `perry publish android` | Google Play |\n| Windows | `perry publish windows` | GitHub release asset |\n| Linux | `perry publish linux` | GitHub release asset |\n| Web | `wasm-pack` bundle | `bloomengine.dev/jump` |\n\nThe workflow installs Perry, injects the version/build number from the release tag, decodes signing credentials from repository secrets, and publishes. Per-platform signing identities, bundle IDs, and distribution channels are configured in **`perry.toml`**.\n\n\u003e **To cut a release:** tag a version (`vX.Y.Z`), publish a GitHub Release, and the workflow fans out to every platform.\n\n---\n\n## 🛠️ Perry compiler notes\n\nBecause the game compiles straight to native code, a few TypeScript patterns are written defensively. The most important:\n\n- `Math.max` / `Math.min` / `Math.pow` may return boxed objects — compute inline instead.\n- Integer literal `0` infers `i32`; use `0.0` for float math.\n- Prefer `const` arrays for mutable state over module-level `let`.\n- Use index-based loops, not `for…of`.\n- Compare strings with numeric constants + `if/else`, not `switch` on strings.\n\nThe full, current list lives in [`CLAUDE.md`](CLAUDE.md).\n\n---\n\n## 📜 Credits \u0026 license\n\n**Bloom Jump** © 2026 **Skelpo GmbH**. All rights reserved.\n\nBuilt with **Bloom Engine** · Compiled with **Perry**.\n\n\u003e *No frameworks were harmed in the making of this game. Pure TypeScript. Compiled to native. No VM. No interpreter. No GC.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbloom-engine%2Fjump","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbloom-engine%2Fjump","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbloom-engine%2Fjump/lists"}