From 56cc120b213d767aed3965e2dd240799634622de Mon Sep 17 00:00:00 2001 From: qchantel Date: Fri, 13 Nov 2026 17:57:00 +0100 Subject: [PATCH 1/3] docs(docs): publish maya.scenario.com as a handbook built from the docs with plugin-site The site was a one-page landing that repeated a little of the README; the Photoshop and Blender sites are full handbooks with contents and search. - handbook.config.json names the chapters, from README.md, PRIVACY.md and CHANGELOG.md, with Install and Sign in first. - pages.yml builds the site with scenario-labs/plugin-site's action. - site/, its stamping tool and its test go. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/pages.yml | 97 ++++---------- AGENTS.md | 2 +- RELEASING.md | 2 +- handbook.config.json | 231 ++++++++++++++++++++++++++++++++++ site/assets/scenario-logo.svg | 15 --- site/index.html | 140 --------------------- tests/unit/test_site.py | 46 ------- tools/release/stamp_site.py | 50 -------- 8 files changed, 254 insertions(+), 329 deletions(-) create mode 100644 handbook.config.json delete mode 100644 site/assets/scenario-logo.svg delete mode 100644 site/index.html delete mode 100644 tests/unit/test_site.py delete mode 100644 tools/release/stamp_site.py diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 7e9fe53..a213491 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,9 +1,9 @@ -# GitHub Pages publish for https://maya.scenario.com, as photoshop-plugin does -# for photoshop.scenario.com: the page in site/ at the root, docs/media under -# /media/, and the latest release's ZIP under /download/. Runs after each -# release, on every push to main that changes the page or its pictures, and by -# hand. The page and its pictures come from the newest published release, so -# the site never describes a feature people cannot download yet. +# GitHub Pages publish for https://maya.scenario.com: the handbook built from +# the docs (handbook.config.json) at the root, and the latest release's ZIP +# under /download/, by scenario-labs/plugin-site, the site tooling the Scenario +# plug-ins share. Runs after each release, on every push to main that changes +# the docs, and by hand. The handbook comes from the newest published release, +# so the site never describes a feature people cannot download yet. # Pages serves it at https://scenario-labs.github.io/maya-plugin/; the Vercel # project on tools/site_proxy holds maya.scenario.com and forwards every path # there. RELEASING.md ("Site") lists what an administrator sets once. @@ -20,9 +20,10 @@ on: push: branches: [main] paths: - - "site/**" - - "docs/media/**" - - "tools/release/stamp_site.py" + - "README.md" + - "CHANGELOG.md" + - "docs/**" + - "handbook.config.json" - ".github/workflows/pages.yml" workflow_dispatch: @@ -50,76 +51,20 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: main + fetch-depth: 0 persist-credentials: false - # The newest published release: its page and pictures replace main's, and - # its version and tag fill the page's {{version}} and {{ref}}. Before the - # first release, main's own, with no download. - - name: Take the page and its pictures from the newest published release - id: release - env: - GH_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - # An empty answer means no release yet; an error from GitHub fails the - # step rather than publishing the site without its download. - tag="$(gh release list --repo "$GITHUB_REPOSITORY" --json tagName,isLatest --jq '[.[] | select(.isLatest)][0].tagName // ""')" - if [ -z "$tag" ]; then - echo "::notice::No release yet: main's page, with no download" - version="$(python3 -c 'import sys; sys.path.insert(0, "tools"); import package; print(package.version())')" - { echo "tag="; echo "version=$version"; echo "ref=main"; } >> "$GITHUB_OUTPUT" - exit 0 - fi - version="${tag#maya-plugin-v}" - [[ "$tag" == "maya-plugin-v$version" && "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "::error::Unexpected release tag $tag"; exit 1; } - git fetch --no-tags --depth=1 origin "refs/tags/$tag:refs/tags/$tag" - commit="$(git rev-parse "refs/tags/$tag^{commit}")" - # A release from before the site has no page: main's is published - # for it, with the release's version and links to main. - if git cat-file -e "$commit:site/index.html" 2>/dev/null; then - git restore --source="$commit" -- site docs/media - ref="$tag" - else - echo "::warning::$tag has no site/: publishing main's page with version $version" - ref=main - fi - { echo "tag=$tag"; echo "version=$version"; echo "ref=$ref"; } >> "$GITHUB_OUTPUT" - - name: Put the page and its pictures together - env: - VERSION: ${{ steps.release.outputs.version }} - REF: ${{ steps.release.outputs.ref }} - run: | - set -euo pipefail - cp -R site "$RUNNER_TEMP/site" - cp -R docs/media "$RUNNER_TEMP/site/media" - python3 tools/release/stamp_site.py "$RUNNER_TEMP/site/index.html" "$VERSION" "$REF" - # The latest release's ZIP, served from the site's own domain at - # download/scenario-maya-X.Y.Z.zip, where the Vercel middleware - # (tools/site_proxy/middleware.ts) counts downloads; download/latest.json - # names its version and /download/latest redirects to it. Checked - # against the release's SHA256SUMS and its build attestation first. - - name: Add the latest release's ZIP - if: steps.release.outputs.tag != '' - env: - GH_TOKEN: ${{ github.token }} - tag: ${{ steps.release.outputs.tag }} - version: ${{ steps.release.outputs.version }} - run: | - set -euo pipefail - file="scenario-maya-$version.zip" - dir="$RUNNER_TEMP/release" - mkdir -p "$dir" "$RUNNER_TEMP/site/download" - gh release download "$tag" --repo "$GITHUB_REPOSITORY" --dir "$dir" --pattern SHA256SUMS --pattern "$file" - grep -E "^[0-9a-f]{64} $file\$" "$dir/SHA256SUMS" > "$RUNNER_TEMP/site/download/SHA256SUMS" - (cd "$dir" && sha256sum -c "$RUNNER_TEMP/site/download/SHA256SUMS") - # Built by this repository's release workflow from the tagged commit. - gh attestation verify "$dir/$file" --repo "$GITHUB_REPOSITORY" \ - --signer-workflow "$GITHUB_REPOSITORY/.github/workflows/release-please.yml" - cp "$dir/$file" "$RUNNER_TEMP/site/download/" - printf '{ "version": "%s" }\n' "$version" > "$RUNNER_TEMP/site/download/latest.json" - - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version-file: .nvmrc + # The handbook from the newest release's docs, and its ZIP once the + # release's SHA256SUMS and build attestation verify. + - id: site + uses: scenario-labs/plugin-site@1acb13a05820668eca37ce8f2e787432ad597457 # main, before v0.1.0 + with: + download: scenario-maya-{version}.zip - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: - path: ${{ runner.temp }}/site + path: ${{ steps.site.outputs.path }} deploy: needs: build diff --git a/AGENTS.md b/AGENTS.md index ae02e55..017e280 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,7 +164,7 @@ Any paid run needs explicit authorization for the project and budget first. | `project.yml` | non-draft PRs, when opened, reopened or marked ready (not Dependabot's) | adds them to the Plugins project (31) | | `release-please.yml` | push to `main` | the release PR; once merged, builds, checks, attests and attaches the ZIP to a draft, checks it again on macOS, publishes it (RELEASING.md) | | `publish-changelog.yml` | release published, or by hand | posts the release notes to www.scenario.com/changelog | -| `pages.yml` | after `release-please`, changes to `site/` or `docs/media/`, by hand | publishes maya.scenario.com: the release's page, `docs/media`, the release ZIP under `/download/` (RELEASING.md, Site) | +| `pages.yml` | after `release-please`, changes to the docs, by hand | publishes maya.scenario.com with scenario-labs/plugin-site: the handbook from the release's docs (`handbook.config.json`), the release ZIP under `/download/` (RELEASING.md, Site) | GitHub runners have no Maya, so `tools/test_maya.sh` and `tools/test_maya_gui.sh` run on a Mac with Maya before each release; their diff --git a/RELEASING.md b/RELEASING.md index 4897128..50054c7 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -47,7 +47,7 @@ It checks the answer for this release's version, since an HTTP 200 alone can car ## Site -`.github/workflows/pages.yml` publishes https://maya.scenario.com after each release, on changes to `site/` or `docs/media/`, and by hand: the page from the newest published release (stamped with its version by `tools/release/stamp_site.py`), its pictures under `/media/`, and the release's ZIP under `/download/` with `download/latest.json`. The Vercel project on `tools/site_proxy` holds the domain, forwards every path to GitHub Pages, counts downloads in PostHog and answers `/download/latest`. +`.github/workflows/pages.yml` publishes https://maya.scenario.com after each release, on changes to the docs, and by hand, through [scenario-labs/plugin-site](https://github.com/scenario-labs/plugin-site), the site tooling the plug-ins share: the handbook built from the newest published release's docs (chapters in `handbook.config.json`), its pictures under `/media/`, and the release's ZIP under `/download/` with `download/latest.json`. Preview it from a checkout with `npx github:scenario-labs/plugin-site handbook --no-pdf --out build/handbook`. The Vercel project on `tools/site_proxy` holds the domain, forwards every path to GitHub Pages, counts downloads in PostHog and answers `/download/latest`. Set once by an administrator: diff --git a/handbook.config.json b/handbook.config.json new file mode 100644 index 0000000..8122357 --- /dev/null +++ b/handbook.config.json @@ -0,0 +1,231 @@ +{ + "product": "Scenario for Maya", + "brand": "for Maya", + "repository": "scenario-labs/maya-plugin", + "files": "scenario-maya", + "site": "https://maya.scenario.com", + "description": "User handbook for Scenario for Maya {version}: install, sign in, every mode with real results (3D from a prompt, an image or views, mesh edits, motion, images), prices and privacy.", + "version": { + "file": "ScenarioForMaya/scripts/scenario_maya/__init__.py", + "pattern": "__version__ = \"([^\"]+)\"" + }, + "analytics": "/page.js", + "cta": [ + [ + "Download for Maya 2025 to 2027", + "/download/latest" + ], + [ + "Install", + "#install" + ] + ], + "nav": [ + [ + "Install", + "#install" + ], + [ + "Downloads", + "#downloads" + ], + [ + "Changelog", + "#changelog" + ] + ], + "cover": [ + [ + "Maya", + "2025 to 2027, tested on 2027.2 on macOS" + ] + ], + "downloads": [ + "The plug-in: `scenario-maya-{version}.zip` from [maya.scenario.com/download/latest](https://maya.scenario.com/download/latest), installed as described in [Install](#install). Each release lists its SHA-256 in `SHA256SUMS`." + ], + "trademarks": "Autodesk and Maya are trademarks of Autodesk. This project is not affiliated with or endorsed by Autodesk.", + "checks": { + "prefixed": [ + [ + "MCP", + "Scenario" + ] + ] + }, + "fileNames": { + "docs/PRIVACY.md": "Privacy", + "docs/spec/SPEC.md": "design specification", + "AGENTS.md": "contributor guide", + "SUPPORT.md": "Support", + "SECURITY.md": "Security", + "CONTRIBUTING.md": "Contributing" + }, + "chapters": [ + { + "id": "install", + "title": "Install", + "parts": [ + { + "file": "README.md", + "section": "Install a release" + } + ] + }, + { + "id": "sign-in", + "title": "Sign in", + "parts": [ + { + "file": "README.md", + "section": "Sign in" + } + ] + }, + { + "id": "downloads", + "title": "Downloads", + "generated": "downloads" + }, + { + "id": "generate-a-3d-model", + "title": "Generate a 3D model", + "newPage": true, + "parts": [ + { + "file": "README.md", + "section": "Generate a 3D model" + } + ] + }, + { + "id": "turn-an-image-into-a-3d-model", + "title": "Turn an image into a 3D model", + "parts": [ + { + "file": "README.md", + "section": "Turn an image into a 3D model" + } + ] + }, + { + "id": "turn-views-of-an-object-into-a-3d-model", + "title": "Turn views of an object into a 3D model", + "parts": [ + { + "file": "README.md", + "section": "Turn views of an object into a 3D model" + } + ] + }, + { + "id": "quad-meshes-and-fbx-results", + "title": "Quad meshes and FBX results", + "parts": [ + { + "file": "README.md", + "section": "Quad meshes and FBX results" + } + ] + }, + { + "id": "edit-a-mesh-of-the-scene", + "title": "Edit a mesh of the scene", + "newPage": true, + "parts": [ + { + "file": "README.md", + "section": "Edit a mesh of the scene" + } + ] + }, + { + "id": "animate-a-character", + "title": "Animate a character", + "newPage": true, + "parts": [ + { + "file": "README.md", + "section": "Animate a character" + } + ] + }, + { + "id": "generate-an-image", + "title": "Generate an image", + "newPage": true, + "parts": [ + { + "file": "README.md", + "section": "Generate an image" + } + ] + }, + { + "id": "choose-a-model", + "title": "Choose a model", + "parts": [ + { + "file": "README.md", + "section": "Choose a model" + } + ] + }, + { + "id": "how-a-request-is-paid", + "title": "How a request is paid", + "newPage": true, + "parts": [ + { + "file": "README.md", + "section": "How a request is paid" + } + ] + }, + { + "id": "what-leaves-your-machine", + "title": "What leaves your machine", + "newPage": true, + "parts": [ + { + "file": "docs/PRIVACY.md" + } + ] + }, + { + "id": "how-it-is-built", + "title": "How it is built", + "newPage": true, + "parts": [ + { + "file": "README.md", + "section": "How it is built" + }, + { + "file": "README.md", + "only": "Tests" + } + ] + }, + { + "id": "changelog", + "title": "Changelog", + "newPage": true, + "parts": [ + { + "file": "CHANGELOG.md" + } + ] + }, + { + "id": "licence", + "title": "Licence", + "parts": [ + { + "file": "README.md", + "section": "More" + } + ], + "generated": "licence" + } + ] +} diff --git a/site/assets/scenario-logo.svg b/site/assets/scenario-logo.svg deleted file mode 100644 index 35ff6a0..0000000 --- a/site/assets/scenario-logo.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/site/index.html b/site/index.html deleted file mode 100644 index a3fe55e..0000000 --- a/site/index.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - -Scenario for Maya - - - - - - - - -
- - -
-
-
-

