mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
docs(free-tiers): richer budget-card image (28 models + first-month strip) + soften ToS framing to caution (#3284)
- Regenerate the README/dashboard mockup from the catalog: 28 pools in the grid
(was 9), a balance-floored stacked bar (Mistral now ~40% of the bar, was ~90%),
and a first-month signup-credit strip (~586M). Add the data-driven generator.
- FREE_TIERS.md: drop the alarming '🚫 Avoid / terms prohibit' framing — relabel
those 19 providers as 'caution — worth checking', note their access is real and
the OAuth/keyless ones aren't token-quantifiable (so out of the headline, not
excluded as unusable).
This commit is contained in:
committed by
GitHub
parent
a7e445edea
commit
7abb40c64c
@@ -32,15 +32,18 @@ Biggest **documented** contributors: `mistral` 1.00B, `longcat` 150M, `cloudflar
|
||||
- Numbers are **upper-bound estimates** from each provider's documented free-tier limits as of **2026-06-05**, gathered by web research (confidence tagged per row). Free tiers change constantly — re-verify before relying on a figure.
|
||||
- `estMonthlyFreeTokens` = recurring monthly tokens only. **One-time signup credits do not recur** and count as 0 (29 providers are signup-credit-only). Discontinued tiers (6) are also 0.
|
||||
- Daily token cap → `monthly = daily × 30`. Only RPD documented → `RPD × ~800 output tokens × 30`. Only RPM/TPM (no daily cap) → treated as **theoretical**, excluded from the defensible total.
|
||||
- **ToS matters as much as quota.** 19 providers' terms **prohibit** routing through a self-hosted proxy or forbid non-personal use — see the [ToS attention table](#tos-attention-table). A free quota you are not allowed to proxy is not usable headroom.
|
||||
- **A note on terms.** ~19 providers have personal-use or proxy clauses worth a glance before you lean on them (see the [provider-terms table](#tos-attention-table)). Their access is real — we simply don't fold the **un-quantifiable** OAuth/keyless ones (e.g. `gemini-cli`, `agy`, `amazon-q` — they share quota already counted under the base provider) into the headline. None of this is legal advice; you decide.
|
||||
|
||||
---
|
||||
|
||||
## ToS attention table
|
||||
|
||||
> Whether a self-hosted, single-user personal proxy may use each free tier. `avoid` = terms prohibit proxy/non-personal use; `caution`/`ambiguous` = gray area; `ok` = explicitly permitted. Informational, not legal advice.
|
||||
> A quick read on each provider's terms for a self-hosted, single-user personal proxy. `caution` = a personal-use or proxy clause worth checking; `ambiguous` = unclear; `ok` = explicitly permitted. Informational, not legal advice — you decide.
|
||||
|
||||
### ⚠️ Caution — personal-use / proxy clauses worth checking (19)
|
||||
|
||||
> Their free access is real and OmniRoute can route to them; the clauses below are just worth knowing. The OAuth/keyless ones aren't token-quantifiable, so they're not in the headline number (not because they're unusable).
|
||||
|
||||
### 🚫 Avoid — terms prohibit proxy / non-personal use (19)
|
||||
|
||||
| Provider | Note |
|
||||
|---|---|
|
||||
@@ -64,7 +67,7 @@ Biggest **documented** contributors: `mistral` 1.00B, `longcat` 150M, `cloudflar
|
||||
| `qwen-web` | The free OAuth tier is discontinued; no ToS permits a self-hosted proxy using session tokens against chat.qwen.ai. Even before shutdown, automated/pr… |
|
||||
| `t3-web` | ToS explicitly restricts accounts to personal use only, prohibits credential sharing with third parties, and bans automated/bot/scraping access — a s… |
|
||||
|
||||
### ⚠️ Caution / ambiguous / ok (the rest)
|
||||
### ✅ Generally permissive — caution / ambiguous / ok (the rest)
|
||||
|
||||
| Provider | ToS | Note |
|
||||
|---|---|---|
|
||||
@@ -183,61 +186,61 @@ Biggest **documented** contributors: `mistral` 1.00B, `longcat` 150M, `cloudflar
|
||||
| `huggingchat` | llm-chat | recurring-monthly | 500K | med | caution | HuggingChat free tier provides $0.10/month in Hugging Face Inference Provider credits (recurring monthly). The previous… |
|
||||
| `morph` | llm-code | recurring-monthly | 400K | med | caution | Morph offers a free tier with 200 requests/month and 250K credits, described as intended for testing and personal proje… |
|
||||
| `huggingface` | aggregator | recurring-monthly | 200K | high | caution | Free HuggingFace accounts receive $0.10/month in recurring Inference Provider credits (explicitly "subject to change") … |
|
||||
| `kiro` | llm-code | recurring-monthly | 25K | high | avoid | Kiro AI offers a perpetual free tier of 50 credits/month (recurring, resets each billing cycle, unused credits do not c… |
|
||||
| `kiro` | llm-code | recurring-monthly | 25K | high | caution | Kiro AI offers a perpetual free tier of 50 credits/month (recurring, resets each billing cycle, unused credits do not c… |
|
||||
| `360ai` | llm-chat | one-time-trial-credit | — | low | unknown | 360 AI (360智脑) API requires formal application and approval to access. New users historically received a one-time promo… |
|
||||
| `agentrouter` | aggregator | one-time-trial-credit | — | low | caution | AgentRouter offers a one-time credit on signup ($100 for standard, $200 via referral) to use across 30+ LLM providers v… |
|
||||
| `agy` | llm-code | account-oauth | — | med | avoid | Antigravity CLI (agy) offers a free tier requiring OAuth login with a personal Google account, with a weekly-based rate… |
|
||||
| `ai21` | llm-chat | one-time-trial-credit | — | med | avoid | AI21 Labs offers new accounts $10 in trial credits valid for 7 days (no credit card required); after expiry, pay-as-you… |
|
||||
| `agy` | llm-code | account-oauth | — | med | caution | Antigravity CLI (agy) offers a free tier requiring OAuth login with a personal Google account, with a weekly-based rate… |
|
||||
| `ai21` | llm-chat | one-time-trial-credit | — | med | caution | AI21 Labs offers new accounts $10 in trial credits valid for 7 days (no credit card required); after expiry, pay-as-you… |
|
||||
| `aimlapi` | aggregator | discontinued | — | high | ambiguous | The free tier is officially paused as of mid-2025 (docs last updated ~May 2026). AI/ML API now operates exclusively on … |
|
||||
| `amazon-q` | llm-code | discontinued | — | high | avoid | Amazon Q Developer is discontinued for new signups as of May 15, 2026 — both free tier and paid subscriptions can no lo… |
|
||||
| `amazon-q` | llm-code | discontinued | — | high | caution | Amazon Q Developer is discontinued for new signups as of May 15, 2026 — both free tier and paid subscriptions can no lo… |
|
||||
| `baichuan` | llm-chat | one-time-trial-credit | — | med | ambiguous | Baichuan operates on a pay-as-you-go model with a one-time 80 CNY (~$11 USD) trial credit for new accounts (valid 3 mon… |
|
||||
| `baseten` | other | one-time-trial-credit | — | med | caution | Baseten offers $30 one-time trial credits for new workspaces on the Startup (Basic) plan. After those credits are used,… |
|
||||
| `blackbox` | llm-code | keyless-limited | — | med | avoid | Blackbox AI offers a free web/IDE tier with unlimited basic chat but restricts advanced models (GPT-4o, Claude, etc.) t… |
|
||||
| `blackbox` | llm-code | keyless-limited | — | med | caution | Blackbox AI offers a free web/IDE tier with unlimited basic chat but restricts advanced models (GPT-4o, Claude, etc.) t… |
|
||||
| `brave-search` | search | recurring-credit | — | high | caution | As of February 12, 2026, Brave removed its previously free (5,000 queries/month, no card required) plan and replaced it… |
|
||||
| `byteplus` | llm-chat | one-time-trial-credit | — | high | caution | BytePlus ModelArk provides new users a one-time free trial of 500,000 tokens per LLM model (2,000,000 for vision models… |
|
||||
| `bytez` | aggregator | recurring-credit | — | med | ambiguous | Bytez offers $1 in free credits that refresh every 4 weeks (credits expire if unused within the cycle). Free tier is li… |
|
||||
| `chutes` | aggregator | discontinued | — | high | unknown | The free Early Access program (200 requests/day) was officially discontinued on March 15, 2026. Chutes.ai now operates … |
|
||||
| `comfyui` | image | keyless-unlimited | — | high | ok | ComfyUI is a fully open-source (GPL-3.0), self-hosted diffusion model interface that runs entirely on local hardware wi… |
|
||||
| `completions` | aggregator | keyless-unlimited | — | med | avoid | Completions.me claims to offer completely free, unlimited access to Claude Opus 4.6, GPT-5.2, Gemini 3.1 Pro, and 15+ m… |
|
||||
| `coze` | aggregator | recurring-daily | — | med | avoid | Coze's free plan provides 10 message credits per day — a platform-level unit (not raw LLM tokens) where each model call… |
|
||||
| `completions` | aggregator | keyless-unlimited | — | med | caution | Completions.me claims to offer completely free, unlimited access to Claude Opus 4.6, GPT-5.2, Gemini 3.1 Pro, and 15+ m… |
|
||||
| `coze` | aggregator | recurring-daily | — | med | caution | Coze's free plan provides 10 message credits per day — a platform-level unit (not raw LLM tokens) where each model call… |
|
||||
| `deepinfra` | aggregator | one-time-trial-credit | — | med | caution | DeepInfra is a pay-as-you-go inference provider that explicitly requires a credit card or prepayment to use services; a… |
|
||||
| `deepseek` | llm-chat | one-time-trial-credit | — | high | caution | DeepSeek offers a one-time signup credit of 5 million tokens (no credit card required) valid for 30 days from account c… |
|
||||
| `dify` | other | one-time-trial-credit | — | med | caution | Dify Cloud offers a Sandbox (free) plan with 200 message credits (one-time trial for testing with bundled LLM keys), 5 … |
|
||||
| `duckduckgo-web` | llm-chat | keyless-limited | — | high | avoid | Duck.ai is free and keyless (no account or API key required), with anonymous daily usage limits that DuckDuckGo deliber… |
|
||||
| `duckduckgo-web` | llm-chat | keyless-limited | — | high | caution | Duck.ai is free and keyless (no account or API key required), with anonymous daily usage limits that DuckDuckGo deliber… |
|
||||
| `exa-search` | search | recurring-monthly | — | high | caution | Exa offers a permanently free plan with 1,000 search requests per month (no expiration), with contents (text and highli… |
|
||||
| `featherless-ai` | llm-chat | discontinued | — | high | avoid | Featherless AI has no free tier or free trial for general users as of June 2026. Paid subscriptions start at $10/month … |
|
||||
| `featherless-ai` | llm-chat | discontinued | — | high | caution | Featherless AI has no free tier or free trial for general users as of June 2026. Paid subscriptions start at $10/month … |
|
||||
| `firecrawl` | tool | recurring-monthly | — | high | caution | Firecrawl offers a free plan with 1,000 credits per month (1 credit = 1 page scraped), 2 concurrent requests, and low r… |
|
||||
| `fireworks` | llm-chat | one-time-trial-credit | — | high | avoid | Fireworks AI offers $1 in one-time starter credits on signup; no recurring free tier exists. Without a payment method o… |
|
||||
| `fireworks` | llm-chat | one-time-trial-credit | — | high | caution | Fireworks AI offers $1 in one-time starter credits on signup; no recurring free tier exists. Without a payment method o… |
|
||||
| `freemodel-dev` | llm-chat | one-time-trial-credit | — | low | unknown | FreeModel.dev (domain registered April 30, 2026) offers $300 in one-time free credits on signup with no payment info re… |
|
||||
| `friendliai` | llm-chat | keyless-limited | — | med | avoid | FriendliAI offers a Tier 0 account for new signups with adaptive (dynamically throttled) rate limits and 8K max output … |
|
||||
| `gemini-cli` | llm-chat | account-oauth | — | high | avoid | Gemini CLI's free tier (Google Account OAuth, 1,000 req/day, 60 RPM) is being deprecated on June 18, 2026 for all non-e… |
|
||||
| `friendliai` | llm-chat | keyless-limited | — | med | caution | FriendliAI offers a Tier 0 account for new signups with adaptive (dynamically throttled) rate limits and 8K max output … |
|
||||
| `gemini-cli` | llm-chat | account-oauth | — | high | caution | Gemini CLI's free tier (Google Account OAuth, 1,000 req/day, 60 RPM) is being deprecated on June 18, 2026 for all non-e… |
|
||||
| `gitlawb` | aggregator | unknown | — | low | unknown | The original free MiMo (xiaomi/mimo-v2.5) model was revoked server-side around May 24, 2026. As of June 2026 the platfo… |
|
||||
| `gitlawb-gmi` | llm-chat | keyless-limited | — | med | ambiguous | As of June 2026, Gitlawb Opengateway is primarily a pay-as-you-go credit-balance gateway; the only recurring-free model… |
|
||||
| `glhf` | llm-chat | one-time-trial-credit | — | med | caution | GLHF Chat ended its free beta in January 2025 and moved to pay-as-you-go pricing (per-token, no subscription required).… |
|
||||
| `hackclub` | aggregator | account-oauth | — | med | caution | Free AI API access for Hack Club members via OAuth sign-in; no public rate limit numbers documented. Provides 30+ model… |
|
||||
| `hyperbolic` | llm-chat | one-time-trial-credit | — | med | caution | Hyperbolic gives new users $1 in one-time trial credits on signup, with a Basic plan rate limit of 60 RPM; upgrading to… |
|
||||
| `iflytek` | llm-chat | keyless-limited | — | med | avoid | Spark Lite remains permanently free as of June 2026, with unlimited tokens but a 2 QPS (≈120 RPM) rate limit per App ID… |
|
||||
| `iflytek` | llm-chat | keyless-limited | — | med | caution | Spark Lite remains permanently free as of June 2026, with unlimited tokens but a 2 QPS (≈120 RPM) rate limit per App ID… |
|
||||
| `inference-net` | llm-chat | recurring-monthly | — | med | caution | Inference.net currently offers a free plan ($0 forever) with $1 in recurring monthly credits that can be spent on pay-a… |
|
||||
| `jina-ai` | search | one-time-trial-credit | — | med | caution | New API keys receive 10 million free tokens (one-time, non-commercial) usable across all Jina AI endpoints (embeddings,… |
|
||||
| `jina-reader` | web-reverse | keyless-limited | — | med | caution | Jina Reader is freely accessible without any API key at 20 RPM (keyless, rate-limited by IP). New accounts registering … |
|
||||
| `kluster` | llm-chat | one-time-trial-credit | — | med | ambiguous | New users receive $5 in free credits on signup and email verification; multiple sources also indicate a permanent free … |
|
||||
| `liquid` | llm-chat | unknown | — | high | unknown | Liquid AI does not currently offer a hosted API of their own; models are open-source and available via Hugging Face, LE… |
|
||||
| `modal` | other | recurring-monthly | — | high | avoid | Modal's Starter plan gives every account $30/month in recurring free compute credits (GPU + CPU per-second billing), wi… |
|
||||
| `modal` | other | recurring-monthly | — | high | caution | Modal's Starter plan gives every account $30/month in recurring free compute credits (GPU + CPU per-second billing), wi… |
|
||||
| `monsterapi` | llm-chat | one-time-trial-credit | — | low | ambiguous | MonsterAPI offers a free tier that gives new users one-time trial credits upon signup (no credit card required), but th… |
|
||||
| `muse-spark-web` | llm-chat | account-oauth | — | high | avoid | Meta AI at meta.ai is free for any user with a Meta/Facebook account, with no published hard rate or token limits for c… |
|
||||
| `muse-spark-web` | llm-chat | account-oauth | — | high | caution | Meta AI at meta.ai is free for any user with a Meta/Facebook account, with no published hard rate or token limits for c… |
|
||||
| `nebius` | llm-chat | one-time-trial-credit | — | med | caution | Nebius AI Studio (Token Factory) offers ~$1 in one-time trial credits to new signups with no credit card required, givi… |
|
||||
| `nlpcloud` | llm-chat | recurring-monthly | — | med | avoid | NLP Cloud offers a permanent recurring free plan with 10,000 API requests per month at up to 3 requests per minute, wit… |
|
||||
| `nlpcloud` | llm-chat | recurring-monthly | — | med | caution | NLP Cloud offers a permanent recurring free plan with 10,000 API requests per month at up to 3 requests per minute, wit… |
|
||||
| `nomic` | embeddings | one-time-trial-credit | — | med | caution | Nomic offers a one-time free allowance of 1 million tokens for the Embed API; after that, a paid subscription is requir… |
|
||||
| `nous-research` | aggregator | recurring-credit | — | med | ambiguous | Nous Portal (launched April 27, 2026) offers a free tier at $0/month with $0.10 in monthly recurring credits, plus perm… |
|
||||
| `novita` | aggregator | one-time-trial-credit | — | med | caution | Novita AI provides $0.50 one-time trial credits upon signup with a 60 RPM rate limit; no recurring free tier exists, th… |
|
||||
| `nscale` | llm-chat | one-time-trial-credit | — | med | caution | nScale offers $5 in free credits to every new user signing up for their serverless inference API; this is a one-time tr… |
|
||||
| `opencode` | llm-code | keyless-limited | — | med | avoid | OpenCode is an open-source AI coding agent (client tool); its companion hosted service "OpenCode Go" offers a free tier… |
|
||||
| `opencode` | llm-code | keyless-limited | — | med | caution | OpenCode is an open-source AI coding agent (client tool); its companion hosted service "OpenCode Go" offers a free tier… |
|
||||
| `phind` | llm-code | discontinued | — | high | unknown | Phind permanently shut down on January 16, 2026, without advance notice, just over a month after raising $10M in fundin… |
|
||||
| `pollinations` | aggregator | keyless-limited | — | med | caution | Pollinations AI provides a keyless public API (no signup required for basic access) for image, text, audio, and video g… |
|
||||
| `predibase` | llm-code | one-time-trial-credit | — | med | caution | Predibase was acquired by Rubrik in June/July 2025 and its main domain now redirects to Rubrik marketing pages. The pro… |
|
||||
| `puter` | aggregator | account-oauth | — | med | caution | Puter provides 500+ AI models (GPT, Claude, Gemini, Llama, DeepSeek, Grok, etc.) via an OpenAI-compatible endpoint at a… |
|
||||
| `qoder` | llm-code | one-time-trial-credit | — | med | caution | Qoder offers a free Community Edition (launched April 30, 2026) that includes unlimited code completions/next-edit sugg… |
|
||||
| `qwen-web` | llm-chat | discontinued | — | high | avoid | The Qwen OAuth free tier (which powered token-based API access to chat.qwen.ai) was discontinued on April 15, 2026. New… |
|
||||
| `qwen-web` | llm-chat | discontinued | — | high | caution | The Qwen OAuth free tier (which powered token-based API access to chat.qwen.ai) was discontinued on April 15, 2026. New… |
|
||||
| `reka` | llm-chat | recurring-monthly | — | med | caution | Reka offers $10/month in recurring free API credits (refreshed at the start of each month) usable across all API featur… |
|
||||
| `scaleway` | llm-chat | one-time-trial-credit | — | med | ok | New Scaleway accounts receive 1,000,000 free tokens (plus 60 minutes of audio transcription) as a one-time trial credit… |
|
||||
| `sdwebui` | image | keyless-unlimited | — | high | ok | AUTOMATIC1111 Stable Diffusion WebUI is a free, open-source (AGPL-3.0) self-hosted web UI for Stable Diffusion image ge… |
|
||||
@@ -245,7 +248,7 @@ Biggest **documented** contributors: `mistral` 1.00B, `longcat` 150M, `cloudflar
|
||||
| `sensenova` | llm-chat | one-time-trial-credit | — | med | caution | As of June 2026, SenseNova offers a limited-time free public beta ("Token Plan") giving developers 1,500 API calls per … |
|
||||
| `serper-search` | search | one-time-trial-credit | — | high | caution | Serper offers 2,500 free queries as a one-time trial with no credit card required. These credits do not renew — after e… |
|
||||
| `stepfun` | llm-chat | one-time-trial-credit | — | med | ambiguous | StepFun's platform (platform.stepfun.ai / platform.stepfun.com) no longer offers free LLM model access — all LLM API ca… |
|
||||
| `t3-web` | aggregator | recurring-daily | — | med | avoid | t3.chat offers a free tier with limited daily messages (exact count undisclosed) across a restricted set of models, res… |
|
||||
| `t3-web` | aggregator | recurring-daily | — | med | caution | t3.chat offers a free tier with limited daily messages (exact count undisclosed) across a restricted set of models, res… |
|
||||
| `tavily-search` | search | recurring-monthly | — | high | caution | Tavily offers 1,000 free API credits per month with no credit card required. Credits cover basic search (1 credit each)… |
|
||||
| `theoldllm` | llm-chat | keyless-unlimited | — | low | unknown | The Old LLM is a keyless, no-signup web chat UI hosted on Vercel that claims unlimited free access to 60+ AI models, bu… |
|
||||
| `together` | llm-chat | one-time-trial-credit | — | med | caution | Together AI offers a one-time trial credit (reported as $25 by third-party aggregators, though official billing docs sa… |
|
||||
|
||||
@@ -1,59 +1,123 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="430" viewBox="0 0 760 430" font-family="-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif">
|
||||
<rect width="760" height="430" rx="14" fill="#0d1117"/>
|
||||
<rect x="16" y="16" width="728" height="398" rx="12" fill="#161b22" stroke="#30363d"/>
|
||||
|
||||
<!-- header -->
|
||||
<text x="36" y="56" fill="#e6edf3" font-size="17" font-weight="700">Monthly free-token budget</text>
|
||||
<text x="724" y="56" fill="#7d8590" font-size="13" text-anchor="end">1.86B remaining · 98% of 1.90B</text>
|
||||
|
||||
<!-- stacked bar (segments ∝ pool-deduped budget) -->
|
||||
<g>
|
||||
<rect x="36" y="76" width="688" height="16" rx="8" fill="#21262d"/>
|
||||
<clipPath id="bar"><rect x="36" y="76" width="688" height="16" rx="8"/></clipPath>
|
||||
<g clip-path="url(#bar)">
|
||||
<rect x="36" y="76" width="472" height="16" fill="#6c5ce7"/>
|
||||
<rect x="508" y="76" width="71" height="16" fill="#00b894"/>
|
||||
<rect x="579" y="76" width="58" height="16" fill="#0984e3"/>
|
||||
<rect x="637" y="76" width="28" height="16" fill="#e17055"/>
|
||||
<rect x="665" y="76" width="28" height="16" fill="#fdcb6e"/>
|
||||
<rect x="693" y="76" width="14" height="16" fill="#e84393"/>
|
||||
<rect x="707" y="76" width="9" height="16" fill="#00cec9"/>
|
||||
<rect x="716" y="76" width="8" height="16" fill="#d63031"/>
|
||||
</g>
|
||||
</g>
|
||||
<text x="36" y="116" fill="#7d8590" font-size="12.5">Up to <tspan fill="#3fb950" font-weight="600">~2.5B</tspan> in your first month with signup credits · stretched further by RTK + Caveman compression</text>
|
||||
|
||||
<!-- per-model legend grid (3 cols) -->
|
||||
<g font-size="13" fill="#c9d1d9">
|
||||
<!-- row 1 -->
|
||||
<circle cx="42" cy="158" r="5" fill="#6c5ce7"/><text x="54" y="162">Mistral Large — <tspan fill="#7d8590">1.0B</tspan></text>
|
||||
<circle cx="282" cy="158" r="5" fill="#00b894"/><text x="294" y="162">LongCat 2.0 — <tspan fill="#7d8590">150M</tspan></text>
|
||||
<circle cx="522" cy="158" r="5" fill="#0984e3"/><text x="534" y="162">Cloudflare WAI — <tspan fill="#7d8590">122M</tspan></text>
|
||||
<!-- row 2 -->
|
||||
<circle cx="42" cy="190" r="5" fill="#e17055"/><text x="54" y="194">Gemini 2.5 Flash — <tspan fill="#7d8590">60M</tspan></text>
|
||||
<circle cx="282" cy="190" r="5" fill="#fdcb6e"/><text x="294" y="194">Doubao — <tspan fill="#7d8590">60M</tspan></text>
|
||||
<circle cx="522" cy="190" r="5" fill="#e84393"/><text x="534" y="194">Cerebras Qwen3 — <tspan fill="#7d8590">30M</tspan></text>
|
||||
<!-- row 3 -->
|
||||
<circle cx="42" cy="222" r="5" fill="#00cec9"/><text x="54" y="226">GitHub Models — <tspan fill="#7d8590">18M</tspan></text>
|
||||
<circle cx="282" cy="222" r="5" fill="#d63031"/><text x="294" y="226">Groq Llama 3.3 — <tspan fill="#7d8590">15M</tspan></text>
|
||||
<circle cx="522" cy="222" r="5" fill="#636e72"/><text x="534" y="226">OpenRouter :free — <tspan fill="#7d8590">1.2M</tspan></text>
|
||||
</g>
|
||||
|
||||
<line x1="36" y1="252" x2="724" y2="252" stroke="#30363d"/>
|
||||
|
||||
<!-- three honest tiers -->
|
||||
<g>
|
||||
<text x="36" y="284" fill="#7d8590" font-size="12">Steady / month</text>
|
||||
<text x="36" y="312" fill="#e6edf3" font-size="22" font-weight="700">~1.94B</text>
|
||||
<text x="282" y="284" fill="#7d8590" font-size="12">First month (+ signup credits)</text>
|
||||
<text x="282" y="312" fill="#3fb950" font-size="22" font-weight="700">~2.53B</text>
|
||||
<text x="522" y="284" fill="#7d8590" font-size="12">Pools · models</text>
|
||||
<text x="522" y="312" fill="#e6edf3" font-size="22" font-weight="700">50 · 530</text>
|
||||
</g>
|
||||
|
||||
<!-- footer note -->
|
||||
<rect x="36" y="338" width="688" height="40" rx="8" fill="#1c2230" stroke="#30363d"/>
|
||||
<text x="50" y="363" fill="#d29922" font-size="12.5">⚠ 19 providers are ToS-restricted (proxy not permitted) and excluded · figures are pool-deduped — no inflated rate-limit ceilings.</text>
|
||||
|
||||
<text x="724" y="400" fill="#484f58" font-size="10.5" text-anchor="end">OmniRoute · /dashboard/free-tiers · preview mockup</text>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="596" viewBox="0 0 900 596" font-family="-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif">
|
||||
<rect width="900" height="596" rx="16" fill="#0d1117"/>
|
||||
<rect x="16" y="16" width="868" height="580" rx="13" fill="#161b22" stroke="#30363d"/>
|
||||
<text x="868" y="588" fill="#484f58" font-size="10.5" text-anchor="end">OmniRoute · /dashboard/free-tiers · preview mockup</text>
|
||||
<text x="32" y="50" fill="#e6edf3" font-size="18" font-weight="700">Monthly free-token budget</text>
|
||||
<text x="868" y="50" fill="#7d8590" font-size="13" text-anchor="end">31 free pools · 530 models · one endpoint</text>
|
||||
<text x="32" y="84" fill="#7d8590" font-size="11.5">Steady / month</text>
|
||||
<text x="32" y="114" fill="#e6edf3" font-size="27" font-weight="800">~1.94B</text>
|
||||
<text x="330" y="84" fill="#7d8590" font-size="11.5">First month (+ signup credits)</text>
|
||||
<text x="330" y="114" fill="#3fb950" font-size="27" font-weight="800">~2.53B</text>
|
||||
<text x="700" y="84" fill="#7d8590" font-size="11.5">ToS-flagged (you decide)</text>
|
||||
<text x="700" y="114" fill="#d29922" font-size="27" font-weight="800">17 providers</text>
|
||||
<clipPath id="bar"><rect x="32" y="132" width="836" height="16" rx="8"/></clipPath>
|
||||
<g clip-path="url(#bar)"><rect x="32" y="132" width="836" height="16" fill="#21262d"/>
|
||||
<rect x="32.0" y="132" width="337.5" height="16" fill="#6c5ce7"/>
|
||||
<rect x="368.9" y="132" width="57.1" height="16" fill="#00b894"/>
|
||||
<rect x="425.3" y="132" width="47.8" height="16" fill="#0984e3"/>
|
||||
<rect x="472.6" y="132" width="47.2" height="16" fill="#e17055"/>
|
||||
<rect x="519.2" y="132" width="47.2" height="16" fill="#fdcb6e"/>
|
||||
<rect x="565.7" y="132" width="27.4" height="16" fill="#e84393"/>
|
||||
<rect x="592.5" y="132" width="27.4" height="16" fill="#00cec9"/>
|
||||
<rect x="619.3" y="132" width="17.5" height="16" fill="#d63031"/>
|
||||
<rect x="636.2" y="132" width="15.8" height="16" fill="#a29bfe"/>
|
||||
<rect x="651.5" y="132" width="15.8" height="16" fill="#55efc4"/>
|
||||
<rect x="666.7" y="132" width="15.8" height="16" fill="#74b9ff"/>
|
||||
<rect x="682.0" y="132" width="15.8" height="16" fill="#ffeaa7"/>
|
||||
<rect x="697.2" y="132" width="15.8" height="16" fill="#fab1a0"/>
|
||||
<rect x="712.5" y="132" width="15.8" height="16" fill="#81ecec"/>
|
||||
<rect x="727.7" y="132" width="15.5" height="16" fill="#6c5ce7"/>
|
||||
<rect x="742.6" y="132" width="14.2" height="16" fill="#00b894"/>
|
||||
<rect x="756.2" y="132" width="13.5" height="16" fill="#0984e3"/>
|
||||
<rect x="769.1" y="132" width="12.5" height="16" fill="#e17055"/>
|
||||
<rect x="781.1" y="132" width="12.5" height="16" fill="#fdcb6e"/>
|
||||
<rect x="793.0" y="132" width="10.0" height="16" fill="#e84393"/>
|
||||
<rect x="802.4" y="132" width="9.6" height="16" fill="#00cec9"/>
|
||||
<rect x="811.4" y="132" width="9.6" height="16" fill="#d63031"/>
|
||||
<rect x="820.4" y="132" width="9.6" height="16" fill="#a29bfe"/>
|
||||
<rect x="829.4" y="132" width="9.0" height="16" fill="#55efc4"/>
|
||||
<rect x="837.8" y="132" width="8.8" height="16" fill="#74b9ff"/>
|
||||
<rect x="846.0" y="132" width="8.0" height="16" fill="#ffeaa7"/>
|
||||
<rect x="853.4" y="132" width="7.9" height="16" fill="#fab1a0"/>
|
||||
<rect x="860.6" y="132" width="7.8" height="16" fill="#81ecec"/>
|
||||
</g>
|
||||
<text x="32" y="172" fill="#7d8590" font-size="12">Each segment = one free pool · widths floored so every provider shows · honest numbers in the grid.</text>
|
||||
<circle cx="37" cy="196" r="5" fill="#6c5ce7"/>
|
||||
<text x="48" y="200" fill="#c9d1d9" font-size="12.5">Mistral Large 3 <tspan fill="#7d8590">1.00B</tspan></text>
|
||||
<circle cx="250" cy="196" r="5" fill="#00b894"/>
|
||||
<text x="261" y="200" fill="#c9d1d9" font-size="12.5">LongCat Flash-Lite <tspan fill="#7d8590">150M</tspan></text>
|
||||
<circle cx="463" cy="196" r="5" fill="#0984e3"/>
|
||||
<text x="474" y="200" fill="#c9d1d9" font-size="12.5">Llama 3.3 70B <tspan fill="#7d8590">122M</tspan></text>
|
||||
<circle cx="676" cy="196" r="5" fill="#e17055"/>
|
||||
<text x="687" y="200" fill="#c9d1d9" font-size="12.5">Gemini 3.1 Flash Lite Pr <tspan fill="#7d8590">120M</tspan></text>
|
||||
<circle cx="37" cy="226" r="5" fill="#fdcb6e"/>
|
||||
<text x="48" y="230" fill="#c9d1d9" font-size="12.5">Gemini 2.5 Flash Lite <tspan fill="#7d8590">120M</tspan></text>
|
||||
<circle cx="250" cy="226" r="5" fill="#e84393"/>
|
||||
<text x="261" y="230" fill="#c9d1d9" font-size="12.5">Gemini 2.0 Pro Experimen <tspan fill="#7d8590">60M</tspan></text>
|
||||
<circle cx="463" cy="226" r="5" fill="#00cec9"/>
|
||||
<text x="474" y="230" fill="#c9d1d9" font-size="12.5">Doubao Pro 32K <tspan fill="#7d8590">60M</tspan></text>
|
||||
<circle cx="676" cy="226" r="5" fill="#d63031"/>
|
||||
<text x="687" y="230" fill="#c9d1d9" font-size="12.5">GLM 4.7 <tspan fill="#7d8590">30M</tspan></text>
|
||||
<circle cx="37" cy="256" r="5" fill="#a29bfe"/>
|
||||
<text x="48" y="260" fill="#c9d1d9" font-size="12.5">Gemini 2.0 Flash <tspan fill="#7d8590">25M</tspan></text>
|
||||
<circle cx="250" cy="256" r="5" fill="#55efc4"/>
|
||||
<text x="261" y="260" fill="#c9d1d9" font-size="12.5">Gemini 3 Flash Preview <tspan fill="#7d8590">25M</tspan></text>
|
||||
<circle cx="463" cy="256" r="5" fill="#74b9ff"/>
|
||||
<text x="474" y="260" fill="#c9d1d9" font-size="12.5">Gemini 3.5 Flash <tspan fill="#7d8590">25M</tspan></text>
|
||||
<circle cx="676" cy="256" r="5" fill="#ffeaa7"/>
|
||||
<text x="687" y="260" fill="#c9d1d9" font-size="12.5">Gemini 2.5 Flash <tspan fill="#7d8590">25M</tspan></text>
|
||||
<circle cx="37" cy="286" r="5" fill="#fab1a0"/>
|
||||
<text x="48" y="290" fill="#c9d1d9" font-size="12.5">Gemini 2.0 Flash Thinkin <tspan fill="#7d8590">25M</tspan></text>
|
||||
<circle cx="250" cy="286" r="5" fill="#81ecec"/>
|
||||
<text x="261" y="290" fill="#c9d1d9" font-size="12.5">Gemini 1.5 Flash <tspan fill="#7d8590">25M</tspan></text>
|
||||
<circle cx="463" cy="286" r="5" fill="#6c5ce7"/>
|
||||
<text x="474" y="290" fill="#c9d1d9" font-size="12.5">Grok-3 <tspan fill="#7d8590">24M</tspan></text>
|
||||
<circle cx="676" cy="286" r="5" fill="#00b894"/>
|
||||
<text x="687" y="290" fill="#c9d1d9" font-size="12.5">DeepSeek V4 Pro <tspan fill="#7d8590">20M</tspan></text>
|
||||
<circle cx="37" cy="316" r="5" fill="#0984e3"/>
|
||||
<text x="48" y="320" fill="#c9d1d9" font-size="12.5">GPT-4.1 <tspan fill="#7d8590">18M</tspan></text>
|
||||
<circle cx="250" cy="316" r="5" fill="#e17055"/>
|
||||
<text x="261" y="320" fill="#c9d1d9" font-size="12.5">Llama 4 Scout <tspan fill="#7d8590">15M</tspan></text>
|
||||
<circle cx="463" cy="316" r="5" fill="#fdcb6e"/>
|
||||
<text x="474" y="320" fill="#c9d1d9" font-size="12.5">Inclusion Model <tspan fill="#7d8590">15M</tspan></text>
|
||||
<circle cx="676" cy="316" r="5" fill="#e84393"/>
|
||||
<text x="687" y="320" fill="#c9d1d9" font-size="12.5">GPT-4o <tspan fill="#7d8590">7M</tspan></text>
|
||||
<circle cx="37" cy="346" r="5" fill="#00cec9"/>
|
||||
<text x="48" y="350" fill="#c9d1d9" font-size="12.5">Gemini 3.1 Pro Preview <tspan fill="#7d8590">6M</tspan></text>
|
||||
<circle cx="250" cy="346" r="5" fill="#d63031"/>
|
||||
<text x="261" y="350" fill="#c9d1d9" font-size="12.5">Gemini 2.5 Pro <tspan fill="#7d8590">6M</tspan></text>
|
||||
<circle cx="463" cy="346" r="5" fill="#a29bfe"/>
|
||||
<text x="474" y="350" fill="#c9d1d9" font-size="12.5">MiniMax-M2.7 <tspan fill="#7d8590">6M</tspan></text>
|
||||
<circle cx="676" cy="346" r="5" fill="#55efc4"/>
|
||||
<text x="687" y="350" fill="#c9d1d9" font-size="12.5">GPT-4o mini <tspan fill="#7d8590">4M</tspan></text>
|
||||
<circle cx="37" cy="376" r="5" fill="#74b9ff"/>
|
||||
<text x="48" y="380" fill="#c9d1d9" font-size="12.5">Auto Free <tspan fill="#7d8590">4M</tspan></text>
|
||||
<circle cx="250" cy="376" r="5" fill="#ffeaa7"/>
|
||||
<text x="261" y="380" fill="#c9d1d9" font-size="12.5">Auto <tspan fill="#7d8590">1M</tspan></text>
|
||||
<circle cx="463" cy="376" r="5" fill="#fab1a0"/>
|
||||
<text x="474" y="380" fill="#c9d1d9" font-size="12.5">Command A Reasoning <tspan fill="#7d8590">800K</tspan></text>
|
||||
<circle cx="676" cy="376" r="5" fill="#81ecec"/>
|
||||
<text x="687" y="380" fill="#c9d1d9" font-size="12.5">Llama 3.3 70B <tspan fill="#7d8590">500K</tspan></text>
|
||||
<line x1="32" y1="416" x2="868" y2="416" stroke="#30363d"/>
|
||||
<text x="32" y="442" fill="#3fb950" font-size="13" font-weight="700">+ First month: one-time signup credits (~586M)</text>
|
||||
<rect x="32" y="451" width="90" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="77" y="466" fill="#7ee787" font-size="11.5" text-anchor="middle">vertex 300M</text>
|
||||
<rect x="130" y="451" width="123" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="191" y="466" fill="#7ee787" font-size="11.5" text-anchor="middle">agentrouter 200M</text>
|
||||
<rect x="261" y="451" width="96" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="309" y="466" fill="#7ee787" font-size="11.5" text-anchor="middle">together 25M</text>
|
||||
<rect x="365" y="451" width="103" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="417" y="466" fill="#7ee787" font-size="11.5" text-anchor="middle">predibase 25M</text>
|
||||
<rect x="476" y="451" width="70" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="511" y="466" fill="#7ee787" font-size="11.5" text-anchor="middle">ai21 10M</text>
|
||||
<rect x="554" y="451" width="90" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="599" y="466" fill="#7ee787" font-size="11.5" text-anchor="middle">deepseek 5M</text>
|
||||
<rect x="652" y="451" width="83" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="693" y="466" fill="#7ee787" font-size="11.5" text-anchor="middle">kluster 5M</text>
|
||||
<rect x="743" y="451" width="103" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="794" y="466" fill="#7ee787" font-size="11.5" text-anchor="middle">hyperbolic 5M</text>
|
||||
<rect x="32" y="481" width="76" height="22" rx="11" fill="#13311f" stroke="#238636"/>
|
||||
<text x="70" y="496" fill="#7ee787" font-size="11.5" text-anchor="middle">nscale 5M</text>
|
||||
<rect x="32" y="522" width="836" height="34" rx="8" fill="#1c2230" stroke="#30363d"/>
|
||||
<text x="46" y="544" fill="#7d8590" font-size="12">Some providers' terms suggest personal-use only — we flag them so you can decide. Figures are pool-deduped: no inflated rate-limit ceilings.</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 9.7 KiB |
119
scripts/research/gen-budget-card-svg.mjs
Normal file
119
scripts/research/gen-budget-card-svg.mjs
Normal file
@@ -0,0 +1,119 @@
|
||||
// Generates docs/screenshots/free-tier-budget-card.svg from the per-model catalog.
|
||||
// Run: node scripts/research/gen-budget-card-svg.mjs
|
||||
import fs from "node:fs";
|
||||
|
||||
const txt = fs.readFileSync("open-sse/config/freeModelCatalog.data.ts", "utf8");
|
||||
const recs = [
|
||||
...txt.matchAll(
|
||||
/\{ provider: "([^"]+)", modelId: "([^"]+)", displayName: "([^"]+)", monthlyTokens: (\d+), creditTokens: (\d+), freeType: "([^"]+)", poolKey: (null|"[^"]+"), tos: "([^"]+)" \}/g
|
||||
),
|
||||
].map((m) => ({
|
||||
provider: m[1],
|
||||
modelId: m[2],
|
||||
displayName: m[3],
|
||||
monthlyTokens: +m[4],
|
||||
creditTokens: +m[5],
|
||||
freeType: m[6],
|
||||
poolKey: m[7] === "null" ? null : m[7].slice(1, -1),
|
||||
tos: m[8],
|
||||
}));
|
||||
|
||||
const fmt = (n) =>
|
||||
n >= 1e9 ? (n / 1e9).toFixed(2) + "B" : n >= 1e6 ? Math.round(n / 1e6) + "M" : Math.round(n / 1e3) + "K";
|
||||
|
||||
const poolMap = new Map();
|
||||
for (const r of recs) {
|
||||
if (!["recurring-daily", "recurring-monthly", "keyless"].includes(r.freeType)) continue;
|
||||
const k = r.poolKey || `${r.provider}:${r.modelId}`;
|
||||
const cur = poolMap.get(k);
|
||||
if (!cur || r.monthlyTokens > cur.monthlyTokens) poolMap.set(k, r);
|
||||
}
|
||||
const pools = [...poolMap.values()].filter((r) => r.monthlyTokens > 0).sort((a, b) => b.monthlyTokens - a.monthlyTokens);
|
||||
const steady = pools.reduce((s, r) => s + r.monthlyTokens, 0);
|
||||
|
||||
const otMap = new Map();
|
||||
for (const r of recs) {
|
||||
if (r.freeType !== "one-time-initial" || r.creditTokens <= 0) continue;
|
||||
const k = r.poolKey || r.provider;
|
||||
otMap.set(k, { provider: r.provider, v: Math.max(otMap.get(k)?.v || 0, r.creditTokens) });
|
||||
}
|
||||
const oneTime = [...otMap.values()].sort((a, b) => b.v - a.v);
|
||||
const oneTimeSum = oneTime.reduce((s, r) => s + r.v, 0);
|
||||
const firstMonth = steady + oneTimeSum + 1_000_000;
|
||||
const avoidProviders = [...new Set(recs.filter((r) => r.tos === "avoid").map((r) => r.provider))].length;
|
||||
|
||||
const GRID = pools.slice(0, 28);
|
||||
const STRIP = oneTime.slice(0, 9);
|
||||
const PAL = ["#6c5ce7","#00b894","#0984e3","#e17055","#fdcb6e","#e84393","#00cec9","#d63031","#a29bfe","#55efc4","#74b9ff","#ffeaa7","#fab1a0","#81ecec"];
|
||||
const color = (i) => PAL[i % PAL.length];
|
||||
const cleanName = (r) => (r.displayName || r.provider).replace(/\s*\(.*$/, "").replace(/ —.*$/, "").slice(0, 24);
|
||||
|
||||
// bar segments (min width so every pool shows)
|
||||
const BAR_X = 32, BAR_W = 836, MIN = 7;
|
||||
const extra = BAR_W - MIN * GRID.length;
|
||||
let bx = BAR_X;
|
||||
const segs = GRID.map((r, i) => {
|
||||
const w = MIN + (r.monthlyTokens / steady) * extra;
|
||||
const s = { x: bx, w, c: color(i) };
|
||||
bx += w;
|
||||
return s;
|
||||
});
|
||||
|
||||
const B = []; // body elements
|
||||
// title
|
||||
B.push(`<text x="32" y="50" fill="#e6edf3" font-size="18" font-weight="700">Monthly free-token budget</text>`);
|
||||
B.push(`<text x="868" y="50" fill="#7d8590" font-size="13" text-anchor="end">${pools.length} free pools · 530 models · one endpoint</text>`);
|
||||
// stats
|
||||
const stat = (sx, label, val, vc) => {
|
||||
B.push(`<text x="${sx}" y="84" fill="#7d8590" font-size="11.5">${label}</text>`);
|
||||
B.push(`<text x="${sx}" y="114" fill="${vc}" font-size="27" font-weight="800">${val}</text>`);
|
||||
};
|
||||
stat(32, "Steady / month", `~${fmt(steady)}`, "#e6edf3");
|
||||
stat(330, "First month (+ signup credits)", `~${fmt(firstMonth)}`, "#3fb950");
|
||||
stat(700, "ToS-flagged (you decide)", `${avoidProviders} providers`, "#d29922");
|
||||
// bar
|
||||
B.push(`<clipPath id="bar"><rect x="${BAR_X}" y="132" width="${BAR_W}" height="16" rx="8"/></clipPath>`);
|
||||
B.push(`<g clip-path="url(#bar)"><rect x="${BAR_X}" y="132" width="${BAR_W}" height="16" fill="#21262d"/>`);
|
||||
for (const s of segs) B.push(`<rect x="${s.x.toFixed(1)}" y="132" width="${(s.w + 0.6).toFixed(1)}" height="16" fill="${s.c}"/>`);
|
||||
B.push(`</g>`);
|
||||
B.push(`<text x="32" y="172" fill="#7d8590" font-size="12">Each segment = one free pool · widths floored so every provider shows · honest numbers in the grid.</text>`);
|
||||
// model grid 4 cols
|
||||
const COLS = 4, COLW = 213, GX = 32, GY = 200, RH = 30;
|
||||
GRID.forEach((r, i) => {
|
||||
const col = i % COLS, row = (i / COLS) | 0;
|
||||
const cx = GX + col * COLW, cy = GY + row * RH;
|
||||
B.push(`<circle cx="${cx + 5}" cy="${cy - 4}" r="5" fill="${color(i)}"/>`);
|
||||
B.push(`<text x="${cx + 16}" y="${cy}" fill="#c9d1d9" font-size="12.5">${cleanName(r)} <tspan fill="#7d8590">${fmt(r.monthlyTokens)}</tspan></text>`);
|
||||
});
|
||||
let y = GY + Math.ceil(GRID.length / COLS) * RH + 6;
|
||||
// first-month strip (wrapping)
|
||||
B.push(`<line x1="32" y1="${y}" x2="868" y2="${y}" stroke="#30363d"/>`);
|
||||
y += 26;
|
||||
B.push(`<text x="32" y="${y}" fill="#3fb950" font-size="13" font-weight="700">+ First month: one-time signup credits (~${fmt(oneTimeSum)})</text>`);
|
||||
y += 24;
|
||||
let sxp = 32;
|
||||
for (const r of STRIP) {
|
||||
const label = `${r.provider} ${fmt(r.v)}`;
|
||||
const w = 16 + label.length * 6.7;
|
||||
if (sxp + w > 862) { sxp = 32; y += 30; }
|
||||
B.push(`<rect x="${sxp.toFixed(0)}" y="${(y - 15).toFixed(0)}" width="${w.toFixed(0)}" height="22" rx="11" fill="#13311f" stroke="#238636"/>`);
|
||||
B.push(`<text x="${(sxp + w / 2).toFixed(0)}" y="${y.toFixed(0)}" fill="#7ee787" font-size="11.5" text-anchor="middle">${label}</text>`);
|
||||
sxp += w + 8;
|
||||
}
|
||||
y += 26;
|
||||
// ToS note (softened)
|
||||
B.push(`<rect x="32" y="${y}" width="836" height="34" rx="8" fill="#1c2230" stroke="#30363d"/>`);
|
||||
B.push(`<text x="46" y="${(y + 22).toFixed(0)}" fill="#7d8590" font-size="12">Some providers' terms suggest personal-use only — we flag them so you can decide. Figures are pool-deduped: no inflated rate-limit ceilings.</text>`);
|
||||
y += 34;
|
||||
const H = y + 24; // card content bottom
|
||||
const CANVAS = H + 16;
|
||||
|
||||
const out = [];
|
||||
out.push(`<svg xmlns="http://www.w3.org/2000/svg" width="900" height="${CANVAS}" viewBox="0 0 900 ${CANVAS}" font-family="-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif">`);
|
||||
out.push(`<rect width="900" height="${CANVAS}" rx="16" fill="#0d1117"/>`);
|
||||
out.push(`<rect x="16" y="16" width="868" height="${H}" rx="13" fill="#161b22" stroke="#30363d"/>`);
|
||||
out.push(`<text x="868" y="${(H + 8).toFixed(0)}" fill="#484f58" font-size="10.5" text-anchor="end">OmniRoute · /dashboard/free-tiers · preview mockup</text>`);
|
||||
out.push(...B);
|
||||
out.push(`</svg>`);
|
||||
fs.writeFileSync("docs/screenshots/free-tier-budget-card.svg", out.join("\n") + "\n");
|
||||
console.log(`SVG: ${GRID.length} models, ${STRIP.length} first-month chips, canvas ${CANVAS}px. steady=${fmt(steady)} firstMonth=${fmt(firstMonth)} oneTime=${fmt(oneTimeSum)}`);
|
||||
Reference in New Issue
Block a user