ruffle-rs/ruffle
A Flash Player emulator written in Rust
Healthy across the board
non-standard license (Other)
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ⚠Non-standard license (Other) — review terms
- ✓Last commit today
- ✓17 active contributors
- ✓Distributed ownership (top contributor 37% of recent commits)
- ✓Other licensed
- ✓CI configured
- ✓Tests present
What would improve this?
- →Use as dependency Concerns → Mixed if: clarify license terms
Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/ruffle-rs/ruffle)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card
This card auto-renders when someone shares https://repopilot.app/r/ruffle-rs/ruffle on X, Slack, or LinkedIn.
Ask AI about ruffle-rs/ruffle
Grounded in the actual source code. Pick a starter question or write your own.
Onboarding doc
Onboarding: ruffle-rs/ruffle
Generated by RepoPilot · 2026-06-24 · Source
🎯Verdict
GO — Healthy across the board
- Last commit today
- 17 active contributors
- Distributed ownership (top contributor 37% of recent commits)
- Other licensed
- CI configured
- Tests present
- ⚠ Non-standard license (Other) — review terms
<sub>Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests</sub>
⚡TL;DR
Ruffle is a Flash Player emulator written in Rust that executes Adobe Flash content (SWF files) on desktop and web via WebAssembly, supporting ActionScript 1, 2, and 3. It replaces the deprecated Adobe Flash Player, allowing legacy Flash games and applications to run in modern browsers and as native desktop applications without requiring the proprietary Flash runtime. Monorepo with workspace members: core/ is the emulation engine (ActionScript VM, display list, rendering interface), render/ has platform-specific backends (wgpu for desktop, webgl for web, naga-agal for shader transpilation), video/ handles FLV/H.264 decoding, desktop/ and web/ are distribution targets, swf/ parses binary SWF format, wstr/ manages wide strings for ActionScript compatibility. Each has its own Cargo.toml under shared workspace config (Cargo.toml).
👥Who it's for
Web developers and end-users who need to run legacy Flash content on modern systems; archivists preserving Flash-based media; contributors building emulation layer for esoteric bytecode (ActionScript VM, AGAL shader compilation, FLV video parsing). Target users are non-technical—they just want their Flash games to work.
🌱Maturity & risk
Actively developed with strong community engagement (Discord badge, Crowdin translations, Flathub/AUR/npm releases visible). Multi-platform shipping (desktop, web, Android, extension) indicates production readiness for many use cases, but ActionScript 3 and advanced features still incomplete per README's 'still not finished by any means' caveat. Robust CI/CD setup (.github/workflows/) with linting, testing, and release automation.
Large polyglot monorepo (8M+ lines Rust, 798K ActionScript, custom TypeScript build chain) increases cognitive load; dependencies on external projects like gc-arena (git fork), regress (custom AS3 regex fork), and naga for shader compilation introduce supply-chain friction. Desktop and web codepaths diverge significantly (render/webgl vs render/wgpu), risking platform-specific bugs. Single-organization ownership (Ruffle LLC) with volunteer contributions means feature velocity depends on available maintainer time.
Active areas of work
Visible from workflows: continuous Rust builds (test_rust.yml), web builds (test_web.yml), translation synchronization (download_translations.yml, upload_texts.yml), and nightly release automation (release.yml). Repository shows active localization effort (40+ language files in core/assets/texts/). Extension dockerfile testing (test_extension_dockerfile.yml) suggests ongoing work on browser extension distribution.
🚀Get running
Clone: git clone https://github.com/ruffle-rs/ruffle.git && cd ruffle. Install Rust 1.70+ (workspace edition = 2024). Build desktop: cargo build --release -p ruffle_desktop. Build web: cargo build --release --target wasm32-unknown-unknown -p ruffle_web. Run desktop: ./target/release/ruffle_desktop (or ruffle if installed).
Daily commands:
Desktop dev: cargo run -p ruffle_desktop -- path/to/file.swf (debug build) or cargo run --release -p ruffle_desktop (no args opens file picker). Web locally: cargo build --target wasm32-unknown-unknown -p ruffle_web && npm start (in web/ directory if package.json present). Tests: cargo nextest run (parallel via .config/nextest.toml).
🗺️Map of the codebase
core/Cargo.toml— Core workspace configuration defining the Flash emulator's primary library, asset compilation, and player global bootstrapCargo.toml— Root workspace manifest with 16+ crates (desktop, web, render backends, video, tests) — essential for understanding the modular architecturecore/build.rs— Build script that compiles ActionScript globals and manages asset embedding (fonts, translations) — critical for build process.github/workflows/test_rust.yml— Primary CI pipeline for testing Rust code across platforms; defines build matrix and coverage expectationscore/build_playerglobal/Cargo.toml— Compile-time ActionScript code generation using asc.jar; understanding this unlocks how Flash builtins are bootstrapped.cargo/config.toml— Cargo configuration with workspace-level settings, profiles, and feature flags affecting all 16 cratesREADME.md— Project overview, feature matrix, and deployment targets (desktop, web, mobile); context for architectural decisions
🛠️How to make changes
Add a new rendering backend
- Create
render/my-backend/Cargo.tomlwith a dependency onruffle_render_common(render/my-backend/Cargo.toml) - Implement the
RendererandBitmapHandletraits from the core render API (render/my-backend/src/lib.rs) - Register the backend in
core/Cargo.tomlas an optional feature and use conditional compilation in core's renderer selection logic (core/Cargo.toml) - Add feature gating and instantiation logic in the main entry point (e.g.,
desktop/src/main.rsorweb/src/lib.rs) (desktop)
Add a new localization / context menu language
- Create directory
core/assets/texts/[locale]/(e.g.,core/assets/texts/it-IT/) (core/assets/texts) - Copy and translate
core/assets/texts/en-US/context_menu.ftlinto the new locale directory (core/assets/texts/en-US/context_menu.ftl) - Run build system or translator scripts to register the locale (see
.github/workflows/upload_texts.ymlanddownload_translations.yml) (.github/workflows/upload_texts.yml)
Add a new ActionScript standard library class (Player Global)
- Write ActionScript source in
core/build_playerglobal/and reference it in the build script (core/build_playerglobal/Cargo.toml) - Run
core/build.rswhich invokesasc.jarto compile.assource to ABC bytecode (core/build.rs) - Embedded bytecode is loaded into the AVM at runtime; verify by adding test case in
tests/framework(tests/framework)
Add a new test case for Flash file regression testing
- Define test metadata in
tests/input-format(file format for test specifications) (tests/input-format) - Place
.swfor.flafile + expected output in repository and reference in test suite manifest (tests) - Run
tests/fs-tests-runnerwhich compares emulation output against golden snapshots (tests/fs-tests-runner)
🔧Why these technologies
- Rust — Memory safety without GC; critical for emulating low-level Flash behavior and managing large SWF assets without pauses
- WGPU + WebGL + Canvas — Multi-target rendering: GPU-accelerated on desktop (WGPU) and web (WebGL), with 2D fallback (Canvas) for compatibility
- WebAssembly (web target) — Enables Flash playback in modern browsers without plugins; wasm-bindgen bridges Rust and JavaScript
- ActionScript (player global bytecode) — Implements flash.* standard library; compiled to ABC bytecode at build time and loaded at runtime by AVM
- Fluent (FTL) localization — Declarative translation format for context menu and UI strings across 30+ locales
⚖️Trade-offs already made
-
Multiple rendering backends (WGPU, WebGL, Canvas) instead of single unified renderer
- Why: Different platforms have different capabilities: desktop GPUs are powerful, browsers are sandboxed, fallbacks needed for older clients
- Consequence: More code to maintain, but better performance on each target; abstraction layer (Renderer trait) mitigates coupling
-
Compile ActionScript to ABC bytecode at build time (playerglobal) rather than ship source
- Why: Reduces runtime startup cost and binary size; prevents end-users from modifying standard library
- Consequence: Changes to flash.* classes require rebuild; complex build-time toolchain (asc.jar dependency)
-
Dual AVM support (AVM1 for AS2, AVM2 for AS3) instead of unified interpreter
- Why: Flash evolved from ActionScript 2 (AVM1) to 3 (AVM2) with incompatible semantics; many legacy SWFs require AVM1
- Consequence: Significant code duplication; complex dispatch logic to choose VM at load time
-
Software video decoders (VP6, H.264) alongside external library bindings
- Why: Ensures playback works on all platforms; external libs provide better performance on supported systems
- Consequence: undefined
🪤Traps & gotchas
WASM-bindgen version pinning: Cargo.toml explicitly pins wasm-bindgen to =0.2.120 and requires matching wasm-bindgen-cli version—mismatches cause cryptic linker failures. gc-arena git fork: Uses custom fork of gc-arena from kyren with specific commit hash—cannot upgrade without careful testing of GC behavior. Shader compilation: naga-agal converts AGAL (Adobe's low-level shader language) to WGSL; if shaders fail, check both transpiler and backend support. Cross-platform rendering: wgpu backend differs significantly from webgl backend; desktop-only fixes may not help web users. ActionScript semantics: Ruffle implements Flash semantics (loose typing, prototype chains, XML object) which differ from JavaScript—code that looks valid may fail due to AS3 quirks.
🏗️Architecture
💡Concepts to learn
- ActionScript Virtual Machine (AVM2) — Ruffle's core is a bytecode interpreter for ActionScript 3; understanding call stack, scope chains, and opcode dispatch is essential for fixing execution bugs or optimizing hot paths
- Display List & Scene Graph — Flash renders via a hierarchical tree (DisplayObject) rather than immediate-mode; Ruffle must maintain this tree, apply transforms, and dispatch events—bugs here affect all visual output
- AGAL to WGSL Shader Transpilation — Flash's low-level AGAL shaders must be converted to WGSL for wgpu or GLSL for WebGL; the render/naga-agal module handles this critical but non-obvious translation
- SWF Binary Format Parsing — SWF files are binary blobs with variable-length records and nested structures; the swf crate's bitreader-based parser must handle compression (ZLIB/LZMA), frame tags, and sprite nesting correctly
- WebAssembly FFI (wasm-bindgen) — Web target compiles Rust to WASM; wasm-bindgen bridges Rust ↔ JavaScript for file I/O, DOM integration, and event loops—version mismatches cause silent failures
- Garbage-Collected Arena Allocation (gc-arena) — ActionScript 3 objects are garbage-collected; Ruffle uses gc-arena's arena allocator instead of std::heap to manage AS3 objects safely without Rust's borrow checker overhead
- Cross-Platform Graphics Abstraction (wgpu) — wgpu abstracts Vulkan/DX12/Metal/WebGL2 behind a single API; understanding wgpu's pipeline, bind groups, and queue submission is crucial for render performance and cross-platform parity
🔗Related repos
lightspark/lightspark— Alternative Flash emulator in C++ focusing on speed and LLVM compilation; predecessor project that inspired Ruffle's designswftools/swftools— Legacy SWF analysis and manipulation suite; Ruffle's SWF parser was informed by swftools' reverse-engineered format documentationadobe-flash/flash-runtime-extensions— Historical Flash Player source/specs (limited release); reference for ActionScript semantics and bytecode interpretationwebpack/webpack— Module bundler used in Ruffle's web build pipeline (TypeScript compilation for extension and web packages)gfx-rs/gfx— Abstraction layer that informed wgpu design; Ruffle chose wgpu over raw gfx for cross-platform GPU access in render/wgpu
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for SWF parsing and rendering pipeline
The repo has a comprehensive test infrastructure (tests/ workspace with framework, fs-tests-runner, socket-format) but lacks visible integration tests that validate end-to-end SWF parsing through the core/swf modules and rendering via render/wgpu. This would catch regressions early when changes affect the parsing→rendering pipeline. The tests/framework already exists but appears underutilized.
- [ ] Review tests/framework/Cargo.toml to understand the existing test harness
- [ ] Create tests/swf-rendering-integration/ with test cases for common SWF features (shapes, sprites, ActionScript)
- [ ] Add test SWF files or reference existing ones from tests/fs-tests-runner
- [ ] Integrate into .github/workflows/test_rust.yml to run on every commit
- [ ] Document in CONTRIBUTING.md how to add new integration test cases
Add Windows/macOS-specific CI workflows for desktop builds
The .github/workflows/ contains test_rust.yml and test_web.yml but appears to lack platform-specific builds for the desktop crate on Windows and macOS. The Cargo.toml shows desktop is the default-member, meaning it's a primary deliverable. Cross-platform CI ensures the desktop build works reliably on all target platforms before release.
- [ ] Review .github/workflows/test_rust.yml to understand current matrix setup
- [ ] Create .github/workflows/test_desktop.yml with matrix strategy for [ubuntu-latest, windows-latest, macos-latest]
- [ ] Configure desktop-specific build steps (handle different audio backends via cpal features)
- [ ] Add artifact upload for desktop binaries to enable testing
- [ ] Reference new workflow in README.md CI status badges
Add video codec compatibility testing in render pipeline
The repo has video/software and video/external workspace members indicating video playback is a core feature, but there's no visible test coverage for different video codecs (H.264, VP6, Sorenson Spark). The render/ modules have extensive test infrastructure but video compatibility isn't addressed, risking silent failures when video decoding paths break.
- [ ] Review video/software/Cargo.toml and video/external/Cargo.toml for current codec support
- [ ] Create tests/video-codec-compatibility/ with test fixtures for each supported codec
- [ ] Add tests/framework integration for video playback validation
- [ ] Create .github/workflows/test_video.yml or extend test_rust.yml with video test matrix
- [ ] Document supported codecs and test coverage in core/README.md
🌿Good first issues
- Add missing ActionScript 3 built-in methods: grep core/src/avm2/globals/ for TODO comments on unimplemented String/Array/Object methods, write test cases in tests/, implement the Rust-side handler, wire up via call_method macro.
- Improve SWF tag parsing coverage: swf/src/tags/ has placeholder Unimplemented variants for rare tag types (e.g., ExtendedBinaryData); pick an unimplemented tag, write a parser using bitreader crate patterns already in use, add test fixture SWF.
- Fix rendering glitches in specific test cases: tests/framework/ contains SWF fixtures with known visual diffs; pick one failing test in tests/update_tests.sh output, reproduce in desktop app, trace through render/wgpu/src/ to find the shader/transform bug, add regression test.
⭐Top contributors
Click to expand
Top contributors
- @kjarosh — 37 commits
- @Dinnerbone — 17 commits
- @Lord-McSweeney — 8 commits
- @torokati44 — 7 commits
- @dependabot[bot] — 7 commits
📝Recent commits
Click to expand
Recent commits
4edd243— web: Remove redundant variables (tygyh)9efe2e3— web: Match clipboard shortcuts on physical key, not produced char (evil1morty)0648d30— avm2: Remove now-unusedErrorObject::display_full(Lord-McSweeney)3339f20— tests: Add test forError.getStackTraceedge cases (Lord-McSweeney)fb8f0fa— avm2:Error.getStackTraceshould calltoStringon theError(Lord-McSweeney)812c5b1— chore: Run npm update (danielhjacobs)dad56df— core: Fix LoaderInfo.width/height returning 0 for loaded raster images (1bugproof)bb7639c— chore: Bump the @peculiar asn1 suite in package-lock.json (torokati44)5c15175— chore: Bump browserstack-local in package-lock.json (torokati44)2ca684f— chore: npm update memfs (danielhjacobs)
🔒Security observations
Ruffle is a well-structured Rust project with generally good security practices. The primary concerns are: (1) a malformed/incomplete Cargo.toml file that should be fixed immediately, (2) use of git dependencies which should be regularly audited, (3) complex rendering backends that introduce attack surface, and (4) network/filesystem capabilities that require careful sandboxing. The project appears to follow Rust best practices and benefits from memory safety guarantees. Recommended actions include fixing the Cargo.toml, establishing a dependency audit schedule, and conducting security reviews of the rendering and network components. The codebase would benefit from fuzzing campaigns targeting Flash parsing and rendering logic.
- Medium · Pinned Dependency Version Mismatch —
Cargo.toml - workspace.package.edition. The workspace specifies edition = '2024' which does not exist in Rust. The latest stable edition is 2021. This may cause build failures or unexpected behavior. Fix: Change edition to '2021' or the appropriate Rust edition being targeted. Verify all workspace members use consistent edition values. - Medium · Git Dependency Without Version Pinning —
Cargo.toml - gc-arena and regress dependencies. The project uses git dependencies (gc-arena and regress) pinned to specific commits, which bypasses Cargo's security verification. While commits are pinned, upstream repositories should be regularly audited and monitored for security updates. Fix: Regularly audit git dependencies for security issues. Consider switching to crates.io versions when available. Implement dependency update checks in CI/CD pipeline. - Medium · Incomplete Dependency Declaration —
Cargo.toml - end of file. The Cargo.toml file appears truncated with an incomplete line 'walkdi' at the end, suggesting the file may be malformed or incomplete. This could cause cargo build failures. Fix: Complete and verify the Cargo.toml file is properly formatted. Run 'cargo check' to validate the configuration. - Low · Multiple High-Risk Rendering Backends —
render/ subdirectories. The project includes multiple rendering backends (wgpu, webgl, canvas, pixel_bender) which expand the attack surface. Each backend introduces potential security risks related to GPU acceleration and memory handling. Fix: Implement security audits specific to GPU rendering code. Use fuzzing for shader compilation and rendering pipeline. Document known limitations for each backend. - Low · Network Socket Support —
tests/socket-format, video/external. The presence of socket-format tests and external video support suggests network capabilities. Flash player emulators handling network code require careful security review for SSRF, DNS rebinding, and other network-based attacks. Fix: Implement strict network sandboxing. Validate all network requests. Implement rate limiting and timeout mechanisms. Document any network APIs exposed to Flash content. - Low · File System Access in Tests —
tests/fs-tests-runner. The fs-tests-runner component suggests file system access capabilities. If Flash content can interact with the file system, this creates potential information disclosure risks. Fix: Implement strict file system sandboxing. Use allowlists for accessible paths. Implement proper permission checks before any file operations by Flash content. - Low · Web Build Distribution —
web/, web/packages/extension/safari. The project supports web deployment via npm/wasm. Ensure CORS policies and Content Security Policy headers are properly configured in web deployments. Fix: Verify CORS headers are restrictive. Implement strong CSP headers. Use subresource integrity (SRI) for all external dependencies. Audit browser extension permissions.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ruffle-rs/ruffle shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live ruffle-rs/ruffle
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/ruffle-rs/ruffle.
What it runs against: a local clone of ruffle-rs/ruffle — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in ruffle-rs/ruffle | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 30 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ruffle-rs/ruffle. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ruffle-rs/ruffle.git
# cd ruffle
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of ruffle-rs/ruffle and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ruffle-rs/ruffle(\\.git)?\\b" \\
&& ok "origin remote is ruffle-rs/ruffle" \\
|| miss "origin remote is not ruffle-rs/ruffle (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "core/Cargo.toml" \\
&& ok "core/Cargo.toml" \\
|| miss "missing critical file: core/Cargo.toml"
test -f "Cargo.toml" \\
&& ok "Cargo.toml" \\
|| miss "missing critical file: Cargo.toml"
test -f "core/build.rs" \\
&& ok "core/build.rs" \\
|| miss "missing critical file: core/build.rs"
test -f ".github/workflows/test_rust.yml" \\
&& ok ".github/workflows/test_rust.yml" \\
|| miss "missing critical file: .github/workflows/test_rust.yml"
test -f "core/build_playerglobal/Cargo.toml" \\
&& ok "core/build_playerglobal/Cargo.toml" \\
|| miss "missing critical file: core/build_playerglobal/Cargo.toml"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 30 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~0d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/ruffle-rs/ruffle"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.
Embed this chat in your README →
Drop this iframe anywhere — the widget runs against the same live analysis cache as the main app.
<iframe src="https://repopilot.app/embed/ruffle-rs/ruffle" width="100%" height="500" style="border:1px solid #d0d7de; border-radius:8px;" allow="microphone" loading="lazy" ></iframe>