Skip to content

AI Image Generator — JavaScript source

Turn a text prompt into a 1024×1024 image with FLUX.1 [schnell] on Cloudflare Workers AI. No account, no API key — rate-limited for fair use. Your prompt goes to the model through our Worker; we store no prompts and no images.

This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

/**
 * AI Image Generator — prompt validation, D1 usage-gate verdicts, and
 * ?prompt= URL state for FLUX.1-schnell image generation.
 *
 * Language: JavaScript (ES2022, standard library only)
 * Source:   CosmoDev polyglot showcase port of the AI Image Generator tool,
 *           from src/lib/image-gen.ts (the canonical TypeScript implementation).
 */

export const MODEL = '@cf/black-forest-labs/flux-1-schnell';
export const STEPS = 4; // flux-1-schnell's design point -> 57.6 neurons/image
export const PROMPT_MAX_CHARS = 600; // UX clamp, below the model's 2048 limit
export const IP_HOUR_CAP = 10;
export const DAILY_CAP = 100;

/** Control chars except \n: C0 minus U+000A, DEL, and C1. */
const CONTROL_CHARS = /[\x00-\x09\x0B-\x1F\x7F-\x9F]/;

export function validatePrompt(raw) {
  // Normalize CRLF/CR first so pasted text keeps its line structure.
  const prompt = raw.replace(/\r\n?/g, '\n').trim();
  if (prompt.length === 0) return { ok: false, reason: 'empty' };
  if (prompt.length > PROMPT_MAX_CHARS) return { ok: false, reason: 'tooLong' };
  if (CONTROL_CHARS.test(prompt)) return { ok: false, reason: 'controlChars' };
  return { ok: true, prompt };
}

/** Minutes (>= 1) until the next UTC midnight — the daily window reset. */
function minutesToUtcMidnight(now) {
  const d = new Date(now);
  const nextMidnight = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() + 1);
  return Math.max(1, Math.ceil((nextMidnight - now) / 60_000));
}

export function checkGate(ipCount, dailyCount, now = Date.now()) {
  if (dailyCount >= DAILY_CAP) {
    return {
      ok: false,
      error: 'RATE_LIMITED_DAILY',
      retryAfterMinutes: minutesToUtcMidnight(now),
    };
  }
  if (ipCount >= IP_HOUR_CAP) {
    return { ok: false, error: 'RATE_LIMITED_IP', retryAfterMinutes: 60 };
  }
  return { ok: true };
}

/** Encode the shareable state: '' when there is nothing to share. */
export function encodeUrlState(prompt) {
  return prompt ? `?prompt=${encodeURIComponent(prompt)}` : '';
}

/** Inverse of encodeUrlState — a missing param decodes to ''. */
export function decodeUrlState(search) {
  return new URLSearchParams(search).get('prompt') ?? '';
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →