# Detail & Texture Source: https://docs.thrixel.com/detail import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import { Callout } from 'fumadocs-ui/components/callout'; Phase 4 takes a completed submission as the source mesh and produces a high-resolution textured model. You can also remesh or retexture an existing result without regenerating from scratch. Endpoints split across two routers: - `/api/v1/detailer/*` — full detail + texture pass, geometry-only operations (remesh). - `/api/v1/texture/*` — texture-only operations on an existing mesh (generate, rebake). --- ## Detail and texture a model Requires API key. Generate a high-resolution textured mesh from a parent submission. A reference image and prompt guide the texture style; if omitted, they are auto-generated from the parent. ### Request Body | Name | Type | Description | | --- | --- | --- | | `parent_submission_id` | string (required) | ID of the submission to detail. | | `image` | string | Reference image (base64 or HTTPS URL). Auto-generated if omitted. | | `mesh` | string | Override source mesh (base64 or URL). Defaults to the parent's GLB. | | `prompt` | string | Text description of the desired appearance. | | `seed` | integer | Random seed for reproducibility. 0–999,999. Default: `42`. | | `texture_size` | integer | Output texture resolution. Values: `512`, `768`, `1024`, `2048`. Default: `768`. | | `decimation_target` | integer | Target triangle count after decimation. 10,000–500,000. Default: `160000`. | | `preserve_parts` | boolean | Keep separate mesh parts intact during decimation. Default: `true`. | | `focus_on_node_names` | string[] | Node names to focus the generation on. Empty = whole mesh. | | `project_id` | string | Assign to a project. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/detailer/submit \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{ "parent_submission_id": "a1b2c3d4-...", "prompt": "weathered bronze, green patina", "texture_size": 1024 }' ``` ### Example Response ```json { "submission_id": "e5f6a7b8-...", "status": "queued", "created_at": "2026-04-20T14:45:30Z", "reference_image_url": "https://api.thrixel.com/api/v1/detailer/reference/e5f6a7b8-..." } ``` --- ## Re-decimate a Phase 4 mesh Requires API key. Produce a new triangle count from an existing Phase 4 checkpoint without regenerating texture. Fast — reuses cached intermediate results. ### Request Body | Name | Type | Description | | --- | --- | --- | | `parent_submission_id` | string (required) | ID of a completed Phase 4 submission. | | `decimation_target` | integer | Target triangle count. 10,000–500,000. Default: `200000`. | | `remesh` | boolean | Run quad remeshing before decimation. Default: `true`. | | `project_id` | string | Assign to a project. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/detailer/remesh \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{ "parent_submission_id": "e5f6a7b8-...", "decimation_target": 80000 }' ``` --- ## Generate textures for an existing mesh Requires API key. Produce fresh PBR textures from a reference image. Geometry is preserved; only materials change. Works on any completed submission (phase 1–5), not just Phase 4 output. Image priority: user-supplied → cached parent input → auto-generated from the GLB. ### Request Body | Name | Type | Description | | --- | --- | --- | | `parent_submission_id` | string (required) | ID of a completed submission to retexture. | | `texture_size` | integer | Output texture resolution. Values: `512`, `768`, `1024`, `2048`. Default: `1024`. | | `image` | string | Reference image (base64 data URI). Auto-generated from the GLB if omitted. | | `apply_to_node_names` | string[] | Restrict texturing to specific mesh nodes. Empty = whole mesh. | | `project_id` | string | Assign to a project. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/texture/generate \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{ "parent_submission_id": "e5f6a7b8-...", "texture_size": 1024 }' ``` --- ## Rebake textures at a new resolution Requires API key. Re-bake the existing texture at a different resolution. Picks the cheapest viable path automatically: fast bake from a prior `/texture/generate` checkpoint when available, otherwise the full reprocessing path. ### Request Body | Name | Type | Description | | --- | --- | --- | | `parent_submission_id` | string (required) | ID of a completed submission. | | `texture_size` | integer | Output texture resolution. Values: `512`, `768`, `1024`, `2048`. Default: `1024`. | | `project_id` | string | Assign to a project. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/texture/rebake \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{ "parent_submission_id": "e5f6a7b8-...", "texture_size": 2048 }' ``` --- ## Fetch reference image Public. Returns the user-provided or auto-generated reference image used to guide the Phase 4 pipeline. PNG. ### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of a Phase 4 submission. | ### Example Request ```bash curl -L -o reference.png \ https://api.thrixel.com/api/v1/detailer/reference/e5f6a7b8-... ``` --- # Download Source: https://docs.thrixel.com/download import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import { Callout } from 'fumadocs-ui/components/callout'; GLB is produced when a submission completes. Other formats are converted on-demand: either inline via the unified `/download` endpoint (which waits for the result), or asynchronously via the `/convert` job API. --- ## Download a submission asset Public. Unified endpoint for all downloadable artifacts. GLB is always ready; FBX/OBJ/STL/USDZ trigger an on-demand conversion if not yet cached. ### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | ### Query Parameters | Name | Type | Description | | --- | --- | --- | | `format` | string | Asset format. Values: `glb`, `fbx`, `obj`, `stl`, `usdz`, `py`, `thumbnail`, `reference_image`. Default: `glb`. | | `index` | integer | Index for `reference_image` format (0–5). Default: `0`. | ### Example Request ```bash # GLB (instant) curl -L -o model.glb \ "https://api.thrixel.com/api/v1/a1b2c3d4-.../download?format=glb" # FBX (triggers conversion, may take a few seconds) curl -L -o model.fbx \ "https://api.thrixel.com/api/v1/a1b2c3d4-.../download?format=fbx" ``` --- ## Queue a conversion job Public. Async alternative to `/download` for non-GLB formats. Returns immediately with a `job_id` to poll. Re-requesting the same (submission, format) returns the existing ready job unless `force=true`. ### Request Body | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission to convert. | | `format` | string (required) | Target format. Values: `fbx`, `obj`, `stl`, `usdz`. | | `force` | boolean | Re-run the conversion even if a ready job exists. Default: `false`. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/convert \ -H "Content-Type: application/json" \ -d '{"submission_id": "a1b2c3d4-...", "format": "usdz"}' ``` ### Example Response ```json { "job_id": "f7a8b9c0-...", "submission_id": "a1b2c3d4-...", "format": "usdz", "status": "queued", "error": null, "download_url": null, "status_url": "https://api.thrixel.com/api/v1/convert/f7a8b9c0-..." } ``` --- ## Check conversion status Public. Returns the current status of a conversion job. Poll until status becomes `ready` or `failed`. ### Path Parameters | Name | Type | Description | | --- | --- | --- | | `job_id` | string (required) | UUID returned by `POST /convert`. | ### Example Request ```bash curl https://api.thrixel.com/api/v1/convert/f7a8b9c0-... ``` ### Example Response ```json { "job_id": "f7a8b9c0-...", "submission_id": "a1b2c3d4-...", "format": "usdz", "status": "ready", "error": null, "download_url": "https://api.thrixel.com/api/v1/convert/f7a8b9c0-.../download", "status_url": "https://api.thrixel.com/api/v1/convert/f7a8b9c0-..." } ``` --- ## Download a converted file Public. Returns the converted file once ready. 409 if still queued/running, 410 if the job failed. ### Path Parameters | Name | Type | Description | | --- | --- | --- | | `job_id` | string (required) | UUID of a ready conversion job. | ### Example Request ```bash curl -L -o model.usdz \ https://api.thrixel.com/api/v1/convert/f7a8b9c0-.../download ``` --- # Ratings & Favorites Source: https://docs.thrixel.com/feedback import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import { Callout } from 'fumadocs-ui/components/callout'; There are two ways to register that you liked (or didn't like) a submission: - **Ratings** — a thumbs-up / thumbs-down signal. Thrixel uses these in aggregate to evaluate model quality. One rating per API key per submission; re-calling flips the value. - **Favorites** — a personal bookmark. Surfaces the submission in your "Favorite Assets" view. Independent of ratings (so you can love a model for personal reasons even while thumbs-downing it for the quality signal). Both are scoped to your API key — nothing here is public. ## Ratings --- ### Set a rating Requires API key. Upserts the rating for the calling API key on this submission. Re-calling with a different value flips the rating; the response always reflects the current state. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `rating` | integer (required) | `1` for thumbs-up, `-1` for thumbs-down. | #### Example Request ```bash curl -X PUT https://api.thrixel.com/api/v1/$SUBMISSION_ID/rating \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{"rating": 1}' ``` #### Example Response ```json { "submission_id": "sub-3c4d...", "rating": 1 } ``` #### Errors | Code | Meaning | | --- | --- | | `404` | Submission not found. | | `422` | `rating` is not `1` or `-1`. | --- ### Clear a rating Requires API key. Removes the calling API key's rating on this submission. Idempotent — no error if no rating exists. The response has `rating: null`. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Example Response ```json { "submission_id": "sub-3c4d...", "rating": null } ``` ## Favorites --- Favorites are a **personal collection** — they don't affect Thrixel's internal quality signal. Use them to bookmark models you want to find later in the "Favorite Assets" sidebar view. ### Favorite a submission Requires API key. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `is_favorite` | boolean (required) | `true` to favorite, `false` to remove. | #### Example Request ```bash curl -X PATCH https://api.thrixel.com/api/v1/$SUBMISSION_ID/favorite \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{"is_favorite": true}' ``` #### Example Response ```json { "submission_id": "sub-3c4d...", "is_favorite": true } ``` --- ### Pin a favorite Requires API key. Pin or unpin a favorited submission so it sorts to the top of the **Favorite Assets** grid. Independent of the chat-sidebar pin (`PATCH /pin` in [Organize](/docs/organize)) — pinning here only affects the favorites view. The submission must already be a favorite (i.e. `is_favorite=true`) for pinning to have a visible effect. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `is_favorite_pinned` | boolean (required) | `true` to pin within favorites, `false` to unpin. | #### Example Response ```json { "submission_id": "sub-3c4d...", "is_favorite_pinned": true } ``` --- # Getting Started Source: https://docs.thrixel.com/getting-started import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## What is Thrixel? Thrixel turns text prompts and reference images into production-ready 3D models through a five-phase pipeline. You submit a request, poll (or stream) until it's ready, then download the result in GLB, FBX, OBJ, STL, or USDZ. ## Base URL ```bash https://api.thrixel.com/api/v1 ``` ## Authentication Authenticated endpoints require an API key passed as a Bearer token. Keys are in the format `sk-thrixel-...` and are issued by the Thrixel team — contact us to obtain one. ```bash Authorization: Bearer sk-thrixel- ``` Public endpoints (info, stream, downloads, convert, gallery) do not require authentication. ## Rate Limits Each API key is subject to three limits (defaults shown — your plan may differ): - **Concurrent jobs** — 3 active (queued or processing) submissions at a time - **Hourly** — 10 requests per rolling hour - **Daily** — 50 requests per rolling 24 hours ## Quickstart Submit a text prompt, wait for the job to complete, and download the GLB: ```bash # 1. Submit a prompt curl -X POST https://api.thrixel.com/api/v1/phase1/submit \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{"task": "a small stone gargoyle holding a lantern"}' # → {"submission_id": "abc-123", "status": "queued", "created_at": "..."} # 2. Poll until completed curl https://api.thrixel.com/api/v1/abc-123/info # → {"status": "completed", ...} # 3. Download the GLB curl -L -o model.glb https://api.thrixel.com/api/v1/abc-123/download?format=glb ``` ```python import requests, time BASE = "https://api.thrixel.com/api/v1" KEY = "sk-thrixel-" # 1. Submit r = requests.post( f"{BASE}/phase1/submit", headers={"Authorization": f"Bearer {KEY}"}, json={"task": "a small stone gargoyle holding a lantern"}, ) submission_id = r.json()["submission_id"] # 2. Poll while True: info = requests.get(f"{BASE}/{submission_id}/info").json() if info["status"] in ("completed", "failed"): break time.sleep(5) # 3. Download glb = requests.get(f"{BASE}/{submission_id}/download?format=glb") open("model.glb", "wb").write(glb.content) ``` --- # Thrixel API Source: https://docs.thrixel.com/ The Thrixel API turns text prompts and reference images into production-ready 3D models through a five-phase pipeline. You submit a request, poll (or stream) until it's ready, then download the result in GLB, FBX, OBJ, STL, or USDZ. ## Where to start - [Getting Started](/docs/getting-started) — base URL, authentication, rate limits, and a quickstart. - [Generation](/docs/workflow) — the main endpoints that create a 3D model (Phase 1, 2, 3, 5). - [Writing Prompts](/docs/prompts) — what works and what doesn't, written for users with no 3D background. - [Job Status](/docs/progress) — polling, streaming (SSE), and submission listing. - [Download](/docs/download) — get the model out in GLB, FBX, OBJ, STL, or USDZ. - [Detail & Texture](/docs/detail) — Phase 4 GPU detailing, remesh, and texture generate/rebake. - [Projects & Sources](/docs/organize) — group submissions, attach style references, rename/archive/pin. - [Ratings & Favorites](/docs/feedback) — thumbs up/down + personal bookmarks. ## Base URL ```bash https://api.thrixel.com/api/v1 ``` --- # Projects & Sources Source: https://docs.thrixel.com/organize import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import { Callout } from 'fumadocs-ui/components/callout'; Group related submissions into projects, give them nicknames, pin favorites, and archive older work. All endpoints below require authentication and act on resources owned by your API key. ## Projects --- ### List projects Requires API key. Returns all projects owned by the authenticated API key. #### Query Parameters | Name | Type | Description | | --- | --- | --- | | `include_archived` | boolean | Include archived projects. Default: `false`. | #### Example Request ```bash curl -H "Authorization: Bearer sk-thrixel-" \ https://api.thrixel.com/api/v1/projects ``` #### Example Response ```json { "projects": [ { "id": "p1q2r3s4-...", "name": "Gargoyle variations", "description": "Stylistic experiments", "is_archived": false, "created_at": "2026-04-18T09:00:00Z", "updated_at": "2026-04-20T14:00:00Z", "submission_count": 7 } ], "count": 1 } ``` --- ### Create a project Requires API key. #### Request Body | Name | Type | Description | | --- | --- | --- | | `name` | string (required) | Project name. 1–255 characters. | | `description` | string | Optional description. Max 2000 characters. | #### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/projects \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{"name": "Gargoyle variations"}' ``` --- ### Get a project Requires API key. Returns project metadata plus an embedded list of its submissions (soft-deleted excluded). #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `project_id` | string (required) | UUID of the project. | --- ### Update a project Requires API key. Rename or re-describe. At least one field required. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `project_id` | string (required) | UUID of the project. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `name` | string | New name. 1–255 characters. | | `description` | string | New description. Max 2000 characters. | --- ### Delete a project Requires API key. Permanently deletes the project. Submissions in the project are unlinked (`project_id` set to `null`) — they are not deleted. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `project_id` | string (required) | UUID of the project. | ## Project Sources --- Each project can carry up to **256 KB of plain-text reference material** split across files (max **64 KB per file**). Allowed extensions: `.md`, `.markdown`, `.txt`, `.text`. When you submit a new generation inside the project, the parsed text of every source file is injected into the LLM's system prompt — so this is where you put your style guide, glossary of in-world names, dimensions you want respected ("chairs are always 45 cm tall"), or any other context the model should treat as constant. Drop a `style.md` in a "Gargoyle variations" project that describes your preferred polycount, the materials you want, and the silhouette rules. Every Phase 1 prompt in that project will be evaluated against those constants without you re-typing them. ### List source files Requires API key. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `project_id` | string (required) | UUID of the project. | #### Example Response ```json { "project_id": "p1q2r3s4-...", "sources": [ { "id": "src-9a8b...", "project_id": "p1q2r3s4-...", "filename": "style.md", "mime_type": "text/markdown", "size_bytes": 1842, "created_at": "2026-04-20T14:00:00Z" } ], "count": 1, "total_bytes": 1842 } ``` `total_bytes` is the sum across the whole project — useful for checking how much of the 256 KB budget is left before uploading more. --- ### Get a single source Requires API key. Returns the metadata plus the **parsed text** of the file (what actually gets injected into the prompt — line endings normalized, content decoded UTF-8). #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `project_id` | string (required) | UUID of the project. | | `source_id` | string (required) | UUID of the source file. | --- ### Upload a source file Requires API key. `multipart/form-data`. The file is parsed at upload time and stored in the database; the raw upload is also mirrored to S3. The parsed content is injected into the system prompt for every new submission created in the project. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `project_id` | string (required) | UUID of the project. | #### Form Fields | Name | Type | Description | | --- | --- | --- | | `file` | file (required) | `.md`, `.markdown`, `.txt`, or `.text`. Max 64 KB per file. | #### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/projects/$PROJECT_ID/sources \ -H "Authorization: Bearer sk-thrixel-" \ -F "file=@style.md" ``` #### Errors | Code | Meaning | | --- | --- | | `400` | Empty file, or invalid UTF-8 content. | | `413` | File exceeds 64 KB, or the project would exceed 256 KB total. | | `415` | Unsupported file extension. | --- ### Update a source file Requires API key. Rename or rewrite the file's content. At least one of `filename` / `content` must be present. Per-file and per-project caps still apply. #### Request Body | Name | Type | Description | | --- | --- | --- | | `filename` | string | New filename including an allowed extension. | | `content` | string | Replacement UTF-8 text. | --- ### Delete a source file Requires API key. Removes the DB row and the S3 mirror. Submissions already created in the project are unaffected; only **new** submissions after this point will see the reduced source set in the system prompt. ## Submission Management --- ### Set or clear the nickname Requires API key. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `nickname` | string \| null | Display label. Pass `null` to clear. Max 255 characters. | --- ### Archive or unarchive Requires API key. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `is_archived` | boolean (required) | `true` to archive, `false` to restore. | --- ### Toggle visibility Requires API key. Hides or shows the submission in list endpoints without deleting it. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `is_visible` | boolean (required) | `true` to show, `false` to hide. | --- ### Pin or unpin Requires API key. Pinned submissions sort to the top of lists. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `is_pinned` | boolean (required) | `true` to pin, `false` to unpin. | --- ### Assign to a project Requires API key. Move the submission into a project, or pass `null` to remove. Both the submission and the target project must belong to your API key. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | #### Request Body | Name | Type | Description | | --- | --- | --- | | `project_id` | string \| null | UUID of the target project, or `null` to unassign. | --- ### Soft-delete a submission Requires API key. Hides the submission from listings but preserves its data. Include soft-deleted items in `/submissions` via `include_deleted=true`. #### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID of the submission. | --- # Job Status Source: https://docs.thrixel.com/progress import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import { Callout } from 'fumadocs-ui/components/callout'; Once a submission is created, monitor its lifecycle by polling `/info`, streaming `/stream` (Server-Sent Events), or listing all your submissions. --- ## Get submission metadata Public. Returns current status, phase, input, and parent chain. Use this for simple polling. ### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID returned by any submit endpoint. | ### Example Request ```bash curl https://api.thrixel.com/api/v1/a1b2c3d4-.../info ``` ### Example Response ```json { "submission_id": "a1b2c3d4-...", "phase": 1, "status": "completed", "model": "thrixel+", "input": { "type": "text", "task": "a small stone gargoyle holding a lantern", "image": null, "images": null, "modification_request": null }, "parent_submission_id": null, "nickname": null, "is_archived": false, "is_visible": true, "is_deleted": false, "is_pinned": false, "adaptive_thinking": false, "created_at": "2026-04-20T14:32:11Z", "completed_at": "2026-04-20T14:34:02Z" } ``` --- ## Stream progress (SSE) Public. Server-Sent Events stream that emits progress updates, log messages, and status transitions in real time. Closes automatically when the submission reaches a terminal state. ### Path Parameters | Name | Type | Description | | --- | --- | --- | | `submission_id` | string (required) | UUID returned by any submit endpoint. | ### Example Request ```bash curl -N https://api.thrixel.com/api/v1/a1b2c3d4-.../stream ``` ```javascript const es = new EventSource( "https://api.thrixel.com/api/v1/a1b2c3d4-.../stream" ); es.onmessage = (e) => { const event = JSON.parse(e.data); console.log(event.type, event); }; ``` Event frames arrive as `data:` lines containing JSON. Common shapes: ```json // Progress update {"type": "progress", "percent": 0.42, "message": "Generating geometry..."} // Status change {"type": "status", "status": "processing"} // Terminal event — stream closes after this {"type": "status", "status": "completed"} ``` --- ## List your submissions Requires API key. Returns all submissions owned by the authenticated API key. Filter by status, phase, or project. ### Query Parameters | Name | Type | Description | | --- | --- | --- | | `status` | string | Filter by status. Values: `queued`, `processing`, `completed`, `failed`. | | `phase` | integer | Filter by phase. Values: `1`, `2`, `3`. | | `project_id` | string | Filter by project. | | `include_deleted` | boolean | Include soft-deleted submissions. Default: `false`. | | `limit` | integer | Max results. Default: `50`. | ### Example Request ```bash curl -H "Authorization: Bearer sk-thrixel-" \ "https://api.thrixel.com/api/v1/submissions?status=completed&limit=20" ``` ### Example Response ```json { "submissions": [ { "submission_id": "a1b2c3d4-...", "phase": 1, "status": "completed", "nickname": null, "is_pinned": false, "project_id": null, "created_at": "2026-04-20T14:32:11Z" } ], "count": 1 } ``` --- # Writing Prompts Source: https://docs.thrixel.com/prompts import { Callout } from 'fumadocs-ui/components/callout'; import PromptRefiner from '@/components/PromptRefiner'; You don't need any 3D background to write good prompts, but a few wording patterns swing the result dramatically. This page is a cookbook of recipes that work — same rules whether you're describing something new or editing an existing model. Type a rough draft, optionally drop a screenshot of your current model (and a reference image of what you want), and a refined version comes back that you can copy straight into Thrixel. The widget applies the same rules described below. --- ## Five rules that apply everywhere **1. Numbers beat adjectives.** "Decimate to 50,000 triangles" works; "make it simpler" gambles. "Scale to 2 meters tall" works; "make it bigger" doesn't say how. If you can put a number on it, do. **2. Name the part, don't describe it.** Once a model is generated, open the **Scene Hierarchy** panel — every named group (Body, Wheels, Chimney) is a handle you can refer to. Prompts that reference part names ("scale up the Wheels group by 1.5x") behave dramatically better than spatial guesses ("make the round things at the bottom bigger"). In the SPA, you can also **click a part in the 3D viewer** to scope an edit to that part. A chip appears above the Edit prompt ("Apply to: Wheels"), and when you Apply Edit, the LLM is told to leave every other part bit-identical. Same applies to the Refine button — it'll rewrite your draft to stay within that scope rather than expanding to the whole model. Via the API, pass `focus_on_node_names: ["Wheels"]` on `POST /api/v1/phase3/submit` or `POST /api/v1/prompts/refine` to get the same behaviour. **3. Anchor scale and direction to known things, not axes.** "The size of a coffee mug" is unambiguous. "Facing the camera" beats "rotated 90° on Y" — *forward / left / front / behind* gets re-projected correctly more reliably than raw axes. **4. One change per edit.** The single biggest mistake. If you say "make the wheels red AND raise the body AND add a roof", at least one of those three will silently revert or interact badly. Split into three sequential edits; editing is iterative by design. **5. "Keep X unchanged" is a real instruction.** Without it, a small change can pull other parts along with it. Adding "keep the body, smokestack, and tender exactly as they are" ties everything else down. --- ## Creating a model A new-from-scratch prompt has to invent everything — geometry, proportions, materials, parts — so specifics buy you a lot. A useful prompt usually has three components: - **Subject** — what the object actually is. - **Style** — visual aesthetic (low-poly, stylized, realistic, voxel, cartoon). - **Scale anchor** — a reference for size, if it matters. "A wooden barrel with iron rings, low-poly stylized, the size of a person." "A cool barrel." The bad version leaves style, materials, scale, and detail level entirely unconstrained. Each of those guesses will surprise you. ### When you have a reference image If you upload an image, the prompt's job changes — it describes *intent*, not appearance. Use the prompt to call out: - The **focus** in the image (e.g. "model the dragon, ignore the background rocks"). - Anything the image doesn't show (e.g. "the back side has a tail similar to the front legs"). - Style overrides ("the image shows a real dog, but model it low-poly"). "Model the central character only. Stylized hand-painted look. The arms not visible in the image should match the legs." "Make this." *(prompt is empty, image attached)* The empty-prompt case actually works *okay* most of the time, but framing is guessed and the entire scene sometimes gets modelled rather than the subject you cared about. ### Style vocabulary | What you want | What works in the prompt | | --- | --- | | Cartoon look | "stylized", "exaggerated proportions", "no surface detail", "flat colors" | | Realistic look | "PBR materials", "photoreal", "fine surface detail" | | Game-asset look | "low-poly", "stylized PBR", "clean topology" | | Toy / blocky look | "voxel-style", "blocky geometry" | | Specific colors | Hex codes (`#a83232`) or named colors ("dark forest green") | --- ## Editing a model Edit prompts are imperative — they describe *what to change* on top of the existing model. The structure is already known, so you can refer to specific named parts and they'll be matched. ### Geometry edits | Goal | Recipe | | --- | --- | | Reduce triangle count | `Decimate the mesh so that there are 50000 triangles.` | | Uniform resize | `Scale the entire model up by 1.5x.` | | Anisotropic resize | `Scale only the height by 2x. Keep width and depth the same.` | | Move a part | `Move the Chimney 0.3 units forward. Keep everything else unchanged.` | | Rotate a part | `Rotate the Wheels group by 30 degrees.` | | Add a part | `Add a small handle on the right side of the Body, near the top.` | | Remove a part | `Remove the Antenna group entirely.` | | Smooth surfaces | `Apply smooth shading to the Body and Roof groups.` | ### Color and material edits | Goal | Recipe | | --- | --- | | Change one part's color | `Make the Wheels red (#cc2222). Keep the Body color unchanged.` | | Change material type | `Change the Body material from matte plastic to polished chrome.` | | Add an accent color | `Add a thin gold trim around the rim of the Hat.` | "Reduce the polygon count of the Body group to 8000 triangles. Keep the Wheels and Chimney unchanged." "Make it less complex. Also bigger. And the wheels should be black." The bad version mashes three unrelated edits into one prompt. Run them as three separate edits and you'll keep all three. ### Common phrases that misfire - **"Make it look better"** — there's no signal for what's wrong. Tell it. - **"Add more detail"** — *where*? On which part? At what scale? - **"More realistic"** — name the material instead ("rough cast iron", "polished chrome", "weathered painted wood"). - **"A bit bigger"** — give a number or a multiplier. - **"Like a [thing] but cooler"** — describe the cool part directly. --- ## Texturing — material vocabulary When you're dialing in surface appearance (the Texture / Detailer steps), prompts are usually shorter — 2 to 6 words — and a reference image does most of the work. For texture work, **paste or drop a screenshot of what you want before typing a prompt**. The reference image dominates appearance; the prompt is a tiebreaker on material vocabulary. Long prompts without a reference image rarely beat short prompts with one. These short phrases work better than full sentences: | Surface | Phrase that works | | --- | --- | | Old / aged | `weathered`, `oxidized`, `peeling paint`, `green patina` | | Smooth metal | `polished chrome`, `brushed steel`, `gold leaf` | | Rough metal | `cast iron`, `rusted steel`, `corroded bronze` | | Wood | `rough wood grain`, `dark walnut`, `whitewashed pine` | | Stone | `polished marble`, `weathered sandstone`, `mossy granite` | | Plastic / paint | `matte plastic`, `glossy enamel paint`, `flat acrylic` | | Cloth / leather | `worn leather`, `faded denim`, `quilted cotton` | | Glass / glow | `frosted glass`, `tinted glass`, `glowing emissive panel` | "Weathered bronze with green patina, especially in the recessed details." "Make it look real and old." --- ## Putting it together A typical newbie-friendly flow: 1. **Create** with a subject + style + scale anchor. Don't sweat materials yet. 2. **Auto-refine** (no prompt) to clean up obvious geometry issues. 3. **Edit** in one or more passes — one focused change per prompt, referencing part names from the Scene Hierarchy panel, with explicit "keep X unchanged" for everything you're not touching. 4. **Texture** with a short material descriptor and (ideally) a reference image. If something misfires, the fastest fix is almost always to **shrink the prompt**, not lengthen it. --- # Generation Source: https://docs.thrixel.com/workflow import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; import { Callout } from 'fumadocs-ui/components/callout'; Generate a model from a text prompt, images, or an existing mesh. All four endpoints return a `submission_id` that you track via the endpoints on [Track Progress](/docs/progress). --- ## Create a model Requires API key. Start a new generation from a text prompt, a reference image, or up to six images. At least one of `task`, `image`, or `images` is required. ### Request Body | Name | Type | Description | | --- | --- | --- | | `task` | string | Natural-language description of the model to create. | | `image` | string | Single reference image — base64 data URL or HTTPS URL. | | `images` | string[] | Up to 6 reference images (base64 or HTTPS URLs). Mutually exclusive with `image`. | | `model` | string | LLM model override. Leave unset to use the default. | | `project_id` | string | Group the submission under a project. | | `adaptive_thinking` | boolean | Enable deeper reasoning pass. Slower but higher quality. Default: `false`. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/phase1/submit \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{"task": "a small stone gargoyle holding a lantern"}' ``` ```python import requests requests.post( "https://api.thrixel.com/api/v1/phase1/submit", headers={"Authorization": "Bearer sk-thrixel-"}, json={"task": "a small stone gargoyle holding a lantern"}, ) ``` ### Example Response ```json { "submission_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "queued", "created_at": "2026-04-20T14:32:11Z" } ``` --- ## Auto-refine Requires API key. Run a vision-critique pass on a completed Phase 1 or Phase 2 submission. The backend inspects the result and produces an improved version. ### Request Body | Name | Type | Description | | --- | --- | --- | | `parent_submission_id` | string (required) | ID of a completed Phase 1 or Phase 2 submission. | | `project_id` | string | Inherit or override the parent's project. | | `adaptive_thinking` | boolean | Enable deeper reasoning pass. Default: `false`. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/phase2/submit \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{"parent_submission_id": "a1b2c3d4-..."}' ``` ### Example Response ```json { "submission_id": "b2c3d4e5-...", "status": "queued", "created_at": "2026-04-20T14:35:22Z" } ``` --- ## Modify a model Requires API key. Apply a natural-language edit to an existing model. Example: "make the lantern glow blue". ### Request Body | Name | Type | Description | | --- | --- | --- | | `parent_submission_id` | string (required) | ID of the submission to modify. | | `modification_request` | string (required) | Description of the change to apply. | | `project_id` | string | Inherit or override the parent's project. | | `adaptive_thinking` | boolean | Enable deeper reasoning pass. Default: `false`. | | `focus_on_node_names` | string[] | Part names from the parent mesh to scope the edit to. Every part outside the list is held bit-identical. Empty/omitted = whole-mesh edit. Get part names from `/api/v1/{submission_id}/hierarchy`. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/phase3/submit \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{ "parent_submission_id": "a1b2c3d4-...", "modification_request": "make the lantern glow blue" }' ``` ```bash # Edit scoped to specific parts — the LLM is told to leave every # other part bit-identical to the input. curl -X POST https://api.thrixel.com/api/v1/phase3/submit \ -H "Authorization: Bearer sk-thrixel-" \ -H "Content-Type: application/json" \ -d '{ "parent_submission_id": "a1b2c3d4-...", "modification_request": "make it black", "focus_on_node_names": ["Seat_Group"] }' ``` ### Example Response ```json { "submission_id": "c3d4e5f6-...", "status": "queued", "created_at": "2026-04-20T14:38:01Z" } ``` --- ## Upload an existing model Requires API key. Bring your own GLB file into Thrixel so you can run Phase 2, 3, or 4 operations on it. Multipart form upload, max 100 MB. ### Request Body | Name | Type | Description | | --- | --- | --- | | `glb_file` | file (required) | Binary `.glb` file (`Content-Type: multipart/form-data`). | | `task` | string | Optional label describing the uploaded model. Max 2000 chars. | | `project_id` | string | Assign to a project. | ### Example Request ```bash curl -X POST https://api.thrixel.com/api/v1/phase5/submit \ -H "Authorization: Bearer sk-thrixel-" \ -F "glb_file=@./my_model.glb" \ -F "task=hand-sculpted base mesh" ``` ```python import requests requests.post( "https://api.thrixel.com/api/v1/phase5/submit", headers={"Authorization": "Bearer sk-thrixel-"}, files={"glb_file": open("my_model.glb", "rb")}, data={"task": "hand-sculpted base mesh"}, ) ``` ### Example Response ```json { "submission_id": "d4e5f6a7-...", "status": "completed", "original_filename": "my_model.glb", "file_size_bytes": 4528192, "created_at": "2026-04-20T14:40:15Z" } ``` ---