TL;DR: I built MagicKit — a free AI toolbox for image generation, AI writing, and video making. No sign-up, no API key, no paywall. The whole thing is open source on GitHub.
Why I built this
Every AI tool these days wants you to sign up, hand over an API key, or subscribe before you can even try it. I wanted the opposite: open the page and just create.
So I spent a few evenings building MagicKit — three tools in one page:
- 🖼️ AI Image Generator — text-to-image with the FLUX model, multiple aspect ratios
- ✍️ AI Writer — scripts, copywriting, naming, translation
- 🎬 AI Video Maker — combine generated images into a short video
The stack (boring on purpose)
| Layer | Choice | Why |
|---|---|---|
| Backend | Node.js + Express | One file, easy to deploy |
| Frontend | Pure HTML/CSS/JS | No build step, no framework bloat |
| AI | Pollinations free API | No key required |
| Video | FFmpeg | Battle-tested, runs on a tiny VPS |
The entire backend sits at around 60 MB RAM, because my server only has 1.6 GB to work with.
The hard parts
1. Aggressive rate limits
The free image API only allows one queued request per IP. Concurrent requests instantly return 429 Queue full. My first naive implementation fell over immediately.
The fix:
- A fully serial queue (concurrency = 1)
- A global minimum 3-second interval between requests
- Retry with exponential-ish backoff (up to 5 attempts), detecting 429 responses that come back as tiny error pages instead of real JPEGs
async function generateImageWithRetry(prompt, width, height) {
for (let attempt = 0; attempt < 5; attempt++) {
await globalRateLimitGate(); // 3s minimum spacing
const file = await downloadWithCurl(buildUrl(prompt, width, height));
if (!isRateLimitError(file)) return file;
await sleep(3000 * (attempt + 1)); // 3s, 6s, 9s...
}
throw new Error('Image service busy, please try again');
}
2. socket hang up from the HTTP client
Node's https module kept dropping connections to the image endpoint under slow responses. I replaced it with a curl child process:
curl -L --max-redirs 5 --max-time 120 --connect-timeout 10 -o output.jpg "$URL"
Boring, predictable, and it never hangs half-open.
3. FFmpeg can silently corrupt output
My first video pipeline used zoompan + xfade filters together. On a 2-core box with 1.6 GB RAM, long runs produced truncated, unplayable MP4s.
The reliable version uses the concat demuxer and a single simple filter for scaling/padding:
ffmpeg -f concat -safe 0 -i list.txt \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,\
pad=1080:1920:(ow-iw)/2:(oh-ih)/2,format=yuv420p" \
-c:v libx264 out.mp4
No fancy transitions, but the file always plays. Lesson: on constrained hardware, finish reliably beats fancy.
4. Memory discipline
1.6 GB RAM means nothing can be buffered in memory. Generated images go straight to disk, videos stream through FFmpeg, and the queue keeps at most one job in flight.
Try it / run it yourself
🔗 Live demo: http://47.80.8.174
💻 Source: https://github.com/kaketiti/magickit
Self-hosting takes about a minute:
git clone https://github.com/kaketiti/magickit.git
cd magickit
npm install
npm start
It's MIT licensed — fork it, remix it, deploy your own.
Honest limitations
- The free image API gets slow during peak hours — that's what the retry queue is for
- Text generation has daily free-tier limits, and the UI tells you plainly when they're exhausted
- Video synthesis takes a few minutes for longer clips
What's next
- Pluggable image backends (so when one free provider is throttled, another takes over)
- Optional self-supplied API keys for power users
- More aspect-ratio presets and a simple gallery
Feedback is genuinely welcome — what would you add first? Drop a comment or open an issue on GitHub.
Top comments (0)