{"id":50307186,"url":"https://github.com/pavlov-net/bevy_asset_preprocess","last_synced_at":"2026-05-28T17:30:29.255Z","repository":{"id":355683695,"uuid":"1229132953","full_name":"pavlov-net/bevy_asset_preprocess","owner":"pavlov-net","description":"Headless CLI/library that compresses Bevy image assets to KTX2 (BCn/ASTC + mipmaps + zstd) via CompressedImageSaver","archived":false,"fork":false,"pushed_at":"2026-05-04T19:12:09.000Z","size":30,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-04T20:37:10.648Z","etag":null,"topics":["asset-pipeline","bevy","bevy-engine","game-development","ktx2","mipmaps","rust","texture-compression"],"latest_commit_sha":null,"homepage":null,"language":"Rust","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/pavlov-net.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-05-04T18:26:09.000Z","updated_at":"2026-05-04T19:12:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pavlov-net/bevy_asset_preprocess","commit_stats":null,"previous_names":["pavlov-net/bevy_asset_preprocess"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/pavlov-net/bevy_asset_preprocess","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlov-net%2Fbevy_asset_preprocess","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlov-net%2Fbevy_asset_preprocess/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlov-net%2Fbevy_asset_preprocess/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlov-net%2Fbevy_asset_preprocess/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pavlov-net","download_url":"https://codeload.github.com/pavlov-net/bevy_asset_preprocess/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlov-net%2Fbevy_asset_preprocess/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33619964,"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-05-28T02:00:06.440Z","response_time":99,"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":["asset-pipeline","bevy","bevy-engine","game-development","ktx2","mipmaps","rust","texture-compression"],"created_at":"2026-05-28T17:30:28.111Z","updated_at":"2026-05-28T17:30:29.248Z","avatar_url":"https://github.com/pavlov-net.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bevy_asset_preprocess\n\nHeadless CLI + library for pre-processing Bevy assets. Drives Bevy's\n[`AssetProcessor`][ap] from a one-shot binary so you can bake compressed\ntextures (and process every other asset type whose loader you have a\nplugin for) at build time, without launching a game.\n\n[ap]: https://docs.rs/bevy_asset/latest/bevy_asset/processor/struct.AssetProcessor.html\n\n```bash\ncargo run --release -- assets/ assets-baked/\n# Hash-based change detection skips unchanged inputs; pass --force to\n# reprocess every image regardless of cache.\ncargo run --release -- --force assets/ assets-baked/\n```\n\nStatus: **prototype**. Tracks bevy `main` — depends on the\n`compressed_image_saver` feature added in [bevyengine/bevy#23567][pr].\n\n[pr]: https://github.com/bevyengine/bevy/pull/23567\n\n## What it does\n\nThe crate spins up a minimal `App` (no renderer, no window, no game\nlogic) configured with `AssetMode::Processed` and a small set of asset\nplugins:\n\n- `ImagePlugin` — registers `LoadTransformAndSave\u003cImageLoader, _,\n  CompressedImageSaver\u003e` as the default processor for `png` / `jpg` /\n  `jpeg` (this is `ImagePlugin`'s built-in behavior when the\n  `compressed_image_saver` feature is on).\n- `GltfPlugin` and a manual `ShaderLoader` registration — pulled in\n  solely so the processor can resolve `bevy_gltf::loader::GltfLoader`\n  and `bevy_shader::shader::ShaderLoader` referenced by source `.meta`\n  files (or synthesized for files without metas).\n- A hand-rolled stub for `bevy_seedling::sample::assets::SampleLoader`\n  with the right `TypePath` — the processor's lookup-by-name resolves\n  to it at meta deserialize time. We avoid pulling in `bevy_seedling`\n  because its plugin only registers the real loader after starting a\n  cpal audio stream, which fails on Linux CI without an audio device.\n\nOther asset types (scenes, custom loaders, etc.) need their own plugin\nor stub registration added to `run_bake_app`, otherwise their source\n`.meta` files fail to deserialize.\n\n`AssetProcessor` then walks the input tree and produces an output tree\nat the same relative paths. Images get compressed to KTX2 in place\n(`texture.png` → `output/texture.png` containing KTX2 bytes), with a\n`.meta` sidecar carrying the runtime `ImageLoaderSettings`. Non-image\nfiles fall through the processor's no-processor branch and are\nbyte-copied unchanged with a matching `.meta`.\n\nThe game then runs in `AssetMode::Processed` and reads from the output\ntree; the `.meta` sidecars tell the asset server which loader to use\nfor each file.\n\n## Source `.meta` files are authoritative\n\n`AssetProcessor` reads source `.meta` files to decide what to do with\neach asset. There are three actions:\n\n- `AssetAction::Process { processor, settings }` — run the named\n  processor (e.g. `LoadTransformAndSave\u003c...\u003e` to compress an image).\n- `AssetAction::Load { loader, settings }` — byte-copy the file and\n  emit a meta in the output that points at the named loader.\n- `AssetAction::Ignore` — skip the file entirely.\n\nWhen a file has no source `.meta`, the processor synthesizes one based\non extension: it picks a default processor if one is registered for the\nextension, otherwise a default loader, otherwise `Ignore`.\n\n**Practical consequence:** if you want a `.png` *compressed*, its\nsource meta must say `Process` (or there must be no source meta — the\nprocessor's default for `png`/`jpg`/`jpeg` is the compression\nprocessor). If the source meta says `Load`, the file is byte-copied\nuncompressed.\n\n## Build dependencies\n\n- **clang** — `ctt-compressonator` (the encoder behind\n  `CompressedImageSaver`) uses `-march=knl`, which GCC ≥ 15 doesn't\n  recognize. Set `CXX=clang++` if the default compiler is GCC.\n\n## Caveats\n\n### Normal maps + BCn don't preserve unit length\n\n`CompressedImageSaver` has no \"this is a normal map\" hint; CTT\ncompresses every channel independently. Renormalize in your shader\nafter sampling/blending, or pre-compress with a normal-aware tool.\nBevy's in-engine usage of the saver has the same property.\n\n### Wasm format choice\n\nWebGPU's BC support exists on desktop Chrome/Edge/Firefox but not\nSafari/mobile. If you target broad wasm, you'll want\n`compressed_image_saver_universal` (UASTC/Basis, no mipmaps) — Bevy\ndoesn't yet have a story for serving format-variants per device.\n\n### `.meta` sidecars in output\n\n`AssetProcessor` writes a `.meta` next to every processed asset\nholding the loader settings (sampler, sRGB flag, etc.). They're tiny\nand load-time authoritative; ship them with your processed assets.\n\n### `imported_assets/` directory\n\nThe processor writes a transaction log to\n`\u003coutput\u003e/imported_assets/log` for crash recovery. It's harmless and\nnot needed by the game at runtime, but currently isn't cleaned up.\n\n## Library use\n\n```rust\nuse bevy_asset_preprocess::{preprocess, PreprocessConfig};\n\nlet stats = preprocess(\n    Path::new(\"assets\"),\n    Path::new(\"assets-baked\"),\n    \u0026PreprocessConfig { force: false },\n)?;\n```\n\nThe `cli` feature gates `walkdir` and the `bevy-asset-preprocess`\nbinary; library consumers can `default-features = false` to drop both.\n\n## License\n\nMIT OR Apache-2.0, matching the Bevy ecosystem.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpavlov-net%2Fbevy_asset_preprocess","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpavlov-net%2Fbevy_asset_preprocess","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpavlov-net%2Fbevy_asset_preprocess/lists"}