Scenario for Maya {{version}}

-

Every Scenario model, inside Maya.

-

Images, 3D models, edits of your own meshes and characters that move, from a panel docked beside the Channel Box. Each Generate shows its exact price first, sends once, and lands the result in your scene as one undo step.

- -
The Scenario panel in Maya, with a generated lantern and chest on the ground
-
- -
-

What it does

-

From a prompt to your scene

-
-
A generated image on a card in the viewport
ImagesAs a textured card, a material on your selection, or an image plane.
-
A textured treasure chest generated from one image
3D modelsFrom a prompt, an image or named views, imported at real-world size.
-
A remeshed crate in wireframe
Edit your meshesRemesh, UV unwrap or retexture the selection, applied after a review.
-
A robot character waving
MotionA prompt to a rigged character that moves, on your own character if you like.
-
-
- -
-

Example

-

One prop, start to finish

-

A weathered brass lantern for a game scene, made in the 3D tab with Meshy 7.1 without leaving Maya.

-
-
-
The 3D tab with Meshy 7.1 and the price on the Generate button
Type the prompt. The settings come from the model, and Generate shows what the run will cost.
-
The result card while Scenario generates
Scenario builds the model while you keep working; the card follows the job, even across a Maya restart.
-
The result card after the import, with the import checks
The lantern lands on the ground at real-world size with its materials and textures, checked on import. One Ctrl+Z removes it.
-
-
The lantern and a treasure chest turning in Maya's viewport
-
- -
-

Install

-

Two minutes, no restart

-

You need Maya 2025, 2026 or 2027 and a Scenario account with API access.

-
    -
  1. Download scenario-maya-{{version}}.zip and unzip it.
  2. -
  3. Drag install_scenario.py from the unzipped folder onto a Maya viewport. It copies the module into your Maya modules folder, loads the plug-in and opens the Scenario panel.
  4. -
  5. Maya 2027 asks whether to load a plug-in from a new location: choose Allow.
  6. -
  7. Click Sign in with Scenario in the panel, approve in your browser, and choose your project.
  8. -
-

Maya 2025, 2026 and 2027 on macOS, Windows and Linux. Each release lists the ZIP's SHA-256 in SHA256SUMS and carries a build attestation. The guide covers every mode; privacy says what is sent to Scenario and when.

-
-
- - - diff --git a/tests/unit/test_site.py b/tests/unit/test_site.py deleted file mode 100644 index db41d86..0000000 --- a/tests/unit/test_site.py +++ /dev/null @@ -1,46 +0,0 @@ -"""The page of maya.scenario.com (site/index.html) and its stamping.""" - -import os -import re -import sys - -import pytest - -ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -sys.path.insert(0, os.path.join(ROOT, "tools", "release")) - -import stamp_site # noqa: E402 - -PAGE = os.path.join(ROOT, "site", "index.html") - - -def page(): - with open(PAGE, encoding="utf-8") as handle: - return handle.read() - - -def test_the_page_leads_to_the_download_and_names_only_the_support_address(): - html = page() - assert 'href="/download/latest"' in html - assert chr(0x2014) not in html, "no em dashes" - assert set(re.findall(r"[\w.+-]+@[\w-]+\.[\w.]+", html)) == {"support@scenario.com"} - - -def test_every_local_file_the_page_uses_is_published(): - """``assets/`` ships with the page; ``media/`` is docs/media, copied in by pages.yml.""" - for ref in re.findall(r'(?:src|href)="([^"#:]+)"', page()): - if ref.startswith("/"): - continue # served by the proxy: /download/latest, /page.js - source = os.path.join(ROOT, "docs", ref) if ref.startswith("media/") else os.path.join(ROOT, "site", ref) - assert os.path.isfile(source), ref - - -def test_stamping_fills_the_version_and_the_ref(): - out = stamp_site.stamp(page(), "0.2.0", "maya-plugin-v0.2.0") - assert "{{" not in out and "scenario-maya-0.2.0.zip" in out and "/blob/maya-plugin-v0.2.0/README.md" in out - - -@pytest.mark.parametrize("version, ref", [("0.2", "main"), ("0.2.0", "feature"), ("0.2.0", "photoshop-plugin-v0.2.0")]) -def test_stamping_refuses_what_is_not_a_release(version, ref): - with pytest.raises(ValueError): - stamp_site.stamp(page(), version, ref) diff --git a/tools/release/stamp_site.py b/tools/release/stamp_site.py deleted file mode 100644 index 80cd5bd..0000000 --- a/tools/release/stamp_site.py +++ /dev/null @@ -1,50 +0,0 @@ -"""Fills the page of maya.scenario.com with the release it describes. - -``site/index.html`` says ``{{version}}`` where it names the build and ``{{ref}}`` -in its links to the repository; ``.github/workflows/pages.yml`` stamps them with -the newest published release (its version and tag) when it publishes. The -repository spells no version in the page, so a release never leaves it naming -the one before. Ported from photoshop-plugin's ``tools/release/stamp-site.js``. - - python3 tools/release/stamp_site.py -""" - -import re -import sys - -VERSION = re.compile(r"^\d+\.\d+\.\d+$") -REF = re.compile(r"^(main|maya-plugin-v\d+\.\d+\.\d+)$") - - -def stamp(html, version, ref): - if not VERSION.match(version): - raise ValueError(f"Not a release version: {version!r}") - if not REF.match(ref): - raise ValueError(f"Not main or a release tag: {ref!r}") - if "{{version}}" not in html: - raise ValueError("The page has no {{version}} to fill") - out = html.replace("{{version}}", version).replace("{{ref}}", ref) - left = re.search(r"\{\{\s*[\w.-]+\s*\}\}", out) - if left: - raise ValueError(f"The page keeps {left.group(0)}") - return out - - -def main(argv=sys.argv[1:]): - if len(argv) != 3: - sys.stderr.write("usage: python3 tools/release/stamp_site.py \n") - return 2 - path, version, ref = argv - try: - with open(path, encoding="utf-8") as handle: - html = stamp(handle.read(), version, ref) - except ValueError as error: - sys.stderr.write(f"stamp_site: {error}\n") - return 1 - with open(path, "w", encoding="utf-8") as handle: - handle.write(html) - return 0 - - -if __name__ == "__main__": - sys.exit(main()) From 0b04cfde3bf650740b89d692993b3d3247acf2fe Mon Sep 17 00:00:00 2001 From: qchantel Date: Fri, 13 Nov 2026 18:19:57 +0100 Subject: [PATCH 2/3] docs(docs): write a user guide and build the handbook from it Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 5 +- README.md | 528 +++++++--------------------------------- docs/PRIVACY.md | 77 +++--- docs/USER_GUIDE.md | 560 +++++++++++++++++++++++++++++++++++++++++++ handbook.config.json | 229 ++++++++++++++---- 5 files changed, 875 insertions(+), 524 deletions(-) create mode 100644 docs/USER_GUIDE.md diff --git a/AGENTS.md b/AGENTS.md index 017e280..88dd5f9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,8 +1,9 @@ # maya-plugin: agent instructions Root `AGENTS.md` is the repository rulebook for humans and coding agents. -[README.md](README.md) describes the plug-in for users; the design is in -[docs/spec/SPEC.md](docs/spec/SPEC.md). +[README.md](README.md) and [docs/USER_GUIDE.md](docs/USER_GUIDE.md) describe the +plug-in for users (the handbook is built from them, `handbook.config.json`); +the design is in [docs/spec/SPEC.md](docs/spec/SPEC.md). ## What this repository is diff --git a/README.md b/README.md index ad43a8d..92e5776 100644 --- a/README.md +++ b/README.md @@ -12,25 +12,31 @@ OpenSSF Scorecard

-Every Scenario model inside Autodesk Maya, for artists and for agents. +Make 3D models, mesh edits, motion and images with Scenario's models without +leaving Maya 2025, 2026 or 2027. Give the panel a prompt, an image, views of +an object, a mesh or a character, see the exact price on the button, and the +result lands in the open scene as one undo step. ![Maya 2027 with the Scenario panel docked on the right: a brass lantern generated with Meshy 7.1 and a wooden chest, imported side by side](docs/media/hero.png) -Scenario for Maya is a plug-in for Maya 2025, 2026 and 2027. Write a prompt -in a docked panel, see the exact price on the Generate button, and the result -lands in the open scene: a 3D model on the ground in front of the camera, or -an image as a card, a material or an image plane. A 3D model can start from a -prompt, an image, or views of an object captured in the scene; a mesh of -the scene can be remeshed, UV unwrapped or retextured; and a prompt can make -a character move, the model's own or one selected in the scene. Each landing -is one Ctrl+Z. -Every request is priced before it is sent, sent once, and recorded on disk, so -a crash or a dropped connection never charges twice. - -**Status:** in development, not released. Tested on Maya 2027.2 on macOS, in -the real Maya window and headless with `mayapy` (the Multi-view, Edit -selection and Motion modes headless only so far). Two tabs work today, Image and 3D; the table lists -what comes next. +## What it does + +- **3D from a prompt, an image or views of an object.** A model lands on the + ground in front of the camera at its real size, or over the object its + views were captured from, with PBR materials and import checks. +- **Edits your meshes.** Remesh, UV unwrap or retexture a mesh of the scene; + the result comes back fitted over it, or applied onto it after a review. +- **Animates characters.** A prompt makes a character move: the model's own, + or yours, rigged and animated, landed with its joints, skin and clip. +- **Images in the scene.** As a card, a material or an image plane, and one + click away from a 3D model. +- **Shows the price first.** The exact price is on the Generate button before + you click, every request is sent once and recorded on disk, and every + landing is one Ctrl+Z. + +**Status:** early version. Tested on Maya 2027.2 on macOS, in the real Maya +window and headless with `mayapy` (the Multi-view, Edit selection and Motion +modes headless only so far). | Area | Today | Next | | --- | --- | --- | @@ -42,378 +48,83 @@ what comes next. | Agents | | A local Scenario MCP server inside Maya, so Claude Code, Codex or Cursor drive the same actions | | Other lanes | | Materials, environment (sky domes), render a view, video, audio | -## Generate a 3D model +Each mode, with real results and model comparisons, is in the +[User Guide](docs/USER_GUIDE.md). -![Typing a prompt, pricing it, generating with Meshy 7.1 and importing the lantern into the scene](docs/media/flow-3d.gif) +## Install -*Recorded in Maya 2027.2 with a live Scenario model. The wait for Scenario -is sped up; everything else plays in real time. Videos: -[this flow](docs/media/flow-3d.mp4), [the whole session](docs/media/session.mp4).* +You need Maya 2025, 2026 or 2027 and a Scenario account on a plan with API +access. -| 1. Priced before sending | 2. Followed on Scenario | 3. Imported and checked | -| --- | --- | --- | -| ![The 3D tab with Meshy 7.1 and the price on the Generate button](docs/media/panel-3d-priced.png) | ![The result card while Scenario generates](docs/media/panel-3d-generating.png) | ![The result card after the import, with the import checks](docs/media/panel-3d-imported.png) | - -1. Open the **3D** tab. The default model is Meshy 7.1 Text-to-3D, preset to - a 30,000-face game mesh (the raw mesh is close to a million triangles for - the same price). **Change** lists the other text-to-3D models, with Meshy - T2.5 Smart Topology as the low-cost choice. -2. Write a prompt. The button shows the exact price as soon as Scenario has - checked it; the check is free. -3. **Generate** sends the request once. The card follows the job, downloads - the GLB when it is ready and shows what came back: format, faces and size - in metres, with Scenario's preview picture. -4. **Import** adds the model as a new group at the size Scenario returns, its - bottom centre on the ground below the camera's centre of interest. - Materials are openPBR, with their textures written to - `sourceimages/scenario/`. The panel reports the import checks: size, - materials and textures, non-manifold edges, missing textures. One Ctrl+Z - removes the whole import; redo brings it back. - -

