Skip to content

fox2d-engine/ScratchLove

Repository files navigation

ScratchLove

Love2D License Scratch Discord

A native (browser-free) Scratch 3.0 runtime for LÖVE (Love2D)

Join our Discord community to discuss, share projects, and get help!


Overview

ScratchLove is a native reimplementation of the Scratch 3.0 runtime in Lua for the LÖVE framework. Created to break free from browser limitations, it delivers a superior native experience with access to hardware sensors, haptic feedback, and fine-grained performance control unconstrained by browser sandboxing. It supports a wide range of platforms (desktop, mobile) and devices including embedded Linux systems, gaming consoles, and handheld gaming devices.

Games Running on ScratchLove

Key Highlights

  • 🎮 Full Scratch Compatibility: Nearly 100% compatible with Scratch 3.0 .sb3 format
  • 📱 Cross-Platform: Powered by Love2D's cross-platform capabilities, supports desktop and mobile operating systems
  • High Performance: Scratch blocks compiled to native Lua code, powered by LuaJIT for near-native execution speed

Features

Compiler & Runtime

  • IR-Based Compiler: Three-stage compilation (IR generation → optimization → Lua codegen)
  • Optimization Passes: Constant folding, dead code elimination, control flow analysis
  • Cooperative Threading: Efficient coroutine-based execution for concurrent scripts

Memory Management

  • Lazy Loading: Costume textures load on-demand rather than all at startup, significantly reducing initial load time and memory footprint
  • Automatic Cleanup: Time-based LRU cache automatically releases unused costume textures after configurable inactivity period

Graphics & Effects

  • Visual Effects: Color, fisheye, whirl, pixelate, mosaic, brightness, ghost
  • SVG Rendering: Native SVG support via resvg library with intelligent caching
  • Collision Detection: Color-based collision detection consistent with Scratch behavior

Advanced Features

  • Project Options: Compatible with TurboWarp project configuration (custom framerate, stage dimensions, runtime options like fencing, miscLimits, maxClones)
  • Online Loading: Direct loading from scratch.mit.edu by project ID

Supported Extensions

  • Pen Extension: Fully supported with GPU-accelerated rendering ✅
  • Custom Reporters Extension: Fully supported ✅
    • Custom procedures with return values (procedures_return)
    • Reporter-style procedure calls (procedures_call)
    • Compatible with TurboWarp custom reporters
  • Text-to-Speech Extension: Supported with async HTTPS implementation ✅
    • All 5 voices (alto, tenor, squeak, giant, kitten)
    • 44 language locales matching Scratch
    • Non-blocking async synthesis using background threads
    • Limitation: Uses single worker thread - multiple concurrent requests are queued and processed serially (unlike native Scratch which processes them in parallel)
    • Note: Requires lua-https to be compiled for HTTPS support

Known Limitations

  • Extensions: Only Pen, Custom Reporters, and Text-to-Speech extensions are supported. Other Scratch extensions (Music, Video Sensing, Translate, etc.) are not available as ScratchLove cannot run JavaScript-based extensions
  • User Input: The "ask and wait" block is not yet supported (user input not implemented)
  • Microphone Input: The loudness sensing block always returns 0 (microphone input not implemented)
  • Cloud Variables: Only basic local storage is supported

Quick Start

Prerequisites

  • LÖVE (Love2D) 11.x: Download here
  • LuaJIT (optional, for running tests): Included with LÖVE

Installation

# Clone the repository (with submodules)
git clone --recurse-submodules https://github.com/fox2d-engine/ScratchLove.git
cd ScratchLove

# If you already cloned without --recurse-submodules, initialize submodules:
git submodule update --init --recursive

# Run with a local .sb3 file
love . path/to/project.sb3

# Or run with a Scratch project ID (downloads from scratch.mit.edu)
love . 276932192

# Or drag & drop a .sb3 file into the window

Optional Dependencies

Building lua-https (Required for Online Project Loading & Text-to-Speech)

ScratchLove includes lua-https as a submodule for HTTPS support. This module must be compiled to enable:

  • Online project loading from scratch.mit.edu
  • Text-to-Speech extension (requires HTTPS API calls to Scratch synthesis service)

To compile lua-https:

  1. See detailed compilation instructions in lib/lua-https/readme.md
  2. The compiled library can be left in lib/lua-https/src/ (ScratchLove will automatically find it there)
  3. Alternatively, copy it to a system Lua path like /usr/local/lib/lua/5.1/ or ~/.luarocks/lib/lua/5.1/

Note: Without lua-https, online loading and Text-to-Speech will not work, but local .sb3 files can still be loaded and run normally.

Building Enhanced lua-cjson (Recommended for Better Performance)

ScratchLove includes an enhanced version of lua-cjson as a submodule, which provides 4-9x faster JSON parsing compared to the pure Lua implementation. By default, ScratchLove will fall back to a pure Lua JSON parser if the compiled library is not available.

To build lua-cjson for improved performance:

# Option 1: Build with LuaRocks (recommended)
cd lib/lua-cjson
luarocks --lua-version 5.1 make lua-cjson-local-1.rockspec

# Option 2: Build with Make (for development)
cd lib/lua-cjson
make clean && make

# The compiled cjson.so will be installed to ~/.luarocks/lib/lua/5.1/ (Option 1)
# or lib/lua-cjson/cjson.so (Option 2)

Requirements for building:

  • LuaJIT 2.1+ (included with LÖVE)
  • LuaRocks (for Option 1)
  • GCC or Clang compiler
  • Development headers for LuaJIT

