Sd build html embed
Skill SimplerDevelopment/simplerdevelopment-skills/sd-build-html-embed
Claude Code skills for the SimplerDevelopment.com portal — draft pages, decks, emails, surveys, and full websites via MCP, all human-in-the-loop.
npx -y skills add SimplerDevelopment/simplerdevelopment-skills --skill sd-build-html-embedAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 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
Author a self-contained HTML experience (single index.html OR multi-file bundle with css/js/images/fonts) entirely in Claude Code, then upload it to the SimplerDevelopment portal as a draft page or single-slide pitch deck. The output is a sandboxed iframe-rendered `html-embed` block — useful for interactive prototypes, motion-design experiments, custom calculators, immersive landing pages, or anything that would otherwise be impossible inside the visual block editor. Supports two upload paths — `posts_upload_html` for a single ≤1 MB HTML file, or `posts_upload_html_zip` (and the deck variants) for a multi-file zipped bundle up to 50 MB. Returns a portal post + approval URL. Use when the user says 'build an HTML embed', 'make an interactive widget', 'custom landing page with a working demo', 'huashu-style hi-fi mockup', 'upload this prototype', 'zip and ship', 'embed this single-file HTML into the portal'.
SKILL.md
11.9 KB, as published. Nobody here has run it
sd-build-html-embed
A skill for authoring HTML content locally first, in this Claude Code session, then uploading the finished artifact to the SimplerDevelopment portal as an html-embed block. Two upload paths exist:
- Single-file — one
index.htmlwith everything inlined (CSS in<style>, JS in<script>, images as data-URLs). Goes throughposts_upload_html/decks_upload_html. Cap: 1 MB raw. - Multi-file bundle — a directory tree (
index.html+style.css+script.js+assets/) zipped and shipped throughposts_upload_html_zip/decks_upload_html_zip. Cap: 50 MB total / 200 files / 10 MB per file. Relative refs inindex.htmlresolve through the path-based media proxy.
Pick the bundle path when the artifact needs real fonts, real images, modular JS, or genuinely large assets. Pick single-file when the artifact is small and you want zero infrastructure complexity.
Pre-flight
-
Read
.sd/config.json— confirmclient.id,defaultSiteId,brand. -
Read
.sd/learnings.mdif present. -
Read
SD_DESIGN_PRINCIPLES.md— every authoring rule applies here, doubly so because there's no editor safety net. -
Decide path: single-file or bundle? Default to single-file unless one of these is true:
- Custom non-system fonts (woff/woff2).
- Real photography or non-trivial illustrations (> 200KB each, > 5 images).
- Modular JS (multiple .js files, ES modules, or a small framework).
- The HTML alone exceeds 800KB.
If yes to any: bundle path.
Authoring conventions
The vendored huashu-design skill is the gold standard for hi-fi HTML — read its references/content-guidelines.md if doing motion design / hi-fi prototype work. Don't paste huashu output directly into a CMS block (per the repo's CLAUDE.md hard rule); use it as inspiration, then translate into your own authored HTML.
Working directory
Author files under a project-local scratch dir, e.g. ./.sd/embeds/<slug>/. Never commit these to git — .sd/ is already gitignored. The skill writes:
.sd/embeds/<slug>/
index.html
style.css (only if bundle path)
script.js (only if bundle path)
assets/
hero.jpg
logo.svg
fonts/inter.woff2
index.html — the constants
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>...</title>
<!-- Single-file: inline <style>. Bundle: <link rel="stylesheet" href="style.css"> -->
</head>
<body>
...
<!-- Single-file: inline <script>. Bundle: <script src="script.js"></script> -->
</body>
</html>
Critical constraints (this is rendered in a sandboxed iframe):
- The iframe defaults to
sandbox="scripts"— allows JS, NOTsame-origin, NOTforms(except withiframeTitle-prefixed permissions). So local-storage / cookies / parent-window access are blocked. Fine for visuals; do not rely on persistence. - The iframe height is fixed (
100vhby default). Author the document to fit; tall documents are scrollable inside the frame. - No external requests get a same-origin cookie. Calling
fetch(...)is allowed but cross-origin and cookieless. - Relative paths (
./style.css,assets/img.png) resolve relative to the index.html's S3 location through the media-proxy. Absolute paths (/something) DO NOT — they hit the parent site, which is wrong.
Design system — apply, don't invent
The brand profile in .sd/config.json:brand is your palette + type pairing source:
<style>
:root {
--primary: <brand.primaryColor>;
--secondary: <brand.secondaryColor>;
--accent: <brand.accentColor>;
--bg: <brand.backgroundColor>;
--text: <brand.textColor>;
--heading-font: '<brand.headingFont>', system-ui;
--body-font: '<brand.bodyFont>', system-ui;
}
body { font: 16px/1.6 var(--body-font); color: var(--text); background: var(--bg); }
h1, h2, h3 { font-family: var(--heading-font); letter-spacing: -0.025em; }
</style>
Run a contrast check on --text vs --bg before shipping. Call branding_check_contrast to confirm ≥ 4.5:1 for body, ≥ 3:1 for large text.
Logo
If brand.logoUrl is set, fetch it server-side once (via WebFetch) and either:
- Single-file path: base64-encode and inline as a
<img src="data:image/...">. - Bundle path: save to
./assets/logo.svg(or .png) and reference relatively.
Never hot-link the logo from S3 inside the embed — the embed is sandboxed without same-origin, and intermittent failures look terrible.
Accessibility
The same WCAG rules from SD_DESIGN_PRINCIPLES.md apply:
- Body 16px+, headings 36+ for hero scale.
prefers-reduced-motionrespected for any animation.alton informational images,alt=""on decorative.- Headings in hierarchical order, one
h1. - Buttons / links have accessible names.
Build steps
Single-file path
- Write
./.sd/embeds/<slug>/index.htmlwith<style>and<script>inline. - Inline images as data-URLs:
import { readFileSync } from 'node:fs'; const b64 = readFileSync('./hero.jpg').toString('base64'); const dataUrl = `data:image/jpeg;base64,${b64}`; - Verify size ≤ 1 MB (
wc -c index.html). - Base64-encode the whole file and call
posts_upload_html:mcp__simplerdevelopment__posts_upload_html { websiteId: <defaultSiteId>, filename: "<slug>.html", contentBase64: "<base64 of index.html>" } - Returns
{ id, slug, ..., approval: { url, ... } }. Done.
Bundle path
- Author the tree under
./.sd/embeds/<slug>/. - Verify the entry:
ls -la ./.sd/embeds/<slug>/index.htmlexists. - Verify total size:
Must be < 52428800 (50 MB).du -sb .sd/embeds/<slug>/ | awk '{print $1}' - Zip the directory contents (NOT the wrapper directory):
The zip should havecd .sd/embeds/<slug> zip -r ../<slug>.zip . -x '.DS_Store' '*/.DS_Store'index.htmlat the root, NOT<slug>/index.html. - Base64-encode and call
posts_upload_html_zip:base64 -i .sd/embeds/<slug>.zip -o /tmp/sd-zip.b64mcp__simplerdevelopment__posts_upload_html_zip { websiteId: <defaultSiteId>, filename: "<slug>.zip", contentBase64: "<paste of /tmp/sd-zip.b64>" } - Returns
{ id, slug, ..., bundleFileCount, bundlePrefix, url, approval: { ... } }.
Deck variants
Same flow but call decks_upload_html (single-file) or decks_upload_html_zip (bundle). The result is a 1-slide deck with showSlideNumber: false for full-bleed presentation. Approve the deck to flip status to published and call decks_publish_all to make the slide live.
Self-review (the 5 dimensions)
Run before returning the approval URL. The HTML path has higher risk of slop because there's no block-shaped guardrail.
- Philosophy alignment — does the design carry the brand voice? Or did Claude default to neutral / "Apple knockoff"?
- Visual hierarchy — squint test. Three to four clear levels.
- Craft quality — 8pt grid? Real type pairing? Color contrast ≥ 4.5:1?
- Functionality — every section earns its place. Cut whatever fails the test.
- Originality — does it look like any other huashu hero, or does it look like SimplerDevelopment / the client?
Score 1–10. If any < 6, surface explicitly and recommend a revision pass before approval.
MCP response handling — read errors first
SimplerDevelopment's MCP wraps every response — successes AND errors — in a JSON-RPC success envelope shaped like:
{"result":{"content":[{"type":"text","text":"{...JSON...}"}]}}
Before reporting success to the user, parse result.content[0].text as JSON. If the parsed object contains an error key (e.g. {"error":"Site not found"} or {"error":"Unauthorized"}), the call FAILED — even though the JSON-RPC envelope said result. STOP immediately. Surface the error verbatim to the user. Do NOT invent a successful response with a made-up post id, approval URL, slug, or site name. Hallucinated success is worse than a visible failure — the user will publish content that doesn't exist or copy approval URLs to stakeholders that 404.
Only treat the call as successful when the parsed text contains the expected entity shape (e.g. {"id":..., "approval":{...}} for posts_create).
Output
Return to the user:
- Local working directory:
.sd/embeds/<slug>/ - File tree (so the user can inspect)
- Total upload size in bytes
- Post id + portal edit URL:
/portal/websites/<siteId>/posts/<id>/edit - Public preview URL (once approved):
/sites/<siteId>/<slug>or whatever the site routing is. - Approval URL — share for review
- Self-review scores + quick wins
Failure modes
- No
.sd/config.json→ runsd-init. - Bundle has no .html file → upload tool rejects. Verify
index.htmlexists at the root of the zip. - Bundle exceeds limits (200 files, 10 MB/file, 50 MB total) → split or downsample assets.
- Disallowed file extension → only html/css/js/png/jpg/jpeg/webp/gif/svg/ico/woff/woff2/ttf/otf/eot/json/txt/xml/csv are accepted. Move others to a hosted URL and reference absolutely.
- Same-origin / cookie need → cannot work in the sandboxed iframe. Re-scope the artifact.
- External CDN dependency (e.g. Google Fonts via
<link>) → works fine, the iframe can hit external URLs. But you lose offline-style reliability; prefer self-hosted fonts in the bundle. - Relative path with
..→ the zip pipeline rejects path-traversal entries. Restructure your tree.
Iteration
To revise the embed:
- Same slug, different content → author locally again, then re-upload. The new upload creates a new post (the slug auto-bumps
-2,-3, ...). The old post stays. - Same post, edited HTML → there's no in-place edit for the embedded HTML via MCP today. Best path is to re-upload (new post) and update any pages that reference the previous one.
The new MCP tool posts_update on an html-embed post would need a new code path; for now, treat embeds as immutable once uploaded.
Self-improvement
After every run where the user accepts or rejects the result, invoke sd-learn with the artifact + feedback. Rules that accumulate here:
- "Always use the bundle path for client X — they need real photography."
- "Single-file path is fine for prototypes; bundle for production."
- "Inline the brand's webfont; don't load from Google Fonts."
Install
This skill ships as part of the SimplerDevelopment client skills bundle. Install the full skill bundle in one step from the portal:
https://simplerdevelopment.com/install
macOS, Windows, and Linux installers download the bundle to ~/.claude/skills/. Both Claude Desktop and Claude Code auto-discover skills from that path on next restart.
See CLIENT_QUICKSTART.md (installed alongside this file) for the full setup walkthrough, including the MCP-server config Claude Desktop needs and the one-time sd-init bootstrap.
Gives 0 of the 12 instructions most css styling skills give
Counted across 586 of the 596 authors here whose files we hold, read 2026-08-06
- avoid excessive centered layoutsin 55 of 586, across 12 files
- bundle code into single HTML filein 54 of 586, across 14 files
- Respect prefers-reduced-motion user settingsin 52 of 586, across 35 files
- avoid purple gradientsin 51 of 586, across 11 files
- avoid uniform rounded cornersin 51 of 586, across 11 files
- avoid Inter fontin 51 of 586, across 11 files
- edit generated files to develop artifactin 50 of 586, across 10 files
- animate only transform and opacity propertiesin 43 of 586
- Make touch targets at least 44x44 pixelsin 41 of 586, across 15 files
- Ensure minimum color contrast of 4.5:1in 39 of 586, across 10 files
- use tailwind cssin 39 of 586, across 24 files
- Use SVG icons instead of emojisin 38 of 586, across 11 files
Said here and by no other author read
- read project configuration before authoring
- default to single-file path unless limits apply
- author files under a local scratch directory
- apply the brand design system from config
- use relative paths for asset references
- verify total file size before uploading
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once.