The lantern and the chest turning in Maya's viewport

-

Viewport 2.0 with one key light. MP4

- -Any local GLB can be imported the same way with **Scenario > Import GLB...**, -without signing in. Maya has no glTF importer for scripts, so the plug-in -builds the scene itself: meshes with UVs and normals, PBR materials, joints, -skins, blend shapes and the first animation clip. - -## Turn an image into a 3D model - -| The image | The model, imported in Maya | -| --- | --- | -| ![A concept image of a carved wooden treasure chest](docs/media/image-to-3d-input.jpg) | ![The chest generated from it with Meshy 7.1, in Maya's viewport](docs/media/image-to-3d-result.jpg) | - -

The generated chest turning in Maya's Viewport 2.0

- -*The image was generated in the Image tab with GPT Image 2.5 Flare. The -model is Meshy 7.1 Image to 3D at the 30,000-face preset (28,984 faces), -imported by the plug-in and rendered in Maya's Viewport 2.0 with -`tools/render_glb.py`.* - -1. Open the **3D** tab and choose **Image** (beside **Text**). -2. Add the image: **File...** for a PNG, JPEG or WebP; **Viewport** for a - capture of the view you look through, with the grid and the selection - highlight hidden; **Image results** for anything made in the Image tab. - An Image result also has **Make a 3D model from this image** in its menu, - which opens this mode with the image in place. -3. A file or a capture is sent to your Scenario project when you add it - (once per session: the same file added again is not sent twice). An - Image result is already on Scenario and is used as it is. -4. The price shows on **Generate**, then the result card follows the job, - downloads the GLB and offers **Import**, as for text to 3D. A job - without a prompt is named after its image. - -One clear image of one object works best. Meshy 7.1 also takes up to four -views of the same object; models that take one image use the first. - -**Which model.** Both quick picks below started from the image above, one -run each: - -| Meshy 7.1 Image to 3D, the default | Tripo P2 | -| --- | --- | -| ![Meshy 7.1 result, front and back](docs/media/image-to-3d-meshy.jpg) | ![Tripo P2 result, front and back](docs/media/image-to-3d-tripo.jpg) | -| 28,984 faces (30,000 preset), carving kept on every side, about 140 s, 120 CU, up to four views | 4,222 faces, clean mesh with flatter carving and a plain back, about 85 s, 220 CU, one image | - -## Turn views of an object into a 3D model - -The **Multi-view** mode builds a model from pictures of one object taken from -named sides. Start from a blockout, a kitbash or an old asset in your scene: -the plug-in photographs it from the front, left, back and right, and the -model returns a textured mesh of the same object, facing the same way. - -| | Front, left, back, right | -| --- | --- | -| Captured around a blockout | ![The four views captured around a blockout robot](docs/media/views-capture.jpg) | -| Tripo P2 Multi View, the default | ![The Tripo P2 result seen from the same four sides](docs/media/views-tripo-p2.jpg) | -| Tripo 3.1 Multi View | ![The Tripo 3.1 result seen from the same four sides](docs/media/views-tripo-v31.jpg) | - -

The Tripo P2 robot turning in Maya's Viewport 2.0 The Tripo P2 robot with every edge drawn: 4,987 faces

- -*A robot blocked out from cubes in Maya, its four views captured by the -plug-in, and one run of each Tripo model on those views. Results rendered in -Viewport 2.0 with `tools/render_glb.py`; right, Tripo P2's mesh with every -edge drawn.* - -```mermaid -flowchart LR - A[Select an object] --> B[Capture views
temporary orthographic cameras,
one per side, no undo step] - B --> C[Views sent to your project
once each] - C --> D[Generate
priced first] - D --> E[Import
over the object, at its size,
facing the same way] -``` - -1. Open the **3D** tab and choose **Multi-view**. Each view the model takes - has a slot: Front, Left, Back and Right for the Tripo models; Hunyuan 3D - Pro 3.1 adds Top, Bottom and the two front three-quarter views. -2. Select one object and press **Capture views**. The plug-in renders it from - each side with temporary orthographic cameras, all at one scale, clipped - close around the object so the floor and its neighbours stay out of the - pictures. Nothing is added to the scene or to the undo queue, and the - render settings it touches are put back. Left is the object's own left: - with the object facing front (+Z), the side Maya's Right view shows. -3. A slot also takes a file or an Image result, from its menu. Each view is - sent to your Scenario project once. The Tripo models need the front and - at least one more view; the Generate button says what is missing, then - shows the price. -4. **Import** places the result over the object its views came from, at the - object's size and facing the same way, as a new group (the object itself - is not changed). Views added as files land like any 3D result, on the - ground in front of the camera. - -**Which model.** Same four views, one run each: - -| Model | Faces | GLB | Price | -| --- | --- | --- | --- | -| Tripo P2 Multi View, the default | 4,987, a clean low-poly mesh | 1.4 MB | 220 CU | -| Tripo 3.1 Multi View, the low-cost choice | 1,425,173, dense | 42 MB | 45 CU | -| Hunyuan 3D Pro 3.1 Multiview | starts at 40,000, its lightest setting | not run yet | 120 CU | - -Both Tripo results kept the shape and colours on every side, took under four -minutes and landed on the blockout within half a centimetre of its 82 cm -height. - -## Quad meshes and FBX results - -The Tripo models have a **quad** setting: the mesh comes back in quads, -delivered as an FBX file (Scenario sends no GLB then). The plug-in imports -FBX results through Maya's own FBX importer, as one Ctrl+Z, and lands them -like a GLB: on the ground in front of the camera, or over the captured object -in the Multi-view mode. - -

The robot from Tripo 3.1 Multi View with quad on: as imported, and with every edge drawn, a grid of quads

- -*Tripo 3.1 Multi View with quad on and a face limit of 8,000, from the four -robot views above: 8,153 faces, 8,132 of them quads. 53 CU.* - -Around Maya's FBX importer, the plug-in: - -- keeps the scene's unit, up axis, playback range, current frame and frame - rate (the importer would change them); -- imports even when the scene already has nodes of the same names; -- writes the file's textures under `sourceimages/scenario/`; -- cleans the names the FBX format escaped (`FBXASC045` for a dash); -- keeps the importer's materials (Phong), with colour textures in sRGB, every - other texture Raw and normal maps read as tangent-space normals; -- lets skinned meshes follow their joints only, so a rig lands upright in a - Z-up scene and in one piece wherever it is placed or fitted; -- starts a clip on the scene's start frame, as for a GLB; -- reports the same import checks as for a GLB. - -## Edit a mesh of the scene - -The **Edit selection** mode of the 3D tab sends one of your meshes to an -edit model and brings the result back: over the mesh as a new object, or -onto the mesh itself. - -```mermaid -flowchart LR - mesh["Selected mesh"] --> glb["GLB written by the plug-in
object space, metres, Y up,
its UVs and base colour textures,
neutral names"] - glb --> check["Checked against the model
format, triangle cap"] - check --> send["Sent to your project
once per unchanged mesh"] - send --> model["Edit model
remesh, UV unwrap, retexture"] - model --> fit["Fitted onto the sent mesh
one uniform scale and an offset,
checked by surface distance"] - fit --> land["Import
a new group over the mesh, one Ctrl+Z"] - fit --> proof["Same surface?
vertices, faces, winding, UVs
(remesh: same shape)"] - proof --> review["Review
what changes, what is kept"] - review --> apply["Apply onto the mesh
new UVs, new material or
new geometry, one Ctrl+Z"] -``` - -1. Select one mesh (the object, or some of its faces) and open **3D**, - **Edit selection**. -2. Choose the task: **Remesh**, **UV unwrap** or **Retexture**. Each task - keeps its own model; the defaults are Tripo Retopology v3, Tripo Smart UV - and Meshy 7 Retexture. -3. **Use selection** writes the mesh as a GLB in the project's - `images/scenario/captures` folder. Object, scene and path names stay on - your machine: the file says `scn_input_0`. The mesh is checked against - the model before anything is sent (Tripo Smart UV takes up to 80,000 - triangles, Meshy UV Unwrap 44,000, Hunyuan UV Unwrapping 30,000); a mesh - it cannot take shows why and is not sent. -4. Retexture needs a prompt. The price shows on **Generate**. -5. **Import** places the result over the mesh it came from, as a new group, - even if you moved the mesh after sending it. Your mesh is not changed. -6. **Apply...** writes the result onto the mesh itself, after a review of - what changes, what is kept and what needs your confirmation. One Ctrl+Z - undoes it. - -Most edit models return the mesh resized and centred: on 2026-10-19, Tripo -models returned it 1 m long (also when it was sent 1.5 m off the origin), -Meshy Remesh and Meshy 7 Retexture 2 m long, while Meshy UV Unwrap returned -it in place; none rotated it. The plug-in keeps the file it sent and fits the -result back onto it with one uniform scale and an offset from the bounding -boxes, then applies the mesh's current transform. It then checks that the two -surfaces meet: 1,500 points spread over each must lie within 2% of the mesh's -size from the other (at most 5% farther, none beyond 10%). A result that fails -still lands over the mesh, and the import message says it is not the same shape. - -**What came back.** A bevelled crate of 1,052 triangles with the cube's -default UVs, sent by the plug-in, one run per model: - -| Your mesh | Meshy 7 Retexture | Tripo 3.0 Texturing | -| --- | --- | --- | -| ![The crate sent, grey, before any edit](docs/media/edit-input.jpg) | ![The crate retextured by Meshy 7 as weathered planks with metal corners](docs/media/edit-meshy-retexture.jpg) | ![The crate retextured by Tripo 3.0 in dark brown wood](docs/media/edit-tripo-texturing.jpg) | -| 1,052 triangles | Same triangles and the same UVs; base colour, normal, metallic and roughness maps; 40 CU | Same triangles and the same UVs; PBR textures; 15 CU | - -| Your UVs, on a checker | Tripo Smart UV | -| --- | --- | -| ![The crate with its default UVs on a checker: large squares, stretched on the bevels](docs/media/edit-uv-input.jpg) | ![The crate with Tripo Smart UV's layout on the same checker: even squares across the faces](docs/media/edit-uv-smart.jpg) | -| The cube's default layout | A new layout on the same triangles; 40 CU | - -| What was sent | Meshy Remesh | Tripo Retopology v3 | -| --- | --- | --- | -| ![The crate as sent, every edge drawn: an even grid of bevelled panels split in triangles](docs/media/edit-remesh-sent.jpg) | ![The crate remeshed by Meshy: larger, irregular triangles over the same shape](docs/media/edit-remesh-meshy.jpg) | ![The crate remeshed by Tripo: larger triangles in a more regular pattern over the same shape](docs/media/edit-remesh-tripo.jpg) | -| 1,052 triangles (398 faces in Maya) | 522 triangles, new UVs, base colour and metal-roughness maps baked; 20 CU | 560 triangles, a baked normal map; 70 CU | - -*Stills rendered headless in Maya's Viewport 2.0 with `tools/render_glb.py` -(`--checker 6` for the UV pair, `--wire` for the remeshes).* - -**Apply.** Before anything changes, the plug-in proves the result is the -same surface as your mesh (`core/topology.py`): every result vertex sits on -a vertex of the mesh after the fit, every triangle lies inside one face with -the same winding, every face is covered exactly, and each face corner gets -one UV. A remesh has new triangles by design, so Replace geometry asks for -the same shape instead, by the surface-distance check above. Then: - -| Task | What Apply changes | What it keeps | -| --- | --- | --- | -| UV unwrap | The current UV set gets the result's UVs | The old layout as `_scnPrev`, geometry, other UV sets, materials | -| Retexture | A new material from the result's maps (base colour, metal and roughness, normal) is assigned to the mesh; UVs too if the model changed them | The old material, unassigned; Maya's default material is never edited | -| Remesh | The mesh's shape is replaced by the result's mesh, under your transform and with your shape's name; it gets the result's material when the result has textures, otherwise keeps yours | The transform (name, place, attributes, parent, sets, connections); the old shape, hidden, as `_scnPrev` with its history; connections from the old shape move to the new one | - -All five results above apply onto the crate: the texture and UV results -exactly, the two remeshes as Replace geometry (farthest point 0.4% and 0.5% -of the crate's size from the original surface). Apply asks before deleting -the mesh's construction history (history would overwrite new UVs) and when -a mesh with several materials would get one; it refuses deformed (skinned), -referenced and locked meshes, and Replace geometry refuses instanced ones, -in this version. +1. Download `scenario-maya-.zip` from + [maya.scenario.com/download/latest](https://maya.scenario.com/download/latest) + or the [releases page](https://github.com/scenario-labs/maya-plugin/releases) + and unzip it. +2. Drag `install_scenario.py` from the unzipped folder onto a Maya viewport. It + copies the module into your Maya modules folder, loads the plug-in, turns + on autoload and opens the Scenario panel. +3. Maya 2027 asks whether to load a plug-in from a location it does not trust + yet. Choose **Allow**. -## Animate a character +**Scenario > Scenario Panel** opens the panel later. Each release lists the +ZIP's SHA-256 in `SHA256SUMS`, and +`gh attestation verify scenario-maya-.zip --repo scenario-labs/maya-plugin` +checks it was built from this repository. -The **Motion** mode turns a prompt into a character that moves: a skinned -mesh, its joints and a clip, imported into the scene as one Ctrl+Z. Some -models bring their own character; others rig and animate yours. +To uninstall, run `import install_scenario; install_scenario.uninstall()` in +the Script Editor (Python). Your settings, job list and results stay. -

A wooden mannequin waving its right hand, from Meshy Text to Motion The Multi-view robot, rigged and animated by Uthana Text to Motion 3.0, raising its right arm

+## First generation -*"waves hello with the right hand". Left, Meshy Text to Motion from the -prompt alone: its own mannequin, 52 joints, 3 seconds. Right, Uthana Text to -Motion 3.0 on the robot from the Multi-view section, sent from the scene: -rigged with 52 joints and animated for 4 seconds; its box arms bend as one -piece. Imported by the plug-in and rendered in Viewport 2.0 with -`tools/render_glb.py --play`.* +1. In the panel, choose **Sign in with Scenario** and approve in your browser + (or sign in on another device with a code, or use an API key). If your + account has several teams or projects, pick one. +2. Open the **3D** tab and write a prompt. The Generate button shows the + exact price once Scenario has checked it, for free. +3. Press **Generate**. When the result is ready, **Import** lands it in the + scene; one Ctrl+Z removes it. -```mermaid -flowchart LR - A[Describe a motion] --> B{Character} - B -- none --> C[The model makes its own] - B -- select it,
Use selection --> D[Your meshes sent as one GLB
once, no undo step] - C --> E[Generate
priced first] - D --> E - E --> F[Import
joints, skin and clip,
over your character if you sent one] -``` +The full walkthrough, with every mode, is in the +[User Guide](docs/USER_GUIDE.md#quick-start). -1. Open the **3D** tab and choose **Motion**. The default model, Meshy Text - to Motion, needs only the prompt: one simple action works best (a walk, a - wave, a jump), 2 to 10 seconds, 40 CU whatever the length. -2. To animate your own character, press **Change** and pick Uthana Text to - Motion 3.0 or Cartwheel Text to Motion. Select the character (its group or - its meshes) and press **Use selection**: the meshes are written as one GLB, - with neutral names, and sent to your Scenario project once. Nothing is - added to the scene or to the undo queue. Cartwheel needs a character, and - the Generate button says so until one is sent; Uthana takes one or makes - its own. -3. A model's frame-rate setting starts at the scene's rate when the model - offers it (Uthana: 24, 30 or 60 fps), so the clip is asked for at the - scene's rate. For - Cartwheel the plug-in asks for its Maya FBX, never a `.ma` or `.mb` scene - file, which would have to be imported in a way that clears Maya's undo - history. -4. **Import** brings the character in as a new group with its joints, skin - and clip. The clip starts on the scene's start frame and the playback - range is not changed. A result made from your character lands over it, at - its size, measured on the clip's first frame; your character is not - changed. When a clip was made at another rate than the scene's (30 fps in - a 24 fps scene), its keys fall between frames and the result says so. - -**Which model.** One prompt, one run each: - -| Model | Character | Result | Price | -| --- | --- | --- | --- | -| Meshy Text to Motion, the default | Its own wooden mannequin (52 joints) | FBX, in about 30 seconds | 40 CU, 2 to 10 s | -| Uthana Text to Motion 3.0, first pick for your character | Yours (auto-rigged) or its own (160 joints) | GLB, in about 3 minutes | 104 CU for 4 s; 124 CU with a character | -| Cartwheel Text to Motion | Yours, required | Maya FBX, in 2 to 4 minutes | 72 CU for 3 s | - -![One row per run: Meshy's mannequin and Uthana's own character wave from the prompt alone; Uthana rigs the robot facing front; Cartwheel's rig faces the robot's back](docs/media/motion-shootout.jpg) - -*Frames from the start to the end of each clip, rendered with -`tools/render_glb.py --play`. With the robot as the character, Uthana rigged -it facing the way it faces. Cartwheel's rig faced the robot's back, whichever -way the robot was sent and also with its forward option set to -Z; that is one -character, whose back panel may read as a front. Check which way a rig faces -before animating further.* - -Not built yet: putting a motion onto a rig already in the scene -(retargeting, HumanIK), video to motion, and Meshy Animation's library of -ready-made clips. - -## Generate an image - -| Ready | As a card facing the camera | As a material on a selected mesh | -| --- | --- | --- | -| ![The Image tab with a ready result](docs/media/panel-image-ready.png) | ![A generated image as a card in the viewport](docs/media/image-card.png) | ![The image as the material of a cube](docs/media/image-material.png) | +## Guides -The **Image** tab works the same way. A result lands as a **Card** (a -textured plane facing the camera, at its centre of interest), a **Material** -(base colour of a new material on the selected meshes or faces) or an -**Image plane** on the current camera. Files go to `sourceimages/scenario/`. +- [User Guide](docs/USER_GUIDE.md): every mode with real results, the panel, + prices, jobs and recovery, where results are saved, settings, + troubleshooting. +- [Privacy](docs/PRIVACY.md): what leaves your computer and what stays. +- Handbook: the guide, the privacy notes and the changelog as one page, a + single HTML file and a PDF, at [maya.scenario.com](https://maya.scenario.com). +- [Changelog](CHANGELOG.md). -## Choose a model +## Install from a checkout -![The model picker on the 3D tab](docs/media/picker-3d.png) +1. Clone this repository and unpack Scenario's Python SDK into it: + `python3 tools/vendor_sdk.py` (Python 3.11 or later; it downloads the + wheels pinned in `tools/sdk_wheels.json`). +2. Drag `ScenarioForMaya/scripts/install_scenario.py` onto a Maya viewport. It + copies the module into your Maya modules folder, loads the plug-in, turns + on autoload and opens the Scenario panel. No restart and no `userSetup.py` + edit. +3. Maya 2027 asks whether to load a plug-in from a location it does not trust + yet. Choose **Allow**; tick "Apply to all plugins in this location" to stop + it asking again. -**Change** opens the picker for the current tab: the tab's quick picks -first, then the other models of that kind in Scenario's catalog, with search, -a **Team models** filter for your team's own models, and legacy models on -request. +For development, point Maya at the checkout instead of copying it. Run this +once in the Script Editor (Python); run it again to reload after a change: -## How a request is paid +```python +import sys -The plug-in follows the same money rules as Scenario's other plug-ins. They -sit in `core/`, below every button and every agent tool, so no caller can -skip them. +sys.path.insert(0, "/path/to/maya-plugin/ScenarioForMaya/scripts") +import install_scenario -```mermaid -sequenceDiagram - actor You - participant Panel - participant Ledger as Job ledger (SQLite) - participant Scenario as Scenario API - You->>Panel: edit the prompt or a setting - Panel->>Scenario: price check (dry run, free) - Scenario-->>Panel: exact price - Panel-->>You: Generate . 120 CU - You->>Panel: Generate - Panel->>Ledger: save the intent (payload hash, quote, price) - Panel->>Scenario: run the model, once - Scenario-->>Panel: job id - loop until the job ends - Panel->>Scenario: read the job - end - Panel->>Panel: download the result, check its SHA-256 - You->>Panel: Import - Panel-->>You: one undo step in the scene +install_scenario.install(link=True) ``` -- A quote is used once and is bound to the exact model, settings, workspace - and scene. Any edit asks for a new price. Quotes expire after 120 seconds. -- The intent is written to disk before the paid request. If Maya crashes or - the connection drops while it is being sent, the job shows as **Not - confirmed** and blocks an identical request until you link it to a Scenario - job or mark it checked. -- The plug-in sets no spending cap of its own. Team limits set on Scenario - apply, and `SCENARIO_NO_SPEND=1` refuses every paid call. +or set `MAYA_MODULE_PATH=/path/to/maya-plugin` (the repository's +`ScenarioForMaya.mod` uses a relative path) and load `scenario_for_maya` in +Windows > Settings/Preferences > Plug-in Manager. ## How it is built @@ -451,70 +162,7 @@ flowchart TB sourceimages/scenario// images, and the textures written from a GLB ``` -## Install a release - -1. Download `scenario-maya-.zip` from the - [latest release](https://github.com/scenario-labs/maya-plugin/releases/latest) - and unzip it. -2. Drag `install_scenario.py` from the unzipped folder onto a Maya viewport. It - copies the module into your Maya modules folder, loads the plug-in, turns - on autoload and opens the Scenario panel. -3. Maya 2027 asks whether to load a plug-in from a location it does not trust - yet. Choose **Allow**. - -Each release lists the ZIP's SHA-256 in `SHA256SUMS`; `gh attestation verify -scenario-maya-.zip --repo scenario-labs/maya-plugin` checks it was -built from this repository. - -## Install from a checkout - -1. Clone this repository and unpack Scenario's Python SDK into it: - `python3 tools/vendor_sdk.py` (Python 3.11 or later; it downloads the - wheels pinned in `tools/sdk_wheels.json`). -2. Drag `ScenarioForMaya/scripts/install_scenario.py` onto a Maya viewport. It - copies the module into your Maya modules folder, loads the plug-in, turns - on autoload and opens the Scenario panel. No restart and no `userSetup.py` - edit. -3. Maya 2027 asks whether to load a plug-in from a location it does not trust - yet. Choose **Allow**; tick "Apply to all plugins in this location" to stop - it asking again. - -For development, point Maya at the checkout instead of copying it. Run this -once in the Script Editor (Python); run it again to reload after a change: - -```python -import sys - -sys.path.insert(0, "/path/to/maya-plugin/ScenarioForMaya/scripts") -import install_scenario - -install_scenario.install(link=True) -``` - -or set `MAYA_MODULE_PATH=/path/to/maya-plugin` (the repository's -`ScenarioForMaya.mod` uses a relative path) and load `scenario_for_maya` in -Windows > Settings/Preferences > Plug-in Manager. - -## Sign in - -The sign-in page of the Scenario panel - -Open the Scenario panel (Scenario > Scenario Panel) and choose **Sign in with -Scenario**: your browser opens, you approve, and Maya picks up the session. -"Sign in on another device" shows a code to enter on any device; "Use an API -key" takes a key and secret from Scenario's web app. - -Secrets go to the system keychain (macOS Keychain, Windows Credential Manager -or Secret Service), never to the scene or Maya's preferences. For scripts and -CI, `SCENARIO_API_KEY` and `SCENARIO_API_SECRET` are read from the -environment. - -Nothing is sent to Scenario until you press Generate or allow an agent to. -What the plug-in sends and stores is in [docs/PRIVACY.md](docs/PRIVACY.md). - -
- -## Tests +### Tests | Layer | What it covers | Where it runs | | --- | --- | --- | @@ -523,14 +171,20 @@ What the plug-in sends and stores is in [docs/PRIVACY.md](docs/PRIVACY.md). | GUI | Scripted sessions in the real Maya window: install, sign-in, restart recovery, live generation, undo after a click | A Mac with Maya: `tools/test_maya_gui.sh`, `tools/readme_media.sh` | | Contract | Reads and dry runs against the live Scenario REST API, nothing spent | Weekly in CI with a test key | -The pictures and recordings on this page come from `tools/readme_media.sh`, +The pictures and recordings in the README and the +[User Guide](docs/USER_GUIDE.md) come from `tools/readme_media.sh`, which drives the panel in a real Maya 2027.2 session with live Scenario models and checks undo and redo on the way. +## License + +MIT, see [LICENSE](LICENSE). + +Autodesk and Maya are trademarks of Autodesk. This project is not affiliated +with or endorsed by Autodesk. + ## More - Design and decisions: [docs/spec/SPEC.md](docs/spec/SPEC.md) -- Changes: [CHANGELOG.md](CHANGELOG.md) - Contributing and the repository rules: [CONTRIBUTING.md](CONTRIBUTING.md), [AGENTS.md](AGENTS.md) - Help: [SUPPORT.md](SUPPORT.md); security reports: [SECURITY.md](SECURITY.md) -- License: [MIT](LICENSE) diff --git a/docs/PRIVACY.md b/docs/PRIVACY.md index 8b6edb7..89034ce 100644 --- a/docs/PRIVACY.md +++ b/docs/PRIVACY.md @@ -1,60 +1,65 @@ # Privacy: Scenario for Maya -Status: **draft, 2026-10-18**, written with the spec before any code. It describes what the plug-in will do; every statement is checked against the built plug-in before release. - -Scenario for Maya connects Autodesk Maya to the Scenario platform. This page says what leaves your computer, when, where it goes, and what stays on your machine. Scenario's own handling of the data it receives follows Scenario's Terms of Service, Privacy Policy and [Trust Portal](https://trust.scenario.com) [links to confirm before release]. +Scenario for Maya connects Autodesk Maya to the Scenario platform. This page +says what leaves your computer, when, where it goes, and what stays on your +machine. Scenario's own handling of the data it receives follows Scenario's +Terms of Service and Privacy Policy, and its [Trust Portal](https://trust.scenario.com). ## What is sent to Scenario, and when -Nothing is sent before you sign in. After that, the plug-in sends data to Scenario (`api.cloud.scenario.com`, `clerk.scenario.com` for sign-in, and Scenario's file storage) only for these actions: +Nothing is sent before you sign in. After that, the plug-in talks to Scenario +(`api.cloud.scenario.com`, `clerk.scenario.com` for sign-in, and Scenario's +file storage) only for these actions: | Action | What is sent | |---|---| -| Opening the panel | Requests for the model catalog, your teams and projects, and your project's credit balance | -| Editing a form | The form's content (model, prompt, settings, the ids of files already uploaded) for a free price check, about 0.7 s after you stop typing | -| Generate, Run workflow, Approve (Prompt Spark) | The same form, as a paid request | -| Adding a reference (image file, viewport or camera capture, playblast, selected meshes) | The file, uploaded to your Scenario project when you add it to a form | -| Mesh edits | An export of the meshes you selected: geometry, UVs, normals, materials and their textures, and the skin and skeleton when the task needs them. Node and material names are replaced by neutral names by default; the mapping stays on your computer | -| Jobs, results, library | Requests for job status, result files, your project's history and library | - -Not sent: the rest of your scene, file paths, node names (unless you turn off neutral names), your Maya project contents, or anything from other open scenes. - -Signed storage transfers use the link's own authorization; they do not carry your Scenario credentials. +| Opening the panel, the picker or the workspace menu | Requests for the model catalog and your teams and projects | +| Editing a request | The request (model, prompt, settings, the ids of files already sent) for a free price check, 0.7 s after you stop typing | +| Generate | The same request, as a paid request | +| Adding an image (a file, a viewport capture, views captured around an object) | The picture, uploaded to your Scenario project when you add it | +| Use selection, for a mesh edit or a character to animate | The selected meshes as one GLB: geometry, UVs, normals and base colour textures. Object, material, scene and path names are replaced by neutral names | +| Jobs and results | Requests for the status of your jobs and their result files | -## Agents +Not sent: the rest of your scene, file paths, node names, your Maya project's +contents, or anything from other open scenes. -The plug-in can run a local server for AI agents (Claude Code, Codex, Cursor, Claude Desktop and others). It listens only on your own computer (`127.0.0.1`) and asks for a token that the plug-in writes into the agent's settings when you press Connect. - -What an agent reads through it (scene summaries, node details, screenshots, job results) goes to that agent's own model provider, under your agreement with that provider, not to Scenario. Agents cannot change your scene unless you turn on **Allow agents to change this scene**, and cannot run Python unless you also turn on **Allow agents to run Python**. These switches are not a sandbox: once on, an agent acts with your rights in Maya. Connect only agents you trust with those actions. - -Every agent call that spends credits or changes the scene is listed in the Agents activity log. +Result files are downloaded through signed links from Scenario's storage, +which carry their own authorization, never your Scenario credentials. ## What is stored on your computer | Item | Where | |---|---| -| Sign-in token or API secret, agent server token | Your operating system's credential store (macOS Keychain, Windows Credential Manager, Linux Secret Service). If none is available, a file readable only by your user account, and the plug-in tells you so | -| Settings, model catalog cache, job ledger, logs | `/scenario/` | -| Downloaded results, captures and mesh exports | Your Maya project, in `scenario/`, `sourceimages/scenario/`, `sound/scenario/`, `movies/scenario/` and `images/scenario/` | -| Provenance (model, prompt, cost, job and asset ids) | Attributes on the nodes the plug-in creates or edits, saved inside your `.ma` or `.mb` file | - -Secrets are never written into scenes, Maya preferences (`userPrefs.mel`), `Maya.env`, project files or logs. If you put credentials in `Maya.env` yourself, the plug-in warns you that it is a plain text file. +| Sign-in token or API secret | Your operating system's credential store (macOS Keychain, Windows Credential Manager, Secret Service on Linux). If none is available, a file readable only by your user account | +| Settings, model catalog cache, job list, logs | `scenario/` in Maya's user folder (`MAYA_APP_DIR`) | +| Results, captures and the meshes sent for an edit | Your Maya project, in `scenario/`, `sourceimages/scenario/` and `images/scenario/` | +| Provenance (model, prompt, price, job and asset ids) | Attributes on the nodes the plug-in creates, saved inside your `.ma` or `.mb` file | -Provenance travels with your scene file: anyone you send the scene to can read the prompts and ids stored on its nodes. A project setting leaves prompts out. +Secrets are never written into scenes, Maya preferences, `Maya.env`, project +files, settings or logs. -## Other network requests +Provenance travels with your scene file: anyone you send the scene to can +read the prompts and ids stored on its nodes. Setting `store_prompts_on_nodes` +to `false` in `settings.json` leaves the prompts out. -- **Update check**: once a day the plug-in asks GitHub for the latest release number. No account or scene data is sent. You can turn it off. -- **Usage data**: off by default. The plug-in asks once. If you agree, it sends anonymous events (plug-in and Maya versions, OS, which features were used, error types) to Scenario; never prompts, files, scene content or credentials. The list of fields is published in the docs before the feature is turned on. +The plug-in sends nothing else: no usage data, no update check. ## Your controls -- **Sign out** removes the token from your credential store and asks Scenario to revoke it. -- **API keys** can be revoked at any time from your team page on [app.scenario.com](https://app.scenario.com/team). -- **Offline mode** (`SCENARIO_MAYA_OFFLINE=1`) stops all network access from the plug-in. -- **No spending** (`SCENARIO_NO_SPEND=1`) refuses every paid request and upload from the plug-in. -- **Uninstall** removes the plug-in; ticking "Also remove my Scenario data in Maya" also removes the settings, ledger and stored credentials. +- **Sign out** asks Scenario to revoke the session and removes the secret + from your credential store. +- **API keys** can be revoked at any time from your team page on + [app.scenario.com](https://app.scenario.com/team). +- **Offline mode** (`SCENARIO_MAYA_OFFLINE=1`) stops all network access from + the plug-in; importing a local GLB still works. +- **No spending** (`SCENARIO_NO_SPEND=1`) refuses every paid request from the + plug-in. +- **Uninstall** (in Maya's Script Editor, Python: + `import install_scenario; install_scenario.uninstall()`) removes the + plug-in and keeps your settings, job list and results; delete `scenario/` in Maya's user + folder to remove them, and sign out first to remove the stored secret. ## Contact -Security issues: see [SECURITY.md](../SECURITY.md). Other questions: Scenario support [contact to confirm before release]. +Security issues: see [SECURITY.md](../SECURITY.md). Other questions: +support@scenario.com. diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md new file mode 100644 index 0000000..8371915 --- /dev/null +++ b/docs/USER_GUIDE.md @@ -0,0 +1,560 @@ +# User Guide + +Scenario for Maya puts Scenario's models in a panel docked beside the Channel +Box. You describe what you need, or hand it something from your scene (an +image, views of an object, a mesh, a character), see the exact price on the +Generate button, and the result comes back into the open scene as one undo +step. This guide covers every mode with real results; the pictures come from +Maya 2027.2 with live Scenario models. + +## Quick start + +1. Install the plug-in: download `scenario-maya-.zip` from + [maya.scenario.com/download/latest](https://maya.scenario.com/download/latest), + unzip it and drag `install_scenario.py` onto a Maya viewport + ([Install](../README.md#install)). +2. In the Scenario panel, choose **Sign in with Scenario** and approve in your + browser. If your account has several teams or projects, pick one. +3. Open the **3D** tab, keep the **Text** mode and its default model, Meshy + 7.1, and write a prompt: `a brass lantern with a glass cage`. +4. The button shows the price once Scenario has checked it, for example + `Generate . 120 CU`; the check is free. Press it. +5. When the card says Ready to apply, press **Import**. The lantern lands on the ground + in front of the camera at its real size. Ctrl+Z removes it in one step. + +## Find your way around + +![The Scenario panel on the 3D tab: workspace at the top, the Text mode with Meshy 7.1, a prompt, the price on Generate and a result card](media/panel-3d-priced.png) + +### The panel + +Open it with **Scenario > Scenario Panel**. It docks beside the Channel Box +and comes back with your workspace layout. From top to bottom: + +- **Workspace**: the team and project the panel works in (`My Team / My + Project`). Click it to switch. Prices, uploads, results and the job list + belong to that project. +- **Tabs**: **Image** and **3D**. The 3D tab has five modes: **Text**, + **Image**, **Multi-view**, **Edit selection** and **Motion**. A tab opens on + the mode you used last in it. +- **The mode**: its model, with **Change** to pick another; the inputs the + mode needs (an image, views, a mesh, a character); the prompt, which hides + when the model takes none; the model's settings, read from Scenario; and the + **Generate** button with its price. Ctrl+Enter presses it. +- **Results**: one card per job of this mode, with its status, its price and + the actions valid now (Import, Apply..., Card, Retry download). The **...** + menu of a card has Show file, Open on Scenario, Re-run settings (fills the + form with that job's settings, sends nothing) and Copy details. +- **Jobs**: every job of the project, from every Maya session (see + [Jobs and recovery](#jobs-and-recovery)). + +The **...** button at the top right has Workspace..., Refresh jobs, Copy +diagnostics, the handbook, Privacy, Report a problem and Sign out. + +### The Scenario menu + +Maya's main menu bar gets a **Scenario** menu: Scenario Panel, Jobs, Import +GLB... (any GLB, no sign-in needed), Workspace..., Sign In... or Sign Out, and +Help (Handbook, Privacy, Report a Problem, Copy Diagnostics, About). + +### Sign in + +The sign-in page of the Scenario panel + +- **Sign in with Scenario**: your browser opens on Scenario's sign-in page, + you approve, and Maya picks up the session. +- **Sign in on another device**: the panel shows a code to enter on any + device, for a machine without a browser. +- **Use an API key**: a key and its secret from your project's API keys on + [app.scenario.com](https://app.scenario.com). + +Secrets go to the system's credential store (macOS Keychain, Windows +Credential Manager or Secret Service), never to the scene or Maya's +preferences. Scripts and render farms can set `SCENARIO_API_KEY` and +`SCENARIO_API_SECRET` in the environment instead. Nothing is sent to +Scenario until you sign in. + +
+ +## 3D from a prompt + +![Typing a prompt, pricing it, generating with Meshy 7.1 and importing the lantern into the scene](media/flow-3d.gif) + +*Recorded in Maya 2027.2 with a live Scenario model. The wait for Scenario +is sped up; everything else plays in real time. Videos: +[this flow](media/flow-3d.mp4), [the whole session](media/session.mp4).* + +### Generate + +| 1. Priced before sending | 2. Followed on Scenario | 3. Imported and checked | +| --- | --- | --- | +| ![The 3D tab with Meshy 7.1 and the price on the Generate button](media/panel-3d-priced.png) | ![The result card while Scenario generates](media/panel-3d-generating.png) | ![The result card after the import, with the import checks](media/panel-3d-imported.png) | + +1. Open the **3D** tab, **Text** mode. The default model is Meshy 7.1 + Text-to-3D, preset to a 30,000-face game mesh (the raw mesh is close to a + million triangles for the same price). **Change** lists the other + text-to-3D models: Meshy T2.5 Smart Topology, the low-cost choice, Tripo P2 + and Rodin Gen-2.5. +2. Describe one object. The button shows the exact price as soon as Scenario + has checked it. +3. **Generate** sends the request once. The card follows the job, downloads + the GLB when it is ready and shows what came back: format, faces and size + in metres, with Scenario's preview picture. + +### Import + +**Import** adds the model as a new group at the size Scenario returns, its +bottom centre on the ground below the camera's centre of interest. Materials +are openPBR, with their textures written to `sourceimages/scenario/`. The +card reports the import checks: size, materials and textures, non-manifold +edges, missing textures. One Ctrl+Z removes the whole import; redo brings it +back. + +