Note: Building lua-cjson is optional. ScratchLove will work perfectly fine with the pure Lua fallback, though JSON parsing will be slower for large projects.

Running Tests

# Run all tests
luajit tests/run.lua

# Run specific test category
luajit tests/run.lua control
luajit tests/run.lua data
luajit tests/run.lua motion

Porting to Other Platforms

ScratchLove leverages LÖVE's cross-platform capabilities, making it possible to distribute your Scratch projects to various platforms including Windows, macOS, Linux, Android, iOS, and handheld gaming devices.

To package and distribute ScratchLove for different platforms:

  1. Follow the LÖVE Game Distribution Guide for platform-specific packaging instructions
  2. Place your .sb3 project file at assets/game.sb3 within the ScratchLove directory, then package everything into a .love archive
  3. Build platform-specific executables or packages as needed

This enables you to turn Scratch projects into standalone native applications for virtually any platform that LÖVE supports.


Architecture

Project Structure

ScratchLove/
├── main.lua                    # Application entry point
├── conf.lua                    # LÖVE configuration
│
├── compiler/                   # Compilation pipeline
│   ├── irgen.lua               # IR generation from Scratch blocks
│   ├── iroptimizer.lua         # IR optimization passes
│   ├── luagen.lua              # Lua code generation from IR
│   └── blocks/                 # Block-specific IR generators
│
├── vm/                         # Virtual machine runtime
│   ├── runtime.lua             # Main runtime orchestration
│   ├── thread.lua              # Script execution threads
│   ├── sprite.lua              # Sprite objects
│   └── stage.lua               # Stage object
│
├── renderer/                   # Rendering system
│   ├── renderer.lua            # Main renderer
│   ├── shaders/                # GLSL shaders for visual effects
│   └── collision/              # Collision detection system
│
├── pen/                        # Pen drawing system
├── audio/                      # Audio system
├── loader/                     # Project loading
├── parser/                     # .sb3 parsing
├── ui/                         # User interface
├── utils/                      # Utility modules
├── resvg/                      # SVG rendering (FFI bindings)
├── tests/                      # Test suite
├── lib/                        # Third-party libraries
└── assets/                     # Fonts, gamepad mappings, etc.

Development

Development Setup

# Install dependencies
# Love2D should be installed system-wide

# Run in development mode
love .

# Run with debug logging
env LOG_LEVEL=debug love . project.sb3

Debug Commands

# Skip compilation and use existing project.lua (for debugging compiled code)
env SKIP_COMPILE=1 love . project.sb3

# Run with timeout (useful for testing)
timeout --kill-after=3s 10s love . project.sb3

Testing

-- Example test
local SB3Builder = require("tests.sb3_builder")

it("should execute motion blocks correctly", function()
    SB3Builder.resetCounter()
    local stage = SB3Builder.createStage()
    local sprite = SB3Builder.createSprite("TestSprite")

    local hatId, hatBlock = SB3Builder.Events.whenFlagClicked()
    local moveId, moveBlock = SB3Builder.Motion.moveSteps(10)

    SB3Builder.addBlock(sprite, hatId, hatBlock)
    SB3Builder.addBlock(sprite, moveId, moveBlock)
    SB3Builder.linkBlocks(sprite, {hatId, moveId})

    local projectJson = SB3Builder.createProject({stage, sprite})
    local project = ProjectModel:new(projectJson, {})
    local runtime = Runtime:new(project)
    runtime:initialize()
    runtime:broadcastGreenFlag()

    -- Execute with safety limits
    local maxIterations = 100
    local iterations = 0
    while #runtime:getActiveThreads() > 0 and iterations < maxIterations do
        runtime:update(1/60)
        iterations = iterations + 1
    end

    expect(runtime:getSpriteTargetByName("TestSprite").x).to.equal(10)
end)

Code Quality Standards

  • Type Annotations: All code uses LuaLS type annotations for IDE support
  • Testing: New features must include test coverage
  • Documentation: Functions should have clear docstrings
  • Code Style: Follow existing Lua conventions in the codebase

Contributing

We welcome contributions! Here's how you can help:

Ways to Contribute

  • 🐛 Report bugs: Open an issue with reproduction steps
  • 💡 Suggest features: Share ideas for improvements
  • 📝 Improve docs: Help clarify documentation
  • 🧪 Write tests: Increase test coverage
  • 🔧 Fix issues: Submit pull requests

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Implement your changes
  5. Run the test suite (luajit tests/run.lua)
  6. Commit with clear messages (git commit -m 'Add amazing feature')
  7. Push to your fork (git push origin feature/amazing-feature)
  8. Open a Pull Request

Commit Guidelines

  • Use clear, descriptive commit messages
  • Reference issues where applicable (Fixes #123)
  • Keep commits atomic and focused
  • Follow conventional commits format when possible

License

Copyright © 2025 Fox2D.com. All rights reserved.

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0)


Acknowledgments

Special Thanks

We are deeply grateful to the TurboWarp project and team. TurboWarp's innovative compiler architecture served as an invaluable reference during ScratchLove's development, helping us understand the nuances of Scratch VM behavior and optimization techniques. For running Scratch projects in the browser, we highly recommend using TurboWarp.

Other Acknowledgments

  • Scratch Team: For creating an amazing platform that inspires creativity and learning
  • LÖVE: For the excellent Lua game framework
  • All contributors and users who have helped improve this project

About

A native (browser-free) Scratch 3.0 runtime for LÖVE

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages