Vizen Shop

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 haveGo
a folder, ZIP, repo or export that already renders in a browserhere
nothing yet — a page to build from scratchvizen-start and its three questions
a question about vz- keys, partial releases, images inside one widgetvizen-own-markup
groups, bindings, system pages (cart, account…), stickyvizen-chrome
goods, categories, filtersvizen-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.html at 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, 100vw and 100dvh resolve against the viewport, and there is no platform box around you (unless you ask for one with props.html.boxed: true).
  • Your `<body>` becomes <div class="vz-body vz-body-{doc}" data-vz-base="/_html/{doc}/{rid}/">; body, html and :root selectors in your CSS are rewritten to that class; from <head> the platform keeps link/style/script/noscript, moves title and meta description into 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's vz:navigate event; never wait for DOMContentLoaded alone. Paths built by script start from document.currentScript?.closest('.vz-body')?.dataset.vzBase ?? window.VZ_ASSET_BASE ?? '' (external or defer script: document.querySelector('.vz-body-<id>')?.dataset.vzBase).
  • The cascade is shared. The storefront ships Tailwind preflight: h1–h6 inherit size and weight, ul/ol lose bullets, a inherits colour and loses the underline, * has zero margin and padding, img is display: block, button is 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 from GET /docs/vz-keys.json, never from memory.

3. The order of work

  1. 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.
  2. 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: './'.
  3. 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 with group_type == "theme", the earliest is the shop's default). Verify: GET /themes/<id>/site answers base and scope_class; a page root carries .vz-theme-{doc}.
  4. Header and footer. transfer.mjs ./header --name "Header" — without --page it 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 group group_type:"chrome" with props.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-sticky on 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.
  5. Pages. The page must exist as type:"page" (GET /categories; create with POST /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> --rollback returns 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:top zone block (/docs/transfer §4.5). Verify: open the url the command prints — nothing of the platform above your first section.
  6. Product and category templates. transfer.mjs ./product --name "Product template" → html block → group group_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 group category in the slot body; keep the platform productListing inside it when filters and paging are needed. Verify: two product pages show one card each and the price equals GET /products/{id}.
  7. 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 → /path or vz:page/<id>. Put vz-for and vz-if on different nodes. Verify: curl the page and grep a real product name in the raw HTML; add an item to the cart, watch the counter.
  8. 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/; /cart still shows your header; --doc <id> --list shows 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 .html in 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 DOMContentLoaded alone; 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.
  • GET /docs/transfer — the contract, copy · remap · drop, frameworks, silently ignored
  • vizen-chrome — groups, bindings, system pages, sticky
  • vizen-own-markup §2–3 and GET /docs/vz-keys.json — keys and scope fields
  • backend-3D/tools/html-transfer/README.md — every flag; examples/ — a starter kit
  • vizen-troubleshoot — when the API said yes and the site says no

Исходник: https://api.vizen.shop/docs/skill/vizen-transfer

Работает в демо-режиме