Skip to content

Product downloads

Every CodeAndWeb app has a download URL that never changes. Ask for https://www.codeandweb.com/download/texturepacker/latest/mac and you get the installer of the newest stable release, whatever that happens to be today.

This page is for the scripts rather than for the people: a Dockerfile, an install script, a Windows or Linux packager, an agent fetching a build. Anything that wants the current installer without parsing an XML feed that was designed for the macOS updater. If you are here to install one of our apps on your own machine, the per-product download pages are the friendlier place to be, and they are linked from every row of the table below.

Current downloads

These are the current stable releases. The page is rebuilt whenever a release ships, so the version numbers are as fresh as the last build of this site, on October 12, 2026. The /latest/ URLs above are always live: they redirect to the newest installer at the moment you request them, even when this table is a day behind.

The URL pattern

https://www.codeandweb.com/download/<product>/latest/<platform>

The product is one of texturepacker, texturepacker3d, physicseditor, spriteilluminator or babeledit. The platform is one of the tokens below. Both are case-insensitive, so /download/TexturePacker/latest/Mac works exactly like the lowercase form.

The URL answers with a 302 to the versioned installer, so the file you end up with still carries its version in the name. The 302 also carries an X-Latest-Version header, which is the cheapest way to find out what the URL currently points at from a shell:

curl -fsSI https://www.codeandweb.com/download/texturepacker/latest/mac | grep -i x-latest-version

From a browser, read the version out of the manifest instead. A cross-origin fetch() of this URL does not work at all: with the default redirect: "follow" the browser re-runs the CORS check against the installer the 302 points at, that file is served straight off disk without an Access-Control-Allow-Origin header, and the whole call rejects with a TypeError rather than returning anything you can read. With redirect: "manual" you get an opaque response whose headers are unreadable by definition, so X-Latest-Version is out of reach either way. The manifest below is not a redirect, so its version is readable from a browser like any other JSON field.

Both /latest and /latest/ serve the manifest, and both will keep doing so. Prefer the form without the trailing slash: it is the one every example here uses, and picking one spelling keeps you off a second cache entry for the same document.

Platform tokens

Every token the /latest/ URLs accept. An alias resolves to exactly the same installer as its canonical token.
PlatformTokenAlso acceptedGets you
macOSmacmacososxdarwin.dmg
Windowswindowswin.msi
Linux (.deb)linux-debdebubuntulinux.deb
Linux (Flatpak)linux-flatpakflatpak.flatpak

Not every app ships every platform. TexturePacker3D has no Linux build at all, and PhysicsEditor and SpriteIlluminator ship no Flatpak, so those three apps list fewer platforms in the downloads table at the top of this page. Asking for a platform we do not build returns a 404 that names the platforms that app does have.

The manifests

If you would rather resolve the version yourself than follow a redirect, every app publishes a small JSON manifest:

https://www.codeandweb.com/download/<product>/latest.json
{
    "schemaVersion": 1,
    "product": "TexturePacker",
    "slug": "texturepacker",
    "version": "8.3.0",
    "released": "2026-09-16",
    "releaseNotes": "https://www.codeandweb.com/texturepacker/download",
    "downloads": {
        "mac": {
            "version": "8.3.0",
            "released": "2026-09-16",
            "url": "https://www.codeandweb.com/download/texturepacker/8.3.0/TexturePacker-8.3.0.dmg",
            "latestUrl": "https://www.codeandweb.com/download/texturepacker/latest/mac",
            "fileName": "TexturePacker-8.3.0.dmg",
            "size": 70131770,
            "sha256": "77891a9afa52c0e67cb26f7bb915b3e3ee77a9558a77681e69d1e7545eae782d",
            "ed25519": "qkdi3cpiEwIpI0b0UFtbdoVdOBttzvDrqCv134q73JoNyyFpdOk8EotHFGroNFxveSIrVweiXtAeeo7BsuMyAw=="
        }
    }
}

url is the immutable, versioned installer. latestUrl is the floating URL from the section above. A platform we do not build is left out of downloads entirely rather than being present with a null, and sha256 or ed25519 can be missing for an older build, so read them defensively.

ed25519 is the same EdDSA signature the appcast carries. See checking what you downloaded for what to do with it.

All five apps in one document:

https://www.codeandweb.com/download/latest.json

That one wraps the same per-app manifests in a products array. If one app's release data cannot be read, that app drops out of the array and the other four still answer.

Manifests and redirects are both sent with Cache-Control: max-age=60, public and Access-Control-Allow-Origin: *, so the manifests are readable from a browser as well as from a build script. The redirects are not: following one cross-origin puts the browser on the installer file itself, which carries no such header, so fetch() rejects. Use the manifests from a browser and the /latest/<platform> URLs from anything that is not one.

