agentsclimarketplace

Shapediver viewer

Skill shapediver/agent-skills/skills/shapediver-viewer

Agent skills for ShapeDiver

Install
npx -y skills add shapediver/agent-skills --skill shapediver-viewer

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill when the user needs to write custom code using the ShapeDiver Viewer V3 API (@shapediver/viewer or the ShapeDiver CDN bundle) to build a 3D product configurator — including session/viewport setup, parameter controls, commit patterns, export downloads, React integration, and interaction features (selection, hover, drag, gumball, drawing tools, attribute visualization). Covers CDN and NPM workflows.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

27.0 KB, as published. Nobody here has run it

ShapeDiver Viewer V3 API

Prerequisite: This skill assumes you have already read and followed the shapediver-router skill. If you arrived here directly, stop — read shapediver-router first. It selects the correct integration strategy and gathers required credentials before any implementation skill is read.

Follow every rule in this file exactly. Do not improvise or work around any constraint.

Scope discipline: Touch only what the user asked for. Do not add features, refactor adjacent code, or "improve" files beyond the stated request. If the user asks for a slider, build a slider — do not add export buttons, camera controls, or interaction features they did not request.


Workflow

Follow these steps in order. Do not skip steps or jump ahead to writing code. Each step has a checkpoint — do not proceed until the checkpoint is met.

Step 1: Collect Credentials and Model Metadata

Obtain ticket, modelViewUrl, and parameter/output/export metadata. Use the API script (Option A below) or manual values from the user (Option B).

Checkpoint: You have real values for ticket and modelViewUrl, OR you have inserted placeholders and asked the user to provide them. You have confirmed the AppBuilder output check below.

Step 1a: AppBuilder Output Check (mandatory before writing any code)

Scan the outputs list from the script or user-provided metadata for an output named "AppBuilder" (exact name, case-insensitive). Do this before reading further.

If found: Stop. Ask the user:

"This model has an AppBuilder output — it is configured for the ShapeDiver App Builder. Are you sure you want a custom Viewer API integration instead? The App Builder may already cover your needs with less effort."

If they confirm custom integration, document their reason and continue. If they want App Builder, hand off to the shapediver-appbuilder skill.

Checkpoint: You have confirmed no AppBuilder output exists, OR the user has explicitly confirmed they want a custom integration despite the AppBuilder output.

Step 2: Choose CDN or NPM

Ask the user's stack if not obvious. Use CDN + plain HTML for single-page demos, prototypes, and embeds. Use NPM + framework for production apps with build tooling. See "Setup" below.

Checkpoint: CDN or NPM decision is made. If CDN: you will use a single bundle.js script tag (Rule 7). If NPM: you know the framework (React, Vue, plain TS).

Step 3: Scaffold the Page / Component

Create the HTML file or React component with the canvas element.

Checkpoint: The canvas element is always present in the DOM — not conditionally rendered (Rule 11). If showing a loading state, it is an overlay on top of the always-present canvas. The correct script tag (CDN) or imports (NPM) are in place.

Step 4: Create Viewport and Session

Write the initialization code: create viewport first, then session. Always await both. See "Quick API Overview" below.

Checkpoint: createViewport is called before createSession. Both calls are awaited. ticket and modelViewUrl are hardcoded from user-provided values — not exposed as UI inputs (Rule 5). Error handling wraps initialization with getSDErrorMessage (Rule 8).

Step 5: Build Parameter Controls

Render UI controls for each parameter based on param.type. Filter out param.hidden, sort by param.order, group by param.group.

Checkpoint — verify ALL of these before proceeding:

  • Sliders (Int, Float, Even, Odd): commit on onMouseUp / onChangeEnd, NOT onChange (Rule 1). React sliders use useRef to avoid stale closures (Rule 3).
  • Color pickers: commit at end of interaction, not on every movement (Rule 2). Format is 0xRRGGBBAA (Rule 4).
  • Dropdowns (StringList) and checkboxes (Bool): these are the ONLY controls where onChange is safe.
  • Text inputs (String): commit on onBlur, NOT onChange (Rule 1).
  • session.customize() is called explicitly after setting param.value (Rules 9–10).
  • Values are formatted correctly per type — see "Parameter Formatting" reference.
  • When multiple parameter types are requested, ALL must appear in the delivered file. A partial implementation is not acceptable — do not truncate or omit any requested control type. Prioritize complete code over explanatory prose.

Step 6: Add Interaction Features (if requested)

Only if the user asked for interactions (selection, drag, drawing tools, gumball, etc.). Load the specific reference file listed in "Interaction Features" below.

Checkpoint: Type guards are used before accessing param.settings (Rule 6). Settings are extracted with param.settings?.props ?? param.settings — never read directly from param.settings. The correct reference file has been read and its rules followed.

Step 7: Add Exports and Outputs (if requested)

Only if the user asked for file downloads or data output reading. export.request() must be called explicitly — exports do not auto-trigger.

Checkpoint: Export requests use the correct API. Output data is read from output.content. Error handling is in place.

Step 8: Add Cleanup

Add session.close() and viewport.close() in the appropriate cleanup path (React useEffect return, window.onbeforeunload, etc.).

Checkpoint: Both session and viewport are closed on teardown. No dangling sessions.

Step 9: Review Against Critical Rules

Before delivering, re-read Critical Rules 1–12 below and verify the generated code against every one. Fix any violations.

Checkpoint — exit criteria (all must be true):

  • Every Critical Rule (1–12) has been checked and the code complies.
  • No model-specific values are invented — only user-provided or placeholder values are used.
  • Credentials are not exposed in UI input fields.
  • The code is a complete, runnable file — not a fragment.

Step 10: Serve Locally

If model metadata was retrieved via the API script (Option A), check the allowedDomains array in the script output for a localhost entry (e.g., localhost:5000, 127.0.0.1:8080).

If a localhost domain with a specific port is found, serve the generated file on that port:

npx serve -l <port>

If no localhost entry exists in allowedDomains, inform the user that they need to add their local development domain (e.g., localhost:3000) to the model's embedding domains at https://www.shapediver.com/app/settings/domains before the viewer session will work locally — otherwise session creation will fail with HTTP 403.

Checkpoint: The file is served on a port that matches a whitelisted domain, or the user has been informed about the domain whitelisting requirement.


Obtaining Model-Specific Values

Option A: Retrieve via API (preferred)

If the user provides a model slug (the URL identifier from shapediver.com/app/m/{slug}) and Platform API access keys (access key ID + secret), you can retrieve ticket, modelViewUrl, and full parameter/output/export metadata automatically.

Run the shared script at the repository root (self-contained — auto-installs dependencies on first run, requires Node.js):

node ../../scripts/get-model-info.js <accessKeyId> <accessKeySecret> <slug>

Note: Adjust ../../scripts/ to the actual path of the script relative to your current working directory. From a project at the workspace root, use scripts/get-model-info.js.

The script outputs clean JSON to stdout (diagnostics to stderr). The model object contains two tickets and the model view URL:

  • ticket — the embedding ticket for Viewer use in the browser. Use this in generated frontend code.
  • backendTicket — the backend ticket for headless/server-side SDK use.
  • modelViewUrl — the Geometry Backend URL.

It also includes parameters, outputs, and exports. Run with --help for full usage and exit codes.

It performs a three-step flow:

  1. Authenticate with the ShapeDiver Platform Backend API (POST /oauth/token)
  2. Get model info by slug (GET /api/v1/models/{slug}?embed=backend_ticket,backend_system) — returns backend_ticket and backend_system.model_view_url
  3. Init session on the Geometry Backend (POST /api/v2/ticket/{ticket}) — returns all parameters, outputs, and exports with their IDs, types, defaults, etc. The session is closed immediately after retrieving the metadata.

Use the returned data to populate ticket, modelViewUrl, parameter names/IDs, etc. in generated code.

Important: The model must have "backend access" enabled. The script will attempt to enable it automatically. Access keys are created at https://www.shapediver.com/app/settings/developers

After running the script: Before reading the full JSON, extract and review all output names to check for an AppBuilder output:

# Linux / macOS
cat model-info.json | node -e "const d=require('fs').readFileSync('/dev/stdin','utf8'); JSON.parse(d).outputs.forEach(o=>console.log(o.name))"

# Windows PowerShell
Get-Content model-info.json | node -e "const d=require('fs').readFileSync('/dev/stdin','utf8'); JSON.parse(d).outputs.forEach(o=>console.log(o.name))"

This reveals all output names in under a second and prevents missing a late-appearing AppBuilder output in a long JSON file.

Option B: Manual values from the user

If the user provides ticket and modelViewUrl directly (from the "Developers" tab on shapediver.com), use those values as-is.

Placeholders — Never Invent Model-Specific Values

Use ONLY values the user has explicitly provided or that were retrieved via the API script. If missing, use the placeholder and ask.

ValuePlaceholder
ticket"PASTE_YOUR_TICKET_HERE"
modelViewUrl"PASTE_YOUR_MODEL_VIEW_URL_HERE"
Parameter name/ID"PARAM_NAME_OR_ID"
Output name/ID"OUTPUT_NAME_OR_ID"
Export name/ID"EXPORT_NAME_OR_ID"

When the user provides values (e.g., ticket: abc123 in the prompt): use them exactly as-is. Do NOT add comments calling them placeholders or suggesting they need to be replaced — they are the real values.

Do NOT filter or group parameters by guessing names. If grouping is needed, ask the user for exact names/IDs. param.type tells you how to render a control, not which group it belongs to.


Critical Rules

These are the most commonly violated patterns. Read all before writing code. For code examples of each rule, see references/core-patterns.md.

Rule 1: NEVER use onChange to commit parameters

Every session.customize() call is a network request. onChange on sliders, color pickers, and text inputs fires continuously, causing HTTP 429 rate-limit errors. Dropdown and checkbox are the ONLY controls where onChange is safe. Use onMouseUp/onChangeEnd/onBlur for all others. See core-patterns.md § Commit Function.

Rule 2: Color picker — use debounced input + immediate change, not onChange or onMouseUp

onChange on <input type="color"> fires on every mouse movement — causes 429 errors. This applies to both React (onChange) and vanilla JS — in both environments the event fires continuously while the user drags. Do NOT use onChange (React) or oninput (DOM) for color pickers, even indirectly through a wrapper function — if onChange triggers any path that calls session.customize(), it violates this rule. onMouseUp fires when opening the picker, not when selecting a color — wrong event.

For CDN / vanilla JS, use Pattern E2: add an input listener with a ~300 ms debounce for live preview while dragging, plus a DOM change listener that clears the timer and commits immediately when the picker closes. Both listeners are required — change-only (Pattern E3) gives no live preview and feels unresponsive. For React, onChange on <input type="color"> maps to the DOM change event (fires only when the picker closes, not on every movement) — so onChange can be used for the final commit. Pair it with a debounced onInput for live preview (Pattern E2). See ui-patterns.md Pattern E for all implementations.

Rule 3: Slider — use useRef to avoid stale closures

React state is async. Reading state in onMouseUp captures the previous render's value. See ui-patterns.md Pattern D.

Rule 4: Color format is 0xRRGGBBAA

<input type="color"> only accepts #RRGGBB. Convert with slice(2, 8), NOT slice(-6). See parameter-formatting.md § Color.

Rule 5: Never expose credentials in UI

ticket and modelViewUrl are developer credentials. Hardcode them directly from what the user provides. Never create input fields for end users to enter these values.

Rule 6: Check param.type before using type-specific APIs

Use type guards (isDrawingParameterApi, isSelectionParameterApi, etc.) before accessing param.settings. Do not assume a type from the user's description.

Warning — Interaction param.settings is nested at runtime: The structure is { type: "selection", props: { nameFilter, maximumSelection, ... } }. The actual properties are under settings.props, NOT directly on settings. Always extract: const settings = param.settings?.props ?? param.settings; Reading param.settings.nameFilter directly returns undefined.

Rule 7: CDN — single bundle.js, correct globals

  • Use https://viewer.shapediver.com/v3/latest/bundle.js with crossorigin="anonymous" (REQUIRED)
  • The global is SDV, not SDV3
  • Do NOT add extra <script> tags or use esm.sh/unpkg/jsDelivr

Rule 8: Show actual errors, never generic messages

Use getSDErrorMessage(e) to extract the real error. See core-patterns.md § Error Extraction.

Rule 9: Do NOT enable customizeOnParameterChange

Leave it false (default). Call session.customize() explicitly after setting values.

Rule 10: Setting param.value does NOT send a request

Always call session.customize() after setting values.

Rule 11: Canvas MUST be in the DOM before createViewport

Never conditionally render the canvas. Use a loading overlay on top of an always-present canvas. See core-patterns.md § React Architectural Rules.

Rule 12: Live color preview — use client-side material mutation, NOT session.customize()

When the user wants live color preview without committing to the server immediately, do NOT call session.customize() on every color picker movement — this causes 429 errors and lag. Instead, mutate color on the existing MaterialStandardData objects in-place using an output.updateCallback + viewport.update() pattern. Stage the value and commit only when the user explicitly clicks Apply.

⚠️ Never replace a material object with new MaterialStandardData() — this discards all texture maps and breaks the model's appearance. Always mutate the existing object.

Call updateVersion() on each mutated GeometryData and MaterialStandardData at the leaf level (not just the output node) — geometry can be 6+ levels deep.

Register output.updateCallback so the color override persists after server-triggered geometry updates (e.g., after clicking Apply).

See advanced-patterns.md Pattern L for the full implementation.


Anti-Rationalization Table

These are the shortcuts you will be tempted to take. Each one breaks the integration.

You will think…Why it is wrong
"This is a simple demo, so onChange on the slider is fine."Every customize() is a network request. Even a demo hits HTTP 429 errors within seconds of dragging a slider. Use onChangeEnd / onMouseUp. Always.
"I'll add a text field for the ticket so the user can test easily."Tickets are credentials. Exposing them in a UI input trains users to paste secrets into form fields. Hardcode them from provided values.
"I don't need settings.props — I'll read settings.nameFilter directly."It returns undefined at runtime. The nested structure (settings.props) is how the API works. Always extract via param.settings?.props ?? param.settings.
"I know what parameter names this model has — I'll hardcode them."You do not know. Parameter names are model-specific. Use placeholders or values from the API script. Never invent names.
"The user asked for a configurator, so I'll add export buttons too."The user asked for what they asked for. Adding unrequested features violates scope discipline and bloats the code with untested behavior.
"I'll use esm.sh / unpkg / jsDelivr for the CDN bundle."The only supported CDN URL is https://viewer.shapediver.com/v3/latest/bundle.js. Third-party CDNs serve broken or incomplete builds.
"The code compiles, so it's correct — no need to re-check the rules."Rules 1–4 are violated in the majority of LLM-generated ShapeDiver code. Step 9 of the Workflow exists because this rationalization is the most common failure mode.

Setup

CDN vs. NPM decision: Use CDN + plain HTML for single-page demos, prototypes, and embeds. Use NPM + framework (React, Vue, etc.) for production apps with build tooling.

CDN (plain HTML)

<script
  src="https://viewer.shapediver.com/v3/latest/bundle.js"
  crossorigin="anonymous"
></script>

Use a fixed version (X.X.X) in production. This single script includes ALL features — viewer, interactions, drawing tools, transformation tools, and attribute visualization. Do NOT add extra <script> tags for individual features. Globals: SDV, SDVInteractions, SDVDrawingTools, SDVTransformationTools, SDVAttributeVisualization.

CDN + React

window.SDV is not available at mount time. Use the loadShapeDiverCDN() loader from advanced-patterns.md Pattern K — do NOT write your own.

NPM / React

import { createViewport, createSession } from "@shapediver/viewer";

For SSR (Next.js, Shopify Hydrogen), dynamic-import inside useEffect.

Feature Packages (NPM vs. CDN)

FeatureNPM PackageCDN Global
Selection, Hover, Drag@shapediver/viewer.features.interactionSDVInteractions
Drawing Tools@shapediver/viewer.features.drawing-toolsSDVDrawingTools
Gumball / Rectangle@shapediver/viewer.features.transformation-toolsSDVTransformationTools
Attribute Visualization@shapediver/viewer.features.attribute-visualizationSDVAttributeVisualization

Quick API Overview

Create viewport first, then session. Always await both.

const viewport = await SDV.createViewport({
  id: "vp",
  canvas: canvasRef.current,
});
const session = await SDV.createSession({
  id: "session",
  ticket,
  modelViewUrl,
});
session.automaticSceneUpdate = true;

Key APIs

  • Parameters: session.parameters (by ID), session.getParameterByName(name) (by name)
  • Outputs: session.outputs, session.getOutputByName(name)
  • Exports: session.exports, session.getExportByName(name), session.getExportByType(type) — must call export.request(parameters?) explicitly; accepts optional { [paramId]: value } overrides
  • Customize: param.value = newVal; await session.customize();
  • Sort params for UI: Object.values(session.parameters).filter(p => !p.hidden).sort((a,b) => (a.order??0) - (b.order??0))
  • Close: session.close(); viewport.close(); in cleanup

Parameter Properties

  • param.type — determines how to render a control and format the value: Bool, Int, Float, Even, Odd, String, StringList, Color, File, Drawing, Interaction
  • param.settings — pre-configured settings for Drawing and Interaction params. Use type guards to determine the sub-type: isSelectionParameterApi(param), isDraggingParameterApi(param), isGumballTransformParameterApi(param), isRectangleTransformParameterApi(param), isDrawingParameterApi(param). Warning — For interaction parameters, settings is nested at runtime: { type: "selection", props: { nameFilter, maximumSelection, ... } }. Always extract: const settings = param.settings?.props ?? param.settings;
  • param.group — model-author grouping from Grasshopper. Use this to organize UI sections. Do NOT guess groups from parameter names.
  • param.visualization — hint for UI rendering (e.g., CHECKLIST, SLIDER)
  • param.order — sort order intended by the model author
  • param.hidden — if true, do not show in UI

Some models also define dynamic parameters in their AppBuilder output that change based on model state. See references/dynamic-parameters.md.

For detailed API surfaces, load the specific reference needed:

For code patterns, load the specific reference needed:

For advanced troubleshooting beyond the quick-reference table, see references/troubleshooting.md.


Interaction Features

When the user wants interaction features, load the specific reference:

  • Name Filters (targeting specific nodes for interaction): references/name-filters.md How nameFilter patterns work, dot-separated syntax, wildcards, scene tree traversal
  • Selection (click to select/deselect): references/interactions-selection.md SelectManager + HoverManager + InteractionEngine setup, select/deselect events, multi-select, cleanup/teardown, multiple selection parameters. Always includes hover — do not set up hover separately when using selection.
  • Hovering (visual feedback on hover, standalone): references/interactions-hovering.md HoverManager setup for hover-only use cases. When combined with selection, hover is already included — see selection reference instead.
  • Dragging (move objects by dragging): references/interactions-dragging.md DragManager + constraints. References selection.md for InteractionEngine
  • Gumball Transform (3D translate/rotate/scale gizmo): references/gumball-transform.md GumballTransform setup, axis constraints, events
  • Rectangle Transform (2D planar gizmo): references/rectangle-transform.md RectangleTransform setup, 2D bounds
  • Drawing Tools (draw/edit points and lines): references/drawing-tools-reference.md Rules 10-12, settings tables, restrictions, full CDN + NPM examples, value format
  • HTML Anchors (overlay HTML on 3D scene, in-scene UI): references/html-anchors.md Text labels, image anchors, custom data anchors, in-scene UI elements (buttons, controls, parameter widgets anchored to 3D objects)
  • Attribute Visualization (color-code geometry by data): references/attribute-visualization.md Color-coded geometry overlays, layers, sdTF data inspection
  • Post-Processing (visual effects on rendered scene): references/post-processing.md Bloom, SSAO, HBAO, Depth of Field, Outline, Vignette, Selective Bloom, custom effects, manual EffectComposer access, combining outline with interactions
  • Animations (animate scene nodes): references/animations.md AnimationData + AnimationTracks, translation/rotation/scale keyframes, looping, glTF animations
  • Augmented Reality (AR) (view models in real world): references/augmented-reality.md AR availability check, launch AR on device, QR code session links, scene setup for AR
  • Three.js Objects (add custom three.js objects, access internal meshes): references/threejs-objects.md ThreejsData, adding Object3D to scene tree, accessing converted geometry, updateCallbackThreeJsObject
  • glTF Loader (load external glTF/glb assets into the scene): references/gltf-loader.md DataEngine.loadContent(), external glTF enrichment, glTF preview tool

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.