{"id":14168,"plugin_id":"plugin_asdk_app_6a8e5c09f7788191b376df6d421b1ca8","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:08:57.123Z","digest":"688540c939e370123967179507e26b5acae17e3242d1105915d9c8e70b6f6cff","against":null,"payload":{"description":"This skill should be used when the user asks to \"embed a demo\", \"add our demo to the pricing page\", \"install a Rendemo demo\", \"put the product demo on the site\", mentions `<rendemo-demo>`, `embed.js`, or `rendemo_get_embed`, or wants an interactive Rendemo demo rendered inside their own app or marketing site. Sequences the whole install: pick the demo, detect the framework, write the wrapper, place the script tag.","included_files":[],"name":"embed-a-demo","skill_md_contents":"---\r\nname: embed-a-demo\r\ndescription: 'This skill should be used when the user asks to \"embed a demo\", \"add our demo to the pricing page\", \"install a Rendemo demo\", \"put the product demo on the site\", mentions `<rendemo-demo>`, `embed.js`, or `rendemo_get_embed`, or wants an interactive Rendemo demo rendered inside their own app or marketing site. Sequences the whole install: pick the demo, detect the framework, write the wrapper, place the script tag.'\r\nversion: 0.3.0\r\n---\r\n\r\n# Install a published Rendemo demo on a site\r\n\r\nA **demo** is a recorded replay a visitor **watches** in an iframe. If what the user actually wants is\r\nstep-by-step guidance on their own live product, which they **perform for real**, that is a **tour** —\r\na different artifact and a different skill (`author-a-tour`). Check that before you install anything;\r\nembedding a recording for someone who asked to guide their users is a visible mistake.\r\n\r\nThis works end to end today. `https://www.rendemo.com/embed.js` is live, the `<rendemo-demo>`\r\ncustom element ships `inline` and `modal` modes, and `rendemo_get_embed` returns install code per\r\nframework. Nothing in this procedure is aspirational.\r\n\r\nThe MCP cannot touch a filesystem. Every tool here hands back **text you write**.\r\n\r\n## 1. Find the demo\r\n\r\nCall `rendemo_list_projects`. Each project reports `demo: { id, status, protected }` or `null`.\r\n\r\n- **Exactly one plausible match** by name and the user's stated intent → say which one you picked and\r\n  keep going.\r\n- **Ambiguous, or several published demos** → list name / step count / status and ask which. Do not\r\n  guess: embedding the wrong demo on a pricing page is a visible mistake on a public page.\r\n- `status` is not `published` → **stop and ask.** `rendemo_publish_demo` makes the demo\r\n  world-visible at a public URL. That is not yours to decide. Offer it, wait for a yes.\r\n- `demo: null` → the project has no demo yet. Publishing is the only path, so the same checkpoint\r\n  applies.\r\n- `protected: true` → **stop before writing anything.** A password-protected demo cannot be embedded\r\n  at all: the access cookie is dropped inside a third-party iframe, so the visitor loops back to the\r\n  password form forever. This is not a caveat to mention afterwards — it makes the whole install\r\n  pointless, and the files you would write are files that can never work. Offer the alternatives\r\n  instead: link to `/d/<id>` or `/site/<workspace>/<slug>` in a new tab, or remove the password.\r\n\r\n## 2. Detect the framework — do not ask, look\r\n\r\n`rendemo_get_embed` takes exactly these values, and passing the wrong one produces a snippet that\r\nwill not compile:\r\n\r\n| value | evidence to look for |\r\n|---|---|\r\n| `next-app-router` | `next` in dependencies **and** an `app/` directory containing `layout.tsx`/`layout.jsx` |\r\n| `next-pages` | `next` in dependencies **and** `pages/_app.tsx`/`_app.jsx`, no `app/` router |\r\n| `react` | `react` in dependencies, no `next` |\r\n| `vue` | `vue` in dependencies |\r\n| `svelte` | `svelte` in dependencies |\r\n| `html` | no package.json, or plain static HTML |\r\n\r\nRead `package.json` and glob for the router directory. If a repo has both `app/` and `pages/`\r\n(a mid-migration Next app), pick the router that owns the page the demo is going on, and say which\r\nyou picked and why.\r\n\r\n`mode` is your call from the intent: `inline` for \"put the demo on the page\", `modal` for\r\n\"a Watch-the-demo button\". Ask only if the intent genuinely does not say.\r\n\r\n## 3. Get the code\r\n\r\n`rendemo_get_embed({ projectId, framework, mode })`. It fails with a clear message if the project has\r\nno demo or the demo is not published — that means you skipped step 1, go back.\r\n\r\nIt returns `scriptTag`, `scriptLocation`, `snippet`, `wrapper`, `url`, `posterUrl`, and `events`.\r\n**Use the returned strings verbatim.** Do not retype them from memory or from this file; the tool is\r\nthe single source of the contract and this skill is not.\r\n\r\n## 4. Write the files\r\n\r\nThree writes, in this order:\r\n\r\n1. **The wrapper.** Write `wrapper` to the path in its first-line comment (e.g.\r\n   `components/RendemoDemo.tsx`, `components/RendemoDemo.vue`, `src/lib/RendemoDemo.svelte`).\r\n   `wrapper` is empty for `html` — there is nothing to wrap; skip this step.\r\n   - If the file already exists, **read it first and diff.** A repo that already has a\r\n     `RendemoDemo` wrapper is already installed; you are probably adding a second placement, not\r\n     a second wrapper. Overwriting a hand-adjusted wrapper is a silent regression.\r\n2. **The script tag.** Put `scriptTag` at `scriptLocation`. It must load once per document, not once\r\n   per demo — if the tag is already there, do not add a second one.\r\n   - `scriptLocation` is a starting point, not a law: if the repo already loads third-party scripts\r\n     through a local convention (Next's `next/script`, a `<Scripts>` component, a CMS head block),\r\n     follow that convention and put the same URL there instead. Say what you did.\r\n3. **The snippet.** Put `snippet` where the demo should appear. In modal mode every framework snippet\r\n   except `html` references an `open` state variable — declare it and wire it to whatever button the\r\n   user meant, in that page's own idiom. For `html` the snippet is the bare element; the host\r\n   controls the modal by adding and removing the `open` attribute itself.\r\n\r\n## 5. The wrapper rule — this is a hard constraint\r\n\r\nA wrapper may do **exactly two things**: forward props to attributes, and bridge the element's\r\ndeclared events to callbacks. The five events are the whole surface: `rendemo:ready`,\r\n`rendemo:step`, `rendemo:complete`, `rendemo:lead`, `rendemo:close`.\r\n\r\nNothing else. No loading states, no retry logic, no analytics, no visibility heuristics, no\r\nattribute munging.\r\n\r\nThe reason is not style. The wrapper lives in the customer's repo, where Rendemo cannot patch it.\r\nAnything that belongs in `embed.js` can be fixed for every site at once; the same logic in a wrapper\r\nis frozen until that customer redeploys. If a user asks for behaviour that does not fit those two\r\nthings, say that it belongs in `embed.js` and does not go in the wrapper.\r\n\r\n## 6. Verify, then report the caveats that apply\r\n\r\n- **Typecheck.** In a TypeScript repo, `<rendemo-demo>` is not a known JSX element and the generated\r\n  React wrapper does **not** declare it. Run the repo's typecheck. If it errors on the unknown\r\n  element, add a JSX intrinsic-element declaration for `rendemo-demo` in the wrapper file\r\n  (`declare module \"react\" { namespace JSX { interface IntrinsicElements { \"rendemo-demo\": … } } }`)\r\n  — Rendemo's own `components/RendemoDemo.tsx` does exactly this and is the reference.\r\n- **CSP.** If the host page sets a strict `script-src`, it must allow `https://www.rendemo.com` or\r\n  the element never upgrades and its fallback link renders instead of the demo. Grep for a CSP in\r\n  middleware / headers config and say plainly whether you found one.\r\n- **Password protection was already handled in step 1** — `protected: true` stops the install before\r\n  any file is written, because an embedded protected demo can never work. If you reached this section\r\n  with files written, step 1 was skipped.\r\n- **`mode=\"tour\"` is not this skill's job.** It is a real, working mode — but it renders a *tour*,\r\n  anchored to `data-rendemo` markers in the host's own source, with no iframe and no footage. It has\r\n  its own procedure (`author-a-tour`) with approval gates, because it writes into the customer's\r\n  source. Never set `mode=\"tour\"` on an embed you install here: pointed at a replay demo it 404s and\r\n  the element shows a \"could not be loaded\" note.\r\n\r\n## What not to do\r\n\r\n- Do not hand-write the snippet, the script tag, or the wrapper. Every one of them comes from\r\n  `rendemo_get_embed`, and a hand-written copy drifts the moment the contract changes.\r\n- Do not pin a version of `embed.js`. There is one URL, no versioning, by design.\r\n- Do not publish a demo to make this procedure work. Ask.\r\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}