Transfer a finished site
/docs/skill/vizen-transfercurrentEN
You are moving, not designing. The owner's site defines the look; your job is to make it appear in the shop as it is, re-bind the data the shop owns (menu, prices, cart, forms) and prove the result with screenshots. No redesign, no cutting into sections, no path rewriting, no improvements nobody asked for.
1. Is this your path?
| You have | Go |
|---|---|
| a folder, ZIP, repo or export that already renders in a browser | here |
| nothing yet — a page to build from scratch | vizen-start and its three questions |
| a question about vz- keys, partial releases, images inside one widget | vizen-own-markup |
| groups, bindings, system pages (cart, account…), sticky | vizen-chrome |
| goods, categories, filters | vizen-catalog |
| "200 and nothing changed" | vizen-troubleshoot |
The full contract — what the platform does to your file, the copy · remap · drop table, framework notes — is GET /docs/transfer. Read it once, before step 2.
2. What the platform gives you (measured, not promised)
- Folder = widget. A level-3 html document is a folder:
index.htmlat the root, css/js/assets in subfolders, relative paths from the root. A release uploads it; files are served from/_html/{doc}/{rid}/…with the same nesting. - Real page DOM. No Shadow DOM, no iframe, no sanitiser:
<script>and<link>run,position: fixed,100vwand100dvhresolve against the viewport, and there is no platform box around you (unless you ask for one withprops.html.boxed: true). - Your `<body>` becomes
<div class="vz-body vz-body-{doc}" data-vz-base="/_html/{doc}/{rid}/">;body,htmland:rootselectors in your CSS are rewritten to that class; from<head>the platform keepslink/style/script/noscript, movestitleandmeta descriptioninto the page SEO and drops the rest. A whole document and clean markup are both accepted. - Scripts run on first parse and are re-run after in-site navigation. Init immediately and again on
document'svz:navigateevent; never wait forDOMContentLoadedalone. Paths built by script start fromdocument.currentScript?.closest('.vz-body')?.dataset.vzBase ?? window.VZ_ASSET_BASE ?? ''(external ordeferscript:document.querySelector('.vz-body-<id>')?.dataset.vzBase). - The cascade is shared. The storefront ships Tailwind preflight:
h1–h6inherit size and weight,ul/ollose bullets,ainherits colour and loses the underline,*has zero margin and padding,imgisdisplay: block,buttonis reset. Everything you styled explicitly survives; what you left to browser defaults is reset — ship your own base styles under your root class. - Guarded zones (
/cart,/checkout,/account,/wishlist,/orders,/deals,/dashboard): your markup renders, scripts do not run, and a widget's relative<link rel="stylesheet">is dropped with them — the header's CSS belongs in the layout folder (linked everywhere) or inline. - Live data is server-side substitution:
{{ product.name }},vz-for="p in products"(the section's feed, ≤ 48 rows, no filters or paging),vz-for="m in menu",vz-add-to-cart,vz-cart-count,href="form:<id>". Names come fromGET /docs/vz-keys.json, never from memory.
3. The order of work
- Passport.
GET /v1/account/token.contour: "dev"writes a draft the owner sees at<slug>--dev.<zone>;"prod"writes the live site on every release. Iterate on a dev key; if you hold a prod key, say so and ask for a dev one. Level 3 needs the owner or admin role on the shop. - Inventory. One table: source page or part → target (page widget, layout folder, chrome group, product or category template) → data to re-bind → what cannot move (SPA runtime, router, own fetch, server code, service worker). A client-rendered SPA is exported statically first: one route = one folder,
base: './'. - Layout folder — site-wide CSS, fonts, favicon, scripts:
node backend-3D/tools/html-transfer/transfer.mjs ./theme --theme <id>(the id:GET /content-blocks, rows withgroup_type == "theme", the earliest is the shop's default). Verify:GET /themes/<id>/siteanswersbaseandscope_class; a page root carries.vz-theme-{doc}. - Header and footer.
transfer.mjs ./header --name "Header"— without--pageit creates the document and publishes the release, nothing is mounted; the output prints the document id. Then an html block (kind:"html",props.html:{html_document_id, level:3}) → a groupgroup_type:"chrome"withprops.widgets:[<block id>]→PUT /design/bindings/shop/0 {"slots":{"header":<G_h>,"footer":<G_f>}}(one section:/category/<id>; one layout:/theme/<id>). Request bodies:vizen-chrome§2–3. Sticky header:vz-stickyon your root node; the header's CSS — in the layout folder or inline<style>, not a relative<link>(dropped on/cart). Verify:GET /v1/storefronts/resolve?slug=<shop>→chrome; open the home page, a product page and/cart— styled on all three. - Pages. The page must exist as
type:"page"(GET /categories; create withPOST /categories {"item":{"name":"…","type":"page","is_published":true,"seo":{"slug":"…"}}}).transfer.mjs ./home --page <slug> --validate-only→ fix the report →transfer.mjs ./home --page <slug>. A rerun is a new release and uploads only changed files;--doc <id> --rollbackreturns the previous one. The page keeps the platform's breadcrumbs and heading above your widget; for 1:1 switch them off with{"page":{"hideSystemBlock":true}}on the__page:topzone block (/docs/transfer§4.5). Verify: open theurlthe command prints — nothing of the platform above your first section. - Product and category templates.
transfer.mjs ./product --name "Product template"→ html block → groupgroup_type:"product"→PUT /design/bindings/category_children/<root category id> {"slots":{"body":<G>}}(the whole subtree; one product:/product/<id>). A category template is a groupcategoryin the slotbody; keep the platformproductListinginside it when filters and paging are needed. Verify: two product pages show one card each and the price equalsGET /products/{id}. - Re-bind data. Menu →
vz-for="m in menu"; price →{{ p.price_text }}; buy →vz-add-to-cart="{{ p.id }}"; wishlist →vz-fav; forms →href="form:<id>"; internal links →/pathorvz:page/<id>. Putvz-forandvz-ifon different nodes. Verify:curlthe page and grep a real product name in the raw HTML; add an item to the cart, watch the counter. - Check and report. Open by direct URL and by a click from another page; screenshots at 1440 and 390; console without errors and without 404s under
/_html/;/cartstill shows your header;--doc <id> --listshows the release. Report: links, both screenshots, what was re-bound, what was dropped and why, the rollback command. Never print the token.
4. Never — only what the platform refuses or breaks
- paths that leave the folder (
../x, absolute paths to your own files) —ref.outside/ref.missing;http://resources —ref.http; server executables —file.forbidden;navigator.serviceWorker.register; a second.htmlin one folder —page.extra; more than 500 files, an HTML file over 2 MB, a file over 50 MB, a release over 60 MB; - a prod key for iterations; content that exists only after a script runs (an empty SPA shell); prices or menus typed by hand where the shop has them; init on
DOMContentLoadedalone; uploading files one by one through the storage API; level-1 documents for a transfer; - printing the token;
git; writing to cart, checkout or account flows.
5. Links
GET /docs/transfer— the contract, copy · remap · drop, frameworks, silently ignoredvizen-chrome— groups, bindings, system pages, stickyvizen-own-markup§2–3 andGET /docs/vz-keys.json— keys and scope fieldsbackend-3D/tools/html-transfer/README.md— every flag;examples/— a starter kitvizen-troubleshoot— when the API said yes and the site says no