The lantern and the chest turning in Maya's viewport

+

Viewport 2.0 with one key light. MP4

+ +### Import any GLB + +**Scenario > Import GLB...** imports any local GLB the same way, without +signing in: meshes with UVs and normals, PBR materials, joints, skins, blend +shapes and the first animation clip. + +## 3D from an image + +| The image | The model, imported in Maya | +| --- | --- | +| ![A concept image of a carved wooden treasure chest](media/image-to-3d-input.jpg) | ![The chest generated from it with Meshy 7.1, in Maya's viewport](media/image-to-3d-result.jpg) | + +*The image was generated in the Image tab with GPT Image 2.5 Flare. The +model is Meshy 7.1 Image to 3D at the 30,000-face preset (28,984 faces), +imported by the plug-in and rendered in Maya's Viewport 2.0.* + +### Add the image + +1. Open the **3D** tab and choose the **Image** mode. +2. Add the image: + - **File...**: a PNG, JPEG or WebP; + - **Viewport**: a capture of the view you look through, with the grid and + the selection highlight hidden, so a blockout or a quick paint-over can + be the start; + - **Image results**: anything made in the Image tab. An Image result also + has **Make a 3D model from this image** in its **...** menu, which opens + this mode with the image in place. +3. A file or a capture is sent to your Scenario project when you add it, once + per session. An Image result is already on Scenario and is used as it is. +4. The price shows on **Generate**; the card then follows the job and offers + **Import**, as for a prompt. A job without a prompt is named after its + image. + +One clear image of one object, on a plain background, works best. Meshy 7.1 +also takes up to four views of the same object; models that take one image +use the first. + +### Which model + +Both quick picks, from the image above, one run each: + +| Meshy 7.1 Image to 3D, the default | Tripo P2 | +| --- | --- | +| ![Meshy 7.1 result, front and back](media/image-to-3d-meshy.jpg) | ![Tripo P2 result, front and back](media/image-to-3d-tripo.jpg) | +| 28,984 faces (30,000 preset), carving kept on every side, about 140 s, 120 CU, up to four views | 4,222 faces, clean mesh with flatter carving and a plain back, about 85 s, 220 CU, one image | + +**Change** also lists Rodin Gen-2.5, Tripo 3.1 and Hunyuan 3D Pro 3.1. + +## 3D from views of an object + +The **Multi-view** mode builds a model from pictures of one object taken from +named sides. Start from a blockout, a kitbash or an old asset in your scene: +the plug-in photographs it from the front, left, back and right, and the +model returns a textured mesh of the same object, facing the same way, landed +over it. + +| | Front, left, back, right | +| --- | --- | +| Captured around a blockout | ![The four views captured around a blockout robot](media/views-capture.jpg) | +| Tripo P2 Multi View, the default | ![The Tripo P2 result seen from the same four sides](media/views-tripo-p2.jpg) | +| Tripo 3.1 Multi View | ![The Tripo 3.1 result seen from the same four sides](media/views-tripo-v31.jpg) | + +### Capture the views + +1. Open the **3D** tab and choose **Multi-view**. Each view the model takes + has a slot: Front, Left, Back and Right for the Tripo models; Hunyuan 3D + Pro 3.1 adds Top, Bottom and the two front three-quarter views. +2. Select one object and press **Capture views**. The plug-in renders it from + each side with temporary orthographic cameras, all at one scale, clipped + close around the object so the floor and its neighbours stay out of the + pictures. Nothing is added to the scene or to the undo queue, and the + render settings it touches are put back. +3. Left is the object's own left: with the object facing front (+Z), the side + Maya's Right view shows. Model your blockout facing +Z. +4. A slot also takes a file or an Image result, from its menu. Each view is + sent to your project once. The Tripo models need the front and at least + one more view; the Generate button says what is missing, then shows the + price. + +### Where the result lands + +**Import** places the result over the object its views came from, at the +object's size and facing the same way, as a new group. Your object is not +changed: hide it, or keep it to compare. Views added as files land like any +3D result, on the ground in front of the camera. + +

