Render clean, transparent AQWorlds character portraits from public charpage data.
AQW Charpage PNG API turns an AQWorlds character page into a centered, transparent PNG portrait. It fetches the character data, resolves equipped item SWFs, renders them through a stripped character viewer, and caches the result for faster repeat requests.
It is built for:
- transparent character PNGs
- AQW equipment rendering
- no pet and no ground item by default
- browser previews with animated loading text
- throttled SWF fetching to avoid hammering
game.aq.com - Docker deployment on hosts like Render
http://localhost:3000/character/Selena
http://localhost:3000/api/character/Selena/png?refresh=1
| Method | Route | Description |
|---|---|---|
GET |
/ |
Small route index. |
GET |
/health |
Health check for production hosts. |
GET |
/character/:name |
Browser preview page for a character. |
GET |
/api/character/:name |
Character JSON, FlashVars, equipment, and asset metadata. |
GET |
/api/character/:name/png |
Transparent PNG portrait. |
GET |
/api/character/:name/compositor |
Item SWF manifest and symbol inspection data. |
GET |
/api/custom-character.swf |
Generated minimal SWF viewer used by the renderer. |
| Option | Example | Result |
|---|---|---|
refresh=1 |
/api/character/Selena/png?refresh=1 |
Forces a fresh render. |
pet=1 |
/api/character/Selena/png?pet=1 |
Includes the pet. |
ground=1 |
/api/character/Selena/png?ground=1 |
Includes the ground item. |
source=viewer |
/api/character/Selena/png?source=viewer |
Uses the older full-viewer cleanup path. |
source=download |
/api/character/Selena/png?source=download |
Uses Downloads/<character>.gif if present locally. |
Requirements:
- Node.js 20+
- Python 3 with Pillow
- Chromium for Playwright
Install dependencies:
npm install
npm run install:browsersStart the API:
npm startOpen the preview:
http://localhost:3000/character/Selena
Request a PNG directly:
http://localhost:3000/api/character/Selena/png?refresh=1
Build the image:
docker build -t aqw-charpage-png-api .Run it locally:
docker run --rm -p 3000:3000 aqw-charpage-png-apiThen open:
http://localhost:3000/character/Selena
Render works best with the included Dockerfile because this project needs browser rendering support.
Use these settings:
| Setting | Value |
|---|---|
| Service type | Web Service |
| Runtime | Docker |
| Branch | main |
| Root directory | Leave blank |
| Dockerfile path | Dockerfile |
| Instance type | Free or higher |
| Health check path | /health |
Recommended environment variables:
PORT=3000
PYTHON_EXE=python3
AQW_FETCH_LIMIT=2
AQW_FETCH_WINDOW_MS=3000
NODE_ENV=production
LOG_TIME_ZONE=Asia/Manila
REQUEST_FILE_LOG=0
After deploy, test:
https://your-service-name.onrender.com/character/Selena
https://your-service-name.onrender.com/api/character/Selena/png?refresh=1
Render free services can sleep after inactivity, and local cache files are not permanent on free instances. First renders after wake-up may be slower.
Uncached SWFs from game.aq.com are fetched through a queue. Cached files are served immediately.
Default behavior:
AQW_FETCH_LIMIT=2
AQW_FETCH_WINDOW_MS=3000
That means only 2 AQW game-file requests begin every 3 seconds. If AQW starts returning rate limits, slow it down:
AQW_FETCH_LIMIT=1
AQW_FETCH_WINDOW_MS=5000
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
HTTP port for the API. |
PYTHON_EXE |
python3 on Linux, python on Windows |
Python executable used for image cleanup. |
CHROME_EXE |
auto-detected | Optional explicit Chromium or Chrome executable path. |
AQW_FETCH_LIMIT |
2 |
Number of AQW SWF fetches allowed per throttle window. |
AQW_FETCH_WINDOW_MS |
3000 |
Throttle window duration in milliseconds. |
LOG_TIME_ZONE |
Asia/Manila |
Time zone used in character request logs. |
REQUEST_FILE_LOG |
local: 1, production: 0 |
Set to 1 to also write .cache/logs/requests.log; console logs are always enabled. |
RENDER_CUSTOM_NETWORK_IDLE_MS |
1200 |
Custom viewer network wait before screenshot capture. |
RENDER_CUSTOM_SETTLE_MS |
1800 |
Custom viewer settle wait before screenshot capture. |
Generated and downloaded files are stored under .cache/:
.cache/aqw-gamefiles
.cache/renders
.cache/ruffle
.cache/logs
These files are intentionally ignored by Git. Keep the source clean and let the app rebuild cache as needed.
Character routes log the requested username, IP address, time, and date to stdout for Render or Docker logs:
Username: Selena
IP Address: 127.0.0.1
Time: 01:13:00 PM
Date: 2026-05-04
Set REQUEST_FILE_LOG=1 if you also want local file logs in .cache/logs/requests.log.
.
|-- Dockerfile
|-- README.md
|-- package.json
`-- src
|-- compositor.js
|-- custom-swf.js
|-- render-gif.mjs
`-- server.js
This project does not bundle AQWorlds assets. It fetches public game files on demand and caches them locally for rendering. Use the throttle settings responsibly when deploying publicly.
This project is licensed under the MIT License.
AQWorlds, AdventureQuest Worlds, and related game assets belong to Artix Entertainment.
This project does not bundle AQWorlds assets; it fetches public assets on demand.
This project is not affiliated with, endorsed by, sponsored by, or connected to Artix Entertainment, LLC.
AQWorlds, AdventureQuest Worlds, Artix Entertainment, and all related names, logos, characters, artwork, game files, and assets are the property of their respective owners. All rights belong to Artix Entertainment and the rightful copyright holders.
This project is made for entertainment and educational purposes only.