The Sparkle appcast

Every app publishes a Sparkle feed, and it covers all four platforms, not only macOS:

https://www.codeandweb.com/releases/<product>/updatecheck.php?o=mac

o takes mac, win or linux and defaults to Windows. ov=flatpak gets the Flatpak, bit=32 the last 32-bit build, lang=de localised release-notes links. Stable releases only, newest first, each enclosure signed with sparkle:edSignature and sparkle:dsaSignature. This is the feed Homebrew reads. There is also /releases/<product>/appcast-mac-release.xml, macOS only, no parameters.

It differs from latest.json in two ways that matter. It stops at a version we set by hand, so a release aimed at new installs can go onto the site without prompting existing customers to update for features they did not ask for. And it honours minimum OS versions: pass the running system as ov=12.0.0 and an old mac is offered the newest release it can actually run, which the latest URLs never do.

Every build is scanned before we upload it

Every installer goes through VirusTotal before it reaches our servers. VirusTotal addresses a file by its SHA-256, the same sha256 the manifest publishes, so the report for any build is a URL you can assemble yourself:

https://www.virustotal.com/gui/file/<sha256>

That scan describes the file when we published it. The sha256 is what proves the bytes you downloaded are the ones we scanned, so verify it anyway.

Checking what you downloaded

Three ways, in the order most people should reach for them.

The code signature. Every installer is signed, and your operating system already knows how to check it. No key from us, nothing to pin. On macOS the signature is a notarized Developer ID:

spctl -a -vvv -t install /Applications/TexturePacker.app
# source=Notarized Developer ID
# origin=Developer ID Application: CodeAndWeb GmbH (8P8584JRFS)

On Windows the installer carries an extended-validation certificate issued to CodeAndWeb GmbH:

(Get-AuthenticodeSignature .\TexturePacker-8.3.0.msi).Status
(Get-AuthenticodeSignature .\TexturePacker-8.3.0.msi).SignerCertificate.Subject
# Valid
# CN=CodeAndWeb GmbH, O=CodeAndWeb GmbH, L=Neu-Ulm, S=Bavaria, C=DE

The sha256. For a build machine, pin the versioned url and its sha256 and compare after downloading, as in the CI recipe below. That catches a truncated or swapped file.

The ed25519 signature. The checksum sits on the same server as the installer, so it cannot tell you that server was not compromised. The signing key is not on it, so the signature can. Our public key, the same one Sparkle uses and the same one already inside every app you have installed:

jN2H7aeSZm8Y3vFbDpD80J5pXpnzfJNq5+Uqj5ryUAI=

Pin that value in your build. Checking a signature against a key you fetched in the same breath proves nothing. Then, with OpenSSL 3:

printf '\x30\x2a\x30\x05\x06\x03\x2b\x65\x70\x03\x21\x00' > key.der
echo "jN2H7aeSZm8Y3vFbDpD80J5pXpnzfJNq5+Uqj5ryUAI=" | base64 -d >> key.der
openssl pkey -pubin -inform DER -in key.der -out key.pem
echo "tmlJXdT9EDV5itPc4RwelMiegDwJQntsv7wMw3Hh3uNXiOcgHda4wLHsguSUhlFTo8rLXPoMcseYtiWx/etTDA==" | base64 -d > sig.bin
openssl pkeyutl -verify -pubin -inkey key.pem -rawin -in TexturePacker-8.3.0.msi -sigfile sig.bin
# Signature Verified Successfully

Those twelve bytes are the DER header for an Ed25519 public key: Sparkle publishes the bare 32-byte key and OpenSSL wants it wrapped. Note the macOS system openssl is LibreSSL and cannot do this; use OpenSSL 3 or any language binding.

Using the URLs in a script

Every example below uses curl -fL, and the -f is not decoration. Without it curl treats an HTTP error as success: curl -sLO .../latest/mac against a 404 exits 0 and writes the error page to disk as a file called mac. With -f it exits non-zero and writes nothing. Test for failure, not for a particular exit code: it is 56 over HTTP/2 and 22 over HTTP/1.1.

-O is the other trap. It names the file after the URL you typed, not the redirect target, so /latest/mac saves a file called mac. Browsers and wget keep the versioned name, curl -O does not. Use -o. The one safe place for -O is the pinned CI recipe below, where the URL already ends in the file name.

In CI: resolve, verify, pin

This is the workflow we would run in a build. Read the manifest once, commit the immutable url and its sha256, and let the build fetch that exact file:

# once, by hand: read "url" and "sha256" out of the manifest
curl -fsSL https://www.codeandweb.com/download/texturepacker/latest.json

# in the build, with the committed values:
curl -fLO "$TP_URL" && echo "$TP_SHA256  $(basename "$TP_URL")" | sha256sum -c