The Tripo P2 robot turning in Maya's Viewport 2.0 The Tripo P2 robot with every edge drawn: 4,987 faces

+ +*A robot blocked out from cubes in Maya and one Tripo P2 run on its four +views. Right, the same mesh with every edge drawn.* + +### Which model + +Same four views, one run each: + +| Model | Faces | GLB | Price | +| --- | --- | --- | --- | +| Tripo P2 Multi View, the default | 4,987, a clean low-poly mesh | 1.4 MB | 220 CU | +| Tripo 3.1 Multi View, the low-cost choice | 1,425,173, dense | 42 MB | 45 CU | +| Hunyuan 3D Pro 3.1 Multiview | starts at 40,000, its lightest setting | not run yet | 120 CU | + +Both Tripo results kept the shape and colours on every side, took under four +minutes and landed on the blockout within half a centimetre of its 82 cm +height. + +## Quad meshes and FBX results + +The Tripo models have a **quad** setting: the mesh comes back in quads, +delivered as an FBX file (Scenario sends no GLB then). The plug-in imports it +through Maya's own FBX importer, as one Ctrl+Z, and lands it like a GLB: on +the ground in front of the camera, or over the captured object in the +Multi-view mode. + +

The robot from Tripo 3.1 Multi View with quad on: as imported, and with every edge drawn, a grid of quads

+ +*Tripo 3.1 Multi View with quad on and a face limit of 8,000, from the four +robot views: 8,153 faces, 8,132 of them quads. 53 CU.* + +### What the plug-in does around the FBX importer + +- Keeps the scene's unit, up axis, playback range, current frame and frame + rate, which the importer would change. +- Imports even when the scene already has nodes of the same names. +- Writes the file's textures under `sourceimages/scenario/`. +- Cleans up the names the FBX format mangles. +- Keeps the importer's materials, with colour textures in sRGB and the other + maps Raw. +- Lets skinned meshes follow their joints only, so a rig lands upright in a + Z-up scene and in one piece wherever it is placed. +- Starts a clip on the scene's start frame, as for a GLB, and reports the same + import checks. + +## Edit a mesh of the scene + +The **Edit selection** mode sends one of your meshes to an edit model and +brings the result back: over the mesh as a new object, or onto the mesh +itself. + +### Send a mesh + +1. Select one mesh (the object, or some of its faces) and open **3D**, + **Edit selection**. +2. Choose the task: **Remesh**, **UV unwrap** or **Retexture**. Each task + keeps its own model; the defaults are Tripo Retopology v3, Tripo Smart UV + and Meshy 7 Retexture. +3. **Use selection** writes the mesh, with its UVs and base colour textures, + to a file in the project's `images/scenario/captures` folder. Object, + scene and path names stay on your machine. +4. The mesh is checked against the model before anything is sent (Tripo Smart + UV takes up to 80,000 triangles, Meshy UV Unwrap 44,000, Hunyuan UV + Unwrapping 30,000); a mesh it cannot take shows why and is not sent. An + unchanged mesh is sent once. +5. Retexture needs a prompt. The price shows on **Generate**. + +### Import over the mesh + +**Import** places the result over the mesh it came from, as a new group, even +if you moved the mesh after sending it. Your mesh is not changed. + +Most edit models return the mesh resized and centred. The plug-in keeps the +file it sent, fits the result back onto it and onto the mesh's current place, +then checks that both are the same shape. A result that is not still lands, +and the import message says so. + +### What came back + +A bevelled crate of 1,052 triangles with the cube's default UVs, one run per +model: + +| Your mesh | Meshy 7 Retexture | Tripo 3.0 Texturing | +| --- | --- | --- | +| ![The crate sent, grey, before any edit](media/edit-input.jpg) | ![The crate retextured by Meshy 7 as weathered planks with metal corners](media/edit-meshy-retexture.jpg) | ![The crate retextured by Tripo 3.0 in dark brown wood](media/edit-tripo-texturing.jpg) | +| 1,052 triangles | Same triangles and the same UVs; base colour, normal, metallic and roughness maps; 40 CU | Same triangles and the same UVs; PBR textures; 15 CU | + +| Your UVs, on a checker | Tripo Smart UV | +| --- | --- | +| ![The crate with its default UVs on a checker: large squares, stretched on the bevels](media/edit-uv-input.jpg) | ![The crate with Tripo Smart UV's layout on the same checker: even squares across the faces](media/edit-uv-smart.jpg) | +| The cube's default layout | A new layout on the same triangles; 40 CU | + +| What was sent | Meshy Remesh | Tripo Retopology v3 | +| --- | --- | --- | +| ![The crate as sent, every edge drawn: an even grid of bevelled panels split in triangles](media/edit-remesh-sent.jpg) | ![The crate remeshed by Meshy: larger, irregular triangles over the same shape](media/edit-remesh-meshy.jpg) | ![The crate remeshed by Tripo: larger triangles in a more regular pattern over the same shape](media/edit-remesh-tripo.jpg) | +| 1,052 triangles (398 faces in Maya) | 522 triangles, new UVs, base colour and metal-roughness maps baked; 20 CU | 560 triangles, a baked normal map; 70 CU | + +### Apply onto the mesh + +**Apply...** writes the result onto the mesh itself. Before anything changes, +the plug-in checks that the result is the same surface as your mesh (for a +remesh, the same shape), then a review lists what changes, what is kept and +what needs your confirmation. One Ctrl+Z undoes the whole apply. + +| Task | What Apply changes | What it keeps | +| --- | --- | --- | +| UV unwrap | The current UV set gets the result's UVs | The old layout as `_scnPrev`, geometry, other UV sets, materials | +| Retexture | A new material from the result's maps (base colour, metal and roughness, normal) is assigned to the mesh; UVs too if the model changed them | The old material, unassigned; Maya's default material is never edited | +| Remesh | The mesh's shape is replaced by the result's mesh, under your transform and with your shape's name; it gets the result's material when the result has textures | The transform (name, place, attributes, parent, sets, connections); the old shape, hidden, as `_scnPrev` with its history | + +All five results above apply onto the crate. + +### What Apply asks or refuses + +- It asks before deleting the mesh's construction history, which would + overwrite new UVs, and before giving one material to a mesh that has + several. +- It refuses deformed (skinned), referenced and locked meshes in this + version, and Replace geometry refuses instanced ones. **Import** still works + on them. + +## Animate a character + +The **Motion** mode turns a prompt into a character that moves: a skinned +mesh, its joints and a clip, imported as one Ctrl+Z. Some models bring their +own character; others rig and animate yours. + +

