Zip To Sb3 Extra Quality | Limited & Direct
The phrase "extra quality" also applies to the assets inside your SB3. When converting ZIP to SB3, you can upgrade the project by replacing assets with higher-fidelity versions before zipping.
❌ Direct renaming without unzipping first – If the ZIP contains a folder, Scratch sees MyFolder/project.json and fails.
❌ Image recompression – Resaving a PNG as JPEG inside the assets folder destroys transparency and introduces artifacts.
❌ Sound resampling – Converting a 44.1kHz WAV to 22kHz MP3 inside the ZIP reduces fidelity with no file size benefit.
❌ Altering project.json formatting – Pretty-printing (adding indents) is safe, but changing IDs or asset filenames breaks everything. zip to sb3 extra quality
import zipfile
import json
import os
import shutil
from pathlib import Path
def zip_to_sb3_extra_quality(zip_input_path, sb3_output_path=None, minify_json=True):
"""
Convert a ZIP (extracted .sb3 folder or .zip) to a high-quality .sb3 file. The phrase "extra quality" also applies to the
Args:
zip_input_path: Path to .zip file OR directory containing project.json + assets
sb3_output_path: Desired output .sb3 path (optional)
minify_json: Remove extra whitespace from JSON for smaller size
"""
zip_input_path = Path(zip_input_path)
if sb3_output_path is None:
sb3_output_path = zip_input_path.with_suffix('.sb3')
else:
sb3_output_path = Path(sb3_output_path)
# If input is a directory, zip it first
temp_zip = None
if zip_input_path.is_dir():
temp_zip = zip_input_path.with_suffix('.temp.zip')
with zipfile.ZipFile(temp_zip, 'w', zipfile.ZIP_DEFLATED) as zf:
for file in zip_input_path.rglob('*'):
if file.is_file():
arcname = file.relative_to(zip_input_path)
zf.write(file, arcname)
source_zip = temp_zip
else:
source_zip = zip_input_path
# Create new .sb3 with max compression
with zipfile.ZipFile(sb3_output_path, 'w', zipfile.ZIP_DEFLATED, compresslevel=9) as new_sb3:
with zipfile.ZipFile(source_zip, 'r') as orig_zip:
for item in orig_zip.infolist():
data = orig_zip.read(item.filename)
# Minify JSON if requested
if minify_json and item.filename.endswith('.json'):
try:
json_data = json.loads(data.decode('utf-8'))
data = json.dumps(json_data, separators=(',', ':')).encode('utf-8')
except:
pass # Keep original if not valid JSON
# Write with same filename, max compression
new_sb3.writestr(item.filename, data, compress_type=zipfile.ZIP_DEFLATED)
# Cleanup
if temp_zip and temp_zip.exists():
temp_zip.unlink()
print(f"✅ Created: sb3_output_path")
print(f" Size: sb3_output_path.stat().st_size / 1024:.2f KB")
return sb3_output_path
Corrupted project.json is the #1 cause of failed imports. Use a JSON validator. Extra quality means checking: Corrupted project
Pro tip: Open project.json in VS Code or Notepad++ to detect hidden BOM characters that break Scratch’s parser.