The build is now reproducible, a tampered file fails the checksum, and upgrading is a visible commit rather than something that happens to you on a Tuesday.

The sha256 belongs to url, not to latestUrl. Read the checksum from the manifest and then fetch latestUrl, and a release landing between those two calls looks exactly like a corrupted download. If you want to follow latest, skip the checksum. If you want the checksum, pin the url it came with.

On your own machine: follow latest

For an evaluation, a developer laptop or a throwaway container, following the floating URL is the whole point of it:

curl -fL -o TexturePacker.dmg https://www.codeandweb.com/download/texturepacker/latest/mac

PowerShell

Invoke-WebRequest follows the redirect and fails on an HTTP error on its own, writing nothing to disk, so it needs no equivalent of -f. Do not expect the error to name the status though: against our 404s .NET cannot read the error body and reports WebException: The request was aborted: The connection was closed unexpectedly. Test for failure, not for a message.

Invoke-WebRequest -Uri https://www.codeandweb.com/download/texturepacker/latest/windows -OutFile TexturePacker.msi

Resolve, verify and pin looks like this:

# once, by hand: read the values out of the manifest
$manifest = Invoke-RestMethod https://www.codeandweb.com/download/texturepacker/latest.json
$manifest.downloads.windows.url
$manifest.downloads.windows.sha256

# in the build, with the committed values:
Invoke-WebRequest -Uri $env:TP_URL -OutFile TexturePacker.msi
if ((Get-FileHash TexturePacker.msi -Algorithm SHA256).Hash -ne $env:TP_SHA256) {
    throw "TexturePacker.msi does not match the published checksum"
}

Get-FileHash returns upper-case hex and the manifest publishes lower case. -ne compares case-insensitively, so the line above is right as written. Change it to -cne, or port it to a language that compares bytes, and it fails on every build.

Things to watch out for

Docker caches the layer, not the answer

Docker caches a RUN line by its text alone, and the text of a version-less URL never changes. So a RUN curl .../latest/... layer keeps installing the build it downloaded the first time, months after the redirect moved on. This is the single most common surprise with a floating URL. Prefer ADD with the URL, and when you need the certainty, build with --no-cache or bump a --build-arg that the download line depends on.

Bare linux means Debian packaging

linux is an alias for linux-deb, so it gives you a .deb. That is invisible to somebody on Fedora or Arch who reasonably expected "the Linux build". Ask for linux-flatpak if you want the distro-independent package, and see the table above for which apps have one.

A platform can be retired

A platform token resolves to the newest stable release that shipped that platform, which is not always the newest release. So if we stopped building a .deb, /latest/linux-deb would keep handing you the last one we built, indefinitely and without an error. It will never give you a different package format, but it can silently stop moving.

A 404 means something narrower: we have never shipped that platform for that app, which is why /download/physicseditor/latest/linux-flatpak is a 404 today.

To catch a platform that has stopped moving, watch its per-platform version in latest.json. One release of lag proves nothing, since a release can ship without every platform, but one that stays behind over several releases is no longer being built.

The minimum OS version is not expressed

The in-app updater offers every system the newest release it can run. The latest URLs know nothing about that: they always resolve to the newest stable release. A macOS 12 user who runs the curl line above gets 8.3.0, which may need a newer system. For an older system, take the version from the product's FAQ entry, for example TexturePacker.

A license covers a date range, not a version range

Single User and Volume licenses are perpetual and cover every release, major or minor, published inside their update window: twelve months from purchase, or forever with a Lifetime license. So a major version jump is not itself the problem. A build published after that window closed is, and following latest is a good way to meet one without noticing.

Those licenses also do not permit use on a server or in an automated build at all. The floating Docker/CI license does, and it always permits the newest version, which is what makes it the right one to put behind a latest URL. See Docker and CI installation.

Reserved, and not available today

These shapes are reserved so the contract can grow without breaking. All of them return 404 right now. Do not write them into a script expecting them to start working:

ShapeIntended for
mac-arm64, mac-x64separate Apple Silicon and Intel builds, if we ever stop shipping universal binaries
/download/<product>/beta/<platform>the newest beta instead of the newest stable
/download/<product>/<major>/latest/<platform>the newest release within one major version

win64 is deliberately not a token and will keep returning 404. A URL with "64" in the name must never be able to hand somebody a 32-bit build, and the windows token resolves to whichever Windows build a release actually carries.

Package managers

Homebrew already tracks TexturePacker and BabelEdit through the Sparkle appcast and computes its own checksums, so nothing here changes for brew install. Chocolatey and winget have nothing, because neither of them speaks Sparkle. That is the gap these URLs exist to close, and it is a format gap rather than a platform one: the appcast has carried Windows and Linux builds for years, but only in an RSS dialect written for one updater framework.