Skip to content

feat(tripo3d): add Tripo Studio Smart Mesh adapter - #2477

Open
kienbb wants to merge 1 commit into
jackwener:mainfrom
kienbb:feat/tripo3d-adapter
Open

kienbb wants to merge 1 commit into
jackwener:mainfrom
kienbb:feat/tripo3d-adapter

Conversation

@kienbb

@kienbb kienbb commented Sep 9, 2026

Copy link
Copy Markdown

What

A browser adapter for Tripo Studio (studio.tripo3d.ai), wrapping its Smart Mesh engine — text / image / multi-view to 3D mesh, texture baking, and the read commands needed to drive them.

Command
text-to-model <prompt> untextured mesh from a prompt
image-to-model <image> untextured mesh from one reference image
multiview-to-model <front> untextured mesh from front/left/back/right views
texture <project> bake a texture onto an existing mesh
status <operators> poll tasks by operator id
assets list workspace projects + ids
credits wallet, plan, export allowance, P2 free trials

Strategy

PAGE_FETCH for every call. api.tripo3d.ai authenticates with an HttpOnly cookie on .tripo3d.ai — the captured requests carry no bearer token and no CSRF header — and sits behind Cloudflare bot management (__cf_bm), which binds to the browser's TLS/UA fingerprint. Replaying the calls from Node risks intermittent 403s, so they are issued from the studio's own origin.

Tripo does publish a documented REST API on platform.tripo3d.ai, but it needs a separate API key rather than the studio session these commands reuse, so it is not an alternative here.

Design decisions worth reviewing

Two engines, and the cheaper one stays the default. Smart Mesh's AI Model dropdown offers Nexus-v1.0 (P1, 35 credits, triangles only) and Nexus-v2.0 (P2, 100 credits, quad-capable). The studio itself now defaults to P2; the adapter defaults to --model p1 on purpose, so an existing command line does not silently start costing 3x. --model p2 opts in.

Errors instead of silent coercion, in three places where the page does the opposite:

  • --topology quad on P1 is rejected, not downgraded to triangles — the studio renders the Quad button disabled on that engine.
  • The polycount ceiling depends on both flags (p1 20000 · p2 triangle 50000 · p2 quad 25000). The page clamps with Math.round(Math.min(value, ceiling)); the adapter throws, because a clamp the caller cannot see is a 100-credit generation at a face count nobody asked for.
  • A 403 is no longer reported as a lost session. Measured against the live studio: signed out is HTTP 401 + code 1002, while a plan refusal is HTTP 403 with a real business code (6102 Insufficient membership, 9103 Project count limit exceeded). Only 401 raises AuthRequiredError now.

symmetry is P2-only and has no UI control. The page attaches it only once the dropdown is on P2, filling it from operation/symmetry_check run against the main reference image. The adapter mirrors that exactly: text mode has no reference image and sends a literal false, image mode checks the uploaded image, multi-view checks the front slot.

--visibility defaults to auto. Privacy now sits under a "Members Only" heading; on a free plan the combobox opens the pricing dialog rather than a dropdown, and the API answers anything but public with 403 6102after the reference image has already been uploaded. auto resolves the way the store does (payment.member.type !== 'basic'shareable, else public); explicit values pass straight through.

Testing

clis/tripo3d/tripo3d.test.js — 22 tests covering the polycount matrix, the quad/P1 rejection, the 401-vs-403 split, symmetry forwarding, visibility resolution, and the exact request body runSmartMesh builds for each engine. Each guard was reverse-validated by injecting the corresponding regression and confirming it fails.

npx tsc --noEmit                                  # clean
npm run check:silent-column-drop                  # no new violations
npm run check:typed-error-lint                    # no new violations
npx vitest run --project adapter clis/tripo3d/    # 22 passed

npm test was also run in full; the 11 failing files it reports are pre-existing on this Windows checkout (path/home-expansion assertions in suno, twitter, instagram, xiaoyuzhou, src/cli.test.ts) and fail identically with this branch stashed.

Verified live against a real account (opencli browser verify green for assets, credits, status; an end-to-end image-to-model --model p2 --topology quad --polycount 22000 came back success, and project/detail/v3 echoed the stored operator as {"quad":true,"face_limit":22000,"model_version":"Nexus-v2.0-20260801","symmetry":false}).

Deliberately not included

A download command. File export is not a server-side endpoint here: operation/export-lite returns {} and only bumps the account's monthly export counter, while the FBX/OBJ/STL is produced inside the page and handed to the browser as a Blob — so it has to drive the studio's Export dialog. That surface drifted three times in 24 hours while this was being prepared (the project deep link rendering the SPA's error boundary, the viewer switching from .glb to output_mesh_<operator_id>.fbx, and the Export dialog not opening in a background window), so it is left as a follow-up rather than shipped half-working. operation/download_with_name remains the cheap path for the stored native asset when no format conversion is needed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EPFwuPThapaSgr1QFBtXsQ

Wraps studio.tripo3d.ai's Smart Mesh engine: generate an untextured 3D
mesh from a prompt, one reference image, or front/left/back/right views,
bake a texture onto an existing mesh, and read back tasks, projects and
credits.

Commands: text-to-model, image-to-model, multiview-to-model, texture,
status, assets, credits.

Strategy is PAGE_FETCH for every call. api.tripo3d.ai authenticates with
an HttpOnly cookie and sits behind Cloudflare bot management, so the
requests are issued from the studio's own origin rather than replayed
from Node. Tripo's documented REST API on platform.tripo3d.ai is a
separate product needing its own key, not the studio session these
commands reuse.

Notes on the choices that are easy to get wrong:

* Smart Mesh has two engines. --model p1 (Nexus-v1.0) is 35 credits and
  triangles only; --model p2 (Nexus-v2.0) is 100 credits and the only
  one that can emit quads. p1 is the default even though the studio's
  dropdown now defaults to P2, so no existing command line silently
  starts costing 3x.
* --topology quad is rejected on p1 instead of being downgraded to
  triangles, because the studio renders that button disabled.
* The polycount ceiling moves with both (p1 20000, p2 triangle 50000,
  p2 quad 25000). The page clamps silently; this throws instead, so a
  paid generation never runs at a face count nobody asked for.
* P2 carries a `symmetry` field the UI has no control for: the studio
  runs operation/symmetry_check on the main reference image and forwards
  the verdict. Text mode has no reference image and sends false.
* Privacy is members-only, so --visibility defaults to `auto` and
  resolves the way the store does (public on a free plan, shareable for
  a subscriber). Anything else on a free plan is refused with HTTP 403
  6102 after the image has already been uploaded.
* Only 401 means a lost session (code 1002). A 403 is a business refusal
  against a healthy session and is surfaced with its own code, so
  "Insufficient membership" is not reported as "please log in".

Exporting to a local file is deliberately left out: operation/export-lite
returns {} and only bumps a counter, while the file is built inside the
page and handed to the browser as a Blob, so a download command has to
drive the studio's Export dialog. That surface is still drifting, so it
is a follow-up rather than something shipped half-working.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPFwuPThapaSgr1QFBtXsQ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants