diff --git a/.gitignore b/.gitignore index e6449a44..82274354 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ Thumbs.db # Node node_modules/ +.worktrees/ docs/.astro/ docs/.wrangler/ docs/dist/ diff --git a/README.md b/README.md index a4723299..b373e1d7 100644 --- a/README.md +++ b/README.md @@ -1,235 +1,71 @@ # AnyCap - [![npm](https://img.shields.io/npm/v/@anycap/cli?color=cb3837&logo=npm)](https://www.npmjs.com/package/@anycap/cli) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![GitHub stars](https://img.shields.io/github/stars/anycap-ai/anycap?style=social)](https://github.com/anycap-ai/anycap/stargazers) [![Skills directory](https://img.shields.io/badge/skills.sh-anycap-6f42c1)](https://skills.sh/anycap-ai/anycap) -> **The execution layer for coding agents.** -> Give Claude Code, Cursor, Codex, and any client with local stdio MCP support real-world -> capabilities — image, video, vision, music, web search, and publishing — inside the -> agents you already use. -> Connect through an Agent Skill or the built-in local MCP server. +> **The capability runtime for AI agents.** +> +> Give coding agents a single CLI, Agent Skill, and local MCP server for creating media, +> understanding files, researching the live web, and delivering results people can use. -![AnyCap — the execution layer for coding agents](assets/hero.png) +![AnyCap — the capability runtime for AI agents](assets/hero.png) ---- +## Start here -## Quick start (30 seconds) - -Paste this to Claude Code, Cursor, Codex, or any agent that can run a shell: +Give this to Claude Code, Codex, Cursor, or another agent that can run shell commands: ```text -Read https://raw.githubusercontent.com/anycap-ai/anycap/main/llms.txt and follow the -instructions to install the AnyCap CLI and skill. If you can't access the URL, run: - 1. curl -fsSL https://anycap.ai/install.sh | sh - 2. npx -y skills add anycap-ai/anycap -s '*' -g -y - 3. anycap login - 4. anycap status +Read https://raw.githubusercontent.com/anycap-ai/anycap/main/llms.txt and follow its +instructions to install and configure AnyCap. ``` -That's it. The agent installs the CLI, installs the skill, logs you in, and verifies the -connection — then every capability below becomes a single sentence. Prefer native MCP -tool discovery? Jump to [Connect via MCP](#connect-via-mcp). Prefer to do it by hand? -Jump to [Manual install](#manual-install). - -## Contents - -- [What this fixes](#what-this-fixes) -- [What your agent can do](#what-your-agent-can-do) -- [Install by talking to your agent](#install-by-talking-to-your-agent) -- [Skills and MCP, not SDK glue](#skills-and-mcp-not-sdk-glue) -- [Manual install](#manual-install) -- [Connect via MCP](#connect-via-mcp) -- [Capabilities](#capabilities) -- [Works with](#works-with) -- [FAQ & troubleshooting](#faq--troubleshooting) -- [Links](#links) -- [License](#license) - ---- - -## What this fixes - -Your coding agent can reason and write code. It **still can't** ship a meme, generate a -hero image, read a screenshot a user dropped in, search the live web, or publish a -landing page. - -| Without AnyCap | With AnyCap | -| --------------------------------------- | --------------------------------------------- | -| "I can't generate images." | One command → a finished asset. | -| "I can't see this screenshot." | Reads images, video, and audio. | -| "My knowledge has a cutoff." | Live web search with citations. | -| "You'll need to deploy that yourself." | Ships a hosted page and returns the URL. | - -AnyCap is the missing execution layer — multimodal, web, and delivery behind **one CLI -and one auth**. - -## What your agent can do - -### 1. Make a meme end-to-end - -Agent drafts the caption, generates the image, revises the visual, then returns a -shareable link. - - - -```bash -anycap image generate --prompt "cat in a tiny chef hat, meme caption 'ship it'" \ - --model nano-banana-2 -o meme.png -anycap image generate --prompt "make the caption bigger and yellow" \ - --model nano-banana-2 --mode image-to-image --param images=./meme.png -o meme-v2.png -anycap drive upload meme-v2.png --parent-path /memes -anycap drive share --src-path /memes/meme-v2.png -``` - -### 2. Turn a prompt into a hosted page - -Agent writes the copy, generates hero visuals, and deploys a live URL. - - - -```bash -anycap image generate --prompt "abstract product hero, soft gradient" \ - --model nano-banana-2 -o ./dist/hero.png -anycap page deploy ./dist --name "launch-page" --publish -``` - -### 3. Review a screenshot with a human in the loop - -Agent opens the annotation UI, the human marks issues, the agent reads the feedback and -revises. - - - -```bash -anycap annotate ./screenshot.png --no-wait -anycap annotate poll --session ann_xxxx -anycap actions image-read --file ./screenshot-annotated.png \ - --instruction "List every change requested by the annotations" -``` - -## Install by talking to your agent - -AnyCap installs itself in plain English. No package-manager dance, no doc spelunking, no -version pinning. Hand the [Quick start](#quick-start-30-seconds) paragraph to your agent — -it reads `llms.txt`, installs the CLI, installs the skill, opens the browser to log you -in, and verifies the connection. - -After that one paste, everything else is just conversation. The skill teaches the agent -the full command surface, so future actions become one sentence: - -- **"Upgrade AnyCap and check my status."** -- **"Generate a hero image for the launch page and deploy it."** -- **"Search the web for the latest Cursor changelog and summarize."** - -The agent picks the right capability, runs it, and hands you the result. You never touch a -flag unless you want to. - -## Skills and MCP, not SDK glue - -Most tools ship an SDK and ask you to wire it in. AnyCap gives agents two integration -paths on top of the same CLI runtime: - -- **Agent Skill.** The agent reads `SKILL.md`, learns complete workflows, and invokes the - CLI from plain-English requests. The same skill works across Claude Code, Cursor, - Codex, and [40+ agents](https://skills.sh). -- **MCP server.** Any MCP host can discover typed AnyCap tools through the built-in local - stdio server. No separate package or service is required. -- **One auth, one CLI.** Both paths share the same login, configuration, HTTP client, and - local media handling. -- **No glue code.** You do not import a library, manage API objects, or maintain a custom - tool wrapper. - -## Manual install - -### 1. Install the CLI - -macOS / Linux / Windows (Git Bash): +If your agent cannot reach that URL, use the manual setup below. ```bash +# Install the CLI (macOS, Linux, or Windows through Git Bash) curl -fsSL https://anycap.ai/install.sh | sh -``` - -npm (all platforms): - -```bash -npm install -g @anycap/cli -``` - -Or grab a binary from [GitHub Releases](https://github.com/anycap-ai/anycap/releases). - -### 2. Install the skill -Works with Claude Code, Cursor, Windsurf, OpenCode, and [40+ agents](https://skills.sh): - -```bash +# Install the AnyCap Agent Skill npx -y skills add anycap-ai/anycap -s '*' -g -y -``` - -
-More ways to install the skill - -```bash -# Via AnyCap CLI (installs complete skill directories and references) -anycap skill install --target ~/.agents/skills/ -# Check if the CLI skill is up to date -anycap skill check --target ~/.agents/skills/anycap-cli/SKILL.md -``` - -
- -### 3. Verify - -```bash +# Authenticate once, then confirm the runtime is ready anycap login anycap status ``` -## Connect via MCP +The binary installer is the recommended path. If your environment already uses Node.js, +you can instead run `npm install -g @anycap/cli`. Platform binaries are also available +from [GitHub Releases](https://github.com/anycap-ai/anycap/releases). -AnyCap CLI v0.5.0 includes a local [Model Context Protocol](https://modelcontextprotocol.io/) -server. It runs over stdio inside the existing `anycap` binary, exposes 23 typed tools, -and shares the CLI's credentials and configuration. It has been verified with MCP -protocol version `2025-06-18`. There is no separate MCP package or background service to -install. +## Choose an integration -First verify that your installed CLI includes the server: +| Integration | Use it when | Entry point | +| --- | --- | --- | +| **Agent Skill** | You want an agent to choose the right workflow from a natural-language request. | [`skills/anycap-cli/SKILL.md`](skills/anycap-cli/SKILL.md) | +| **Local stdio MCP** | Your agent host needs typed tool discovery. | `anycap mcp` | +| **CLI** | You want shell automation or direct control. | `anycap ` | -```bash -anycap mcp --help -``` +All three use the same installed runtime and authentication state. The Skill and MCP +server can be used together. -If the command is missing, run `anycap update` and check again. +### Connect through MCP -### Claude Code - -Add AnyCap to the current project using Claude's machine-local scope and authorize local -media under that project: +First confirm that the installed CLI exposes the server: ```bash -claude mcp add --scope local anycap -- anycap mcp --allow-root "$PWD" +anycap mcp --help ``` -Local scope avoids committing a machine-specific absolute path to the shared project -configuration. - -### Codex - -The Codex CLI command creates a global server definition. Omit a permanent absolute root -and let each project session provide client roots or use the server working-directory -fallback: +For Codex, add the local server definition: ```bash codex mcp add anycap -- anycap mcp ``` -### Cursor and other MCP clients - -Add this stdio server to your client's MCP configuration. Replace the example path with -an absolute directory containing media that AnyCap may read: +For a generic stdio MCP client, configure `anycap mcp`. Add a narrowly scoped +`--allow-root` only when the server needs to access local media: ```json { @@ -237,184 +73,76 @@ an absolute directory containing media that AnyCap may read: "anycap": { "type": "stdio", "command": "anycap", - "args": [ - "mcp", - "--allow-root", - "/absolute/path/to/media" - ] + "args": ["mcp", "--allow-root", "/absolute/path/to/media"] } } } ``` -`--allow-root` is optional and repeatable. Effective local access is the union of these -flags, `ANYCAP_MCP_FILE_ROOTS`, and roots advertised by the MCP client; if none are -provided, the server falls back to its working directory. URL-based calls do not need -local access. Keep every configured root as narrow as possible. - -Existing `anycap login` credentials are picked up automatically, including logins -completed after the MCP process starts. MCP clients can also authenticate without -leaving the session through `anycap_auth_status`, `anycap_login`, and -`anycap_login_poll`. Authentication never opens a browser at server startup. - -The 23 tools cover: - -| Group | MCP tools | -| ----- | --------- | -| Authentication | Status, device login, login polling, and logout | -| Discovery | AnyCap status, model listing, and model schemas | -| Image | Generate, edit, upscale, and understand images | -| Video | Generate and understand videos | -| Music and audio | Generate music and analyze or transcribe audio | -| Web | Search the live web and crawl pages to Markdown | -| Drive | List and resolve files and folders (read-only) | -| Page | Inspect sites and versions (read-only) | - -For the complete tool inventory, authentication flow, and local image-to-video example, -see [the MCP reference](skills/anycap-cli/references/cli-reference.md#local-stdio-mcp). - -## Capabilities - -| Capability | Command | What agents do with it | -| ----------------------------- | -------------------------------------------------------------------- | ----------------------------------------------- | -| Image generation / edit | `anycap image generate` (`--mode image-to-image` for edits) | Hero art, meme assets, illustration, photo edit | -| Image / video / audio reading | `anycap actions image-read` / `video-read` / `audio-read` | Screenshot review, meeting transcripts, QA | -| Video generation | `anycap video generate` | Demo clips, animated assets | -| Music generation | `anycap music generate` | Jingles, soundtracks | -| Web search | `anycap search --query` (general) / `--prompt` (grounded with cites) | Live answers, research | -| Web crawl | `anycap crawl ` | Any URL into clean Markdown | -| Annotate | `anycap annotate` | Human-in-the-loop visual feedback | -| Draw | `anycap draw` | Live whiteboard / Mermaid diagrams | -| Drive | `anycap drive upload` / `share` | Shareable file links | -| Page | `anycap page deploy` | Hosted static pages | -| Download | `anycap download` | Save any remote file | - -> **Coming soon:** TTS / voice synthesis. - -## Models - -AnyCap's model lineup evolves quickly, so the **authoritative, always-current list lives -in the CLI** — run `anycap models` to see exactly what your account can use: - -```bash -anycap image models # image generation / edit -anycap video models # video generation -anycap music models # music generation -``` - -Inspect a single model's modes and parameter schema before calling it: - -```bash -anycap image models nano-banana-2 # modes + operations -anycap image models nano-banana-2 schema --mode text-to-image # parameter schema -``` - -The tables below reflect the models available in CLI **v0.3.6** — newer versions add and -retire models, so treat the CLI output as the source of truth. - -### Image generation / edit - -| Model | Name | Modes | -| ------------------ | --------------------- | --------------------------------- | -| `nano-banana-2` | Nano Banana 2 | text-to-image, image-to-image | -| `nano-banana-pro` | Nano Banana Pro | text-to-image, image-to-image | -| `gpt-image-2` | GPT Image 2 | text-to-image, image-to-image | -| `flux-kontext-max` | FLUX.1 Kontext Max | text-to-image, image-to-image | -| `qwen-image` | Qwen Image | text-to-image, image-to-image | -| `seedream-4.5` | Seedream 4.5 | text-to-image, image-to-image | -| `seedream-5` | Seedream 5 | text-to-image, image-to-image | - -### Video generation - -| Model | Name | Modes | -| ------------------- | ---------------- | -------------------------------- | -| `veo-3.1` | Veo 3.1 | text-to-video, image-to-video | -| `veo-3.1-fast` | Veo 3.1 Fast | text-to-video, image-to-video | -| `sora-2-pro` | Sora 2 Pro | text-to-video, image-to-video | -| `kling-3.0` | Kling 3.0 | text-to-video, image-to-video | -| `kling-o1` | Kling O1 | image-to-video | -| `hailuo-2.3` | Hailuo 2.3 | text-to-video, image-to-video | -| `seedance-1.5-pro` | Seedance 1.5 Pro | text-to-video, image-to-video | -| `seedance-2` | Seedance 2.0 | text-to-video, image-to-video | -| `seedance-2-fast` | Seedance 2.0 Fast| text-to-video, image-to-video | - -### Music generation - -| Model | Name | Modes | -| ------------------- | ----------------- | -------------- | -| `suno-v5` | Suno V5 | text-to-music | -| `suno-v5.5` | Suno V5.5 | text-to-music | -| `mureka-v8` | Mureka V8 | text-to-music | -| `elevanlabs-music` | ElevenLabs Music | text-to-music | +Do not commit personal absolute paths into shared project configuration. Read the +[MCP setup guide](https://docs.anyware.ai/getting-started/mcp/) and +[security guide](https://docs.anyware.ai/reference/security/) before granting local +file access. -> **Reading / understanding** (`anycap actions image-read` / `video-read` / `audio-read`) -> automatically selects the best available model. Pass `--model` only when you need a -> specific one. +## What agents can do -## Works with +| Area | Examples | +| --- | --- | +| **Create** | Generate and edit images, generate video, compose music, and create audio scenes. | +| **Understand** | Read screenshots, compare images, summarize video, and transcribe or analyze audio. | +| **Research** | Search the live web and crawl pages into Markdown. | +| **Collaborate** | Gather visual annotations and work with shared drawing surfaces. | +| **Deliver** | Upload and share files, publish static sites, and create project snapshots. | -Claude Code · Cursor · Codex · Windsurf · OpenCode · 40+ agents via -[skills.sh](https://skills.sh) · any client that supports local stdio MCP servers. +For a first end-to-end workflow, see [generate and share an image](https://docs.anyware.ai/guides/generate-and-share-image/). +Other task-oriented guides cover [image-to-video](https://docs.anyware.ai/guides/image-to-video/), +[human feedback](https://docs.anyware.ai/guides/human-feedback/), +[web research](https://docs.anyware.ai/guides/web-research/), and +[static-site publishing](https://docs.anyware.ai/guides/publish-site/). -## FAQ & troubleshooting +## Discover live capabilities -
-Do I need an API key for each capability? +Model availability and input schemas change. Query the installed CLI instead of copying +model IDs or parameters from an old example: -No. One `anycap login` covers every capability — image, video, vision, music, web, and -publishing share a single auth. The CLI and MCP server use the same credentials. -
- -
-Does the MCP server upload every local file? - -No. Only local media explicitly passed to a compatible tool can be uploaded, and its -canonical path must be inside an effective allowed root. Configure repeatable -`--allow-root` flags or client-advertised roots to control access. URL-based inputs do -not require local filesystem access. -
- -
-The agent says it can't reach llms.txt. - -Run the four manual commands from [Quick start](#quick-start-30-seconds), or follow -[Manual install](#manual-install). -
+```bash +# List models available to your account +anycap image models +anycap video models +anycap music models -
-The skill isn't showing up in my agent. +# Inspect the current modes and schema for a selected model +anycap image models +anycap image models schema --mode +``` -Confirm it installed into your agent's skills directory, then re-check: +Run `anycap --help` at any level to inspect commands and options: ```bash -anycap skill check --target ~/.agents/skills/anycap-cli/SKILL.md +anycap --help +anycap image --help +anycap image generate --help ``` -Reload your agent so it re-reads the skills directory. -
+## Documentation and support -
-How do I update? +- [Documentation](https://docs.anyware.ai) — quickstart, capability guides, and reference material. +- [CLI reference](https://docs.anyware.ai/reference/cli/) — command groups, output conventions, and discovery. +- [MCP tool reference](https://docs.anyware.ai/reference/mcp-tools/) — current tools and read/write boundaries. +- [Authentication and configuration](https://docs.anyware.ai/getting-started/authentication/) — interactive, headless, and API-key workflows. +- [Troubleshooting](https://docs.anyware.ai/getting-started/troubleshooting/) — installation and runtime diagnostics. +- [`llms.txt`](llms.txt) — concise installation and usage instructions for agents. +- [Skills directory](https://skills.sh/anycap-ai/anycap) — install the Agent Skills collection. -Tell your agent **"Upgrade AnyCap and check my status,"** or re-run the install script and -`npx -y skills add anycap-ai/anycap -s '*' -g -y`. -
+## Updating -
-Which platforms are supported? +The CLI checks for updates during normal use. Update it explicitly when needed: -macOS, Linux, and Windows (via Git Bash). Install through the script, npm, or a binary -from [Releases](https://github.com/anycap-ai/anycap/releases). -
- -## Links - -- [Documentation](https://docs.anyware.ai) — Guides and reference -- [llms.txt](llms.txt) — Give this to your agent -- [Skill file](skills/anycap-cli/SKILL.md) — Full capability documentation -- [GitHub Releases](https://github.com/anycap-ai/anycap/releases) — CLI binaries -- [skills.sh](https://skills.sh/anycap-ai/anycap) — Skills directory listing -- [Website](https://anycap.ai) +```bash +anycap update +npx -y skills update +anycap status +``` ## License diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index d52fa5a1..cf4a21e1 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -25,9 +25,6 @@ export default defineConfig({ href: 'https://github.com/anycap-ai/anycap', }, ], - editLink: { - baseUrl: 'https://github.com/anycap-ai/anycap/edit/main/docs/', - }, lastUpdated: true, disable404Route: true, customCss: ['./src/styles/custom.css'], @@ -35,7 +32,7 @@ export default defineConfig({ Head: './src/components/Head.astro', }, head: [ - { tag: 'meta', attrs: { name: 'theme-color', content: '#f9faf5' } }, + { tag: 'meta', attrs: { name: 'theme-color', content: '#f4f5f0' } }, { tag: 'meta', attrs: { name: 'color-scheme', content: 'light dark' } }, { tag: 'meta', @@ -74,11 +71,13 @@ export default defineConfig({ label: 'Capabilities', items: [ { label: 'Overview', link: '/capabilities/' }, + { label: 'Models', link: '/capabilities/models/' }, { label: 'Image', link: '/capabilities/image/' }, { label: 'Video', link: '/capabilities/video/' }, + { label: 'Audio', link: '/capabilities/audio/' }, + { label: 'Music', link: '/capabilities/music/' }, { label: 'Media understanding', link: '/capabilities/media-understanding/' }, { label: 'Web search and crawl', link: '/capabilities/web/' }, - { label: 'Music and audio', link: '/capabilities/audio/' }, { label: 'Drive and Page', link: '/capabilities/delivery/' }, { label: 'Annotate and Draw', link: '/capabilities/collaboration/' }, { label: 'Snapshots', link: '/capabilities/snapshots/' }, diff --git a/docs/package-lock.json b/docs/package-lock.json index d00d46b1..a9a1cb88 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@astrojs/sitemap": "3.7.3", "@astrojs/starlight": "0.41.3", + "@fontsource-variable/inter": "^5.2.8", + "@fontsource/space-mono": "^5.2.6", "astro": "7.1.3" }, "devDependencies": { @@ -1365,6 +1367,24 @@ "@expressive-code/core": "^0.44.1" } }, + "node_modules/@fontsource-variable/inter": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.2.8.tgz", + "integrity": "sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/space-mono": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@fontsource/space-mono/-/space-mono-5.2.6.tgz", + "integrity": "sha512-3IOUpd5neu52Ewt7LUyiTHCv31oMq2+rmOeIUlCjGSIBwIY+TswZwCTVKjzhWkr+TEuwdWZeKcjAEDuwmTn2Pw==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@img/colour": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", @@ -1382,6 +1402,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1404,6 +1425,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1423,6 +1445,7 @@ "version": "0.35.3", "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1445,6 +1468,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1461,6 +1485,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1477,6 +1502,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1493,6 +1519,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1509,6 +1536,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1525,6 +1553,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1541,6 +1570,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1557,6 +1587,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1573,6 +1604,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1589,6 +1621,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1605,6 +1638,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1627,6 +1661,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1649,6 +1684,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1671,6 +1707,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1693,6 +1730,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1715,6 +1753,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1737,6 +1776,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1759,6 +1799,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1778,6 +1819,7 @@ "version": "0.35.3", "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { @@ -1797,6 +1839,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "Apache-2.0", "optional": true, "dependencies": { @@ -1816,6 +1859,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1835,6 +1879,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1854,6 +1899,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ diff --git a/docs/package.json b/docs/package.json index c9e40760..5651c800 100644 --- a/docs/package.json +++ b/docs/package.json @@ -18,6 +18,8 @@ "dependencies": { "@astrojs/sitemap": "3.7.3", "@astrojs/starlight": "0.41.3", + "@fontsource-variable/inter": "^5.2.8", + "@fontsource/space-mono": "^5.2.6", "astro": "7.1.3" }, "devDependencies": { diff --git a/docs/public/assets/geist-pixel-square.woff2 b/docs/public/assets/geist-pixel-square.woff2 new file mode 100644 index 00000000..232cae2c Binary files /dev/null and b/docs/public/assets/geist-pixel-square.woff2 differ diff --git a/docs/public/favicon.svg b/docs/public/favicon.svg index 6c0ce84a..e9254967 100644 --- a/docs/public/favicon.svg +++ b/docs/public/favicon.svg @@ -1,5 +1,13 @@ - - - - + + + + + + + + + + + + diff --git a/docs/scripts/audit-build.mjs b/docs/scripts/audit-build.mjs index bee62ef6..e50e4f22 100644 --- a/docs/scripts/audit-build.mjs +++ b/docs/scripts/audit-build.mjs @@ -3,7 +3,7 @@ import { extname, join, relative, resolve } from 'node:path'; const dist = resolve('dist'); const canonicalOrigin = 'https://docs.anyware.ai'; -const expectedIndexablePages = 28; +const expectedIndexablePages = 30; const errors = []; async function walk(directory) { diff --git a/docs/scripts/prepare-assets.mjs b/docs/scripts/prepare-assets.mjs index 16a5851f..ba189c87 100644 --- a/docs/scripts/prepare-assets.mjs +++ b/docs/scripts/prepare-assets.mjs @@ -1,4 +1,4 @@ -import { mkdir, rm } from 'node:fs/promises'; +import { copyFile, mkdir, rm } from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import sharp from 'sharp'; @@ -7,12 +7,41 @@ const source = fileURLToPath(new URL('../../assets/hero.png', import.meta.url)); const destinationDirectory = fileURLToPath(new URL('../public/assets/', import.meta.url)); const destination = fileURLToPath(new URL('../public/assets/social-card.png', import.meta.url)); const legacyDestination = fileURLToPath(new URL('../public/assets/hero.png', import.meta.url)); +const grainDestination = fileURLToPath(new URL('../public/assets/grain.png', import.meta.url)); +const grainSize = 200; +const interSource = fileURLToPath( + new URL('../node_modules/@fontsource-variable/inter/files/inter-latin-wght-normal.woff2', import.meta.url) +); +const interDestination = fileURLToPath(new URL('../public/assets/inter-latin-wght-normal.woff2', import.meta.url)); +const spaceMonoSource = fileURLToPath( + new URL('../node_modules/@fontsource/space-mono/files/space-mono-latin-700-normal.woff2', import.meta.url) +); +const spaceMonoDestination = fileURLToPath(new URL('../public/assets/space-mono-700.woff2', import.meta.url)); await mkdir(destinationDirectory, { recursive: true }); await rm(legacyDestination, { force: true }); +await copyFile(interSource, interDestination); +await copyFile(spaceMonoSource, spaceMonoDestination); +const grainPixels = Buffer.alloc(grainSize * grainSize * 3); + +for (let index = 0; index < grainPixels.length; index += 3) { + const value = Math.floor(Math.random() * 256); + grainPixels[index] = value; + grainPixels[index + 1] = value; + grainPixels[index + 2] = value; +} + +await sharp(grainPixels, { + raw: { width: grainSize, height: grainSize, channels: 3 }, +}) + .png({ compressionLevel: 9, effort: 10 }) + .toFile(grainDestination); await sharp(source) .resize(1200, 630, { fit: 'cover', position: 'centre' }) .png({ compressionLevel: 9, effort: 10 }) .toFile(destination); console.log(`Prepared docs asset: ${destination.replace(`${docsRoot}/`, '')} (1200x630)`); +console.log(`Prepared docs font: ${interDestination.replace(`${docsRoot}/`, '')}`); +console.log(`Prepared docs font: ${spaceMonoDestination.replace(`${docsRoot}/`, '')}`); +console.log(`Prepared docs texture: ${grainDestination.replace(`${docsRoot}/`, '')} (${grainSize}x${grainSize})`); diff --git a/docs/scripts/theme-contract.test.mjs b/docs/scripts/theme-contract.test.mjs new file mode 100644 index 00000000..a61ad620 --- /dev/null +++ b/docs/scripts/theme-contract.test.mjs @@ -0,0 +1,148 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import test from 'node:test'; + +const stylesheet = await readFile(new URL('../src/styles/custom.css', import.meta.url), 'utf8'); +const assetPreparation = await readFile(new URL('./prepare-assets.mjs', import.meta.url), 'utf8'); +const homepage = await readFile(new URL('../src/content/docs/index.mdx', import.meta.url), 'utf8'); +const logo = await readFile(new URL('../src/assets/anycap-logo.svg', import.meta.url), 'utf8'); +const favicon = await readFile(new URL('../public/favicon.svg', import.meta.url), 'utf8'); +const docsConfig = await readFile(new URL('../astro.config.mjs', import.meta.url), 'utf8'); +const capabilitiesPage = await readFile(new URL('../src/content/docs/capabilities/index.mdx', import.meta.url), 'utf8'); +const audioPage = await readFile(new URL('../src/content/docs/capabilities/audio.mdx', import.meta.url), 'utf8'); +const musicPage = await readFile(new URL('../src/content/docs/capabilities/music.mdx', import.meta.url), 'utf8').catch(() => ''); +const videoPage = await readFile(new URL('../src/content/docs/capabilities/video.mdx', import.meta.url), 'utf8'); +const modelsPage = await readFile(new URL('../src/content/docs/capabilities/models.mdx', import.meta.url), 'utf8').catch( + () => '', +); +const liveCatalogComponent = await readFile(new URL('../src/components/LiveModelCatalog.astro', import.meta.url), 'utf8').catch( + () => '', +); +const docsWorker = await readFile(new URL('../worker.mjs', import.meta.url), 'utf8').catch(() => ''); + +test('uses the main-site typography roles', () => { + assert.match(stylesheet, /--sl-font:\s*Inter,/); + assert.match(stylesheet, /--sl-font-heading:\s*"Geist Pixel Square"/); + assert.match(stylesheet, /--sl-font-mono:\s*Inter,/); + assert.match(stylesheet, /h1,[\s\S]*font-family:\s*var\(--sl-font-heading\)/); +}); + +test('maps the main-site light palette and an olive-charcoal dark palette', () => { + for (const declaration of [ + '--ac-page: #f4f5f0', + '--ac-surface: #f4f5f0', + '--ac-raised: #fbfcf8', + '--ac-ink: #1c1f17', + '--ac-muted: #4d5145', + '--ac-accent: #6b7d3a', + '--ac-border: #d4dbb8', + ]) { + assert.ok(stylesheet.includes(declaration), `missing light token: ${declaration}`); + } + + assert.match(stylesheet, /:root\[data-theme='dark'\][\s\S]*--ac-page: #12150f/); + assert.match(stylesheet, /:root\[data-theme='dark'\][\s\S]*--ac-accent: #a8bc62/); +}); + +test('publishes the shared display font as a documentation asset', () => { + assert.match(stylesheet, /url\("\/assets\/geist-pixel-square\.woff2"\)/); +}); + +test('bundles the main-site Inter and Space Mono font roles', () => { + assert.match(stylesheet, /font-family: "Inter"/); + assert.match(stylesheet, /--sl-font-mono: Inter,/); + assert.match(assetPreparation, /inter-latin-wght-normal\.woff2/); + assert.match(assetPreparation, /space-mono-latin-700-normal\.woff2/); + assert.match(logo, /space-mono-700\.woff2/); +}); + +test('uses the main-site brand mark without duplicating it in the homepage hero', () => { + assert.doesNotMatch(homepage, /hero:[\s\S]*?image:/); + assert.match(logo, /fill="#6b7d3a"/); + assert.match(logo, /rotate\(-5 100 100\)/); + assert.match(logo, /any<\/tspan>cap<\/tspan>/); +}); + +test('uses the main-site nested-square mark for the browser favicon', () => { + assert.match(favicon, /viewBox="5 5 190 190"/); + assert.match(favicon, //); + assert.match(favicon, /rotate\(-5 100 100\)/); + assert.match(favicon, /rect x="49" y="49" width="102" height="102" rx="3" fill="#6b7d3a"/); +}); + +test('uses the same off-white page canvas as the main site', () => { + assert.match(stylesheet, /:root\[data-theme='light'\][\s\S]*--ac-page: #f4f5f0/); + assert.match(stylesheet, /--sl-color-bg: var\(--ac-page\)/); + assert.match(docsConfig, /theme-color', content: '#f4f5f0'/); + assert.match(stylesheet, /body::before/); + assert.match(stylesheet, /url\("\/assets\/grain\.png"\)/); + assert.match(stylesheet, /opacity: 0\.07/); + assert.match(assetPreparation, /grain\.png/); + assert.match(stylesheet, /\.sidebar-pane,\s*\.right-sidebar-container[\s\S]*background-color: var\(--ac-page\)/); +}); + +test('uses rendered icons and styled documentation footer controls', () => { + assert.match(homepage, //); + assert.match(stylesheet, /footer\.sl-flex/); + assert.match(stylesheet, /\.pagination-links/); + assert.doesNotMatch(docsConfig, /editLink:/); + assert.match(stylesheet, /footer\.sl-flex \.pagination-links a \{[\s\S]*border: 0;/); + assert.match(stylesheet, /footer\.sl-flex \.pagination-links a \{[\s\S]*border-radius: 0;/); + assert.match(stylesheet, /\[data-has-hero\] footer\.sl-flex \.pagination-links[\s\S]*display: none;/); +}); + +test('routes model discovery to the live catalog instead of duplicating availability claims', () => { + assert.match(docsConfig, /\{ label: 'Models', link: '\/capabilities\/models\/' \}/); + assert.match(modelsPage, /https:\/\/anycap\.ai\/models/); + assert.match(modelsPage, /anycap image models/); + assert.match(modelsPage, /anycap video models/); + assert.match(modelsPage, /anycap music models/); + assert.match(modelsPage, /anycap audio models/); + assert.match(modelsPage, /not duplicated in this documentation site/); + assert.match(modelsPage, /List every currently advertised mode/); +}); + +test('makes audio and model-specific modes discoverable from capabilities', () => { + assert.match( + docsConfig, + /\{ label: 'Video', link: '\/capabilities\/video\/' \},[\s\S]*\{ label: 'Audio', link: '\/capabilities\/audio\/' \},[\s\S]*\{ label: 'Music', link: '\/capabilities\/music\/' \}/, + ); + assert.match(capabilitiesPage, /\[audio\]\(\/capabilities\/audio\/#audio-generation\)/); + assert.match(capabilitiesPage, /\[music\]\(\/capabilities\/music\/\)/); + assert.match(audioPage, /## Audio generation/); + assert.match(audioPage, /`text-to-audio`/); + assert.match(audioPage, /`audio-to-audio`/); + assert.match(audioPage, /`image-to-audio`/); + assert.doesNotMatch(audioPage, /anycap music models/); + assert.match(musicPage, /title: Music Generation/); + assert.match(musicPage, /`text-to-music`/); + assert.match(musicPage, /anycap music models/); + assert.match(videoPage, /`edit-video`/); + assert.match(videoPage, /`first-last-frame-to-video`/); + assert.match(videoPage, /`multi-shot-video`/); + assert.match(videoPage, /`multi-modal-reference`/); +}); + +test('shows live supported models and conversion CTAs before generation workflows', () => { + for (const [page, capability] of [ + [videoPage, 'video'], + [audioPage, 'audio'], + [musicPage, 'music'], + ]) { + assert.match(page, new RegExp(` { + assert.match(homepage, /text: Start in 30 seconds[\s\S]*link: \/getting-started\//); + assert.match(homepage, /text: Install the CLI[\s\S]*link: \/getting-started\/install\//); + assert.match(homepage, /text: Connect through MCP[\s\S]*link: \/getting-started\/mcp\//); + assert.equal((homepage.match(/icon: external/g) ?? []).length, 3); + assert.match(homepage, /title="CLI"[\s\S]*href="\/getting-started\/install\/"/); + assert.match(homepage, /title="Local MCP server"[\s\S]*href="\/getting-started\/mcp\/"/); +}); diff --git a/docs/src/assets/anycap-logo.svg b/docs/src/assets/anycap-logo.svg index 01c195d2..0730a9ae 100644 --- a/docs/src/assets/anycap-logo.svg +++ b/docs/src/assets/anycap-logo.svg @@ -1,8 +1,21 @@ AnyCap - - - - anycap - + + + anycap diff --git a/docs/src/components/LiveModelCatalog.astro b/docs/src/components/LiveModelCatalog.astro new file mode 100644 index 00000000..4e8f560f --- /dev/null +++ b/docs/src/components/LiveModelCatalog.astro @@ -0,0 +1,89 @@ +--- +type CatalogCapability = 'image' | 'video' | 'music' | 'audio'; + +interface Props { + capability: CatalogCapability; +} + +const { capability } = Astro.props; + +const capabilityLabels: Record = { + image: 'image', + video: 'video', + music: 'music', + audio: 'audio', +}; + +const label = capabilityLabels[capability]; +--- + +
+
+
+

Live catalog

+

Supported {label} models

+

Choose a model before you generate. Availability and modes are loaded from the current AnyCap catalog.

+
+ +
+

Loading live models…

+
    + + + diff --git a/docs/src/content/docs/capabilities/audio.md b/docs/src/content/docs/capabilities/audio.md deleted file mode 100644 index 6aae4da6..00000000 --- a/docs/src/content/docs/capabilities/audio.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Music and Audio Generation -description: Generate music, speech, dialogue, and complete audio scenes through live AnyCap model schemas. ---- - -## Generate music - -```bash -anycap music models -anycap music models schema --mode text-to-music -anycap music generate \ - --prompt "warm lo-fi study beat" \ - --model \ - --tags "lofi,warm,study" \ - --instrumental \ - -o study-beat.mp3 -``` - -Use `--title`, `--lyrics`, and schema-advertised parameters when the selected model supports them. A request can return multiple clips under `outputs`. - -```bash -anycap music generate --prompt "..." --model \ - | jq -r '.outputs[].local_path' -``` - -## Generate audio scenes - -Audio models may support text, audio, or image input: - -```bash -anycap audio models -anycap audio models schema --mode text-to-audio -anycap audio generate \ - --prompt 'A calm narrator says: "Welcome to AnyCap." Quiet studio ambience.' \ - --model \ - --mode text-to-audio \ - -o welcome.mp3 -``` - -Other schema-discovered modes can include: - -- `audio-to-audio` for reference-guided performance or scene generation -- `image-to-audio` for a scene guided by an image - -These are generation workflows, not claims of a general-purpose audio editor. Confirm formats, sample rates, reference limits, subtitles, and voice controls against the live schema. - -## Output metadata - -Audio outputs can include `local_path`, `mime_type`, duration, byte size, subtitle data, usage, and diagnostic IDs. If one local download fails after provider generation succeeds, that output reports its own `error` instead of hiding the successful provider result. diff --git a/docs/src/content/docs/capabilities/audio.mdx b/docs/src/content/docs/capabilities/audio.mdx new file mode 100644 index 00000000..eff356bb --- /dev/null +++ b/docs/src/content/docs/capabilities/audio.mdx @@ -0,0 +1,42 @@ +--- +title: Audio Generation +description: Generate audio scenes, speech, and dialogue through live AnyCap model schemas. +--- + +import LiveModelCatalog from '../../../components/LiveModelCatalog.astro'; + + + +## Audio generation + +Audio is a generation capability distinct from music. The selected model may expose one or more of these mode values; inspect the live catalog before choosing one: + +| Mode | Use it for | +| --- | --- | +| `text-to-audio` | Create an audio scene, speech, or dialogue from a prompt | +| `audio-to-audio` | Guide a new result with supported audio references | +| `image-to-audio` | Guide an audio scene with a supported image reference | + +```bash +# Print the modes advertised by every audio model right now. +anycap audio models \ + | jq -r '.models[] | .model as $model | .operations[]?.modes[]?.mode | [$model, .] | @tsv' +``` + +```bash +anycap audio models +anycap audio models schema --mode text-to-audio +anycap audio generate \ + --prompt 'A calm narrator says: "Welcome to AnyCap." Quiet studio ambience.' \ + --model \ + --mode text-to-audio \ + -o welcome.mp3 +``` + +These are generation workflows, not claims of a general-purpose audio editor. Confirm formats, sample rates, reference limits, subtitles, and voice controls against the selected live schema. + +## Output metadata + +Audio outputs can include `local_path`, `mime_type`, duration, byte size, subtitle data, usage, and diagnostic IDs. If one local download fails after provider generation succeeds, that output reports its own `error` instead of hiding the successful provider result. + +For composed tracks, see [Music generation](/capabilities/music/). diff --git a/docs/src/content/docs/capabilities/index.mdx b/docs/src/content/docs/capabilities/index.mdx index e3423efb..fcd98c28 100644 --- a/docs/src/content/docs/capabilities/index.mdx +++ b/docs/src/content/docs/capabilities/index.mdx @@ -9,7 +9,7 @@ AnyCap groups capabilities around four jobs: create something, understand someth - [Images](/capabilities/image/), [video](/capabilities/video/), [music and audio](/capabilities/audio/). + [Images](/capabilities/image/), [video](/capabilities/video/), [audio](/capabilities/audio/#audio-generation), and [music](/capabilities/music/). Analyze images, video, and audio without managing a separate vision or transcription service. diff --git a/docs/src/content/docs/capabilities/models.mdx b/docs/src/content/docs/capabilities/models.mdx new file mode 100644 index 00000000..3c228159 --- /dev/null +++ b/docs/src/content/docs/capabilities/models.mdx @@ -0,0 +1,56 @@ +--- +title: Models +description: Discover the current AnyCap image, video, music, and audio model catalog without relying on stale static lists. +--- + +import { Aside } from '@astrojs/starlight/components'; + +The live AnyCap CLI catalog is the source of truth for model availability, operations, modes, and request parameters. It changes independently of documentation releases, so the full model list is not duplicated in this documentation site. + +For a maintained public overview of the current supported models and workflow guidance, see the [AnyCap Model Guide](https://anycap.ai/models). + +## Discover the live catalog + +Use the capability that matches the output you need: + +| Capability | List current models | Inspect an exact contract | +| --- | --- | --- | +| Image generation and editing | `anycap image models` | `anycap image models schema --mode ` | +| Video generation and editing | `anycap video models` | `anycap video models schema --mode ` | +| Music generation | `anycap music models` | `anycap music models schema --mode text-to-music` | +| Audio generation | `anycap audio models` | `anycap audio models schema --mode ` | + +The current catalog covers image, video, music, and audio generation. It also includes media-understanding actions for images, video, and audio; those actions choose a strong default unless you explicitly pass `--model`. + +## Read the result before selecting a model + +Each `models` command returns machine-readable JSON. Start by listing the model ID, display name, and supported modes: + +```bash +anycap video models \ + | jq -r '.models[] | [.model, (.display_name // .name), ([.operations[]?.modes[]?.mode] | unique | join(", "))] | @tsv' +``` + +## List every currently advertised mode + +Run this whenever you need the complete mode surface rather than an example from a capability guide. It reads the live catalog, so it includes newly added modes and omits retired ones: + +```bash +for capability in image video music audio; do + anycap "$capability" models \ + | jq -r --arg capability "$capability" \ + '.models[] | .model as $model | .operations[]?.modes[]?.mode | [$capability, $model, .] | @tsv' +done +``` + +Then inspect the schema for the one model and mode you selected. The schema is the authority for accepted parameters such as aspect ratio, duration, resolution, or reference inputs. + +```bash +anycap video models schema --mode image-to-video +``` + + + +See [Generation and editing](/capabilities/image/), [Video generation](/capabilities/video/), [Audio generation](/capabilities/audio/), and [Music generation](/capabilities/music/) for capability-specific workflows. diff --git a/docs/src/content/docs/capabilities/music.mdx b/docs/src/content/docs/capabilities/music.mdx new file mode 100644 index 00000000..e96154b6 --- /dev/null +++ b/docs/src/content/docs/capabilities/music.mdx @@ -0,0 +1,47 @@ +--- +title: Music Generation +description: Generate instrumental tracks, songs, and music clips through live AnyCap model schemas. +--- + +import LiveModelCatalog from '../../../components/LiveModelCatalog.astro'; + + + +## Modes + +| Mode | Use it for | +| --- | --- | +| `text-to-music` | Create an instrumental track or song from a prompt | + +The selected model may expose a different subset of controls. Check the live catalog before relying on a prompt field or optional parameter. + +```bash +anycap music models \ + | jq -r '.models[] | .model as $model | .operations[]?.modes[]?.mode | [$model, .] | @tsv' +``` + +## Generate music + +```bash +anycap music models +anycap music models schema --mode text-to-music +anycap music generate \ + --prompt "warm lo-fi study beat" \ + --model \ + --tags "lofi,warm,study" \ + --instrumental \ + -o study-beat.mp3 +``` + +Use `--title`, `--lyrics`, and schema-advertised parameters only when the selected model supports them. A request can return multiple clips under `outputs`. + +```bash +anycap music generate --prompt "..." --model \ + | jq -r '.outputs[].local_path' +``` + +## Output metadata + +Music generation can return one or more output clips, along with duration, byte size, usage, and diagnostic IDs. Inspect every `outputs[]` item rather than assuming a single file. + +For speech, dialogue, and audio scenes, see [Audio generation](/capabilities/audio/). diff --git a/docs/src/content/docs/capabilities/video.md b/docs/src/content/docs/capabilities/video.mdx similarity index 61% rename from docs/src/content/docs/capabilities/video.md rename to docs/src/content/docs/capabilities/video.mdx index a303e278..72702b12 100644 --- a/docs/src/content/docs/capabilities/video.md +++ b/docs/src/content/docs/capabilities/video.mdx @@ -3,12 +3,27 @@ title: Video Generation description: Generate video from text or animate a local image after discovering the current AnyCap model schema. --- +import LiveModelCatalog from '../../../components/LiveModelCatalog.astro'; + + + ## Modes -| Mode | Input | +| Mode | Use it for | | --- | --- | -| `text-to-video` | Prompt | -| `image-to-video` | Prompt plus one or more supported image references | +| `text-to-video` | Create a video from a prompt | +| `image-to-video` | Animate one or more supported image references | +| `edit-video` | Refine a supplied video using natural-language instructions | +| `first-last-frame-to-video` | Generate a transition between named first and last frames | +| `multi-shot-video` | Generate a sequence from shot-level prompts and durations | +| `multi-modal-reference` | Guide a video with supported image, video, or audio references | + +A selected model supports only a subset of these modes. Query the live catalog instead of assuming a mode from this reference: + +```bash +anycap video models \ + | jq -r '.models[] | .model as $model | .operations[]?.modes[]?.mode | [$model, .] | @tsv' +``` ## Generate from text diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index 2091cc2f..128a30f1 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -4,14 +4,15 @@ description: Give AI agents image, video, audio, web, storage, and publishing ca template: splash hero: tagline: The capability runtime for AI agents. Create media, understand files, search the live web, and publish results through one CLI and one authentication flow. - image: - file: ../../assets/anycap-logo.svg - alt: AnyCap actions: - text: Start in 30 seconds link: /getting-started/ - icon: right-arrow + icon: external variant: primary + - text: Install the CLI + link: /getting-started/install/ + icon: external + variant: secondary - text: Connect through MCP link: /getting-started/mcp/ icon: external @@ -33,7 +34,7 @@ AnyCap gives Claude Code, Cursor, Codex, and other agents a consistent execution Generate and edit images, produce video, compose music, and build complete audio scenes. - + Read screenshots, compare images, summarize video, and transcribe or analyze audio. @@ -46,6 +47,12 @@ AnyCap gives Claude Code, Cursor, Codex, and other agents a consistent execution ## Choose your integration + + img)) { + grid-template-columns: minmax(0, 1fr); + } + + [data-has-hero] .hero:not(:has(> img)) .stack, + [data-has-hero] .hero:not(:has(> img)) .copy { + align-items: flex-start; + text-align: start; + } + [data-has-hero] .hero .tagline { max-width: 44rem; + color: var(--ac-muted); font-size: clamp(1.05rem, 2vw, 1.35rem); } [data-has-hero] .hero img { - filter: drop-shadow(0 24px 48px color-mix(in srgb, var(--sl-color-accent) 20%, transparent)); + filter: drop-shadow(0 20px 48px color-mix(in srgb, var(--ac-accent) 20%, transparent)); } .sl-link-button.primary { - border-color: var(--sl-color-accent); - background: var(--sl-color-accent); - color: #fffffc; + border-color: var(--ac-accent); + background: var(--ac-accent); + color: #f4f5f0; + } + + .sl-link-button.primary:hover { + background: var(--ac-ink); + color: var(--ac-page); } .sl-link-button.secondary { - border-color: var(--sl-color-hairline); + border-color: var(--ac-border); background: transparent; + color: var(--ac-ink); + } + + .live-model-catalog { + border-top: 1px solid var(--ac-border); + margin-block: 2.75rem; + padding-top: 1.65rem; + } + + .live-model-catalog-header { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + gap: 1.25rem 2rem; + justify-content: space-between; + } + + .live-model-catalog h2 { + border: 0; + margin: 0; + padding: 0; + } + + .live-model-catalog p { + color: var(--ac-muted); + margin-block: 0.6rem 0; + max-width: 42rem; + } + + .live-model-catalog-eyebrow { + color: var(--ac-accent) !important; + font-family: var(--sl-font-mono); + font-size: 0.78rem; + font-weight: 700; + letter-spacing: 0.06em; + margin: 0 0 0.35rem !important; + text-transform: uppercase; + } + + .live-model-catalog-actions { + display: flex; + flex-wrap: wrap; + gap: 0.6rem; + } + + .model-catalog-cta { + align-items: center; + border: 1px solid var(--ac-border); + border-radius: 999px; + display: inline-flex; + font-size: 0.88rem; + font-weight: 650; + min-height: 2.5rem; + padding-inline: 1rem; + text-decoration: none; + } + + .model-catalog-cta.primary { + background: var(--ac-accent); + border-color: var(--ac-accent); + color: #f4f5f0; + } + + .model-catalog-cta.secondary { + color: var(--ac-ink); + } + + .model-catalog-cta:hover { + background: var(--ac-ink); + border-color: var(--ac-ink); + color: var(--ac-page); + } + + .live-model-catalog-status { + font-size: 0.86rem; + } + + .live-model-list { + display: grid; + gap: 0.65rem; + grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); + list-style: none; + margin: 1rem 0 0; + padding: 0; + } + + .live-model-list li { + background: color-mix(in srgb, var(--ac-raised) 65%, transparent); + border: 1px solid var(--ac-border); + border-radius: 0.45rem; + display: grid; + gap: 0.35rem; + min-height: 4.75rem; + padding: 0.75rem; + } + + .live-model-list strong { + color: var(--ac-ink); + font-size: 0.9rem; + line-height: 1.25; + } + + .live-model-list span { + color: var(--ac-muted); + font-family: var(--sl-font-mono); + font-size: 0.72rem; + line-height: 1.35; } table { @@ -170,13 +375,73 @@ } th { + background: color-mix(in srgb, var(--ac-surface) 84%, var(--ac-accent-low)); font-family: var(--sl-font-mono); font-size: 0.82rem; letter-spacing: -0.02em; } + th, + td { + border-color: var(--ac-border); + } + .content-panel + .content-panel { - border-top-color: var(--sl-color-hairline); + border-top-color: var(--ac-border); + } + + footer.sl-flex { + border-top: 1px solid var(--ac-border); + gap: 1rem; + margin-top: 3.5rem; + padding-top: 1.25rem; + } + + footer.sl-flex .meta { + align-items: center; + color: var(--ac-muted); + font-size: 0.8rem; + gap: 0.5rem 1.25rem; + margin-top: 0; + } + + footer.sl-flex .meta a { + color: var(--ac-muted); + text-decoration: none; + } + + footer.sl-flex .meta a:hover { + color: var(--ac-accent); + } + + footer.sl-flex .pagination-links { + gap: 0.75rem; + grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); + } + + footer.sl-flex .pagination-links a { + border: 0; + border-radius: 0; + box-shadow: none; + color: var(--ac-muted); + padding: 0.4rem 0; + transition: color 160ms ease; + } + + footer.sl-flex .pagination-links a:hover { + background: transparent; + color: var(--ac-ink); + } + + footer.sl-flex .pagination-links .link-title { + color: var(--ac-ink); + font-family: var(--sl-font-heading); + font-size: var(--sl-text-base); + letter-spacing: -0.02em; + } + + [data-has-hero] footer.sl-flex .pagination-links { + display: none; } @media (max-width: 50rem) { @@ -188,6 +453,10 @@ display: block; overflow-x: auto; } + + .live-model-catalog-actions { + width: 100%; + } } @media (prefers-reduced-motion: reduce) { diff --git a/docs/superpowers/plans/2026-07-22-main-site-aligned-docs-theme.md b/docs/superpowers/plans/2026-07-22-main-site-aligned-docs-theme.md new file mode 100644 index 00000000..60e87a88 --- /dev/null +++ b/docs/superpowers/plans/2026-07-22-main-site-aligned-docs-theme.md @@ -0,0 +1,208 @@ +# Main-site-aligned documentation theme Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Align the Starlight documentation site's typography and light/dark color system with the AnyCap main site's visual language. + +**Architecture:** The docs site retains Starlight and implements its own visual system in `custom.css`. A small Node contract test prevents font roles and primary palette values from drifting, while Starlight CSS variables map those tokens to the existing documentation UI. + +**Tech Stack:** Astro 7, Starlight 0.41, CSS custom properties, Node.js built-in test runner, Geist package. + +## Global Constraints + +- Preserve documentation content, routes, metadata, sitemap behavior, and deployment configuration. +- Use the main site at `/Users/tyluo/go/src/engineering/anycap/web` only as the typography and palette source of truth. +- Use Inter for body/UI, Geist Pixel Square for branded headings, and Space Mono for code. +- Keep both Starlight light and dark modes selectable and accessible. +- User-facing documentation remains English. + +--- + +### Task 1: Add a theme contract test + +**Files:** + +- Create: `docs/scripts/theme-contract.test.mjs` +- Test: `docs/scripts/theme-contract.test.mjs` + +**Interfaces:** + +- Consumes: `docs/src/styles/custom.css` as UTF-8 text. +- Produces: a Node test command that exits non-zero when required theme declarations drift. + +- [x] **Step 1: Write the failing test** + +Create `docs/scripts/theme-contract.test.mjs` with the following test. It intentionally fails until the new theme declarations exist. + +```js +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import test from 'node:test'; + +const stylesheet = await readFile(new URL('../src/styles/custom.css', import.meta.url), 'utf8'); + +test('uses the main-site typography roles', () => { + assert.match(stylesheet, /--sl-font:\s*Inter,/); + assert.match(stylesheet, /--sl-font-heading:\s*"Geist Pixel Square"/); + assert.match(stylesheet, /--sl-font-mono:\s*"Space Mono"/); + assert.match(stylesheet, /h1,[\s\S]*font-family:\s*var\(--sl-font-heading\)/); +}); + +test('maps the main-site light palette and an olive-charcoal dark palette', () => { + for (const declaration of [ + '--ac-page: #f9faf5', '--ac-surface: #f4f5f0', '--ac-raised: #fbfcf8', + '--ac-ink: #1c1f17', '--ac-muted: #4d5145', '--ac-accent: #6b7d3a', + '--ac-border: #d4dbb8', + ]) assert.ok(stylesheet.includes(declaration), `missing light token: ${declaration}`); + assert.match(stylesheet, /:root\[data-theme='dark'\][\s\S]*--ac-page: #12150f/); + assert.match(stylesheet, /:root\[data-theme='dark'\][\s\S]*--ac-accent: #a8bc62/); +}); +``` + +- [x] **Step 2: Run the test to verify it fails** + +Run: `node --test docs/scripts/theme-contract.test.mjs` + +Expected: FAIL because `custom.css` does not yet define `--sl-font-heading` or the required `--ac-*` tokens. + +- [x] **Step 3: Commit the test scaffold** + +```bash +git add docs/scripts/theme-contract.test.mjs +git commit -m "test(docs): define main-site theme contract" +``` + +### Task 2: Add the display-font dependency and map theme tokens + +**Files:** + +- Modify: `docs/package.json` +- Modify: `docs/package-lock.json` +- Modify: `docs/src/styles/custom.css` + +**Interfaces:** + +- Consumes: main-site palette and typography roles from the approved design spec. +- Produces: font faces and `--ac-*`, `--sl-*` mappings consumed by Starlight and Task 3. + +- [x] **Step 1: Add the dependency** + +Run from `docs/`: + +```bash +npm install --save geist@1.7.0 +``` + +Expected: `docs/package.json` contains `"geist": "1.7.0"` and the lockfile records the resolved package. + +- [x] **Step 2: Replace root theme declarations with the token map** + +In `docs/src/styles/custom.css`, import Geist Pixel Square and define font roles and light tokens before mapping them to Starlight: + +```css +@import "geist/font/pixel"; + +:root[data-theme='light'] { + --ac-page: #f9faf5; + --ac-surface: #f4f5f0; + --ac-raised: #fbfcf8; + --ac-ink: #1c1f17; + --ac-muted: #4d5145; + --ac-accent: #6b7d3a; + --ac-border: #d4dbb8; +} + +:root[data-theme='dark'] { + --ac-page: #12150f; + --ac-surface: #191d14; + --ac-raised: #22271c; + --ac-ink: #f4f5e9; + --ac-muted: #c9d0b9; + --ac-accent: #a8bc62; + --ac-border: #3c4730; +} + +:root { + --sl-font: Inter, ui-sans-serif, system-ui, sans-serif; + --sl-font-heading: "Geist Pixel Square", ui-monospace, monospace; + --sl-font-mono: "Space Mono", "SFMono-Regular", Consolas, monospace; + --sl-color-bg: var(--ac-page); + --sl-color-bg-nav: color-mix(in srgb, var(--ac-page) 92%, transparent); + --sl-color-bg-sidebar: var(--ac-surface); + --sl-color-white: var(--ac-ink); + --sl-color-gray-1: var(--ac-ink); + --sl-color-gray-2: var(--ac-muted); + --sl-color-accent: var(--ac-accent); + --sl-color-hairline: var(--ac-border); +} +``` + +- [x] **Step 3: Run the theme contract test** + +Run: `node --test docs/scripts/theme-contract.test.mjs` + +Expected: PASS with 2 passing tests. + +- [x] **Step 4: Commit the dependency and token map** + +```bash +git add docs/package.json docs/package-lock.json docs/src/styles/custom.css +git commit -m "feat(docs): align theme tokens with main site" +``` + +### Task 3: Apply component treatment and validate the build + +**Files:** + +- Modify: `docs/src/styles/custom.css` +- Test: `docs/scripts/theme-contract.test.mjs` + +**Interfaces:** + +- Consumes: the `--ac-*` tokens and `--sl-font-heading` from Task 2. +- Produces: styled Starlight chrome, prose, cards, controls, code, tables, and accessible interactions. + +- [x] **Step 1: Apply typography and interaction rules** + +Add these focused rules after the token mapping: + +```css +body { background: var(--ac-page); color: var(--ac-ink); letter-spacing: -0.01em; } +h1, h2, h3, h4, .site-title { font-family: var(--sl-font-heading); letter-spacing: -0.035em; } +a:focus-visible, button:focus-visible, summary:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 3px; } +.sl-link-card, .card { border-color: var(--ac-border); background: var(--ac-raised); border-radius: 0.75rem; } +.sl-link-card:hover { border-color: var(--ac-accent); box-shadow: 0 10px 24px color-mix(in srgb, var(--ac-ink) 8%, transparent); transform: translateY(-2px); } +``` + +Retain the existing reduced-motion override and table overflow behavior. Update header, +sidebar, button, code, table, and hero declarations to consume `--ac-*` tokens instead of +hard-coded legacy values. + +- [x] **Step 2: Run diagnostics** + +Run: + +```bash +node --test docs/scripts/theme-contract.test.mjs +make docs-check +``` + +Expected: 3 passing theme tests; Astro reports 0 errors, 0 warnings, and 0 hints. + +- [x] **Step 3: Build and audit the release artifact** + +Run: + +```bash +make docs-audit +git diff --check +``` + +Expected: the SEO audit reports 28 indexable pages and 8 release artifacts; `git diff --check` prints no whitespace errors. + +- [x] **Step 4: Commit the component treatment** + +```bash +git add docs/src/styles/custom.css docs/scripts/theme-contract.test.mjs +git commit -m "feat(docs): apply main-site visual treatment" +``` diff --git a/docs/superpowers/specs/2026-07-22-main-site-aligned-docs-theme-design.md b/docs/superpowers/specs/2026-07-22-main-site-aligned-docs-theme-design.md new file mode 100644 index 00000000..3f8e9bf0 --- /dev/null +++ b/docs/superpowers/specs/2026-07-22-main-site-aligned-docs-theme-design.md @@ -0,0 +1,79 @@ +# Main-site-aligned documentation theme + +## Goal + +Make the Astro Starlight documentation site share the visual language of the AnyCap main +site while preserving Starlight navigation, accessibility, responsive behavior, and +content structure. The existing light and dark theme controls remain available. + +## Source of truth + +The visual source is `/Users/tyluo/go/src/engineering/anycap/web`: + +- `src/app/layout.tsx` defines Inter, Space Mono, and Geist Pixel Square usage. +- Landing and SEO components define the light palette and component treatment. +- The documentation site must not copy the main site's component CSS wholesale. It owns + its Starlight-specific implementation and uses the main site only as a token and + typographic reference. + +## Typography + +- Body text and standard interface text use Inter, matching the main site. +- Display headings, section headings, and the documentation site title use Geist Pixel + Square, matching the main site's branded display treatment. +- Code blocks, inline code, and data-dense controls use Space Mono. +- Typography remains responsive and readable: prose line length and Starlight's existing + semantic hierarchy are preserved. + +## Color system + +### Light theme + +| Purpose | Token/value | +| --- | --- | +| Page background | `#f9faf5` | +| Sidebar and secondary surface | `#f4f5f0` | +| Raised surface | `#fbfcf8` | +| Primary text | `#1c1f17` | +| Secondary text | `#4d5145` | +| Brand accent | `#6b7d3a` | +| Hairline/border | `#d4dbb8` | + +### Dark theme + +The dark theme is a deliberate olive-charcoal extension of the main-site palette, not a +literal inversion. Its page and sidebar surfaces are dark olive-charcoal; text is a warm, +high-contrast pale green; borders and accent states use muted olive values. Token contrast +must preserve readable prose, code, tables, and interactive controls. + +## Component treatment + +- Header and sidebar use the matched surfaces, restrained hairlines, and translucent + backdrop treatment appropriate to their theme. +- Buttons, current navigation states, links, cards, tables, and code blocks use the same + olive accent and border language as the main site. +- Cards retain Starlight semantics but use the main site's restrained rounded-corner, + hover, focus-ring, and shadow behavior. +- The documentation hero retains its content and layout; only its typography, spacing, + background, and visual treatments change. + +## Technical approach + +1. Add the `geist` package at the version compatible with the main site, so Geist Pixel + Square is loaded from the same package rather than approximated with a fallback. +2. Define the main-site font stacks and palette as CSS custom properties in + `docs/src/styles/custom.css`. +3. Map those properties to Starlight theme tokens separately for light and dark themes. +4. Apply narrow component overrides for Starlight chrome, prose headings, cards, buttons, + tables, code blocks, hover states, focus rings, and reduced-motion behavior. +5. Do not change documentation content, routes, metadata, sitemap behavior, or deployment + configuration. + +## Acceptance criteria + +- Light mode uses the specified main-site palette and the three matching font roles. +- Dark mode remains selectable and uses an accessible olive-charcoal counterpart. +- No heading falls back to the previous Space Mono display style. +- Starlight navigation, search, table overflow, focus indicators, and mobile behavior + remain usable. +- `make docs-check`, `make docs-audit`, and `git diff --check` pass after implementation. diff --git a/docs/worker.mjs b/docs/worker.mjs new file mode 100644 index 00000000..f4764ead --- /dev/null +++ b/docs/worker.mjs @@ -0,0 +1,25 @@ +const catalogCapabilities = new Set(['image', 'video', 'music', 'audio']); +const catalogPath = /^\/api\/model-catalog\/([a-z-]+)\/?$/; + +export default { + async fetch(request, env) { + const url = new URL(request.url); + const match = catalogPath.exec(url.pathname); + + if (request.method === 'GET' && match && catalogCapabilities.has(match[1])) { + const capability = match[1]; + const upstream = await fetch(`https://api.anycap.ai/v1/${capability}/models`, { + headers: { Accept: 'application/json' }, + }); + const headers = new Headers(upstream.headers); + + headers.set('Cache-Control', 'public, max-age=300, s-maxage=300, stale-while-revalidate=600'); + headers.set('Content-Type', 'application/json; charset=utf-8'); + headers.delete('Set-Cookie'); + + return new Response(upstream.body, { status: upstream.status, headers }); + } + + return env.ASSETS.fetch(request); + }, +}; diff --git a/docs/wrangler.jsonc b/docs/wrangler.jsonc index 67a3bafb..2d510644 100644 --- a/docs/wrangler.jsonc +++ b/docs/wrangler.jsonc @@ -2,7 +2,9 @@ "$schema": "node_modules/wrangler/config-schema.json", "name": "anycap-docs", "compatibility_date": "2026-07-21", + "main": "./worker.mjs", "assets": { + "binding": "ASSETS", "directory": "./dist", "html_handling": "auto-trailing-slash", "not_found_handling": "404-page"