A wooden mannequin waving its right hand, from Meshy Text to Motion The Multi-view robot, rigged and animated by Uthana Text to Motion 3.0, raising its right arm

+ +*"waves hello with the right hand". Left, Meshy Text to Motion from the +prompt alone: its own mannequin, 52 joints, 3 seconds. Right, Uthana Text to +Motion 3.0 on the robot from the Multi-view chapter, sent from the scene: +rigged with 52 joints and animated for 4 seconds.* + +### From a prompt alone + +Open the **3D** tab and choose **Motion**. The default model, Meshy Text to +Motion, needs only the prompt: one simple action works best (a walk, a wave, +a jump), 2 to 10 seconds, 40 CU whatever the length. + +### On your own character + +1. Press **Change** and pick Uthana Text to Motion 3.0 or Cartwheel Text to + Motion. +2. Select the character (its group or its meshes) and press **Use + selection**. The meshes are written as one GLB, with neutral names, and + sent to your project once. Nothing is added to the scene or to the undo + queue. Cartwheel needs a character, and the Generate button says so until + one is sent; Uthana takes one or makes its own. +3. **Import** lands the result over your character, at its size, measured on + the clip's first frame. Your character is not changed. + +Model the character standing, facing front (+Z), arms away from the body. +Check which way a rig faces before animating further: in our test, +Cartwheel's rig faced the robot's back. + +### Frame rate and timeline + +- A model's frame-rate setting starts at the scene's rate when the model + offers it (Uthana: 24, 30 or 60 fps). When a clip was made at another rate + (30 fps in a 24 fps scene), its keys fall between frames and the result + says so. +- The clip starts on the scene's start frame; the playback range is not + changed. + +### Which model + +One prompt, one run each: + +| Model | Character | Result | Price | +| --- | --- | --- | --- | +| Meshy Text to Motion, the default | Its own wooden mannequin (52 joints) | FBX, in about 30 seconds | 40 CU, 2 to 10 s | +| Uthana Text to Motion 3.0, first pick for your character | Yours (auto-rigged) or its own (160 joints) | GLB, in about 3 minutes | 104 CU for 4 s; 124 CU with a character | +| Cartwheel Text to Motion | Yours, required | Maya FBX, in 2 to 4 minutes | 72 CU for 3 s | + +![One row per run: Meshy's mannequin and Uthana's own character wave from the prompt alone; Uthana rigs the robot facing front; Cartwheel's rig faces the robot's back](media/motion-shootout.jpg) + +## Generate an image + +| Ready | As a card facing the camera | As a material on a selected mesh | +| --- | --- | --- | +| ![The Image tab with a ready result](media/panel-image-ready.png) | ![A generated image as a card in the viewport](media/image-card.png) | ![The image as the material of a cube](media/image-material.png) | + +### Land it in the scene + +The **Image** tab prices and generates like the 3D tab (default model: GPT +Image 2.5 Flare). A ready image lands three ways, each one Ctrl+Z: + +- **Card**: a textured plane facing the camera, at its centre of interest. Use + it as a reference board next to your model. +- **Material**: base colour of a new material on the selected meshes or faces. +- **Image plane**: on the current camera, to model or animate against. + +Files go to `sourceimages/scenario/`. + +### Turn it into a 3D model + +**Make a 3D model from this image**, in a result's **...** menu, opens 3D, +Image with the image in place: concept, then mesh, without leaving Maya. + +## Choose a model + +![The model picker on the 3D tab](media/picker-3d.png) + +**Change** opens the picker for the current mode: the mode's quick picks +first, the ones this guide compares, then the other models of that kind in +Scenario's catalog, with search, a **Team models** filter for your team's own +models, and legacy models on request. The settings below the prompt follow +the model you pick, read from Scenario; the catalog is kept for a day per +project. + +## Prices and spending + +### The price on the button + +Every request is priced before it is sent. When you edit the prompt or a +setting, the panel asks Scenario for the price, a free check, and the button +shows it: `Generate . 120 CU`. **Price unavailable (Retry)** means the check +failed; nothing was spent. + +### What the plug-in guarantees + +- A price is valid for the exact request it was checked for, for two + minutes. Any edit asks for a new price. +- The job is saved on your computer before the request is sent, and it is + sent once. If Maya crashes or the connection drops while it is being sent, the + job shows as **Not confirmed** (see below) rather than being sent again. +- The plug-in sets no spending cap of its own. Your team's limits on Scenario + apply. + +### Ask before spending, or never spend + +- `confirm_above_cu` in the [settings file](#settings) makes Generate ask + before any request priced above that many CU. +- `SCENARIO_NO_SPEND=1` in Maya's environment refuses every paid request; the + button then reads `Spending off` beside the price. + +## Jobs and recovery + +### The job list + +**Jobs**, at the bottom of the panel or in the Scenario menu, lists every job +of the project from every Maya session, newest first: state, model, prompt or +input, quoted and charged CU. Right-click a job for **Copy details** (local +and Scenario job ids, prices, times, the error and its hint), for a support +request. + +A job goes through Preparing, Submitting, Queued, Starting, Generating (with +a percentage when Scenario reports one), Finalizing and Downloading to Ready +to apply, then Applied once it is in the scene. It can also end as Failed, +Blocked (refused by Scenario's content rules), Download failed, Canceled or +Not confirmed. + +### When Maya closes + +Jobs live on Scenario, not in Maya. Close Maya during a long generation and, +at the next start, the panel offers the results that finished meanwhile: +press **Download**. A download that stopped resumes from where it was, with a +fresh link; **Retry download** on the card does the same by hand. If Scenario +cannot be read several times in a row, delivery pauses and the card says why. + +### Not confirmed + +A job is **Not confirmed** when Maya stopped, or the connection dropped, +while its paid request was being sent: Scenario may or may not have received +it, and may have charged it. Maya warns at the next start. To protect you +from paying twice, the plug-in blocks the identical request (same project, +model and settings). Check your project's jobs on +[app.scenario.com](https://app.scenario.com) before generating it again. +Changing anything in the request sends a new one. + +## Files and folders + +Results go into the current Maya project (**File > Set Project**), so they +travel with your scene: + +``` +/ + scenario/// each result: the GLB or FBX and its scenario.json record + sourceimages/scenario// images, and the textures written from a 3D result + images/scenario/captures/ viewport captures, views and the meshes sent for an edit +``` + +Every node the plug-in creates carries its provenance (model, prompt, price, +job and asset ids) as plain string attributes, so the scene opens on machines +without the plug-in and anyone can tell where an asset came from. Anyone you +send the scene to can read those prompts; set `store_prompts_on_nodes` to +`false` in the settings to leave them out. + +The plug-in's own files (settings, the job list, the model catalog cache and +logs) are in `scenario/` inside Maya's user folder (`MAYA_APP_DIR`). + +## Settings + +The panel has no settings page yet. The few settings live in +`/scenario/settings.json`, which never holds a secret: + +| Setting | Default | Effect | +| --- | --- | --- | +| `confirm_above_cu` | `0` (never ask) | Generate asks before a request priced above this | +| `store_prompts_on_nodes` | `true` | Prompts saved on the nodes the plug-in creates | + +Environment variables, set before Maya starts: + +| Variable | Effect | +| --- | --- | +| `SCENARIO_NO_SPEND=1` | Refuses every paid request | +| `SCENARIO_MAYA_OFFLINE=1` | No network access at all; Import GLB still works | +| `SCENARIO_API_KEY`, `SCENARIO_API_SECRET` | Sign in with an API key without storing it | + +## Troubleshooting + +### Sign-in + +- **The browser does not come back to Maya**: use **Sign in on another + device** and type the code, or an API key. +- **"Unlock the login keychain"** (macOS): the Keychain is locked; unlock it + and sign in again. +- **"Sign in again or check the API key"**: the session expired or the key + was revoked. + +### Prices and requests + +- **Price unavailable**: press it to retry. A request the model refuses (a + missing input, a value out of range) shows Scenario's reason. +- **"Upgrade the plan or wait for the limit to reset"**: your team's plan or + limit refused the request; nothing was spent. +- **"Paid requests from Maya cannot name a task yet"**: the project bills + every request to a task; choose another project. +- **"Mesh not accepted by this model"**: too many triangles for the edit + model; reduce the mesh or pick another model. + +### Network + +- **A certificate error behind a company proxy**: the proxy inspects TLS; its + root certificate must be in the system's trust store, which the plug-in + uses. +- **Download failed**: press **Retry download**; it resumes. + +### Reporting a problem + +**Scenario > Help > Copy Diagnostics** copies versions, paths and state, +never a secret, to paste into a [GitHub issue](https://github.com/scenario-labs/maya-plugin/issues) +with the job's **Copy details**. Or write to support@scenario.com. + +## Known limits + +- Agents: a local Scenario MCP server inside Maya, so Claude Code, Codex or + Cursor drive the same actions, is next. +- 3D: rigging without a motion, splitting into parts, putting a motion onto a + rig already in the scene (retargeting, HumanIK), video to motion. +- Images: editing, upscale, LoRAs. +- Other lanes: materials, sky domes, video, audio. +- A settings page, a results history and an "In this scene" view. +- Linking a Not confirmed job to a Scenario job from the panel. +- Tested on Maya 2027.2 on macOS. Maya 2025 and 2026, Windows and Linux are + supported by the code but not yet checked by hand; the Multi-view, Edit + selection and Motion modes were checked headless. diff --git a/handbook.config.json b/handbook.config.json index 8122357..eaf6d88 100644 --- a/handbook.config.json +++ b/handbook.config.json @@ -4,7 +4,7 @@ "repository": "scenario-labs/maya-plugin", "files": "scenario-maya", "site": "https://maya.scenario.com", - "description": "User handbook for Scenario for Maya {version}: install, sign in, every mode with real results (3D from a prompt, an image or views, mesh edits, motion, images), prices and privacy.", + "description": "User handbook for Scenario for Maya {version}: install, the panel, every mode with real results (3D from a prompt, an image or views, mesh edits, motion, images), prices, jobs, files, privacy and troubleshooting.", "version": { "file": "ScenarioForMaya/scripts/scenario_maya/__init__.py", "pattern": "__version__ = \"([^\"]+)\"" @@ -16,8 +16,8 @@ "/download/latest" ], [ - "Install", - "#install" + "Quick start", + "#quick-start" ] ], "nav": [ @@ -25,6 +25,10 @@ "Install", "#install" ], + [ + "Quick start", + "#quick-start" + ], [ "Downloads", "#downloads" @@ -58,26 +62,27 @@ "AGENTS.md": "contributor guide", "SUPPORT.md": "Support", "SECURITY.md": "Security", - "CONTRIBUTING.md": "Contributing" + "CONTRIBUTING.md": "Contributing", + "docs/USER_GUIDE.md": "User Guide" }, "chapters": [ { - "id": "install", - "title": "Install", + "id": "what-it-does", + "title": "What it does", "parts": [ { "file": "README.md", - "section": "Install a release" + "section": "What it does" } ] }, { - "id": "sign-in", - "title": "Sign in", + "id": "install", + "title": "Install", "parts": [ { "file": "README.md", - "section": "Sign in" + "section": "Install" } ] }, @@ -87,33 +92,53 @@ "generated": "downloads" }, { - "id": "generate-a-3d-model", - "title": "Generate a 3D model", - "newPage": true, + "id": "quick-start", + "title": "Quick start", "parts": [ { - "file": "README.md", - "section": "Generate a 3D model" + "file": "docs/USER_GUIDE.md", + "section": "Quick start" } ] }, { - "id": "turn-an-image-into-a-3d-model", - "title": "Turn an image into a 3D model", + "id": "find-your-way-around", + "title": "Find your way around", "parts": [ { - "file": "README.md", - "section": "Turn an image into a 3D model" + "file": "docs/USER_GUIDE.md", + "section": "Find your way around" } ] }, { - "id": "turn-views-of-an-object-into-a-3d-model", - "title": "Turn views of an object into a 3D model", + "id": "3d-from-a-prompt", + "title": "3D from a prompt", "parts": [ { - "file": "README.md", - "section": "Turn views of an object into a 3D model" + "file": "docs/USER_GUIDE.md", + "section": "3D from a prompt" + } + ], + "newPage": true + }, + { + "id": "3d-from-an-image", + "title": "3D from an image", + "parts": [ + { + "file": "docs/USER_GUIDE.md", + "section": "3D from an image" + } + ] + }, + { + "id": "3d-from-views-of-an-object", + "title": "3D from views of an object", + "parts": [ + { + "file": "docs/USER_GUIDE.md", + "section": "3D from views of an object" } ] }, @@ -122,7 +147,7 @@ "title": "Quad meshes and FBX results", "parts": [ { - "file": "README.md", + "file": "docs/USER_GUIDE.md", "section": "Quad meshes and FBX results" } ] @@ -130,54 +155,84 @@ { "id": "edit-a-mesh-of-the-scene", "title": "Edit a mesh of the scene", - "newPage": true, "parts": [ { - "file": "README.md", + "file": "docs/USER_GUIDE.md", "section": "Edit a mesh of the scene" } - ] + ], + "newPage": true }, { "id": "animate-a-character", "title": "Animate a character", - "newPage": true, "parts": [ { - "file": "README.md", + "file": "docs/USER_GUIDE.md", "section": "Animate a character" } - ] + ], + "newPage": true }, { "id": "generate-an-image", "title": "Generate an image", - "newPage": true, "parts": [ { - "file": "README.md", + "file": "docs/USER_GUIDE.md", "section": "Generate an image" } - ] + ], + "newPage": true }, { "id": "choose-a-model", "title": "Choose a model", "parts": [ { - "file": "README.md", + "file": "docs/USER_GUIDE.md", "section": "Choose a model" } ] }, { - "id": "how-a-request-is-paid", - "title": "How a request is paid", - "newPage": true, + "id": "prices-and-spending", + "title": "Prices and spending", "parts": [ { - "file": "README.md", - "section": "How a request is paid" + "file": "docs/USER_GUIDE.md", + "section": "Prices and spending" + } + ], + "newPage": true + }, + { + "id": "jobs-and-recovery", + "title": "Jobs and recovery", + "parts": [ + { + "file": "docs/USER_GUIDE.md", + "section": "Jobs and recovery" + } + ] + }, + { + "id": "files-and-folders", + "title": "Files and folders", + "parts": [ + { + "file": "docs/USER_GUIDE.md", + "section": "Files and folders" + } + ] + }, + { + "id": "settings", + "title": "Settings", + "parts": [ + { + "file": "docs/USER_GUIDE.md", + "section": "Settings" } ] }, @@ -192,17 +247,23 @@ ] }, { - "id": "how-it-is-built", - "title": "How it is built", - "newPage": true, + "id": "troubleshooting", + "title": "Troubleshooting", "parts": [ { - "file": "README.md", - "section": "How it is built" - }, + "file": "docs/USER_GUIDE.md", + "section": "Troubleshooting" + } + ], + "newPage": true + }, + { + "id": "known-limits", + "title": "Known limits", + "parts": [ { - "file": "README.md", - "only": "Tests" + "file": "docs/USER_GUIDE.md", + "section": "Known limits" } ] }, @@ -222,10 +283,80 @@ "parts": [ { "file": "README.md", - "section": "More" + "section": "License" } ], "generated": "licence" } - ] + ], + "flow": { + "from": { + "label": "From your scene", + "items": [ + [ + "A prompt", + "#3d-from-a-prompt" + ], + [ + "An image, or the viewport", + "#3d-from-an-image" + ], + [ + "Views of an object", + "#3d-from-views-of-an-object" + ], + [ + "A mesh", + "#edit-a-mesh-of-the-scene" + ], + [ + "A character", + "#animate-a-character" + ] + ] + }, + "models": { + "label": "Scenario models", + "items": [ + [ + "Text, image or views to 3D", + "#3d-from-a-prompt" + ], + [ + "Remesh, UV unwrap, retexture", + "#edit-a-mesh-of-the-scene" + ], + [ + "Text to motion", + "#animate-a-character" + ], + [ + "Text to image", + "#generate-an-image" + ] + ], + "note": "Priced on the button before you click." + }, + "to": { + "label": "Back in Maya", + "items": [ + [ + "A model on the ground, at real size" + ], + [ + "A result over the object or mesh it came from" + ], + [ + "New UVs, material or geometry on your mesh" + ], + [ + "A rigged, animated character" + ], + [ + "A card, a material or an image plane" + ] + ] + }, + "note": "Each landing is one Ctrl+Z." + } } From 5e1d07da6bb0aec6e6ef48f15835a29dc4c11242 Mon Sep 17 00:00:00 2001 From: qchantel Date: Fri, 13 Nov 2026 18:35:17 +0100 Subject: [PATCH 3/3] docs(docs): proofread the user guide against the plug-in Co-Authored-By: Claude Opus 5.5 --- README.md | 3 --- docs/USER_GUIDE.md | 47 +++++++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 92e5776..1e4708c 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,6 @@ modes headless only so far). | Agents | | A local Scenario MCP server inside Maya, so Claude Code, Codex or Cursor drive the same actions | | Other lanes | | Materials, environment (sky domes), render a view, video, audio | -Each mode, with real results and model comparisons, is in the -[User Guide](docs/USER_GUIDE.md). - ## Install You need Maya 2025, 2026 or 2027 and a Scenario account on a plan with API diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 8371915..d5a9f52 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -16,15 +16,16 @@ Maya 2027.2 with live Scenario models. 2. In the Scenario panel, choose **Sign in with Scenario** and approve in your browser. If your account has several teams or projects, pick one. 3. Open the **3D** tab, keep the **Text** mode and its default model, Meshy - 7.1, and write a prompt: `a brass lantern with a glass cage`. + 7.1, and write a prompt: `weathered brass ship lantern, game prop`. 4. The button shows the price once Scenario has checked it, for example `Generate . 120 CU`; the check is free. Press it. -5. When the card says Ready to apply, press **Import**. The lantern lands on the ground - in front of the camera at its real size. Ctrl+Z removes it in one step. +5. When the card says Ready to apply, press **Import**. The lantern lands on + the ground in front of the camera at its real size. Ctrl+Z removes it in + one step. ## Find your way around -![The Scenario panel on the 3D tab: workspace at the top, the Text mode with Meshy 7.1, a prompt, the price on Generate and a result card](media/panel-3d-priced.png) +

The Scenario panel on the 3D tab: workspace at the top, the Text mode with Meshy 7.1, a prompt, the price on Generate and the job list

### The panel @@ -42,13 +43,15 @@ and comes back with your workspace layout. From top to bottom: when the model takes none; the model's settings, read from Scenario; and the **Generate** button with its price. Ctrl+Enter presses it. - **Results**: one card per job of this mode, with its status, its price and - the actions valid now (Import, Apply..., Card, Retry download). The **...** - menu of a card has Show file, Open on Scenario, Re-run settings (fills the - form with that job's settings, sends nothing) and Copy details. + the actions valid now (Import or Apply... for 3D; Card, Material or Image + plane for an image; Retry download). Before the first result, example + prompts to start from. The **...** menu of a card has Show file, Open on + Scenario, Re-run settings (fills the form with that job's settings, sends + nothing) and Copy details. - **Jobs**: every job of the project, from every Maya session (see [Jobs and recovery](#jobs-and-recovery)). -The **...** button at the top right has Workspace..., Refresh jobs, Copy +The **☰** button at the top right has Workspace..., Refresh jobs, Copy diagnostics, the handbook, Privacy, Report a problem and Sign out. ### The Scenario menu @@ -105,7 +108,7 @@ is sped up; everything else plays in real time. Videos: **Import** adds the model as a new group at the size Scenario returns, its bottom centre on the ground below the camera's centre of interest. Materials -are openPBR, with their textures written to `sourceimages/scenario/`. The +are OpenPBR, with their textures written to `sourceimages/scenario/`. The card reports the import checks: size, materials and textures, non-manifold edges, missing textures. One Ctrl+Z removes the whole import; redo brings it back. @@ -318,7 +321,7 @@ All five results above apply onto the crate. overwrite new UVs, and before giving one material to a mesh that has several. - It refuses deformed (skinned), referenced and locked meshes in this - version, and Replace geometry refuses instanced ones. **Import** still works + version, and a remesh refuses instanced ones. **Import** still works on them. ## Animate a character @@ -406,10 +409,10 @@ Image with the image in place: concept, then mesh, without leaving Maya. **Change** opens the picker for the current mode: the mode's quick picks first, the ones this guide compares, then the other models of that kind in -Scenario's catalog, with search, a **Team models** filter for your team's own -models, and legacy models on request. The settings below the prompt follow -the model you pick, read from Scenario; the catalog is kept for a day per -project. +Scenario's catalog, with search, a **Team models** filter for your team's +own models, and **Show legacy** for older models. The settings below the +prompt follow the model you pick, read from Scenario; the catalog is kept +for a day per project. ## Prices and spending @@ -425,8 +428,8 @@ failed; nothing was spent. - A price is valid for the exact request it was checked for, for two minutes. Any edit asks for a new price. - The job is saved on your computer before the request is sent, and it is - sent once. If Maya crashes or the connection drops while it is being sent, the - job shows as **Not confirmed** (see below) rather than being sent again. + sent once. If Maya crashes or the connection drops while it is being sent, + the job shows as **Not confirmed** (see below) rather than being sent again. - The plug-in sets no spending cap of its own. Your team's limits on Scenario apply. @@ -448,10 +451,10 @@ and Scenario job ids, prices, times, the error and its hint), for a support request. A job goes through Preparing, Submitting, Queued, Starting, Generating (with -a percentage when Scenario reports one), Finalizing and Downloading to Ready -to apply, then Applied once it is in the scene. It can also end as Failed, -Blocked (refused by Scenario's content rules), Download failed, Canceled or -Not confirmed. +a percentage when Scenario reports one), Finalizing, Finished and +Downloading to Ready to apply, then Applied once it is in the scene. It can +also end as Failed, Blocked (refused by Scenario's content rules), Download +failed, Canceled or Not confirmed. ### When Maya closes @@ -495,7 +498,9 @@ logs) are in `scenario/` inside Maya's user folder (`MAYA_APP_DIR`). ## Settings The panel has no settings page yet. The few settings live in -`/scenario/settings.json`, which never holds a secret: +`/scenario/settings.json`, which never holds a secret. +Edit it with Maya closed: Maya writes the file and would overwrite the +change. | Setting | Default | Effect | | --- | --- | --- |