diff --git a/README.md b/README.md
index f179a7d9ce..e0cec309fe 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,7 @@
- [Blog](https://webstudio.is/blog)
- [Documentation](https://docs.webstudio.is/)
-- [Brand and Product Design](https://docs.webstudio.is/contributing/contributing-for-designers)
-- [Contributing Guide for Devs](https://docs.webstudio.is/contributing/contributing-for-developers)
+- [Contributing](https://docs.webstudio.is/contributing/contributions)
- [Builder Issues Tracker](https://github.com/webstudio-is/webstudio/issues)
- [Roadmap](https://github.com/orgs/webstudio-is/projects/11)
diff --git a/apps/builder/e2e/tests/mdx-content-block.[shard-4].e2e.ts b/apps/builder/e2e/tests/mdx-content-block.[shard-4].e2e.ts
index f44c0c39ca..dadb1601b8 100644
--- a/apps/builder/e2e/tests/mdx-content-block.[shard-4].e2e.ts
+++ b/apps/builder/e2e/tests/mdx-content-block.[shard-4].e2e.ts
@@ -53,13 +53,19 @@ const isAssetContentResponse = (response: Response, method = "PUT") =>
response.url().includes("/rest/assets/") &&
response.url().includes("/content");
-const waitForAssetWrite = (page: Page, sourceIncludes?: string) =>
+const waitForAssetWrite = (
+ page: Page,
+ sourceMatches?: (source: string) => boolean
+) =>
page.waitForResponse(
- (response) =>
- isAssetContentResponse(response) &&
- response.status() === 200 &&
- (sourceIncludes === undefined ||
- response.request().postData()?.includes(sourceIncludes) === true),
+ (response) => {
+ const source = response.request().postData() ?? "";
+ return (
+ isAssetContentResponse(response) &&
+ response.status() === 200 &&
+ (sourceMatches === undefined || sourceMatches(source))
+ );
+ },
{ timeout: 30_000 }
);
@@ -465,7 +471,9 @@ test("Empty MDX content supports insertion and keeps the next paragraph focused"
.last()
.waitFor({ state: "visible" });
await page.keyboard.press("Escape");
- const paragraphWrite = waitForAssetWrite(page, "Focused paragraph");
+ const paragraphWrite = waitForAssetWrite(page, (source) =>
+ source.includes("Focused paragraph")
+ );
const paragraphMetadataWrite = waitForChangeToBeSaved({ page });
await page.keyboard.type("Focused paragraph");
const paragraphId = await paragraphEditor.getAttribute("data-ws-id");
@@ -484,6 +492,13 @@ test("Empty MDX content supports insertion and keeps the next paragraph focused"
if (emptyParagraphId === null) {
throw new Error("Expected the new paragraph instance id");
}
+ const finalWrite = waitForAssetWrite(
+ page,
+ (source) =>
+ source.includes("# First heading") &&
+ source.includes("Focused paragraph") &&
+ source.includes('ws:tag="p"') === false
+ );
await page.keyboard.press("ControlOrMeta+A");
await page.keyboard.press("Backspace");
await page.keyboard.press("Backspace");
@@ -499,7 +514,6 @@ test("Empty MDX content supports insertion and keeps the next paragraph focused"
) {
throw new Error("Expected the previous paragraph to regain focus");
}
- const finalWrite = waitForAssetWrite(page);
await page.mouse.click(5, 5);
const finalSource = (await finalWrite).request().postData() ?? "";
if (
diff --git a/docs/.gitbook/assets/assets-detail-dark.png b/docs/.gitbook/assets/assets-detail-dark.png
new file mode 100644
index 0000000000..815cddd23a
Binary files /dev/null and b/docs/.gitbook/assets/assets-detail-dark.png differ
diff --git a/docs/.gitbook/assets/assets-detail-light.png b/docs/.gitbook/assets/assets-detail-light.png
new file mode 100644
index 0000000000..d3d3777121
Binary files /dev/null and b/docs/.gitbook/assets/assets-detail-light.png differ
diff --git a/docs/.gitbook/assets/assets-panel-dark.png b/docs/.gitbook/assets/assets-panel-dark.png
new file mode 100644
index 0000000000..fd4221b2ef
Binary files /dev/null and b/docs/.gitbook/assets/assets-panel-dark.png differ
diff --git a/docs/.gitbook/assets/assets-panel-light.png b/docs/.gitbook/assets/assets-panel-light.png
new file mode 100644
index 0000000000..7be4b45d79
Binary files /dev/null and b/docs/.gitbook/assets/assets-panel-light.png differ
diff --git a/docs/.gitbook/assets/atomic-css-setting-dark.png b/docs/.gitbook/assets/atomic-css-setting-dark.png
new file mode 100644
index 0000000000..ab7a98fdf2
Binary files /dev/null and b/docs/.gitbook/assets/atomic-css-setting-dark.png differ
diff --git a/docs/.gitbook/assets/atomic-css-setting-light.png b/docs/.gitbook/assets/atomic-css-setting-light.png
new file mode 100644
index 0000000000..789958a102
Binary files /dev/null and b/docs/.gitbook/assets/atomic-css-setting-light.png differ
diff --git a/docs/.gitbook/assets/breakpoints-dark.png b/docs/.gitbook/assets/breakpoints-dark.png
new file mode 100644
index 0000000000..a82ceb139c
Binary files /dev/null and b/docs/.gitbook/assets/breakpoints-dark.png differ
diff --git a/docs/.gitbook/assets/breakpoints-edit-dark.png b/docs/.gitbook/assets/breakpoints-edit-dark.png
new file mode 100644
index 0000000000..c7ba53ad4f
Binary files /dev/null and b/docs/.gitbook/assets/breakpoints-edit-dark.png differ
diff --git a/docs/.gitbook/assets/breakpoints-edit-light.png b/docs/.gitbook/assets/breakpoints-edit-light.png
new file mode 100644
index 0000000000..493a504b09
Binary files /dev/null and b/docs/.gitbook/assets/breakpoints-edit-light.png differ
diff --git a/docs/.gitbook/assets/breakpoints-light.png b/docs/.gitbook/assets/breakpoints-light.png
new file mode 100644
index 0000000000..bc1637b89f
Binary files /dev/null and b/docs/.gitbook/assets/breakpoints-light.png differ
diff --git a/docs/.gitbook/assets/build-and-download-static-site-dark.png b/docs/.gitbook/assets/build-and-download-static-site-dark.png
new file mode 100644
index 0000000000..981483e178
Binary files /dev/null and b/docs/.gitbook/assets/build-and-download-static-site-dark.png differ
diff --git a/docs/.gitbook/assets/build-and-download-static-site-light.png b/docs/.gitbook/assets/build-and-download-static-site-light.png
new file mode 100644
index 0000000000..6268888d4b
Binary files /dev/null and b/docs/.gitbook/assets/build-and-download-static-site-light.png differ
diff --git a/docs/.gitbook/assets/builder-hide-ui-menu-dark.png b/docs/.gitbook/assets/builder-hide-ui-menu-dark.png
new file mode 100644
index 0000000000..d0eacd2258
Binary files /dev/null and b/docs/.gitbook/assets/builder-hide-ui-menu-dark.png differ
diff --git a/docs/.gitbook/assets/builder-hide-ui-menu-light.png b/docs/.gitbook/assets/builder-hide-ui-menu-light.png
new file mode 100644
index 0000000000..a6d052d749
Binary files /dev/null and b/docs/.gitbook/assets/builder-hide-ui-menu-light.png differ
diff --git a/docs/.gitbook/assets/builder-modes-dark.png b/docs/.gitbook/assets/builder-modes-dark.png
new file mode 100644
index 0000000000..2d5ec181b7
Binary files /dev/null and b/docs/.gitbook/assets/builder-modes-dark.png differ
diff --git a/docs/.gitbook/assets/builder-modes-light.png b/docs/.gitbook/assets/builder-modes-light.png
new file mode 100644
index 0000000000..57f4391cbd
Binary files /dev/null and b/docs/.gitbook/assets/builder-modes-light.png differ
diff --git a/docs/.gitbook/assets/builder-overview-dark.png b/docs/.gitbook/assets/builder-overview-dark.png
new file mode 100644
index 0000000000..51f4154c53
Binary files /dev/null and b/docs/.gitbook/assets/builder-overview-dark.png differ
diff --git a/docs/.gitbook/assets/builder-overview-light.png b/docs/.gitbook/assets/builder-overview-light.png
new file mode 100644
index 0000000000..0ab9c7fe88
Binary files /dev/null and b/docs/.gitbook/assets/builder-overview-light.png differ
diff --git a/docs/.gitbook/assets/commands-search-dark.png b/docs/.gitbook/assets/commands-search-dark.png
new file mode 100644
index 0000000000..6a874ee233
Binary files /dev/null and b/docs/.gitbook/assets/commands-search-dark.png differ
diff --git a/docs/.gitbook/assets/commands-search-light.png b/docs/.gitbook/assets/commands-search-light.png
new file mode 100644
index 0000000000..6ca71919ae
Binary files /dev/null and b/docs/.gitbook/assets/commands-search-light.png differ
diff --git a/docs/.gitbook/assets/components-panel-dark.png b/docs/.gitbook/assets/components-panel-dark.png
new file mode 100644
index 0000000000..228c505e02
Binary files /dev/null and b/docs/.gitbook/assets/components-panel-dark.png differ
diff --git a/docs/.gitbook/assets/components-panel-light.png b/docs/.gitbook/assets/components-panel-light.png
new file mode 100644
index 0000000000..d83bd1cac2
Binary files /dev/null and b/docs/.gitbook/assets/components-panel-light.png differ
diff --git a/docs/.gitbook/assets/connect-content-block-mdx-dark.png b/docs/.gitbook/assets/connect-content-block-mdx-dark.png
new file mode 100644
index 0000000000..def5393426
Binary files /dev/null and b/docs/.gitbook/assets/connect-content-block-mdx-dark.png differ
diff --git a/docs/.gitbook/assets/connect-content-block-mdx-light.png b/docs/.gitbook/assets/connect-content-block-mdx-light.png
new file mode 100644
index 0000000000..f68cbb76d6
Binary files /dev/null and b/docs/.gitbook/assets/connect-content-block-mdx-light.png differ
diff --git a/docs/.gitbook/assets/content-blocks-navigator-dark.png b/docs/.gitbook/assets/content-blocks-navigator-dark.png
new file mode 100644
index 0000000000..7b37062771
Binary files /dev/null and b/docs/.gitbook/assets/content-blocks-navigator-dark.png differ
diff --git a/docs/.gitbook/assets/content-blocks-navigator-light.png b/docs/.gitbook/assets/content-blocks-navigator-light.png
new file mode 100644
index 0000000000..403033b09a
Binary files /dev/null and b/docs/.gitbook/assets/content-blocks-navigator-light.png differ
diff --git a/docs/.gitbook/assets/create-mdx-file-dark.png b/docs/.gitbook/assets/create-mdx-file-dark.png
new file mode 100644
index 0000000000..ca8f7dd76b
Binary files /dev/null and b/docs/.gitbook/assets/create-mdx-file-dark.png differ
diff --git a/docs/.gitbook/assets/create-mdx-file-light.png b/docs/.gitbook/assets/create-mdx-file-light.png
new file mode 100644
index 0000000000..1079edddd7
Binary files /dev/null and b/docs/.gitbook/assets/create-mdx-file-light.png differ
diff --git a/docs/.gitbook/assets/element-settings-panel-dark.png b/docs/.gitbook/assets/element-settings-panel-dark.png
new file mode 100644
index 0000000000..fa1bc87604
Binary files /dev/null and b/docs/.gitbook/assets/element-settings-panel-dark.png differ
diff --git a/docs/.gitbook/assets/element-settings-panel-light.png b/docs/.gitbook/assets/element-settings-panel-light.png
new file mode 100644
index 0000000000..512f4ea536
Binary files /dev/null and b/docs/.gitbook/assets/element-settings-panel-light.png differ
diff --git a/docs/.gitbook/assets/export-dark.png b/docs/.gitbook/assets/export-dark.png
new file mode 100644
index 0000000000..1a069b47f2
Binary files /dev/null and b/docs/.gitbook/assets/export-dark.png differ
diff --git a/docs/.gitbook/assets/export-light.png b/docs/.gitbook/assets/export-light.png
new file mode 100644
index 0000000000..facc4388d7
Binary files /dev/null and b/docs/.gitbook/assets/export-light.png differ
diff --git a/docs/.gitbook/assets/mdx-editor-preview-dark.png b/docs/.gitbook/assets/mdx-editor-preview-dark.png
new file mode 100644
index 0000000000..e556d2778a
Binary files /dev/null and b/docs/.gitbook/assets/mdx-editor-preview-dark.png differ
diff --git a/docs/.gitbook/assets/mdx-editor-preview-light.png b/docs/.gitbook/assets/mdx-editor-preview-light.png
new file mode 100644
index 0000000000..6dfefd51af
Binary files /dev/null and b/docs/.gitbook/assets/mdx-editor-preview-light.png differ
diff --git a/docs/.gitbook/assets/navigator-panel-dark.png b/docs/.gitbook/assets/navigator-panel-dark.png
new file mode 100644
index 0000000000..391c9a9b03
Binary files /dev/null and b/docs/.gitbook/assets/navigator-panel-dark.png differ
diff --git a/docs/.gitbook/assets/navigator-panel-light.png b/docs/.gitbook/assets/navigator-panel-light.png
new file mode 100644
index 0000000000..47b20f3aa5
Binary files /dev/null and b/docs/.gitbook/assets/navigator-panel-light.png differ
diff --git a/docs/.gitbook/assets/page-settings-custom-metadata-dark.png b/docs/.gitbook/assets/page-settings-custom-metadata-dark.png
new file mode 100644
index 0000000000..823af0f5a8
Binary files /dev/null and b/docs/.gitbook/assets/page-settings-custom-metadata-dark.png differ
diff --git a/docs/.gitbook/assets/page-settings-custom-metadata-light.png b/docs/.gitbook/assets/page-settings-custom-metadata-light.png
new file mode 100644
index 0000000000..bb9ea997ac
Binary files /dev/null and b/docs/.gitbook/assets/page-settings-custom-metadata-light.png differ
diff --git a/docs/.gitbook/assets/page-settings-dialog-dark.png b/docs/.gitbook/assets/page-settings-dialog-dark.png
new file mode 100644
index 0000000000..1660b1575a
Binary files /dev/null and b/docs/.gitbook/assets/page-settings-dialog-dark.png differ
diff --git a/docs/.gitbook/assets/page-settings-dialog-light.png b/docs/.gitbook/assets/page-settings-dialog-light.png
new file mode 100644
index 0000000000..7265f667ae
Binary files /dev/null and b/docs/.gitbook/assets/page-settings-dialog-light.png differ
diff --git a/docs/.gitbook/assets/page-settings-seo-dark.png b/docs/.gitbook/assets/page-settings-seo-dark.png
new file mode 100644
index 0000000000..3dd6eeee54
Binary files /dev/null and b/docs/.gitbook/assets/page-settings-seo-dark.png differ
diff --git a/docs/.gitbook/assets/page-settings-seo-light.png b/docs/.gitbook/assets/page-settings-seo-light.png
new file mode 100644
index 0000000000..3ec0b8a0c6
Binary files /dev/null and b/docs/.gitbook/assets/page-settings-seo-light.png differ
diff --git a/docs/.gitbook/assets/page-settings-social-dark.png b/docs/.gitbook/assets/page-settings-social-dark.png
new file mode 100644
index 0000000000..85e5717e79
Binary files /dev/null and b/docs/.gitbook/assets/page-settings-social-dark.png differ
diff --git a/docs/.gitbook/assets/page-settings-social-light.png b/docs/.gitbook/assets/page-settings-social-light.png
new file mode 100644
index 0000000000..185e2f1ed6
Binary files /dev/null and b/docs/.gitbook/assets/page-settings-social-light.png differ
diff --git a/docs/.gitbook/assets/pages-panel-dark.png b/docs/.gitbook/assets/pages-panel-dark.png
new file mode 100644
index 0000000000..705f24607b
Binary files /dev/null and b/docs/.gitbook/assets/pages-panel-dark.png differ
diff --git a/docs/.gitbook/assets/pages-panel-light.png b/docs/.gitbook/assets/pages-panel-light.png
new file mode 100644
index 0000000000..3e1aeef2aa
Binary files /dev/null and b/docs/.gitbook/assets/pages-panel-light.png differ
diff --git a/docs/.gitbook/assets/project-settings-authentication-dark.png b/docs/.gitbook/assets/project-settings-authentication-dark.png
new file mode 100644
index 0000000000..fcb2e0d7f9
Binary files /dev/null and b/docs/.gitbook/assets/project-settings-authentication-dark.png differ
diff --git a/docs/.gitbook/assets/project-settings-authentication-light.png b/docs/.gitbook/assets/project-settings-authentication-light.png
new file mode 100644
index 0000000000..7d2f94b785
Binary files /dev/null and b/docs/.gitbook/assets/project-settings-authentication-light.png differ
diff --git a/docs/.gitbook/assets/project-settings-menu-dark.png b/docs/.gitbook/assets/project-settings-menu-dark.png
new file mode 100644
index 0000000000..2debd44f73
Binary files /dev/null and b/docs/.gitbook/assets/project-settings-menu-dark.png differ
diff --git a/docs/.gitbook/assets/project-settings-menu-light.png b/docs/.gitbook/assets/project-settings-menu-light.png
new file mode 100644
index 0000000000..5ea7982dfd
Binary files /dev/null and b/docs/.gitbook/assets/project-settings-menu-light.png differ
diff --git a/docs/.gitbook/assets/staging-domain-dark.png b/docs/.gitbook/assets/staging-domain-dark.png
new file mode 100644
index 0000000000..cc1b7be246
Binary files /dev/null and b/docs/.gitbook/assets/staging-domain-dark.png differ
diff --git a/docs/.gitbook/assets/staging-domain-light.png b/docs/.gitbook/assets/staging-domain-light.png
new file mode 100644
index 0000000000..4d2228d16b
Binary files /dev/null and b/docs/.gitbook/assets/staging-domain-light.png differ
diff --git a/docs/.gitbook/assets/style-panel-dark.png b/docs/.gitbook/assets/style-panel-dark.png
new file mode 100644
index 0000000000..b29bca0a00
Binary files /dev/null and b/docs/.gitbook/assets/style-panel-dark.png differ
diff --git a/docs/.gitbook/assets/style-panel-light.png b/docs/.gitbook/assets/style-panel-light.png
new file mode 100644
index 0000000000..25a7e051ec
Binary files /dev/null and b/docs/.gitbook/assets/style-panel-light.png differ
diff --git a/docs/.gitbook/assets/variables-settings-panel-dark.png b/docs/.gitbook/assets/variables-settings-panel-dark.png
new file mode 100644
index 0000000000..84ce016955
Binary files /dev/null and b/docs/.gitbook/assets/variables-settings-panel-dark.png differ
diff --git a/docs/.gitbook/assets/variables-settings-panel-light.png b/docs/.gitbook/assets/variables-settings-panel-light.png
new file mode 100644
index 0000000000..8f8bebcf44
Binary files /dev/null and b/docs/.gitbook/assets/variables-settings-panel-light.png differ
diff --git a/docs/README.md b/docs/README.md
index c6fef49a21..ff49f7686c 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -58,14 +58,10 @@ Our getting started guide will help you navigate through building your first Web
[FAQ.md](basics/FAQ.md)
{% endcontent-ref %}
-### Looking to contribute to Webstudio?
+## Looking to contribute to Webstudio?
-{% content-ref url="contributing/contributing-for-designers.md" %}
-[contributing-for-designers.md](contributing/contributing-for-designers.md)
-{% endcontent-ref %}
-
-{% content-ref url="contributing/contributing-for-developers.md" %}
-[contributing-for-developers.md](contributing/contributing-for-developers.md)
+{% content-ref url="contributing/contributions.md" %}
+[contributions.md](contributing/contributions.md)
{% endcontent-ref %}
{% content-ref url="contributing/marketplace.md" %}
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index 9e78d34445..0a31218aa4 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -149,8 +149,7 @@
## Contributing
-* [🧑🎨 Contributing for Designers](contributing/contributing-for-designers.md)
-* [🧑💻 Contributing for Developers](contributing/contributing-for-developers.md)
+* [Contributions](contributing/contributions.md)
* [Contributing to the Marketplace](contributing/marketplace.md)
***
diff --git a/docs/basics/FAQ.md b/docs/basics/FAQ.md
index 93eec2a16a..4fdc1bcb27 100644
--- a/docs/basics/FAQ.md
+++ b/docs/basics/FAQ.md
@@ -86,11 +86,11 @@ Webstudio automatically converts images to WebP and resizes them to fit webpage
-🚀 How can I use Webstudio today, and how will it evolve?
+🚀 What can I build with Webstudio today?
-Currently, Webstudio excels in building super fast, responsive, dynamic websites. Future enhancements include linked CSS editors, animations engine, and real-time collaboration. Its open-source nature and API integration capabilities allow for extensive customization and connectivity with various services.
+Webstudio builds responsive static and dynamic websites with visual CSS controls, animations, data Resources, Content mode, the Content Engine, and accessible components. You can work in the visual Builder or let an AI agent edit the same project through Webstudio MCP. Projects can be published to Webstudio Cloud or exported for self-hosting.
-[Webstudio Vision Document](https://webstudiois.notion.site/Vision-f52ed097ccaa410eb05076981d446c2f)
+[Webstudio features](https://webstudio.is/features), [Webstudio roadmap](https://wstd.us/roadmap)
diff --git a/docs/basics/building-your-first-site.md b/docs/basics/building-your-first-site.md
index 8ac9e806d3..4a992ed882 100644
--- a/docs/basics/building-your-first-site.md
+++ b/docs/basics/building-your-first-site.md
@@ -6,32 +6,32 @@ Webstudio 101 Playlist
This video series is a quick overview of the most important parts of the builder to get you up to speed.
-### 🚀 Signup to Webstudio
+## 🚀 Sign up for Webstudio
1. Visit [Webstudio](https://webstudio.is/) and click on the "start building" or "sign in" button.
2. Create an account using either Google or Github.
-### 🌟 Create a New Project or Import a Template
+## 🌟 Create a new Project or import a template
Once logged in, you'll be taken to your dashboard. Here, you can view your existing projects and have the option to create a new blank project or start with a premade template.
-### 🖥 Understand the Builder Interface
+## 🖥 Understand the Builder interface
Understanding the interface is key to effectively using any new tool. Familiarize yourself with Webstudio's builder – the heart of your website creation. The Components panel houses elements like text, images, links, and more, which you can drag onto your canvas. For an in-depth guide, read our [Intro to the Anatomy of the Webstudio builder](../university/foundations/anatomy-of-the-webstudio-builder.md).
-### 🎨 Use Design tokens
+## 🎨 Use design tokens
Webstudio utilizes Design tokens for styling, offering consistency across platforms. These reusable styles help avoid naming conflicts and dependency issues common in large projects. Learn more about [Design tokens in Webstudio](../university/foundations/design-tokens.md).
-### 🔧 Experiment With Components
+## 🔧 Experiment with components
Components are the building blocks of your website. Experiment with basic ones like Text and Image, or delve into advanced components like HTML Embeds or Radix. Customize each component’s properties under "Settings."
-### 🌐 Preview & Publish
+## 🌐 Preview and publish
Once you're satisfied with your creation, use the 'Preview' button at the top right corner before publishing it live on the internet! For more details, check our [Publishing and custom domains Guide](../university/foundations/publishing-and-custom-domains.md).
-### 💬 Join the Community
+## 💬 Join the community
Learning a new tool takes time, so don't be discouraged by initial challenges. Keep exploring, experimenting, and [join the Webstudio community](https://wstd.us/community) for support and inspiration.
diff --git a/docs/basics/courses.md b/docs/basics/courses.md
index 42fe5e3e50..2b91e7146e 100644
--- a/docs/basics/courses.md
+++ b/docs/basics/courses.md
@@ -4,9 +4,9 @@ description: Community-made courses
# 🤓 Courses
-### [Webstudio Essentials: 0 to Complete Website With SEO](https://shop.createtoday.io/l/webstudio-essentials)
+## [Webstudio Essentials: 0 to Complete Website With SEO](https://shop.createtoday.io/l/webstudio-essentials)
-
+
## Related
diff --git a/docs/basics/intro.md b/docs/basics/intro.md
index 01e6ee4c73..a5d46143ad 100644
--- a/docs/basics/intro.md
+++ b/docs/basics/intro.md
@@ -4,13 +4,13 @@
Webstudio is an open-source visual development platform that empowers designers and developers to create responsive web designs with ease. Bridging the gap between design and code, it allows users to visually build while maintaining control over the underlying HTML, CSS, and JavaScript.
-### 🧑🎨 For Designers
+## 🧑🎨 For Designers
Webstudio offers a powerful platform for designers to bring their creative visions to life, without needing extensive coding knowledge. Its intuitive visual interface enables the construction of layouts, styling of components, and animation of elements in real-time on a live canvas. This direct manipulation of design elements facilitates immediate feedback and accelerates iteration cycles.
-### 🧑💻 For Developers
+## 🧑💻 For Developers
-Developers will appreciate Webstudio's flexibility and extensibility. It simplifies web development with its visual interface, yet provides full access to the underlying code. Developers can create custom components with complex logic or specific integrations, harnessing the power of coding while benefiting from Webstudio's streamlined visual workflows. As an open-source tool, Webstudio offers the freedom to extend functionality as needed and contribute to the enhancement of its features.
+Developers can combine the visual editor with Resources, expressions, HTML Embed, and Webstudio MCP. Projects can be exported, self-hosted, or extended by contributing to the open-source Builder. Webstudio does not currently provide a visual workflow for defining new reusable component types; use Slots for reusable project content and HTML Embed for custom code.
## Related
diff --git a/docs/basics/roadmap-and-links.md b/docs/basics/roadmap-and-links.md
index 679f7d841d..c34959d0ae 100644
--- a/docs/basics/roadmap-and-links.md
+++ b/docs/basics/roadmap-and-links.md
@@ -32,5 +32,4 @@ Here you will find real-time updates and can see exactly what our team is workin
- [Webstudio Blog](https://webstudio.is/blog) – Read the latest news and tutorials
- [Intro](intro.md) – Learn what Webstudio is and who it's for
- [FAQs](FAQ.md) – Common questions and answers about Webstudio
-- [Contributing for Designers](../contributing/contributing-for-designers.md) – Ways designers can contribute to Webstudio
-- [Contributing for Developers](../contributing/contributing-for-developers.md) – How to contribute code to Webstudio
+- [Contributions](../contributing/contributions.md) – Contribute to Webstudio as a designer or developer
diff --git a/docs/contributing/contributing-for-designers.md b/docs/contributing/contributing-for-designers.md
deleted file mode 100644
index ff35068970..0000000000
--- a/docs/contributing/contributing-for-designers.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# 🧑🎨 Contributing for Designers
-
-Webstudio is not just a tool, but also a community. As an open-source platform, it thrives on the contributions of its users. If you're a designer wondering how you can contribute to the growth and development of Webstudio, here are some ways:
-
-1. #### Share Your Designs
-
- One of the most straightforward ways designers can contribute is by sharing their designs built with Webstudio in [our community](https://wstd.us/community). This could be in the form of templates or individual components that others can use as starting points for their projects. We would also love to share your design showcases with the rest of the Webstudio audience via our socials.
-2. #### Create Tutorials & Guides
-
- If you've mastered certain aspects of using Webstudio, consider creating tutorials or guides to help other users navigate those features more effectively. Tag us in what you create and we'll help spread the word.
-3. #### Participate in Community Discussions
-
- Join discussions on forums or social media platforms where ideas about new features or improvements are being discussed - your perspective as a designer will add unique value. If you're looking for a place to start you can join the [Official Webstudio Community](https://wstd.us/community).
-4. #### Contributing to the Webstudio Builder UI
-
- If you want to contribute to the Builder UI, your first step is to become familiar with our design system in Figma. Start with the first page of our [Design Docs](https://www.figma.com/community/file/1314046494721696168). And for our design system & components see the [Webstudio Library](https://www.figma.com/community/file/1314044856015300004). Please read the docs carefully and thoroughly so you can use our design system properly to create a UI that looks like it's a natural part of Webstudio. If any part of the design is confusing or intimidating you can reach out via our [Discord](https://discord.gg/UNdyrDkq5r) with questions or feedback. We're also happy to give a tour of the design system to anyone who asks.
-5. #### Contributing to the Webstudio Brand
-
- If you want to contribute to our brand design or use our brand assets, you can refer to our [Brand Guidelines](https://www.figma.com/community/file/1253220655531199360).
-
-## Related
-
-- [Contributing for Developers](contributing-for-developers.md) – Technical contribution guide
-- [Contributing to the Marketplace](marketplace.md) – Submit templates and sections
-- [Marketplace](../university/marketplace.md) – Browse community-contributed templates
-- [Craft](../university/craft.md) – The standard for building with Webstudio
diff --git a/docs/contributing/contributing-for-developers.md b/docs/contributing/contributions.md
similarity index 76%
rename from docs/contributing/contributing-for-developers.md
rename to docs/contributing/contributions.md
index 7b07803722..c0a465917b 100644
--- a/docs/contributing/contributing-for-developers.md
+++ b/docs/contributing/contributions.md
@@ -1,18 +1,29 @@
-# 🧑💻 Contributing for Developers
+# Contributions
+
+Contribute fixes and improvements to Webstudio as a designer or developer.
## Process
If you want to contribute and don't know where to start, here is a step-by-step for a complete lifecycle, from idea to deployment.
1. If you have an idea that is not already in [issues](https://github.com/webstudio-is/webstudio/issues), open an issue or reach out on [Discord](https://wstd.us/community).
-2. If you are a DEVELOPER, and you want to contribute to the Builder UI, your first step is to become familiar with our design system in figma. Start with the first page of our [Design Docs](https://www.figma.com/file/xCBegXEWxROLqA1Y31z2Xo/%F0%9F%93%96-Webstudio-Design-Docs?type=design&node-id=234%3A36754&t=w3VxT162RQF0gTrI-1). And for our design system & components see the [Webstudio Library](https://www.figma.com/file/sfCE7iLS0k25qCxiifQNLE/%F0%9F%93%9A-Webstudio-Library?type=design&node-id=2647%3A10046&t=f4xr8mcumXfXkHVh-1). Please read the docs carefully and thoroughly so you can use our design system properly to create a UI that looks like it's a natural part of Webstudio. If any part of the design is confusing or intimidating you can reach out to us on Discord with questions or feedback.
-3. After submitting an enhancement or a bug, we need to agree on a solution. You can jump into implementation right away, but be aware that we have to agree on the solution in the end. Communicating the problem you are solving and why you think the approach you are taking is the best is key for a quick process.
+2. After submitting an enhancement or a bug, we need to agree on a solution. You can jump into implementation right away, but be aware that we have to agree on the solution in the end. Communicating the problem you are solving and why you think the approach you are taking is the best is key for a quick process.
In fact, we are happy to help you communicate your ideas, so if you are not sure - talk to us on discord.
-4. When the implementation is in a mergeable state, a core team member will deploy it to production.
+3. When the implementation is in a mergeable state, a core team member will deploy it to production.
-## Running the Webstudio Project Using VS Code
+## Contributions for designers
+
+Open the Webstudio repository in a local coding agent such as Codex and ask it to start the Builder locally. Open the URL it provides, then describe the changes you want and review them in the running interface.
+
+The agent can handle setup, make the code changes, run the relevant checks, and help prepare the contribution. Follow the process above so the problem and solution are agreed before the change is merged.
+
+## Contributions for developers
+
+Before contributing to the Builder UI, become familiar with the [Design Docs](https://www.figma.com/file/xCBegXEWxROLqA1Y31z2Xo/%F0%9F%93%96-Webstudio-Design-Docs?type=design&node-id=234%3A36754&t=w3VxT162RQF0gTrI-1) and [Webstudio Library](https://www.figma.com/file/sfCE7iLS0k25qCxiifQNLE/%F0%9F%93%9A-Webstudio-Library?type=design&node-id=2647%3A10046&t=f4xr8mcumXfXkHVh-1). Use the established design system so new UI feels like a natural part of Webstudio. Ask questions or share feedback on [Discord](https://wstd.us/community).
+
+## Running the Webstudio project using VS Code
### Prerequisites
@@ -99,7 +110,6 @@ You are done! 🎉
## Related
-- [Contributing for Designers](contributing-for-designers.md) – Ways designers can contribute to Webstudio
- [Contributing to the Marketplace](marketplace.md) – Submit templates and sections
- [FAQs](../basics/FAQ.md) – Common questions including licensing information
- [Roadmap & Links](../basics/roadmap-and-links.md) – See what the team is working on
diff --git a/docs/contributing/marketplace.md b/docs/contributing/marketplace.md
index 7ef22c6f3c..386803c246 100644
--- a/docs/contributing/marketplace.md
+++ b/docs/contributing/marketplace.md
@@ -43,5 +43,5 @@ Learn more about the [Marketplace](../university/marketplace.md).
- [Marketplace](../university/marketplace.md) – Browse and use marketplace templates
- [Craft](../university/craft.md) – The recommended standard for building templates
-- [Contributing for Designers](contributing-for-designers.md) – Other ways designers can contribute
+- [Contributions](contributions.md) – Contribute to Webstudio as a designer or developer
- [Design tokens](../university/foundations/design-tokens.md) – Create consistent, reusable styles
diff --git a/docs/misc/account-limits.md b/docs/misc/account-limits.md
index f498551129..ae70a866c0 100644
--- a/docs/misc/account-limits.md
+++ b/docs/misc/account-limits.md
@@ -2,11 +2,11 @@
As a thank you to our earliest adopters, we've decided to increase the limits of all existing accounts. Here below are the new limits to each account type:
-You can find your plan name from your dashboard beside your profile image as shown below.
+You can find your plan name in the Dashboard beside your profile image.
-
+
-### Webstudio LTDs
+## Webstudio LTDs
Purchase link: [https://wstd.us/pricing](https://wstd.us/pricing)
@@ -17,7 +17,7 @@ Purchase link: [https://wstd.us/pricing](https://wstd.us/pricing)
| LTD T2 | unlimited | 2M |
| LTD T3 | unlimited | unlimited |
-### RocketHub LTDs
+## RocketHub LTDs
No longer available for purchase.
@@ -27,7 +27,7 @@ No longer available for purchase.
| RocketHub T2 | unlimited | 1M |
| RocketHub T3 | unlimited | 2M |
-### Appsumo LTDs
+## AppSumo LTDs
No longer available for purchase.
diff --git a/docs/misc/webstudio-support-process.md b/docs/misc/webstudio-support-process.md
index ff3d2ee2cc..bcfe25f56e 100644
--- a/docs/misc/webstudio-support-process.md
+++ b/docs/misc/webstudio-support-process.md
@@ -9,7 +9,9 @@ description: This page highlights where to get support for all Webstudio custome
If you're looking to upgrade your account and wish to receive a credit for any previous purchase, follow the below steps:
- Visit [https://webstudio.is/pricing](https://webstudio.is/pricing)
-- Select the "Existing Lifetime Customer, Click here" text as illustrated below. 
+- Select **Existing Lifetime Customer, Click here**.
+
+ 
- Fill out the upgrade request form.
## RocketHub account issues
@@ -18,7 +20,7 @@ If you're having trouble with an activation through a RocketHub purchase, please
## AppSumo account issues
-If you're having trouble activating your AppSumo license please read [this article](../errors/appsumo-redemption-failed.md).
+If you're having trouble activating an AppSumo license, ask for help in the [Webstudio community](https://wstd.us/community). Do not post license codes, authentication links, or other private account information.
## Any other type of support
@@ -27,6 +29,5 @@ All other support is run directly via our community. We have a thriving communit
## Related
- [Account Limits](account-limits.md) – View domain and pageview limits for different plans
-- [AppSumo Redemption Failed](../errors/appsumo-redemption-failed.md) – Troubleshoot AppSumo activation issues
- [FAQs](../basics/FAQ.md) – Common questions and answers about Webstudio
- [Roadmap & Links](../basics/roadmap-and-links.md) – Official links and community resources
diff --git a/docs/university/cli.md b/docs/university/cli.md
index 77f0e6fe9e..a654470beb 100644
--- a/docs/university/cli.md
+++ b/docs/university/cli.md
@@ -192,7 +192,7 @@ Build a static site with:
npx webstudio build --template ssg
```
-Please review [the limitations](self-hosting/#ssg-limitations) of using the static site export instead of dynamic templates.
+Please review [the limitations](self-hosting/#static-site-limitations) of using the static site export instead of dynamic templates.
## Other workflows
diff --git a/docs/university/core-components/blockquote.md b/docs/university/core-components/blockquote.md
index dab6009be1..81edd334a5 100644
--- a/docs/university/core-components/blockquote.md
+++ b/docs/university/core-components/blockquote.md
@@ -12,7 +12,7 @@ The Blockquote Component is used to highlight quoted content on a webpage, enhan
---
-### How to use the Blockquote Component
+## How to use the Blockquote component
The "Blockquote" component can be found in Components > Text, and you can place it on your canvas by dragging and dropping it or clicking it in the Components panel. To edit the content of your Blockquote instance, simply double-click it.
@@ -20,7 +20,7 @@ Once the component is placed on your canvas, you can customize its appearance us
For more on Design tokens in Webstudio, refer to [this guide](../foundations/design-tokens.md).
-### Styling a Blockquote
+## Styling a Blockquote
By default, Blockquote components include padding on the left and right, along with a left border. You can customize these in the Style panel:
@@ -31,15 +31,16 @@ When using a Cite tag inside your blockquote, you may want to change its display
---
-### How to attribute a Blockquote
+## How to attribute a Blockquote
It is a good practice to attribute the quoted text you use in a blockquote with the source's title, author, publication, URL, or any relevant information that identifies where the quote came from. This maintains transparency and credibility in your content. It also allows readers to verify the accuracy of the information and fosters ethical use of others' words.
You can add an attribution or citation by using the “Cite” property in your Blockquote instance settings or with the “Cite” Tag from a Text component.
-#### Using the "Cite" Property
+### Using the Cite property
+
+
-
If you want to include a URL link as a citation:
@@ -49,9 +50,10 @@ If you want to include a URL link as a citation:
Please note that this value will not be visible to the end-user.
-#### Using the “Cite” Tag
+### Using the Cite tag
+
+
-
If you want to include a Name/Title as a citation alongside your Blockquote:
diff --git a/docs/university/core-components/collection.md b/docs/university/core-components/collection.md
index 618609dd5c..4582ad23d9 100644
--- a/docs/university/core-components/collection.md
+++ b/docs/university/core-components/collection.md
@@ -72,7 +72,7 @@ It's unclear why each item is correct or incorrect by just looking at the image,
Add the Collection component to the canvas and either manually enter data (less common) or [bind data](../foundations/expression-editor.md#binding) to it (more common).
-**The Collection iterates over the array, so you must bind just the array portion of your variable to it. See** [**What's an Array**](collection.md#whats-an-array) **for more info.**
+**The Collection iterates over the array, so you must bind just the array portion of your variable to it. See** [**What's an array or object?**](collection.md#whats-an-array-or-object) **for more info.**
Optionally, rename the default Collection Item variable to something more semantic. If you are iterating over blog posts, name it "Blog Post."
@@ -88,7 +88,7 @@ When working with [Radix Components](../radix/), you might want to dynamically g
### Accordions
-
The Item has a unique value from the dynamic data bound to the Value field
+
The Item has a unique value from the dynamic data bound to the Value field
### Tabs
@@ -98,9 +98,9 @@ Tab Triggers and Tab Contents maintain their relationship by having the same val
-
Tab Trigger with custom value
+
Tab Trigger with custom value
-
Tab Content with custom value
+
Tab Content with custom value
diff --git a/docs/university/core-components/content-block.md b/docs/university/core-components/content-block.md
index 89a827c747..145e8125f1 100644
--- a/docs/university/core-components/content-block.md
+++ b/docs/university/core-components/content-block.md
@@ -15,8 +15,8 @@ Designers can create a library of templates, from little cards to fully built se
Next is a breakdown of Content Block by mode:
-1. [Design mode](content-block.md#design-mode) ⬇️
-2. [Content mode](content-block.md#content-mode) ⬇️
+1. [Design mode](content-block.md#content-block-in-design-mode) ⬇️
+2. [Content mode](content-block.md#content-block-in-content-mode) ⬇️
## Content Block in Design mode
@@ -40,7 +40,7 @@ Notice that the child of Content Block is Templates.
Drag/build the various instances you want to provide editors here.
-For example, your client wants to update the section under the hero with the latest promotion. Sometimes the promotion is for an event while other times it’s a product. You can create those two designs, add them to “Templates” within Editable Block, and your client can insert instances of the desired template and edit its content.
+For example, your client wants to update the section under the hero with the latest promotion. Sometimes the promotion is for an event while other times it’s a product. You can create those two designs, add them to “Templates” within Content Block, and your client can insert instances of the desired template and edit its content.
{% hint style="info" %}
Editors don’t have access to the Style Panel, so be sure to provide fully designed templates.
@@ -50,13 +50,15 @@ Every top-level instance within Templates will appear in Content mode like this:
Templates in Design mode
Template in Content mode
+
Each time they insert a template, its copy appears inside the Content Block's Body outlet, alongside any initial body content. The Templates container remains protected source material.
### Step 3: Add an initial setup (optional)
Optionally, you can add instances inside the Content Block's Body outlet.
-
The "Feature" instances are provided as a starting point
+
The Feature instances are provided as a starting point
+
Doing so will provide an initial setup for editors.
@@ -64,19 +66,54 @@ Editors can delete children of the Body outlet. They cannot delete the designed
### Store content in an MDX file
-In Design mode, use the **Source** property under **Properties & attributes** to connect a `.mdx` file from Assets. Create the file in Assets first, then select it directly or bind the property to an Asset ID. The file becomes the source of the Body outlet's children; the designed shell and Templates container remain part of the project.
+Connect a `.mdx` file when the Content Block's body should live in Assets instead of the project's regular instance data. The designed shell and Templates list remain in the project. Markdown `.md` files cannot be connected to a Content Block.
-Connecting a file replaces the Body outlet's existing children. In Design mode, select the connected filename to switch files, or select **Open** to edit it. To disconnect, select the **Source** property label and choose **Reset value**. Disconnecting leaves the MDX file unchanged, removes its derived body content from the canvas, and preserves the designed shell with an empty Body outlet.
+#### Prepare the Content Block
-When you connect an older Content Block that has no Body outlet, Webstudio replaces its existing editable content and adds the outlet automatically.
+1. Add the Content Block and design its shell in Design mode.
+2. Place the **Body** outlet where the article body should render.
+3. Add any reusable custom content to **Templates**.
+4. Give every top-level template a unique instance name. MDX uses that name to find the template.
-In Content mode, **Source** shows the connected filename and an **Open** button so editors can identify and edit the file. Changing, binding, resetting, and disconnecting the source remain available only in Design mode.
+New Content Blocks already include a Body outlet. When you connect an older Content Block without one, Webstudio adds it automatically.
-Editors continue to use the normal Content mode controls. Their changes appear immediately on the canvas and then save to the connected file. Changes made in the file editor also update every Content Block connected to that file.
+#### Create and connect the file
+
+1. Open **Assets**, select **Create text file**, and create a file ending in `.mdx`.
+2. Select the Content Block in Design mode.
+3. Under **Properties & attributes**, select **Connect .mdx file** for **Source**.
+4. Select the file, or bind **Source** to an expression that returns an MDX Asset ID.
+5. If the Content Block already has body content, review the warning and confirm the connection. The file replaces the existing Body children.
+
+
+
+
+
+
+
Change the default filename so that it ends in .mdx.
+
+
+
+
+
+
+
+
Connect the file from the Content Block's Source property.
+
+
+Select the connected filename to choose another file. Select **Open** to edit the current file. In Content mode, editors can see the filename and open it, but only a designer can connect, switch, bind, or disconnect the source.
+
+#### Edit the body in Content mode
+
+Edit the connected body with the usual Content mode controls. You can change text and supported properties, insert templates, reorder content, and delete content. Canvas changes appear immediately and then save to the MDX file.
Component properties in Content mode are limited to authored content, such as links, media sources and alternative text, form labels and placeholders, code, and date values. Layout, dimensions, visual themes, form wiring, and interaction settings remain available only in Design mode.
-Use Markdown for headings, paragraphs, links, lists, tables, code, and other standard document content. MDX uses Webstudio elements only for content that Markdown cannot represent:
+If the file changes after a canvas edit starts but before it is saved, reload the Content Block before continuing. Webstudio keeps the local canvas state until reload and does not silently merge or overwrite either version.
+
+#### Write Markdown and MDX
+
+Write headings, paragraphs, links, lists, tables, code, images, and other standard document content as Markdown. Webstudio writes a standard element as `` only when its authored properties cannot be represented by Markdown. It uses `ws:name` only to insert a uniquely named top-level template:
```mdx
# Product update
@@ -88,25 +125,35 @@ Regular document content stays Markdown.
The `ws:name` value must exactly match a unique top-level instance name in the Content Block's Templates list. Missing templates show a warning in Builder and are omitted from the published site. Invalid or unsupported MDX remains editable; Builder reports the source location and renders the valid content it can recover.
-You can connect multiple Content Blocks to the same MDX file. Editing any connected occurrence updates the shared file and the other connected occurrences.
+Keep template names stable after connecting MDX files. Webstudio prevents duplicate top-level template names. Renaming or deleting a referenced template warns that connected files will not be rewritten. If you continue, update the affected `ws:name` references in the MDX files. An MCP-connected agent can preview and confirm that update across a selected group of files.
-If the file changes after a canvas edit starts but before it is saved, Builder asks you to reload. It preserves the local canvas state until reload and does not merge or overwrite either version automatically.
+#### Use frontmatter in the designed shell
-Edit frontmatter as YAML in the MDX file editor. Canvas edits update only the document body and preserve the frontmatter source, including its comments and formatting. Content-mode users with Asset access can open the MDX file from Assets to edit its frontmatter.
+Edit frontmatter as YAML in the MDX file editor. Visual body edits preserve the frontmatter source, including comments and formatting.
-To use frontmatter in the designed part of a Content Block, bind a property or text value to the Content Block's **Document** parameter. For example, bind a heading to `Document.frontmatter.title` or an image source to `Document.frontmatter.featureImage`. Direct frontmatter bindings remain part of the same MDX file and can be edited on the canvas in Content mode. Computed expressions and values supplied through another document's `$ref` remain read-only on the canvas; open the referenced file to edit referenced values.
+To use frontmatter in the designed part of a Content Block, [bind](../foundations/variables.md) a property or text value to the Content Block's **document** variable. For example, bind a heading to `document.frontmatter.title` or an image source to `document.frontmatter.featureImage.src`. Direct frontmatter bindings remain part of the same MDX file and can be edited on the canvas in Content mode. Computed expressions and values supplied through another document's `$ref` remain read-only on the canvas; open the referenced file to edit referenced values.
-New Content Blocks include a **Body** outlet. Place it anywhere inside the designed article layout: the connected file's MDX body renders there, while the surrounding instances can use frontmatter bindings. Templates stay protected and continue to control which custom instances editors may insert into the body.
+#### Use one file in repeated or shared content
+
+For a Content Block inside a Collection, bind **Source** to the current item's MDX Asset ID. Each Collection item then opens and edits its own file.
+
+You can also connect multiple Content Blocks to the same MDX file. Editing the file or any connected occurrence updates every other occurrence.
+
+When you copy a connected Content Block, page, template, or folder to another project, Webstudio copies the MDX file and the local files it references. The pasted Content Block points to those imported copies. If Webstudio cannot parse the MDX, it preserves the source file and reports that its dependencies could not be collected.
To create another post with the same structure, duplicate the existing MDX Asset, edit the duplicate, and connect or bind the appropriate Content Block occurrence to it.
+#### Disconnect the file
+
+In Design mode, select the **Source** property label and choose **Reset value**. Disconnecting leaves the MDX file unchanged, removes its body from the canvas, and keeps the designed shell and Templates list with an empty Body outlet. If the source is bound inside a Collection, review the warning before confirming: resetting the shared Source property disconnects every Collection occurrence.
+
## Content Block in Content mode
In [Content mode](../foundations/modes.md#content), you can edit existing content inside Content Blocks. But what if you want to add _new_ content?
-You can within Editable Block — region(s) on the page the designer designates as a place you can add new content from building blocks to entire sections.
+You can within Content Block — region(s) on the page the designer designates as a place you can add new content from building blocks to entire sections.
-For example, on your homepage, you change out promotions. Sometimes they are events, and other times they are products. The designer can add the Editable Block to that section on your homepage and provide you with an “Events template” and “Products template”. You can then insert instances of each template, delete them, and change out their content. The design is fully provided for you.
+For example, on your homepage, you change out promotions. Sometimes they are events, and other times they are products. The designer can add the Content Block to that section on your homepage and provide you with an “Events template” and “Products template”. You can then insert instances of each template, delete them, and change out their content. The design is fully provided for you.
Next is how to use it.
@@ -114,7 +161,11 @@ Next is how to use it.
On the left-hand side, there is the navigator showing you the various Content Blocks on the page.
-
+
+
+
+
+
You can click on them to navigate to that part of the page.
@@ -124,7 +175,8 @@ Each Content Block can have a unique set of templates you can choose from.
On the canvas, hover where you want to insert, and the blue + button will appear. Click that, and you’ll see a list of templates provided by the designer.
-
Templates the designer provided
+
Templates the designer provided
+
Select the one you want, and it’ll insert an instance/copy of that template.
@@ -137,7 +189,8 @@ You can delete a direct child of the Content Block in one of two ways:
1. The blue + button will turn into a red delete button if you hold the option/alt key on your keyboard.
2. Select the instance in the navigator, and press delete/backspace on your keyboard.
-
Hold option/alt
+
Hold Option or Alt
+
{% hint style="success" %}
You can’t delete the template itself, so you can always add it back.
diff --git a/docs/university/core-components/element.md b/docs/university/core-components/element.md
index c274cccaef..550ddd8a36 100644
--- a/docs/university/core-components/element.md
+++ b/docs/university/core-components/element.md
@@ -12,7 +12,10 @@ The Element component is a versatile component that can represent any HTML eleme
The Element component can be found in **Components > General**, and you can place it on your canvas by dragging and dropping it or clicking it in the Components panel.
-
Components panel
+
+
+
+
---
@@ -72,7 +75,10 @@ The Element component can be rendered as many HTML tags, including but not limit
You can change the HTML tag of the Element by opening the **Settings Panel** located on the right side of the Builder.
-
Settings panel
+
+
+
+
The tag dropdown shows all available HTML elements you can use. When you change the tag, the component's properties automatically update to show relevant attributes for that element type.
diff --git a/docs/university/core-components/head-slot.md b/docs/university/core-components/head-slot.md
index 6fa8611201..b80ada5911 100644
--- a/docs/university/core-components/head-slot.md
+++ b/docs/university/core-components/head-slot.md
@@ -10,7 +10,10 @@ description: >-
{% embed url="https://www.youtube.com/watch?v=LeE52a_EWFw" %}
-
+
+
+
+
The Head Slot provides a visual interface for controlling your website's `` section. Instead of writing code, you can manage meta tags, canonical URLs, and other head elements directly in the builder.
diff --git a/docs/university/core-components/html-embed.md b/docs/university/core-components/html-embed.md
index 072c8f1b6c..7c6f1348ce 100644
--- a/docs/university/core-components/html-embed.md
+++ b/docs/university/core-components/html-embed.md
@@ -10,29 +10,28 @@ The HTML Embed component enables the direct integration of custom HTML, CSS, and
---
-### How to use the HTML Embed component
+## How to use the HTML Embed component
The "HTML Embed" component can be found in Components > General, and you can place it on your canvas by dragging and dropping it or clicking it in the Components panel.
---
-### How to add custom code to an HTML Embed instance
+## How to add custom code to an HTML Embed instance
You can add your custom HTML, CSS, or JavaScript code to the HTML Embed instance by selecting it and accessing its “Settings”.
The **Code** property is also available in Content mode when the HTML Embed is inside an editable Content Block.
-#### Code
+### Code
-
The "Code" section has a text area for adding your custom code. After you paste your code here, it will be rendered on the canvas. You can add anything to your site including custom widgets, third-party services, API integrations, animations, and interactive content.
-### Run Script on Canvas
+## Run script on canvas
The "Run Script on Canvas" toggle allows you to not only render the HTML embed directly on the canvas, but also execute scripts. It will look exactly the same way as when you publish the site.
-### Client Only
+## Client only
If your HTML embed is script-free and only includes items like SVG icons, CSS, or static HTML, you don't need this option.
@@ -40,9 +39,11 @@ For embeds with scripts that change HTML, like GSAP animations or sliders, activ
Check out how to embed [GSAP animations](../how-tos/how-to-add-a-gsap-animation.md).
+
+
---
-### How to reuse your custom code across multiple web pages
+## How to reuse your custom code across multiple web pages
You can reuse your custom code across your project by putting it inside a Slot instance.
@@ -52,7 +53,7 @@ You can reuse your custom code across your project by putting it inside a Slot i
Please note that any updates you make inside your slot will update all other instances of that slot.
-### Avoid creating global variables
+## Avoid creating global variables
When using the tag, every variable you create is global by default, which can lead to unpredictable effects.\
\
@@ -71,7 +72,7 @@ What could go wrong? 😅
1. If you navigate away and come back to the page, the script gets executed again and you will get a syntax error: "Identifier 'a' has already been declared". This is due to the fact that const can be declared only once. You could workaround this by using `var` or `let` instead.
2. If your logic relies on an existing variable and you don't redefine it, it will use any random value that happens to be there at a given time.
-#### Solution 1 - module
+### Solution 1 – module
When using the module type, the script has its own scope, and the variables don't become global.
@@ -81,7 +82,7 @@ When using the module type, the script has its own scope, and the variables don'
```
-#### Solution 2 - function scope
+### Solution 2 – function scope
Use an Immediately Invoked Function Expression (IIFE) to create a function scope.
@@ -93,7 +94,7 @@ Use an Immediately Invoked Function Expression (IIFE) to create a function scope
```
-### Don't use DOMContentLoaded
+## Don't use DOMContentLoaded
The **DOMContentLoaded** event won't fire during client-side navigation between pages because, technically, the page isn't reloaded. Use the same logic you intended to write inside that event handler, and if you need to wait for an element to be rendered first, place the embed after it.
diff --git a/docs/university/core-components/image.md b/docs/university/core-components/image.md
index 5b2dd4be12..a26981a28b 100644
--- a/docs/university/core-components/image.md
+++ b/docs/university/core-components/image.md
@@ -12,23 +12,28 @@ description: >-
---
-### How to use the Image component
+## How to use the Image component
-The "Image Component" can be found in Components > Media, and you can place it on your canvas by dragging and dropping it or clicking it in the Components panel. 
+The Image component is available under **Components > Media**. Drag it onto the canvas or click it to insert it at the selected location.
-#### Responsive Images
+
+
+
+
+
+### Responsive images
Webstudio automatically generates responsive images for your website, so you don't have to worry about manually resizing and optimizing images for different devices.
These responsive images automatically adjust their size based on the user's screen size, ensuring optimal resolution and quick loading whether the user is on a desktop monitor or a smartphone.
-#### Supported Image Formats
+### Supported image formats
All images in Webstudio are automatically optimized and served in WebP or AVIF format, depending on the responsive image resolution and browser support. This eliminates the need for pre-optimization and extra tools to compress or convert images.
WebP is supported by all modern browsers, including Chrome, Edge, and Firefox, while AVIF offers better compression quality and smaller file sizes but lacks support in browsers like Edge and Internet Explorer.
-#### Ensure a Stable Layout for Improved Performance
+### Ensure a stable layout for improved performance
It is essential to ensure that your browser can calculate an image's width and height without waiting for it to load. You can do this by setting the image's width/height in the Style panel or directly in the Image instance's properties.
@@ -38,17 +43,17 @@ If a browser can't calculate an image's size, it continues rendering the page, b
> Note: You can assess page speed using tools like [Page Speed](https://pagespeed.web.dev/). For reference, an unhinted hero image can easily decrease the page speed score from 100 to 70!
-#### Provide Aspect Ratio Upfront
+### Provide aspect ratio upfront
In Webstudio, every image has its aspect ratio set automatically. To prevent any layout shifts on your site, it's best to set the "width" property for each image you add. This ensures that the images fit smoothly into the overall design without causing any unexpected changes in layout.
---
-### How to customize an Image instance's properties
+## How to customize an Image instance's properties
You can customize the properties of an Image instance by selecting it and going to "Settings." Here is an overview of each property:
-#### Source
+### Source
The Source property lets you link an image file from the Assets Panel to your image instance. To add an image to your instance, click "Choose source" and select an image from the Assets Panel.
@@ -58,7 +63,7 @@ You can also drag a single image from the Assets panel directly onto the canvas.
Webstudio inserts a new Image component and selects the dragged asset as its
source.
-#### Width/Height
+### Width and height
The "width" and "height" properties define your image's initial display size in pixels and its aspect ratio. However, the final rendered image size is subject to CSS rules and layout constraints.
@@ -66,17 +71,17 @@ This means that if you set the width or height of an image in the Style panel or
The Width/Height properties are prioritized in some cases. For instance, if you only set the image's height in the Style panel, the width will be automatically determined from the Image Instance's "Width" property, and vice versa. This maintains the aspect ratio while adjusting the image's size with your specified values.
-#### Alternative Text (alt)
+### Alternative text (alt)
The "alt" property provides alternative text for the image. This text is vital for accessibility purposes, as it describes the image's content in case the image cannot be seen.
-#### Loading
+### Loading
The "Loading" property specifies how the browser handles image loading. You can set it to "Lazy" to load the image only when it comes into the viewport or "Eager" to load it immediately.
Here's a helpful tip: If you have an image in the initial viewport, always set it to "Eager." This way, the image gets priority, and it loads quickly, improving your site's overall performance.
-#### Optimize
+### Optimize
The "optimize" property lets you control if the image will go through the image transformation process including resizing, converting, and compressing it. This setting works on first and third-party images (e.g., images that come from a headless CMS). In rare scenarios, the user may want to turn this off.
diff --git a/docs/university/core-components/link.md b/docs/university/core-components/link.md
index 1464f41145..085b80a46c 100644
--- a/docs/university/core-components/link.md
+++ b/docs/university/core-components/link.md
@@ -26,16 +26,16 @@ You can customize the properties of a Link instance by selecting it and going to
### Href
-
+
The "href" property determines what the Link instance will lead to, such as a URL, page, phone, attachment, or email address.
1. **URL**: In its most common form, the "href" property references a URL, linking to another website or page.
2. **Page**: You can link to all of your pages within your site here. You can also link to specific sections within those pages. To link to a section on a page, first go to the section and fill out the `ID` field in Settings. Then go back to the link, select the page, and then in the next dropdown select the `ID` you just created. Like this:
-
First add the ID to the section you want to link to
+
First add the ID to the section you want to link to
-
Then add a page link and select the section.
+
Then add a page link and select the section.
3. **Email**: When you specify an email address as the 'href' value, the link opens the user's default email client (such as Gmail) with the designated email address pre-filled.
4. **Phone**: If you set the "href" property to a phone number, the link becomes a prompt for users to initiate phone calls directly from their devices.
@@ -43,7 +43,7 @@ The "href" property determines what the Link instance will lead to, such as a UR
### Target
-
+
You can use the "Target" property to modify a link instance's behavior and define how linked content is displayed.
@@ -71,7 +71,7 @@ You can add any Webstudio component inside a Link element to make it clickable
When using links for navigation and wanting to highlight the current page, the link component has a "Local Link" state in every style source.
-
+
## Related
diff --git a/docs/university/core-components/list.md b/docs/university/core-components/list.md
index bae1375e94..535b3a5a4a 100644
--- a/docs/university/core-components/list.md
+++ b/docs/university/core-components/list.md
@@ -52,7 +52,7 @@ Setting the List Style Type allows you to define the appearance of the bullet po
### How to customize a List instance's properties in Webstudio
-
+
You can customize a List’s properties by selecting it and going to Settings. Lists come with three base properties: Ordered, Reserved, and Start. To add additional properties, click the “+” next to Properties and add a new property.
diff --git a/docs/university/core-components/slot.md b/docs/university/core-components/slot.md
index 8f0f3d8d6a..78d2c89761 100644
--- a/docs/university/core-components/slot.md
+++ b/docs/university/core-components/slot.md
@@ -24,19 +24,20 @@ Data variables defined on the Global Root are accessible within Slots, while tho
---
-### How to use Slot Component
+## How to use Slot component
Here is the process for creating and reusing Slot instances:
-#### Creating a Slot instance
+### Creating a Slot instance
+
+
- 
1. You can find the Slots component in the “Components Panel.”
2. Drag “Slot” from the Components Panel onto your canvas to create a Slot instance. Alternatively, you can add it to the currently selected instance with a click.
3. Add other instances from the Components Panel into the Slot instance to populate it.
-#### Reusing a Slot instance
+### Reusing a Slot instance
Once you have a Slot on the canvas you can re-use it by simply copying and pasting it anywhere in your project.
@@ -61,7 +62,7 @@ occurrence to change.
---
-### Conclusion
+## Conclusion
With Slots you can re-use content across your site and sync the changes you make to them.
diff --git a/docs/university/core-components/vimeo.md b/docs/university/core-components/vimeo.md
index 16c6d8cedb..e138baf4e3 100644
--- a/docs/university/core-components/vimeo.md
+++ b/docs/university/core-components/vimeo.md
@@ -9,7 +9,7 @@ The Vimeo component for Webstudio allows you to embed Vimeo videos into your sit
---
-### Benefits of Vimeo
+## Benefits of Vimeo
We have picked Vimeo to be Webstudio’s first video component for the following reasons:
@@ -21,19 +21,24 @@ We have picked Vimeo to be Webstudio’s first video component for the following
---
-### How to use the Vimeo component in Webstudio
+## How to use the Vimeo component in Webstudio
You can find the Vimeo Component in the Components Panel in the Media Section. Here is how you can add and use the component on your site:
-#### Adding the Vimeo component to your canvas
+### Adding the Vimeo component to your canvas
+
+
+
+
+
-
1. You can find the Vimeo component in the “Components Panel” in the Media section.
2. Add the component by dragging and dropping it to the canvas or with a click to put it inside the selected instance.
3. Once you have the component on your canvas, you can head to Settings on the right to add your video URL and make other changes.
-
+
+
## Sub-components
The Vimeo component contains three child instances visible in the Navigator:
@@ -43,20 +48,21 @@ The Vimeo component contains three child instances visible in the Navigator:
| **Preview Image** | The thumbnail shown before playback. Replace it with your own image in Settings. |
| **Spinner** | The loading indicator shown while the video buffers. Hide it via the **Show** toggle in Settings. |
| **Play Button** | Contains a Box and a Play Icon. Style the Box (background, border-radius, etc.), swap the icon SVG via the HTML Embed inside, or hide the entire button via the **Show** toggle for background video use. |
-#### Modifying the Preview Image
+### Modifying the preview image
1. Inside the Vimeo Component, you will find three instances- the Preview Image, Spinner and Play Button. These instances define the primary look of the embedded video player.
2. You can add a preview image to your video by selecting the “Preview Image” instance and choosing an image source in the “Properties” section.
---
-### How to customize the Vimeo instance's properties
+## How to customize the Vimeo instance's properties
The Vimeo component comes with several properties that you can use to customize your video player. These properties appear in the Settings panel to the right of the canvas when your Vimeo component is selected.
Here’s how you can use the following properties:
-
+
+
- **Show Preview**\
Toggle this property on to render the preview image from Vimeo rather than the static image in Webstudio. This property is turned off by default because rendering the Vimeo preview requires making an API call which can slow down the speed of your page.
@@ -79,7 +85,7 @@ Here’s how you can use the following properties:
- **Other Properties**\
You can customize your Vimeo component further by adding [other properties](https://developer.vimeo.com/player/sdk/embed) that are not listed in the "Properties" section by default.
-### Customizing the Play Button and Spinner
+## Customizing the play button and spinner
The Vimeo component includes customizable child instances:
@@ -92,7 +98,7 @@ The Vimeo component includes customizable child instances:
- Change the Play Icon's color via typography color on its parent
- Hide the Play Button using the "Show" toggle for background video use
-### Hiding Player Elements
+## Hiding player elements
For background videos or custom player designs, you may want to hide default elements:
diff --git a/docs/university/core-components/xml-node.md b/docs/university/core-components/xml-node.md
index 1836a0c3ce..63c8bdbda8 100644
--- a/docs/university/core-components/xml-node.md
+++ b/docs/university/core-components/xml-node.md
@@ -8,24 +8,26 @@ description: "The XML Node\_is used to create\_an XML document, such as a sitema
Webstudio automatically generates a sitemap for static pages such as Home and About. If you are integrating with a CMS, you can use this component to create a sitemap for CMS data.
{% endhint %}
-
Will display when Document Type is set to "XML"
+
The component appears when Document type is XML
-### How to use the XML Node component
+
+## How to use the XML Node component
1. Go to Page Settings > Document Type and select XML from the dropdown
-
+
+
2. Go to Components > XML and add XML Node (this component won’t show until Step 1 is completed)
3. Set the tag and text content (e.g., “loc” and “https://example.com)
-### Tips
+## Tips
- XML Nodes can be nested within each other
- Use [Collection](collection.md) to iterate over a list of data
- A sitemap skeleton is available in the Marketplace
-### Including the static sitemap
+## Include the static sitemap
While you can use the autogenerated sitemap for static pages and create a separate sitemap for dynamic pages, you can also combine the two.
@@ -36,7 +38,8 @@ To include the static sitemap data in your custom sitemap, follow these steps:
3. Set the page path to /sitemap.xml. This will override the default sitemap.
4. Fetch the static data by clicking Create Variable > System Resource (Type) > Sitemap (Resource)
-
+
+
5. Use a [Collection](collection.md) to iterate over the static sitemap data
diff --git a/docs/university/core-components/youtube.md b/docs/university/core-components/youtube.md
index 3d857d04f2..f0baa79735 100644
--- a/docs/university/core-components/youtube.md
+++ b/docs/university/core-components/youtube.md
@@ -7,7 +7,10 @@ icon: youtube
# YouTube
-
+
+
+
+
While YouTube offers embed codes, the YouTube component enables a much better experience, which is why it’s the recommended way to add YouTube videos to your site.
diff --git a/docs/university/foundations/anatomy-of-the-webstudio-builder.md b/docs/university/foundations/anatomy-of-the-webstudio-builder.md
index 13c8488018..9aecd35621 100644
--- a/docs/university/foundations/anatomy-of-the-webstudio-builder.md
+++ b/docs/university/foundations/anatomy-of-the-webstudio-builder.md
@@ -6,34 +6,34 @@ description: >-
# 🛠️ Anatomy of the Webstudio builder
----
-
{% embed url="https://www.youtube.com/playlist?list=PL4vVqpngzeT4Bfs_D25xNi_qNMY99R928" %}
Webstudio 101 Playlist
{% endembed %}
----
+
+
+
+
## Canvas
-The canvas provides a visual representation of the website you are creating. After adding components from the Components Panel, you can arrange and style their instances on the canvas.
-
-
-
----
+The canvas provides a visual representation of the website you are creating. After adding components from the Components panel, you can arrange and style their instances on the canvas.
## Navigator
The Navigator Panel is a hierarchical overview of all instances on your page. It displays the website’s structure, showing the nesting and relationships between different instances. You can select the instance of any component inside your Project by clicking it on the canvas or inside the navigator.
-### Renaming Instances
+### Rename instances
Double-click any instance in the Navigator to rename it. Use semantic names like "Hero Section" or "Contact Form" to make your project structure easier to understand and maintain.
In the bottom half of the navigator, you will find the CSS Preview section, which is a real-time preview of the CSS styles applied to your selected instance.
-
+
+
+
+
-### Global Root
+### Global root
In the Navigator is the Global Root, the highest level of the page. Changes made to it apply to every page. It’s useful for setting global styles, such as font size and line height, and defining [CSS variables](css-variables.md) so they are accessible on every instance on every page. Changing the font size on the root affects all CSS properties that use REM, as this unit is relative to the root font size. For example, `1rem` outputs as `1 x root font size`.
@@ -41,9 +41,10 @@ In the Navigator is the Global Root, the highest level of the page. Changes made
Global Root uses the`:root` [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/:root) under the hood.
{% endhint %}
-
Global Root
-
----
+
+
+
+
## Breakpoints
@@ -57,7 +58,10 @@ You can create custom breakpoints with any media query condition – not just wi
Adding too many breakpoints or mixing and matching `min-width` and `max-width` will make maintenance difficult. The default breakpoints suffice more in the majority of use cases.
{% endhint %}
-
+
+
+
+
By defining how components should behave at different screen sizes, you can ensure your website looks great on various devices, including desktops, tablets, and smartphones.
@@ -65,23 +69,27 @@ By defining how components should behave at different screen sizes, you can ensu
When you select a breakpoint, such as 991, you’ll notice that the canvas is sized to 768. This is intentional. The goal is to style for the minimum (or maximum, if using min-width) to ensure all design issues are addressed at the "extreme" end of that breakpoint. When the viewport changes to 767, the next breakpoint is triggered.
{% endhint %}
----
-
-## Components Panel
+## Components panel
The Components Panel contains a list of all available [components](../core-components/) that you can add to your Webstudio Project. You can do this by clicking the components in the panel or dragging and dropping them on the canvas.
Components are grouped into sections like General, Text, Media, Forms, and [Radix](../radix/). For example, the Text section has all typography-related components, while the Form section nests the building blocks of a form.
-
+
+
+
+
----
-
-## Assets Panel
+## Assets panel
The Assets Panel is the second panel to the left of your canvas, and this is where all the static files are stored. You can upload, organize, and manage project assets inside this panel before using them on the canvas.
-### Asset Types
+
+
+
+
+
+### Asset types
The Assets Panel supports various file types organized by category:
@@ -92,7 +100,7 @@ The Assets Panel supports various file types organized by category:
This list is not exhaustive – Webstudio supports many additional file formats.
-### Filtering and Sorting
+### Filter and sort
Use the filter dropdown to show only specific asset categories (Images, Fonts, Documents, or All). Assets can be sorted by:
@@ -100,7 +108,7 @@ Use the filter dropdown to show only specific asset categories (Images, Fonts, D
- **Date** – Newest or oldest first
- **Size** – Largest or smallest first
-### Asset Details
+### Asset details
Click on any asset to view its details panel, which shows:
@@ -110,7 +118,7 @@ Click on any asset to view its details panel, which shows:
- **File size** – Size of the asset file
- **Uses** – Number of places the asset is used in your project
-### Asset Actions
+### Asset actions
- **Download** – Download the original asset file to your computer (Pro plan required)
- **Review & Delete** – When an asset is in use, shows where it's used before confirming deletion. Unused assets can be deleted directly.
@@ -124,32 +132,34 @@ Click on any asset to view its details panel, which shows:
Assets that are currently used in your project will show a settings gear icon. Attempting to delete them will display a list of all usages so you can review before confirming.
{% endhint %}
----
-
-## Pages Panel
+## Pages panel
The Pages Panel offers an overview of the website’s page structure and hierarchy, and it is the last panel on the left side of your canvas, under the Components and Assets Panels.
You can use this panel to add new pages to your Webstudio site, set the homepage, rename existing ones, and configure fields for social sharing and search engines.
-### Page Folders
+
+
+
+
+
+### Page folders
Organize your pages into collapsible folders for better project management. Right-click in the Pages Panel to create a new folder, then drag pages into it. Folders help keep large projects organized and make navigation easier.
----
-
-## Style Panel
+## Style panel
The Style Panel is located to the right of the canvas, and you can use it to customize the appearance and layout of a selected instance. It offers access to all CSS properties, visually.
-
+
+
+
+
There are three methods for adding styles:
1. Local - By default, the Local icon is active, meaning any styles you apply to that instance are for that instance only. The dot in the middle of the Local icon indicates that it has styles, whereas no dot indicates that there are no styles applied, making it easy to identify which ones have styles applied.
-
-
2. [CSS variables](css-variables.md) - Instead of pasting in your colors, sizes, and other styles, you can create a variable for each style and access the variables in each input field. For example, you can define a variable called "color-primary," and in your border color field, you can enter the variable name instead of the color itself.
3. [Tokens](design-tokens.md) - These enable reusing groupings of styles across your site. You can either create a new Token and apply styles to it or start with Local and convert it to a Token. Tokens are typically comprised of CSS variables and one-off styles.
@@ -168,9 +178,7 @@ The style input labels change colors indicating there is a style present.
The order of tokens in the Style Source Input matters. When multiple Tokens have a value for the same property, Tokens toward the end of the list will overwrite Tokens toward the beginning of the list.
{% endhint %}
----
-
-## Settings Panel
+## Settings panel
The Settings Panel is on the right side of your canvas. You can use this panel to access and edit component-specific properties (such as ID or class) and [Data variables](variables.md) for a selected instance, enabling you to store reusable content and fetch APIs — a building block of [CMS](cms.md).
@@ -180,9 +188,10 @@ The Settings Panel is on the right side of your canvas. You can use this panel t
[Modes](modes.md) change the Builder's behavior, such as previewing your site without distractions.
-
-
----
+
+
+
+
## Hide UI
@@ -192,23 +201,22 @@ Use Hide UI when you want more canvas space while designing, editing content, or
You can enable Hide UI from **Menu > View > Hide UI** or with `⌘ + \` on Mac and `Ctrl + \` on Windows.
-
Hide UI in the View menu
+
+
+
+
----
-
-## Share Dialog
+## Share dialog
The [Share Dialog](share-links.md) allows you to create shareable personal links to your Project with varying permissions.
---
-## Publish Dialog
+## Publish dialog
The [Publish Dialog](publishing-and-custom-domains.md) enables you to add a custom domain, publish to Staging and/or your custom domain, and [export your Project](../self-hosting/).
-{% hint style="info" %}
-Publishing currently takes around 45 seconds. During publishing, your Project is built into a JavaScript app and deployed to 300+ servers around the world.
-{% endhint %}
+Publishing builds and deploys the current Project. Keep the Publish dialog open to follow its status and review any reported errors.
## Related
diff --git a/docs/university/foundations/assets.md b/docs/university/foundations/assets.md
index e77fe4b22e..8e7e0347e6 100644
--- a/docs/university/foundations/assets.md
+++ b/docs/university/foundations/assets.md
@@ -6,7 +6,11 @@ description: Upload and manage images, fonts, and other files used in your proje
The Assets panel is located on the left side of the builder. It stores all static files used in your project — images, fonts, documents, and more. Upload files here and then reference them in instances and styles throughout your site.
-
The Assets panel
+
+
+
+
+
## Supported file types
@@ -47,14 +51,22 @@ index them immediately.
You can open uploaded `txt`, `csv`, `md`, `mdx`, `js`, `css`, `json`, `html`, `xml`,
and `svg` assets in the same editor. Syntax highlighting follows the file type;
-unsupported text types use plain text. Markdown files also provide formatting
-controls and a preview.
+unsupported text types use plain text. Markdown and MDX files also provide
+formatting controls and a preview.
MDX files use the same Markdown document features and additionally support
Webstudio elements for content that Markdown cannot represent. Rename a `.md`
file to `.mdx` to enable MDX parsing. Webstudio does not rewrite the file while
renaming it; invalid MDX remains editable and reports source-located errors.
+
+
+
+
+
+
Edit MDX source and review its rendered preview side by side.
+
+
Edits save when the editor loses focus or when you press `Command + S` on
macOS, `Ctrl + S` on Windows, or `Command/Ctrl + Enter`. Edit the complete
filename in Asset settings to rename a text file or change its format. When you
@@ -70,7 +82,9 @@ Converting an empty text file to `.json` initializes it with an empty object.
Markdown, MDX, and JSON files in Assets can be the source of truth for a site. The
Content Engine reads their structured fields, queries the files, and resolves
links between them. See [Content Engine](content-engine.md) for the supported
-file structure and a complete article workflow.
+file structure and a complete article workflow. Connect an MDX file to a
+[Content Block](../core-components/content-block.md#store-content-in-an-mdx-file)
+when editors should update its body visually in Content mode.
## Organizing assets with folders
@@ -125,7 +139,11 @@ Folders are included in the current search and sort order.
Hover any asset and click the gear icon to open its detail panel:
-
Asset detail panel
+
+
+
+
+
- **File size** and **MIME type**
- **Dimensions** and **Aspect ratio** (images only)
@@ -167,7 +185,8 @@ Builder.
## Related
-- [Content Engine](content-engine.md) – Build sites from Markdown and JSON files in Assets
+- [Content Engine](content-engine.md) – Build sites from Markdown, MDX, and JSON files in Assets
+- [Content Block](../core-components/content-block.md) – Edit an MDX document visually in Content mode
- [Anatomy of the builder](anatomy-of-the-webstudio-builder.md) – Overview of all builder panels
- [Image](../core-components/image.md) – Display images from assets or external URLs
- [Commands & search](commands-and-search.md) – Quickly find and delete unused assets
diff --git a/docs/university/foundations/breakpoints.md b/docs/university/foundations/breakpoints.md
index ac608f83cc..7c0ac37483 100644
--- a/docs/university/foundations/breakpoints.md
+++ b/docs/university/foundations/breakpoints.md
@@ -43,7 +43,10 @@ Each breakpoint can override styles inherited from the previous one in the casca
3. Set a **min-width** or **max-width** value, or choose a **media condition** (see below).
4. Give it a label.
-
Editing a breakpoint
+
+
+
+
## Editing and deleting breakpoints
diff --git a/docs/university/foundations/cms.md b/docs/university/foundations/cms.md
index 057734ff0b..770b9b9865 100644
--- a/docs/university/foundations/cms.md
+++ b/docs/university/foundations/cms.md
@@ -54,7 +54,8 @@ The Address Bar enables previewing Dynamic Pages in the editor by entering param
For the Dynamic Path `/post/:slug`, you would enter a slug value that exists in the CMS, such as `hello-world`.
-
Entering "hello-world" as a test value
+
Entering hello-world as a test value
+
{% hint style="danger" %}
The static part of the URL (in this case, `/post/`) is already in the Address Bar and should not be included when adding the test value.
@@ -120,9 +121,7 @@ While we do our best to verify the supported features, we may make mistakes in o
While most CMS field types seamlessly map to Webstudio components (e.g., Plain Text → Heading), rich text may not, depending on how the CMS stores/delivers it.
-**Currently, Webstudio supports rich text if it's delivered in HTML or Markdown format.** In the future, we will support rich text regardless of the format delivered by adding conversion libraries for each CMS's flavor of rich text. For example, we'll automatically convert AST to HTML. Refer to [this issue](https://github.com/webstudio-is/webstudio/issues/3398) for more information.
-
-In the meantime, advanced users can set up a proxy on Cloudflare Workers to convert rich text to HTML. However, this is outside the scope of Webstudio's support.
+Webstudio renders rich text delivered as HTML or Markdown. If a CMS returns a proprietary AST or another structured rich-text format, convert it to HTML or Markdown before binding it in Webstudio. This conversion can happen in the CMS, its API layer, or a proxy.
Rich text in the form of HTML can be bound to the [Content Embed Component](../core-components/content-embed.md), and Markdown can be bound to the [Markdown Embed Component](../core-components/markdown-embed.md).
@@ -142,7 +141,8 @@ cmsData.data[0].id ? 200 : 404;
This example looks for the ID of a record. If it's there, output `200` (found!) otherwise `404` (not found).
-
Binding an expression to the Status Code field in Page Settings
+
Binding an expression to the status code
+
{% hint style="info" %}
The exact key to look for will depend on your CMS, but think of something that will always be there if the post/record is found (slug, ID, title).
@@ -158,7 +158,8 @@ Add a component (e.g. a Box) to the page that contains your 404 message. Set its
When this evaluates to `true`, the 404 content is shown.
-
Setting the Show condition on the 404 content Box
+
Setting the Show condition on the 404 content
+
{% hint style="info" %}
To reuse an existing custom 404 page design without rebuilding it, [add a Slot](../core-components/slot.md) and select your 404 page's content as the slot source. This keeps the 404 UI in one place and lets you reuse it across any dynamic page.
@@ -174,7 +175,8 @@ cmsData.data[0].id;
This hides the regular content when there is no data, avoiding an empty-looking page.
-
Setting the Show condition on the regular content Box
+
Setting the Show condition on regular content
+
## Alternative: redirect instead of showing 404 content
diff --git a/docs/university/foundations/commands-and-search.md b/docs/university/foundations/commands-and-search.md
index 9261b2406c..db13bee06e 100644
--- a/docs/university/foundations/commands-and-search.md
+++ b/docs/university/foundations/commands-and-search.md
@@ -12,11 +12,14 @@ Commands & search speeds up the building process and introduces new shortcuts.
**Open Commands & search with ⌘ + K (Control + K for Windows).**
-
Commands & search
+
+
+
+
{% embed url="https://youtu.be/ofUP0Uc_ttY" %}
-### Actions
+## Actions
- Add components
- Search instances by name – find any instance in your project
@@ -40,15 +43,15 @@ Commands & search speeds up the building process and introduces new shortcuts.
- Delete Unused CSS variables – Remove CSS custom properties that are no longer used.
- All other [keyboard shortcuts](shortcuts.md)
-### Secondary Actions with Tab
+## Secondary actions with Tab
Some items in the Commands Panel have secondary actions. Press **Tab** to access them. For example, when searching pages, you can press Tab and arrow to "Settings" to go directly to that page's settings.
-### Find Forgotten Shortcuts
+## Find forgotten shortcuts
If you forget a shortcut like renaming an instance, search for the action (e.g., "edit instance label") and the Commands Panel will show the shortcut so you can learn it.
-### Group Counters
+## Group counters
Each category in the Commands Panel shows a counter indicating how many items it contains, helping you quickly understand the scope of your project.
diff --git a/docs/university/foundations/content-engine-reference.md b/docs/university/foundations/content-engine-reference.md
index d5dd1fa179..3fe37b8e2f 100644
--- a/docs/university/foundations/content-engine-reference.md
+++ b/docs/university/foundations/content-engine-reference.md
@@ -1,18 +1,18 @@
---
-description: Query Markdown and JSON Assets with the Content Engine.
+description: Query Markdown, MDX, and JSON Assets with the Content Engine.
---
# Content Engine reference
-Assets resources query Markdown and JSON files stored in the Assets panel. The Builder and Webstudio MCP use the same structured query contract.
+Assets resources query Markdown, MDX, and JSON files stored in the Assets panel. The Builder and Webstudio MCP use the same structured query contract.
## MCP workflow
Use these tools in order when creating or changing an Assets resource:
-1. Call `get-asset-field-catalog` to inspect standard fields and the fields currently observed in Markdown frontmatter and JSON files.
+1. Call `get-asset-field-catalog` to inspect standard fields and the fields currently observed in Markdown or MDX frontmatter and JSON files.
2. Call `validate-asset-query` to check the query structure, field paths, operators, and bounded operation counts.
3. Call `preview-asset-query` with concrete values and inspect its results and diagnostics.
4. Save the query with `create-assets-resource` or `update-assets-resource`.
@@ -22,7 +22,7 @@ Omit `query` when creating a resource to use the default many-result query for a
## Fields
-Every asset has the standard fields below. Markdown frontmatter and JSON root fields appear under `properties`, for example `properties.slug` or `properties.author.name`. The field catalog reports their observed types, occurrence counts, optionality, and mixed-type state. A JSON content file must contain an object at its root.
+Every asset has the standard fields below. Markdown or MDX frontmatter and JSON root fields appear under `properties`, for example `properties.slug` or `properties.author.name`. The field catalog reports their observed types, occurrence counts, optionality, and mixed-type state. A JSON content file must contain an object at its root.
| Field | Observed type |
| --- | --- |
@@ -109,7 +109,7 @@ Choose `fields` and disable `includeMetadata` when the page needs only selected
## Asset reference metadata
-A plain local asset path in Markdown frontmatter or JSON properties keeps the backward-compatible URL string result. Wrap the path in an exact `$ref` object only when consumers need structured Asset Manager metadata:
+A plain local asset path in Markdown or MDX frontmatter, or in JSON properties, keeps the backward-compatible URL string result. Wrap the path in an exact `$ref` object only when consumers need structured Asset Manager metadata:
```yaml
featureImage:
@@ -143,9 +143,9 @@ External URLs remain ordinary strings. Existing local path strings also keep the
| `none` | Returns no file content. Use this for listings and any query that only needs fields or metadata. |
| `full` | Embeds the complete UTF-8 file content in the content database. `maxBytes` defaults to 1 MiB and cannot be set higher. The query fails if a selected file is larger. |
| `range` | Embeds a byte range selected by `offset` and `length` in the content database. `length` cannot exceed 256 KiB. |
-| `markdown-body-ref` | Stores a reference to a Markdown body. Webstudio filters and paginates first, then reads only the selected bodies from Assets. `maxBytes` defaults to 1 MiB and cannot be set higher. The query fails if a selected source file is larger. |
+| `markdown-body-ref` | Stores a reference to a Markdown or MDX body. Webstudio filters and paginates first, then reads only the selected bodies from Assets. `maxBytes` defaults to 1 MiB and cannot be set higher. The query fails if a selected source file is larger. |
-Returned content has `encoding` and `text`. A range also reports its `offset`, returned `length`, and total file size. Use `markdown-body-ref` for article pages. It keeps article bodies out of the published content database and resolves relative Markdown links when the selected body is loaded.
+Returned content has `encoding` and `text`. A range also reports its `offset`, returned `length`, and total file size. Use `markdown-body-ref` for Markdown or MDX article pages. It keeps article bodies out of the published content database and resolves relative links when the selected body is loaded.
## Preview diagnostics
@@ -168,7 +168,7 @@ Only `database.usedBytes` counts toward `database.maxBytes`. Do not add the quer
| `artifacts` | Optional query and merged compiled artifacts used by detailed Builder diagnostics. |
| `unresolved` | Optional query result before document references are resolved. It helps inspect the authored `$ref` values behind resolved output. |
-If the merged database approaches its limit, remove duplicate reachable resources first. Then remove unused output fields or narrow the candidate documents. Prefer `markdown-body-ref` over embedded `full` content for Markdown articles.
+If the merged database approaches its limit, remove duplicate reachable resources first. Then remove unused output fields or narrow the candidate documents. Prefer `markdown-body-ref` over embedded `full` content for Markdown or MDX articles.
## Document references
@@ -178,7 +178,7 @@ A document reference is an exact object with one string field:
{ "$ref": "[#]" }
```
-Markdown references can appear in YAML frontmatter. JSON references can appear anywhere in the document. Either format can reference Markdown or JSON. References do not run inside a Markdown body.
+Markdown and MDX references can appear in YAML frontmatter. JSON references can appear anywhere in the document. Any format can reference Markdown, MDX, or JSON. References do not run inside a Markdown or MDX body.
| Reference | Inserted value |
| --- | --- |
@@ -210,7 +210,7 @@ Resolve paths relative to the file containing the reference. JSON Pointer uses `
| Limit | Value |
| --- | --- |
-| Markdown frontmatter | 64 KiB |
+| Markdown/MDX frontmatter | 64 KiB |
| Frontmatter nesting depth | 8 |
| Frontmatter fields | 256 |
| Frontmatter string | 16 KiB |
diff --git a/docs/university/foundations/content-engine.md b/docs/university/foundations/content-engine.md
index da90bd5751..70106cea1f 100644
--- a/docs/university/foundations/content-engine.md
+++ b/docs/university/foundations/content-engine.md
@@ -1,10 +1,10 @@
---
-description: Create a file-based blog with Markdown, Assets queries, and dynamic pages.
+description: Create a file-based blog with Markdown or MDX, Assets queries, and dynamic pages.
---
# 📚 Content Engine
-Webstudio's Content Engine turns Markdown and JSON files in Assets into content
+Webstudio's Content Engine turns Markdown, MDX, and JSON files in Assets into content
you can query and bind in the visual editor. The files remain the source of
truth, including their filenames, folders, metadata, and relative links. You
can move the same files between projects or use them outside Webstudio without
@@ -16,15 +16,12 @@ This guide creates a blog overview at `/blog` and one dynamic article page at
To see the finished setup first, start with the
[Markdown Blog marketplace template](https://webstudio.is/marketplace/templates/markdown-blog).
-The screenshots use the Webstudio Updates project as a working example. Its
-filenames, fields, and category filter differ from the tutorial values below.
-
Markdown articles stored alongside their assets
## Decide if the Content Engine fits
Use the Content Engine for bounded, file-based content that should live with
-the site and remain portable as Markdown or JSON.
+the site and remain portable as Markdown, MDX, or JSON.
Good fits include:
@@ -113,6 +110,7 @@ Write the article here.
An article's metadata and body in the Markdown editor
+
### Frontmatter
The opening YAML block is called **frontmatter**. It must be the first block in
@@ -173,7 +171,7 @@ asset ID or generated filename. This is what makes the content portable.
### JSON files
-The Content Engine can query JSON files as well as Markdown. JSON files can
+The Content Engine can query JSON files as well as Markdown and MDX. JSON files can
contain objects, arrays, or scalar values. A root object exposes its fields for
structured queries:
@@ -221,6 +219,7 @@ page-level **Dynamic data**:
An overview query for the Webstudio Updates project
+
Choosing only the fields the page renders keeps the published content data
small. Leaving article bodies out of the overview also avoids loading every
article just to display a list.
@@ -265,7 +264,8 @@ Add another Assets resource to the page-level **Dynamic data**:
- `properties.slug` **equals** `system.params.slug`
- `properties.draft` **does not equal** `true`
-
The article resource uses the dynamic slug from the page URL
+
The article Resource uses the dynamic slug from the page URL
+
**Exactly one** returns the matching article directly at `post.data`. It also
reports an error if two articles use the same slug. You do not need a
@@ -299,6 +299,30 @@ In Page Settings, bind the fields needed for search and sharing:
The status expression returns a real 404 when no article matches the URL.
+### Edit the complete article in Content mode
+
+The setup above uses a `.md` file and Markdown Embed when the article body is
+edited in the file editor. Use an `.mdx` file connected to a
+[Content Block](../core-components/content-block.md#store-content-in-an-mdx-file)
+when an editor should change the article visually in Content mode.
+
+1. Name the article files with the `.mdx` extension and change the resource's
+ `extension` filter from `md` to `mdx`.
+2. Change the article resource's **Content** setting to **Metadata only**. The
+ Content Block loads the selected file directly, so the resource does not
+ need to return its body.
+3. Replace the Markdown Embed with a Content Block and place its **Body** outlet
+ where the article body should render.
+4. Bind the Content Block's **Source** to `post.data.id`. Every Assets query
+ result includes its Asset ID, even when file metadata is disabled.
+5. Move the article title, image, excerpt, and other designed fields inside the
+ Content Block shell. Bind them directly to values such as
+ `document.frontmatter.title` and `document.frontmatter.featureImage.src`.
+
+Editors can now change the MDX body and directly bound frontmatter values on
+the canvas. Computed frontmatter expressions and values reached through a
+document `$ref` remain read-only; edit their source file instead.
+
## 7. Publish the article
Start new articles with `draft: true`. The overview and article queries above
@@ -320,21 +344,22 @@ will render it without another page design.
## Connect content with document references
-The Content Engine calls links between Markdown and JSON files **document
+The Content Engine calls links between Markdown, MDX, and JSON files **document
references**. A document reference replaces an exact `$ref` object with data
from another content file. This is Webstudio's syntax. It uses URI references
for file paths and [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901)
for values inside JSON files, but it does not implement JSON Schema resolution.
-Both supported source formats can reference either target format:
+All supported source formats can reference the other content formats:
-| Source | Where references can appear | JSON target | Markdown target |
+| Source | Where references can appear | JSON target | Markdown or MDX target |
| --- | --- | --- | --- |
-| Markdown | YAML frontmatter | Yes | Yes |
+| Markdown or MDX | YAML frontmatter | Yes | Yes |
| JSON | Anywhere in the document | Yes | Yes |
-References do not work inside a Markdown body. A `$ref` object can be nested in
-an object or array, including inside a file reached through another reference.
+References do not work inside a Markdown or MDX body. A `$ref` object can be
+nested in an object or array, including inside a file reached through another
+reference.
### Reference syntax
@@ -409,12 +434,12 @@ the resolved `properties.author` value is:
}
```
-The same rules cover JSON to Markdown and Markdown frontmatter to JSON. A
-referenced file can contain its own references, so shared records can be
-composed across several files.
+The same rules cover JSON to Markdown or MDX and Markdown or MDX frontmatter to
+JSON. A referenced file can contain its own references, so shared records can
+be composed across several files.
The Content Engine loads referenced data when a query filters, sorts, or
-returns a field that depends on it. The target must be another Markdown or JSON
+returns a field that depends on it. The target must be another Markdown, MDX, or JSON
file in the project's compiled Assets. Missing files, invalid fragments, and
reference cycles fail instead of returning partial data.
diff --git a/docs/university/foundations/css-variables.md b/docs/university/foundations/css-variables.md
index 0fceaef9fc..05994812b4 100644
--- a/docs/university/foundations/css-variables.md
+++ b/docs/university/foundations/css-variables.md
@@ -143,7 +143,10 @@ CSS variables, by nature, are available in the current instance and any of the c
#### Global Variables
-
Global Root
+
+
+
+
Most variables should be defined on the Global Root, which is the highest level of the page and the same for every page. That way, you can define `--my-color`, and it's available on every instance on every page.
@@ -163,7 +166,7 @@ With CSS variables, you can interact with the parent and modify the styles of an
Prefer CSS variables over a [descendant custom state](states-and-selectors.md#custom-states) such as `:hover .button` for parent-child interactions. They keep each property on the child that uses it and are especially useful when one parent state coordinates several properties or children. Define a variable on the parent, use it for the relevant property on each child, and change the variable's value in the parent's `:hover` state.
-
Hovering the link and the children change (icon color, icon bg, and arrow appears)
+
Hovering the link and the children change (icon color, icon bg, and arrow appears)
{% embed url="https://youtu.be/rg49mmDvdlE" %}
Video tutorial
diff --git a/docs/university/foundations/design-tokens.md b/docs/university/foundations/design-tokens.md
index 1ba8d801a7..6639cdaa35 100644
--- a/docs/university/foundations/design-tokens.md
+++ b/docs/university/foundations/design-tokens.md
@@ -71,7 +71,29 @@ First, it's recommended to create [CSS variables](css-variables.md) to use withi
You can style your site using Local or Tokens like this:
-
The top of the Style Panel contains Style Sources. Here is where you can add new Tokens, select existing ones, and switch to Local styling.
The top section of the Style Panel is our Style Sources Input. This is where you’ll create, style, and arrange your tokens.
When you select a component's instance on the canvas, the tokens you see inside this input are sources of the styles on that instance.
Want to style something immediately without making a Token? Use the Local Style Source. Styles applied on Local only impact that instance, but you can easily convert styles from Local to a new Token.
Want to style something immediately without making a token? Go for it. All component instances in Webstudio have this Local style source by default. Styles applied on Local are unique to an instance and can’t be re-used, but you can easily convert styles from Local to a new token through the token menu.
To make a new Token, click inside the Style Sources input, type a name, and hit enter.
To make a new token, click inside the Style Sources Input, type a name, and hit ENTER/RETURN.
The Token you’re currently styling will be blue in the Style Sources input, while others are gray. Simply click on another style source to select it. Any styling you do will be applied to the current Token and reflected across all instances of that Token.
The token you’re currently styling will be blue in the Style Sources Input, while others are gray. Simply click on another style source to select it.
Any styling you do will be applied to the current token and reflected across all instances of that token.
When you add a style, the label for that property will turn blue to show that it is applied on the current token.
Hover the label for a helpful description of where the styles on this property come from.
In this case, we see that the width value that we just applied is coming from the Base breakpoint, the “new token” token on the Body instance. See Label Colors to understand what the different colors mean.
Hover the label for a helpful description of where the styles on this property come from.
In this case we see that the width value that we just applied is coming from the Base breakpoint, the “new token” token, on the Body instance.
A circle in the Token indicates that there are no styles applied to the Token. This will go away as soon as you apply a style. For Local, a dot is added to the center of the circle when styles are added.
+1. Select an instance. The **Style sources** field at the top of the Style panel shows its Local styles and Tokens.
+
+
+
+2. To create a Token, select the Style sources field, enter a name, and press Enter.
+
+
+
+3. Select the source you want to edit. The active source is highlighted, and new styles are written to that source.
+
+
+
+Use the Local source for styles that apply only to the selected instance. You can convert Local styles into a reusable Token later.
+
+
+
+Hover a property label to see which breakpoint and style source provides its current value. See [Label colors](anatomy-of-the-webstudio-builder.md#label-colors) for the full reference.
+
+
+
+An empty circle means the source has no styles. A dot appears in the Local source after you add a style.
+
+
## Exporting human-readable classes
diff --git a/docs/university/foundations/expression-editor.md b/docs/university/foundations/expression-editor.md
index 5577cc9043..37d59043d0 100644
--- a/docs/university/foundations/expression-editor.md
+++ b/docs/university/foundations/expression-editor.md
@@ -6,7 +6,7 @@ description: >-
# ➕ Expression editor
-
+
Expression editor is available on every field when clicking the “+” button.
diff --git a/docs/university/foundations/modes.md b/docs/university/foundations/modes.md
index 74559c64f7..aa6828ce8a 100644
--- a/docs/university/foundations/modes.md
+++ b/docs/university/foundations/modes.md
@@ -17,11 +17,14 @@ You can change modes in the Top Bar or via [keyboard shortcuts](shortcuts.md) if
Additionally, you can open any project in [Safe Mode](modes.md#safe-mode), which disables script execution for security and troubleshooting purposes.
-
+
+
+
+
## Design
-Designer mode provides the full power of the builder. For example, you can add and style components.
+Design mode provides the full power of the Builder. For example, you can add and style components.
## Content
@@ -93,7 +96,7 @@ Here’s what you need to know:
- If the designer provided [Page templates](page-templates.md), you can create new pages from them and edit page details like name, path, SEO title, description, language, social image, and custom metadata.
-- Changes save in real-time, but you must publish your changes when you are ready for them to go live. To do so, open the publish dialog by clicking “Publish” in the top right, then click “Publish”. It takes around 45 seconds for the site to publish. Note, “Publish” may be disabled if the designer didn’t enable the publishing permission for you.
+- Changes save in real time, but you must publish them before they go live. Select **Publish** in the top bar, choose the destinations, and publish. **Publish** may be unavailable if the designer did not grant publishing permission.
## Preview
diff --git a/docs/university/foundations/navigator.md b/docs/university/foundations/navigator.md
index 9c8678aba9..e873528109 100644
--- a/docs/university/foundations/navigator.md
+++ b/docs/university/foundations/navigator.md
@@ -6,7 +6,10 @@ description: Use the Navigator to view, select, and organize instances on your p
The Navigator is a hierarchical panel on the left side of the builder that shows every instance on the current page as a tree. It reflects the exact nesting structure of your page and is the primary way to select, reorder, and organize instances — especially when they are stacked or overlapping on the canvas.
-
The Navigator showing the page structure
+
+
+
+
## Selecting instances
diff --git a/docs/university/foundations/page-settings.md b/docs/university/foundations/page-settings.md
index 8e77b64aca..8e4636d0fc 100644
--- a/docs/university/foundations/page-settings.md
+++ b/docs/university/foundations/page-settings.md
@@ -6,7 +6,10 @@ description: Configure per-page settings such as path, SEO, authentication, redi
Page settings control how an individual page behaves — its URL, SEO metadata, authentication, status code, redirect, and more. Open Page Settings by clicking the gear icon next to any page in the Pages panel.
-
General page settings
+
+
+
+
## Page name
@@ -140,7 +143,7 @@ Page authentication is useful for private previews, client-only pages, internal
Page authentication
{% hint style="info" %}
-Authentication applies to protected pages on custom domains. Staging domains have their own built-in password protection, described in [Publishing & custom domains](publishing-and-custom-domains.md#staging-domain-password-protection).
+Authentication applies to protected pages on custom domains. Staging domains have their own built-in password protection, described in [Publishing & custom domains](publishing-and-custom-domains.md#staging-password-protection).
{% endhint %}
{% hint style="warning" %}
@@ -161,7 +164,10 @@ To protect multiple routes, dynamic paths, or wildcard sections of the site, use
SEO settings that control how the page appears in search engine results.
-
SEO settings with search result preview
+
+
+
+
### Title
@@ -179,13 +185,19 @@ Adds a `noindex` directive to the page, preventing search engines from indexing
The Open Graph image displayed when the page is shared on social media (Facebook, X, LinkedIn, etc.). You can either upload an image or bind a URL expression to a dynamic image from your CMS.
-
Social image with preview
+
+
+
+
## Custom metadata
Add arbitrary `` tags to the page's ``. Each entry has a **property** (the meta tag's `name` or `property` attribute) and a **content** value, both of which support expressions.
-
Adding a custom meta tag
+
+
+
+
Use this for meta tags not covered by the fields above, such as `og:type`, `twitter:card`, or any custom meta needed by third-party integrations.
diff --git a/docs/university/foundations/project-settings.md b/docs/university/foundations/project-settings.md
index 8f2235953b..ab6ccd2aba 100644
--- a/docs/university/foundations/project-settings.md
+++ b/docs/university/foundations/project-settings.md
@@ -6,7 +6,10 @@ description: Set project-wide configuration, including redirects, authentication
Project settings are located in the top left by clicking the Webstudio logo > Project settings.
-
+
+
+
+
## General
@@ -19,7 +22,10 @@ Project settings are located in the top left by clicking the Webstudio logo > Pr
### Atomic CSS
-
+
+
+
+
When enabled, the class and CSS structure under the hood contains one style per class. This algorithm allows classes to be reused, significantly reducing the amount of CSS, ultimately leading to a faster-loading website.
@@ -113,7 +119,10 @@ To add a protected route:
Routes use the same syntax as page paths. See [Path syntax](page-settings.md#path-syntax) for supported static routes, dynamic segments, optional segments, and wildcards.
-
Project route authentication
+
+
+
+
Login and password rules:
@@ -126,7 +135,7 @@ Login and password rules:
If a page has authentication in Page Settings and the same route is also protected in Project Settings, the page setting takes priority for that route.
{% hint style="info" %}
-Authentication applies to protected routes on custom domains. Staging domains have their own built-in password protection, described in [Publishing & custom domains](publishing-and-custom-domains.md#staging-domain-password-protection).
+Authentication applies to protected routes on custom domains. Staging domains have their own built-in password protection, described in [Publishing & custom domains](publishing-and-custom-domains.md#staging-password-protection).
{% endhint %}
{% hint style="warning" %}
diff --git a/docs/university/foundations/publishing-and-custom-domains.md b/docs/university/foundations/publishing-and-custom-domains.md
index dcf84fb0b1..982ad8960e 100644
--- a/docs/university/foundations/publishing-and-custom-domains.md
+++ b/docs/university/foundations/publishing-and-custom-domains.md
@@ -34,7 +34,8 @@ Enter the domain or subdomain you want the site to be available at, for example,
After entering your domain, you will be provided with DNS records, which can be manually added to your DNS or automatically through Entri.
-
+
+
### 2. Add the DNS records
@@ -77,9 +78,7 @@ Verification may take up to 24 hours but usually takes only a few minutes.
You must publish your site _after_ the domain is verified, or else "[Worker not found](publishing-and-custom-domains.md#domain-issues)" will show on the site.
{% endhint %}
-{% hint style="info" %}
-Publishing currently takes around 45 seconds. During publishing, your Project is built into a JavaScript app and deployed to 300+ servers around the world.
-{% endhint %}
+Keep the Publish dialog open to follow the build and deployment status. Resolve any reported error before trying again.
Once your site is live, you can visit it by clicking the open icon next to the green checkmark.
@@ -87,7 +86,11 @@ Once your site is live, you can visit it by clicking the open icon next to the g
## Publish to Staging
-
+
+
+
+
+
You can publish your Project to a separate domain for testing before going live by only checking your staging domain, which can be the default Project subdomain or a custom domain.
@@ -237,7 +240,7 @@ DNS propagation typically takes 10-15 minutes, but can take up to 72 hours in ra
#### Option 2: Publish your website on a `www` subdomain
-Go back to [Step 1](publishing-and-custom-domains.md#id-1.-add-a-new-domain-to-your-project), but this time, prefix your domain with `www`.
+Go back to [Step 1](publishing-and-custom-domains.md#1-add-a-new-domain-to-your-project), but this time, prefix your domain with `www`.
#### Video Tutorial
@@ -263,7 +266,8 @@ To publish to a subdomain:
You may see "Worker not Found" message when opening the site, like this:
-
+
+
Worker not found is due to one of the following reasons:
diff --git a/docs/university/foundations/style-panel.md b/docs/university/foundations/style-panel.md
index b62307378b..5b9c85e30b 100644
--- a/docs/university/foundations/style-panel.md
+++ b/docs/university/foundations/style-panel.md
@@ -6,7 +6,10 @@ description: Use the Style Panel to apply CSS styles to any instance on your pag
The Style Panel is on the right side of the builder. It exposes every CSS property visually and applies styles to the currently selected instance. All style changes are scoped by the active [breakpoint](breakpoints.md) and style source.
-
The Style Panel
+
+
+
+
## Style sources
diff --git a/docs/university/foundations/variables.md b/docs/university/foundations/variables.md
index 6f857d9605..5e244e0f8f 100644
--- a/docs/university/foundations/variables.md
+++ b/docs/university/foundations/variables.md
@@ -10,7 +10,11 @@ description: Data variables enable the definition and use of a value throughout
Data variables are defined on any instance in the navigator such as Global Root, Body, or Heading. Variables can be found on the right panel in the settings tab.
-
+
+
+
+
+
## Variable scope
@@ -111,8 +115,6 @@ By default, several factors determine what gets cached and for how long, but one
\
If you set a custom **Cache Max Age** value, it will define your cache lifetime instead of relying on API response headers.
-Webstudio sees approximately 45% of sub-requests (i.e., fetches from Cloudflare Workers) served from the cache. This means that, on average, roughly half of the time someone visits a page that uses Resources, such as a blog post, the request will go through to the origin/CMS.
-
### GraphQL
A GraphQL Resource variable gets its value from a GraphQL API, allowing data from a remote system to be used within Webstudio. While similar to [Resource](variables.md#resource), it’s unique in that the available fields are specifically designed for interacting with GraphQL APIs.
@@ -131,9 +133,9 @@ A System Resource variable gets its value from internal data.
Available system resources:
-- **Sitemap** – Contains data about the static pages on the website, commonly used to build a custom sitemap that combines dynamic data with static data. Refer to the [XML Node component](../core-components/xml-node.md#including-the-static-sitemap) for more info.
+- **Sitemap** – Contains data about the static pages on the website, commonly used to build a custom sitemap that combines dynamic data with static data. Refer to the [XML Node component](../core-components/xml-node.md#include-the-static-sitemap) for more info.
- **Current Date** – Returns the current date/time, useful for displaying "today's date" or calculating relative times. Can be formatted using the [Time component](../core-components/time.md).
-- **Assets** – Queries project assets, including structured fields and file content from Markdown and JSON files. See [Content Engine](content-engine.md) for a complete article workflow.
+- **Assets** – Queries project assets, including structured fields and file content from Markdown, MDX, and JSON files. See [Content Engine](content-engine.md) for a complete article workflow.
## Related
diff --git a/docs/university/how-tos/how-to-add-a-gsap-animation.md b/docs/university/how-tos/how-to-add-a-gsap-animation.md
index a5712aeff2..2ab322f611 100644
--- a/docs/university/how-tos/how-to-add-a-gsap-animation.md
+++ b/docs/university/how-tos/how-to-add-a-gsap-animation.md
@@ -4,7 +4,7 @@ description: Add GSAP animations to your Webstudio site with custom code.
# 🍀 How to add a GSAP animation
-
+
## Embed GSAP library on the page
@@ -46,8 +46,7 @@ Learn more about script scope [here](../core-components/html-embed.md#avoid-crea
## Demo
-[Preview Link](https://simple-gsap-demo.wstd.io/)\
-[Builder Link](https://apps.webstudio.is/builder/623cdb40-24bb-4809-a610-145b6eefcf21?authToken=d0544921-f4bb-4697-a0d8-2efd2a0c4a11\&mode=preview)
+[Preview the GSAP demo](https://simple-gsap-demo.wstd.io/).
## Related
diff --git a/docs/university/how-tos/how-to-use-custom-fonts.md b/docs/university/how-tos/how-to-use-custom-fonts.md
index 6fd4ba8a7c..2e25adf2bb 100644
--- a/docs/university/how-tos/how-to-use-custom-fonts.md
+++ b/docs/university/how-tos/how-to-use-custom-fonts.md
@@ -55,8 +55,6 @@ Each font stack contains fonts for:
The browser reads the list and uses the first font it finds installed. Webstudio automatically outputs all the font variations for cross-platform compatibility.
-📝 Learn more in the [Webstudio December Update](https://docs.webstudio.is/news/december-update#id-6.-modern-font-stacks).
-
---
## Supported Font Formats
diff --git a/docs/university/integrations/README.md b/docs/university/integrations/README.md
index 5c201a1093..30763b2011 100644
--- a/docs/university/integrations/README.md
+++ b/docs/university/integrations/README.md
@@ -10,19 +10,19 @@ description: >-
This page is a work in progress – much more to come.
{% endhint %}
-### CMSs
+## CMSs
* [Hygraph](hygraph.md)
* [Airtable](airtable-frontend.md)
* [WordPress](wordpress.md)
* [Flotiq](flotiq.md)
-### Databases
+## Databases
* [Notion](notion.md)
* [Supabase](supabase.md)
-### Forms
+## Forms
* [Pabbly](pabbly.md)
* [Zappier](zapier.md)
diff --git a/docs/university/integrations/airtable-form-webhook.md b/docs/university/integrations/airtable-form-webhook.md
index 7c3e766331..e51f8dde0a 100644
--- a/docs/university/integrations/airtable-form-webhook.md
+++ b/docs/university/integrations/airtable-form-webhook.md
@@ -12,7 +12,7 @@ Out of the box, Webstudio automatically sends form data to the site owner’s re
---
-### Integration overview:
+## Integration overview
You can integrate your Webstudio form with Airtable in 3 simple steps:
@@ -20,13 +20,14 @@ You can integrate your Webstudio form with Airtable in 3 simple steps:
2. Setting Up Webhooks in Airtable and Webstudio
3. Mapping Data to the Right Fields
-### Step 1: Configuring your Webstudio Form
+## Step 1: Configure your Webstudio Form
To configure your form for the integration, you will need to define the input name for each field. Select your form input field in the navigator, and head over to “Settings” on the right to fill in the name property. Repeat this for every input field on your form as this is what Airtable will use to identify your website form submissions.
-
+
-### Step 2: Setting Up Webhooks in Airtable and Webstudio
+
+## Step 2: Set up webhooks in Airtable and Webstudio
Airtable simplifies the process of setting up webhooks within the platform.
@@ -35,7 +36,8 @@ Airtable simplifies the process of setting up webhooks within the platform.
3. Create a new automation by selecting "Create Automation" and choose the trigger event. In this case, select "When webhook received" as the trigger.
4. Copy the webhook URL to your clipboard.
-
+
+
Next, link your Webstudio form to this webhook.
@@ -47,7 +49,7 @@ Next, link your Webstudio form to this webhook.
6. Publish your new changes on Webstudio.
7. Head over to the live version of your site and create a test submission on your form. This will trigger send the submission to Airtable and validate your integration.
-### Step 3: Mapping Data to the Right Fields
+## Step 3: Map data to the right fields
With the webhook set up, data will automatically flow into your Airtable automation. Now, let's proceed to map the incoming data to the appropriate feeds within the table.\
To learn more about how to use Airtable's powerful automation tool, refer to their official [documentation](https://support.airtable.com/docs/getting-started-with-airtable-automations).
@@ -61,9 +63,10 @@ To learn more about how to use Airtable's powerful automation tool, refer to the
4. Turn on your automation\
Now that we have finished configuring our automation, we can turn it on.
-
+
-### Conclusion
+
+## Conclusion
Airtable's native [automation](https://support.airtable.com/docs/getting-started-with-airtable-automations) features empower users to streamline data entry and enhance data organization. By setting up a webhook action from your Webstudio form to receive external data and automating the mapping process, you eliminate the need for manual data entry, reduce the risk of errors and gain access to all of Airtable's data management features.
diff --git a/docs/university/integrations/airtable-frontend.md b/docs/university/integrations/airtable-frontend.md
index 940507b3cf..524653fe69 100644
--- a/docs/university/integrations/airtable-frontend.md
+++ b/docs/university/integrations/airtable-frontend.md
@@ -69,7 +69,7 @@ Copy the curl command as shown in the image, then paste it into the URL field in
Now, you need to add several customizations to it.
-First, replace `YOUR_SECRET_API_TOKEN` with your API token. Refer to [Airtable's documentation](https://support.airtable.com/docs/creating-personal-access-tokens) for generating a token. Make sure you keep `Bearer` in front of the token.
+First, replace `YOUR_SECRET_API_TOKEN` with a narrowly scoped personal access token. Refer to Airtable's [personal access token guide](https://airtable.com/developers/web/guides/personal-access-tokens) and grant only the records and bases this Resource needs. Keep `Bearer` in front of the token.
diff --git a/docs/university/integrations/flotiq.md b/docs/university/integrations/flotiq.md
index f4ac5cf67c..876c910d65 100644
--- a/docs/university/integrations/flotiq.md
+++ b/docs/university/integrations/flotiq.md
@@ -20,7 +20,7 @@ Before starting, ensure you have the following:
* **Flotiq account** – [Register here](https://flotiq.com).
* **Flotiq API Key** – Learn more about [Flotiq API Keys](https://flotiq.com/docs).
-* **Webstudio account** – [Sign up here](https://webstudio.com).
+* **Webstudio account** – [Sign up here](https://webstudio.is).
{% hint style="info" %}
> Webstudio’s **Pro tier plan** is required to use the Resource feature. Flotiq does not require a paid plan.
@@ -99,7 +99,7 @@ The variable should be configured as shown in the screenshot below:
Test the variable - if it is configured correctly, the fetched Flotiq content will appear in the **Inspect Tool**.
-
+
### **Bind Flotiq data to your page**
@@ -119,7 +119,7 @@ To bind data:
> For images add an **Image Component**, and bind the **Source Property** to the image URL: `"https://api.flotiq.com/" + VariableName.data.data.blogpost.headerImage[0].url`.
{% endhint %}
-
+
### **Create a listing page**
diff --git a/docs/university/integrations/n8n.md b/docs/university/integrations/n8n.md
index 55dd711220..163c6e2623 100644
--- a/docs/university/integrations/n8n.md
+++ b/docs/university/integrations/n8n.md
@@ -8,7 +8,7 @@ This guide shows you how to link Webstudio Forms with [n8n](https://n8n.io/) for
{% embed url="https://www.youtube.com/watch?v=zeJVpfemwj0" %}
-### What is n8n?
+## What is n8n?
n8n is a platform designed to automate workflows. It helps you set up a series of tasks that run automatically, connecting different apps and services in the process.
@@ -16,11 +16,12 @@ One of the key features of n8n is its visual editor, which allows you to build t
---
-### How to create a Webstudio > n8n integration?
+## Create a Webstudio and n8n integration
For our Webstudio integration, we will create a workflow that sends form submissions to Supabase and notifies a Slack channel if certain requirements are met.
-
+
+
- Get started with n8n
- Create the workflow trigger
@@ -30,14 +31,14 @@ For our Webstudio integration, we will create a workflow that sends form submiss
- Add a Slack Node
- Finalize your workflow
-#### Get started with n8n
+### Get started with n8n
Start by logging in to your n8n account.
- Inside your dashboard, go to Credentials > Add credential. For this demo, we will be using Supabase and Slack. You can find detailed instructions for all [supported credential setups](https://docs.n8n.io/integrations/builtin/credentials).
- After setting up the relevant credentials, go to “Workflows” and create a new workflow to start building your automation.
-#### Create the workflow trigger
+### Create the workflow trigger
To initiate our n8n workflow with a webhook, we need to configure a webhook trigger.
@@ -47,9 +48,10 @@ To initiate our n8n workflow with a webhook, we need to configure a webhook trig
You can learn more about the [Webhook node and its parameters](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/).
-#### Connect the webhook to your Webstudio Form
+### Connect the webhook to your Webstudio Form
+
+
-
1. Open the Webstudio builder, select your form instance, go to Settings and add two properties— _Action_ and _Method_.
2. Paste your copied Test Webhook into the Action property.
@@ -59,7 +61,7 @@ You can learn more about the [Webhook node and its parameters](https://docs.n8n.
6. Open the published version of your website and submit the updated form.
7. Back in n8n, you will now see the submitted form data in the Output Section.
-#### Integrate with External Applications
+### Integrate with external applications
Next, let’s add an external application to our workflow. To demonstrate this step, we will be adding form records to Supabase.
@@ -69,7 +71,7 @@ Next, let’s add an external application to our workflow. To demonstrate this s
You can learn more about the [Supabase node and its parameters](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.supabase).
-#### Add an IF Node
+### Add an IF node
IF and other flow nodes are used to trigger automations when specified conditions are met.
@@ -85,7 +87,7 @@ For this example, we will create a condition to send a Slack channel message onl
You can [learn more about the IF node and its parameters](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.if/).
-#### Add a Slack Node
+### Add a Slack node
Finally, let’s add a Slack node to our workflow. We will configure this node to send a message to the Sales channel in Slack.
@@ -97,7 +99,7 @@ Finally, let’s add a Slack node to our workflow. We will configure this node t
You can [learn more about the Slack node and its parameters](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.slack/).
-#### Finalize your workflow
+### Finalize your workflow
After setting up your workflow, you should test it to ensure it runs properly.
@@ -109,7 +111,8 @@ After the checks are concluded, activate your workflow.
1. Replace the “Test Webhook URL” with the “Production Webhook URL” in your Form’s Action property.
2. Go to the upper left of your n8n canvas and activate your workflow by toggling it from “Inactive” to “Active”.\
- 
+
+ 
## Related
diff --git a/docs/university/integrations/notion.md b/docs/university/integrations/notion.md
index 5120fec0e7..b860b81851 100644
--- a/docs/university/integrations/notion.md
+++ b/docs/university/integrations/notion.md
@@ -10,7 +10,7 @@ coverY: 0
# How to integrate a Notion database with Webstudio
{% hint style="warning" %}
-Disclaimer: Using Notion Page content in Webstudio is impossible (for now), so it is only for Database properties.
+This guide uses properties from a Notion data source. A page's block content requires additional Notion API requests, so fetch it through an API endpoint or automation that returns the complete document to one Webstudio Resource.
{% endhint %}
By the end of this tutorial, you will have the following using your [Notion](https://notion.so/) database and [Webstudio](https://webstudio.is/):
@@ -40,17 +40,15 @@ Webstudio is open source, has all CSS properties, and is dynamic at the speed of
Notion is where many teams and individuals already manage content, typically in preparation for adding it to their website. By integrating the website builder directly with Notion, people can avoid the unnecessary step of manually transferring the data to the website.
-## Use Notion Databases (not Notion Pages)
+## Use Notion data source properties
-You can use Webstudio as a Notion website builder for any properties in your database. **Notion Pages cannot be fetched in Webstudio.**
+You can bind properties returned by a Notion data source query directly to Webstudio. A Notion page response includes its properties, but the page's block content is a separate, paginated API response. A complete page-body integration therefore needs to:
-Notion Pages cannot be used because the Notion API requires three calls to fetch the necessary data.
+1. Query the data source for the page and its properties, such as title, description, and slug.
+2. Read the page's child blocks with the page ID returned by that query.
+3. Follow pagination and recursively read child blocks when the document contains nested content.
-1. **Fetch the database item** – Notion Pages don't contain any properties. You need properties to manage SEO settings such as meta title, meta description, and slug, among other data for managing a blog.
-2. **Fetch page content** – The first call provides an ID to fetch Notion Page content, a wrapper for the actual content.
-3. **Fetch block content** – The Notion Page call provides an ID to use in the third call, which fetches the various blocks within a page (e.g., title, paragraph, link, etc.).
-
-Synchronously calling three APIs would lead to slow performance for your visitors.
+For page bodies, put those requests behind your own API endpoint or automation and return the combined result to Webstudio in one response. Cache the result when appropriate.
## **Steps to building a website using Notion data**
@@ -79,7 +77,7 @@ In this step, you will configure a [Resource](../foundations/variables.md#resour
Go to the Navigator on the left > select Body > Settings on the right > and create a new variable with any name (this example uses "Notion Data"), and in type, use Resource.
-While the URL and remaining fields can be manually entered, there is also a shortcut – you can paste in a curl command, and Webstudio will automatically parse it and populate the respective fields. To get the curl command, go to [Notion's filter database entries doc](https://developers.notion.com/reference/post-database-query-filter).
+While the URL and remaining fields can be entered manually, you can also paste a curl command and let Webstudio populate the Resource fields. Start with Notion's [Query a data source](https://developers.notion.com/reference/query-a-data-source) reference.
@@ -91,11 +89,9 @@ First, replace `$NOTION_API_KEY` with your API key, which you can get by [creati
-Second, you must modify the URL to include your database ID. If you are in a web browser, go to your database, and it'll be in the URL. If you are in the app, go to your data, click the three dots, copy a link to the database, and paste it somewhere temporarily.
+Second, set the URL to `https://api.notion.com/v1/data_sources//query`. Find the data source ID using Notion's API or by copying the linked database information from Notion. It is not necessarily the page ID shown in a browser URL.
-As bolded below, the database ID is after the path and before the `?v`.
-
-https://www.notion.so/**94582558d50a4cb98234f16973f69c8a**?v=1f9c545770334b2091e52c906492143c
+Add `Notion-Version: 2026-03-11`, the version required by the current [data source query API](https://developers.notion.com/reference/query-a-data-source), and keep the `Authorization: Bearer ` header from the curl example.
Third, you must modify the filter in the body to use the currently viewed URL. So, for example, if somebody is viewing `/events/birthday`, the URL needs to filter Notion records using birthday.
diff --git a/docs/university/integrations/supabase.md b/docs/university/integrations/supabase.md
index c57e4441ad..e881f94c30 100644
--- a/docs/university/integrations/supabase.md
+++ b/docs/university/integrations/supabase.md
@@ -8,13 +8,13 @@ In Webstudio, a "Collection" is a powerful feature designed to manage and displa
{% embed url="https://www.youtube.com/watch?v=2MrkfnjYuCo" %}
-## Dynamic Content Creation with Webstudio and Supabase
+## Create dynamic content with Webstudio and Supabase
-To create pages featuring dynamic content in Webstudio by integrating Supabase as your data source.
+This guide creates pages with dynamic content by using Supabase as the data source.
---
-### Setting Up Your Supabase Project
+### Set up your Supabase project
1. Sign up for a free Supabase account.
2. Create a new project. (You'll need to set a strong password for your project to proceed).
@@ -23,7 +23,7 @@ To create pages featuring dynamic content in Webstudio by integrating Supabase a
---
-### Uploading Images to Supabase Storage
+### Upload images to Supabase Storage
1. Go to **Storage** in your Supabase dashboard
2. Create a new bucket and set it as **public**
@@ -32,7 +32,7 @@ To create pages featuring dynamic content in Webstudio by integrating Supabase a
---
-### Configuring Row Level Security (RLS)
+### Configure Row Level Security
1. Navigate to your table → "No active RLS policies"
2. Create a new policy
@@ -41,31 +41,31 @@ To create pages featuring dynamic content in Webstudio by integrating Supabase a
---
-### Integrating Supabase with Webstudio
+### Integrate Supabase with Webstudio
-#### Getting the API URL
+#### Get the API URL
1. Go to **Table Editor** → select your table
2. Click **API** (at the top right of the table view)
3. Switch the example code to **bash**
4. Copy the URL provided
-#### Adding the Resource Variable
+#### Add the Resource variable
1. In Webstudio, select your Collection's parent element
2. Go to **Settings → Add Variable → Type: Resource**
3. Paste the API URL
-4. Add a Header:
+4. Add a header:
- Name: `apikey`
- - Value: Your public API key from **Project settings → API**
+ - Value: Your publishable key from **Project settings → API Keys**
-{% hint style="info" %}
-The API key stays between you and the builder and is not exposed on the frontend.
+{% hint style="warning" %}
+Use only a Supabase publishable key (or the legacy `anon` key) in a website integration. Never use a secret or `service_role` key. Publishable keys identify the project but do not protect its data; configure Row Level Security policies and table grants for every operation the site permits. See [Supabase API keys](https://supabase.com/docs/guides/getting-started/api-keys) and [Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security).
{% endhint %}
---
-### Mapping Data and Finalizing Your Page
+### Map data and finish the page
Map the data from Supabase to your Webstudio project. This involves setting up the data within your collection to inform Webstudio about the available data for use.
diff --git a/docs/university/mcp.md b/docs/university/mcp.md
index 0597a4aea7..3220891d18 100644
--- a/docs/university/mcp.md
+++ b/docs/university/mcp.md
@@ -155,6 +155,36 @@ Rules:
- To work with another previously linked project without changing the directory's default link, start MCP or a shell call with `--project `, for example `webstudio mcp --project ` or `webstudio mcp single-op-call list-pages --project `. Selected projects use isolated local session and checkpoint files.
- If you are a delegated agent and your parent cannot see live stderr/stdout, do not run a long sequence of shortcut or `mcp single-op-call` commands silently and do not wrap many calls in a shell loop. Treat each parent-visible checkpoint as the unit of work. If the parent asks for status within 30 seconds, run exactly one `webstudio ` or `webstudio mcp single-op-call` command, report that command/result, then wait before the next MCP command. For all-component design-system pages, checkpoint after discovery, checkpoint after page creation, call `components.coverage-insert-next` once before checkpointing again, then finish with the `presentation-pass` workflow phase. Coverage alone is not completion; organize examples into styled sections/cards.
+## MDX-backed Content Blocks
+
+Use a connected `.mdx` Asset when editors should change a Content Block body visually while the document remains stored as a file.
+
+1. Create the `.mdx` file under `.webstudio/assets`, then upload it and keep the returned Asset ID.
+2. Inspect the Content Block and its Templates children. Every template referenced from MDX needs a unique top-level instance name.
+3. Connect the Asset with `connect-content-block-source`. Use a stable page-based `renderScope` for a direct occurrence.
+4. If the result returns `requiresConfirmation:true`, tell the user that connecting will replace the existing Body content. Repeat the same call with `confirmReplacement:true` only after approval.
+5. Edit the complete source with `edit-content-block-source`, or replace the complete frontmatter map with `update-content-block-frontmatter`.
+6. Inspect every returned diagnostic. Invalid MDX is preserved, not silently repaired.
+
+```sh
+webstudio upload-asset '{"asset":{"name":"article.mdx","type":"file","format":"mdx","meta":{}},"assetsDir":".webstudio/assets"}'
+webstudio connect-content-block-source '{"blockInstanceId":"","renderScope":"page:/articles/example","source":{"type":"asset","assetId":""}}'
+webstudio inspect-content-block-source '{"blockInstanceId":"","renderScope":"page:/articles/example"}'
+webstudio edit-content-block-source --input-file .temp/edit-content-block-source.json
+webstudio reload-content-block-source '{"blockInstanceId":"","renderScope":"page:/articles/example"}'
+webstudio migrate-content-block-template-references '{"assetIds":[""],"migration":{"type":"rename","from":"Old template name","to":"New template name"}}'
+```
+
+Prefer Markdown whenever it can represent the component and all authored properties. Use `` for a standard HTML element with authored properties Markdown cannot express. Use `` only for a uniquely named top-level Content Block template. Preserve unresolved template names and report their diagnostics.
+
+When a template is renamed or deleted, use `migrate-content-block-template-references` to update the affected MDX files. Its first call returns a plan with changed-file, update, omission, and diagnostic counts. Report the plan and repeat the exact request with its `confirmationToken` only after approval. A rename changes matching `ws:name` values. A removal deletes matching MDX elements. Invalid files remain unchanged and are reported in diagnostics.
+
+Use the dedicated connect, switch, inspect, edit, update-frontmatter, reload, and disconnect operations instead of creating or deleting the Content Block's `src` with generic prop tools. An expression-bound source inside a Collection also needs the occurrence's scoped values and a distinct stable `renderScope`. For example, use `source:{"type":"expression","value":"post.assetId"}` with `variables:{"post":{"assetId":""}}`.
+
+A source edit replaces the complete MDX document. A frontmatter update replaces the complete frontmatter property map. Inspect the current source first and preserve everything the user did not ask to change. Use `update-content-block-frontmatter` for MCP frontmatter edits. MDX-rendered elements are not persistent instance targets for generic `bind-props` or `update-text` calls. Preserve existing `mode:"readwrite"` bindings when encountered; they are valid only for exact direct paths into the connected document's frontmatter. Computed expressions and `$ref` values remain read-only.
+
+If an edit in a long-lived MCP session reports a revision conflict after another client saved the Asset, call `reload-content-block-source`, inspect the latest source, reapply the requested change, and retry. One-shot CLI calls refresh before each operation and normally cannot reproduce a stale session. Never overwrite the newer revision blindly. Use `disconnect-content-block-source` to remove the connection while leaving the Asset unchanged.
+
## Reporting CLI/MCP Issues
If a CLI/MCP tool gives a confusing error, crashes, hangs, produces invalid output, requires an undocumented workaround, or makes you inspect source code to understand normal usage, ask the user to report it in the Webstudio Discord `#help` channel: https://wstd.us/community.
@@ -1944,13 +1974,13 @@ source of truth. For tools with no required arguments, pass `{}`.
## Content Engine reference
-Assets resources query Markdown and JSON files stored in the Assets panel. The Builder and Webstudio MCP use the same structured query contract.
+Assets resources query Markdown, MDX, and JSON files stored in the Assets panel. The Builder and Webstudio MCP use the same structured query contract.
### MCP workflow
Use these tools in order when creating or changing an Assets resource:
-1. Call `get-asset-field-catalog` to inspect standard fields and the fields currently observed in Markdown frontmatter and JSON files.
+1. Call `get-asset-field-catalog` to inspect standard fields and the fields currently observed in Markdown or MDX frontmatter and JSON files.
2. Call `validate-asset-query` to check the query structure, field paths, operators, and bounded operation counts.
3. Call `preview-asset-query` with concrete values and inspect its results and diagnostics.
4. Save the query with `create-assets-resource` or `update-assets-resource`.
@@ -1960,7 +1990,7 @@ Omit `query` when creating a resource to use the default many-result query for a
### Fields
-Every asset has the standard fields below. Markdown frontmatter and JSON root fields appear under `properties`, for example `properties.slug` or `properties.author.name`. The field catalog reports their observed types, occurrence counts, optionality, and mixed-type state. A JSON content file must contain an object at its root.
+Every asset has the standard fields below. Markdown or MDX frontmatter and JSON root fields appear under `properties`, for example `properties.slug` or `properties.author.name`. The field catalog reports their observed types, occurrence counts, optionality, and mixed-type state. A JSON content file must contain an object at its root.
| Field | Observed type |
| --- | --- |
@@ -2047,7 +2077,7 @@ Choose `fields` and disable `includeMetadata` when the page needs only selected
### Asset reference metadata
-A plain local asset path in Markdown frontmatter or JSON properties keeps the backward-compatible URL string result. Wrap the path in an exact `$ref` object only when consumers need structured Asset Manager metadata:
+A plain local asset path in Markdown or MDX frontmatter, or in JSON properties, keeps the backward-compatible URL string result. Wrap the path in an exact `$ref` object only when consumers need structured Asset Manager metadata:
```yaml
featureImage:
@@ -2081,9 +2111,9 @@ External URLs remain ordinary strings. Existing local path strings also keep the
| `none` | Returns no file content. Use this for listings and any query that only needs fields or metadata. |
| `full` | Embeds the complete UTF-8 file content in the content database. `maxBytes` defaults to 1 MiB and cannot be set higher. The query fails if a selected file is larger. |
| `range` | Embeds a byte range selected by `offset` and `length` in the content database. `length` cannot exceed 256 KiB. |
-| `markdown-body-ref` | Stores a reference to a Markdown body. Webstudio filters and paginates first, then reads only the selected bodies from Assets. `maxBytes` defaults to 1 MiB and cannot be set higher. The query fails if a selected source file is larger. |
+| `markdown-body-ref` | Stores a reference to a Markdown or MDX body. Webstudio filters and paginates first, then reads only the selected bodies from Assets. `maxBytes` defaults to 1 MiB and cannot be set higher. The query fails if a selected source file is larger. |
-Returned content has `encoding` and `text`. A range also reports its `offset`, returned `length`, and total file size. Use `markdown-body-ref` for article pages. It keeps article bodies out of the published content database and resolves relative Markdown links when the selected body is loaded.
+Returned content has `encoding` and `text`. A range also reports its `offset`, returned `length`, and total file size. Use `markdown-body-ref` for Markdown or MDX article pages. It keeps article bodies out of the published content database and resolves relative links when the selected body is loaded.
### Preview diagnostics
@@ -2106,7 +2136,7 @@ Only `database.usedBytes` counts toward `database.maxBytes`. Do not add the quer
| `artifacts` | Optional query and merged compiled artifacts used by detailed Builder diagnostics. |
| `unresolved` | Optional query result before document references are resolved. It helps inspect the authored `$ref` values behind resolved output. |
-If the merged database approaches its limit, remove duplicate reachable resources first. Then remove unused output fields or narrow the candidate documents. Prefer `markdown-body-ref` over embedded `full` content for Markdown articles.
+If the merged database approaches its limit, remove duplicate reachable resources first. Then remove unused output fields or narrow the candidate documents. Prefer `markdown-body-ref` over embedded `full` content for Markdown or MDX articles.
### Document references
@@ -2116,7 +2146,7 @@ A document reference is an exact object with one string field:
{ "$ref": "[#]" }
```
-Markdown references can appear in YAML frontmatter. JSON references can appear anywhere in the document. Either format can reference Markdown or JSON. References do not run inside a Markdown body.
+Markdown and MDX references can appear in YAML frontmatter. JSON references can appear anywhere in the document. Any format can reference Markdown, MDX, or JSON. References do not run inside a Markdown or MDX body.
| Reference | Inserted value |
| --- | --- |
@@ -2148,7 +2178,7 @@ Resolve paths relative to the file containing the reference. JSON Pointer uses `
| Limit | Value |
| --- | --- |
-| Markdown frontmatter | 64 KiB |
+| Markdown/MDX frontmatter | 64 KiB |
| Frontmatter nesting depth | 8 |
| Frontmatter fields | 256 |
| Frontmatter string | 16 KiB |
diff --git a/docs/university/radix/accordion.md b/docs/university/radix/accordion.md
index 2db12c4d91..b0816aea7a 100644
--- a/docs/university/radix/accordion.md
+++ b/docs/university/radix/accordion.md
@@ -18,17 +18,17 @@ description: >-
The Accordion Component is in the "Components Panel" under the "Radix" section. Click on it or drag it onto the canvas. The Accordion will populate a template that's easy to adjust for your needs.
-
Radix UI components within Webstudio
+
Radix UI components within Webstudio
You can edit, delete or add more Accordions with ease by copying/pasting any of the "item" components within the Accordion.
-
+
## Changing an Accordion's content
To change the content of an Accordion that isn't currently displayed in the canvas, click on the "item content" instance that you want to change and it will be displayed.
-
+
## Using Collections within Accordions
diff --git a/docs/university/radix/collapsible.md b/docs/university/radix/collapsible.md
index da97f3859e..ace5a075e5 100644
--- a/docs/university/radix/collapsible.md
+++ b/docs/university/radix/collapsible.md
@@ -14,7 +14,7 @@ description: >-
The Collapsible Component is in the "Components Panel" under the "Radix" section. Click on it or drag it onto the canvas. The Collapsible will populate a template that's easy to adjust for your needs.
-
Radix UI Collapsible component within Webstudio
+
Radix UI Collapsible component within Webstudio
The Collapsible component consists of three main parts:
diff --git a/docs/university/self-hosting/README.md b/docs/university/self-hosting/README.md
index 3c455d696c..93770430c8 100644
--- a/docs/university/self-hosting/README.md
+++ b/docs/university/self-hosting/README.md
@@ -11,7 +11,7 @@ The Builder and Projects are hosted separately. The Builder is used to create Pr
## Builder
{% hint style="warning" %}
-While both the Builder and the generated site are open-source, self-hosting the Builder in production is more difficult and currently not recommended. You can still [self-host the Builder for development](../../contributing/contributing-for-developers.md#running-the-webstudio-project-using-github-codespaces), and of course, you can self-host the sites for production.
+While both the Builder and the generated site are open-source, self-hosting the Builder in production is more difficult and currently not recommended. You can still [self-host the Builder for development](../../contributing/contributions.md#running-the-webstudio-project-using-vs-code), and of course, you can self-host the sites for production.
{% endhint %}
## Projects
diff --git a/docs/university/self-hosting/cloudflare-pages.md b/docs/university/self-hosting/cloudflare-pages.md
index 2c1b0f4790..69640b3872 100644
--- a/docs/university/self-hosting/cloudflare-pages.md
+++ b/docs/university/self-hosting/cloudflare-pages.md
@@ -24,7 +24,7 @@ deployment.
### Prerequisites
-Export your project using one of the [export methods](./#exporting).
+Export your project using one of the [export methods](./#export-methods).
**How to upload your project to Cloudflare Pages:**
diff --git a/docs/university/self-hosting/download.md b/docs/university/self-hosting/download.md
index 80f1b474b4..6ddc79e239 100644
--- a/docs/university/self-hosting/download.md
+++ b/docs/university/self-hosting/download.md
@@ -12,14 +12,23 @@ See [export types](./#export-types) for more information about JavaScript applic
## Downloading your project
-1. Click “Publish”
-2. Click “Export”
+1. Select **Publish** in the top bar.
+2. Select **Export**.
- 
-3. Click “Build and download static site”
+
+
+
+
- 
-4. Wait up to a minute while the project is built then downloaded
+3. Set **Destination** to **Static**.
+4. Select **Build and download static site**.
+
+
+
+
+
+
+5. Wait while Webstudio builds and downloads the project.
The export contains a static site consisting of HTML, CSS, JS, and images ready to be uploaded to another platform.
diff --git a/docs/university/self-hosting/github-pages.md b/docs/university/self-hosting/github-pages.md
index 52b6b34c20..94a058a8ba 100644
--- a/docs/university/self-hosting/github-pages.md
+++ b/docs/university/self-hosting/github-pages.md
@@ -16,7 +16,7 @@ Learn how to upload your static site to GitHub Pages.
### Prerequisites
-Export your project using one of the [export methods](./#exporting).
+Export your project using one of the [export methods](./#export-methods).
**How to deploy your project to GitHub Pages:**
diff --git a/docs/university/self-hosting/netlify.md b/docs/university/self-hosting/netlify.md
index 9b56607cab..4ccc0da95d 100644
--- a/docs/university/self-hosting/netlify.md
+++ b/docs/university/self-hosting/netlify.md
@@ -91,7 +91,7 @@ Netlify uses a trailing slash for generated directory index pages. Review the
### Prerequisites
-- Export your project using one of the [export methods](./#exporting).
+- Export your project using one of the [export methods](./#export-methods).
**How to upload your project to Netlify:**
diff --git a/docs/university/self-hosting/vercel.md b/docs/university/self-hosting/vercel.md
index 256eb1bf00..6b67fdb944 100644
--- a/docs/university/self-hosting/vercel.md
+++ b/docs/university/self-hosting/vercel.md
@@ -21,7 +21,7 @@ How to Export and Self-Host Your Site on Vercel
### **Prerequisites**
* Install the [Webstudio CLI](../cli.md)
-* [Build](../cli.md#sync-and-build) your project locally
+* [Build](../cli.md#export-and-build-a-project) your project locally
Once you've built the project locally, you can use the [Vercel CLI](https://vercel.com/docs/cli) to deploy your app directly to Vercel:
@@ -49,7 +49,7 @@ paths with project configuration. Review the
### Prerequisites
-* Export your project using one of the [export methods](./#exporting)
+* Export your project using one of the [export methods](./#export-methods)
* Upload/commit your project to a Git provider (GitHub, Bitbucket, GitLab)
**How to upload your project to Netlify:**
diff --git a/docs/university/webstudio-ai.md b/docs/university/webstudio-ai.md
index f9009fee6e..e72319d622 100644
--- a/docs/university/webstudio-ai.md
+++ b/docs/university/webstudio-ai.md
@@ -1,52 +1,14 @@
-# 🤖 Webstudio AI
+# 🤖 Build with AI
-Webstudio AI has been discontinued and is no longer maintained.
+The original Webstudio AI assistant has been discontinued. Use [Webstudio MCP](mcp.md) when you want an AI agent to build or edit a real Webstudio project. The agent and the visual Builder operate on the same project, so you can review and continue every change visually.
-Separately, the Webstudio team has launched [Inception](inception.md) — a **standalone product** designed specifically for creative design exploration, powered by a much more advanced AI foundation.
+## Inception
-Inception is **not** a new version of Webstudio AI and **not** a replacement for it. Webstudio AI was an experimental open-source project; Inception is a completely independent tool with a different purpose and workflow.
-
-***
-
-### ❗ Important clarification: Inception is _not_ the replacement for the builder’s AI
-
-Some users assumed that Inception replaced the AI inside the Webstudio builder — but that’s not the case.
-
-We removed the old builder AI because it was outdated, low-usage, and no longer delivering value. It wasn’t removed to make room for Inception, and the two products are unrelated.
-
-A **new AI system for the builder** will be introduced in the future, but it is being rebuilt from the ground up and will be integrated directly into the builder itself.
-
-***
-
-### ❓ Is Inception included in existing plans?
-
-**Short answer: No — Inception is not included in any existing plan.** This applies to lifetime deals, monthly subscriptions, and all previous purchases.
-
-Inception is its own product, with its own pricing, because it uses the most advanced models available today — models that are significantly more expensive to run than the older generation.
-
-***
-
-### 🧠 What happened to the old AI assistant in the builder?
-
-The previous AI assistant (originally released in 2023 using GPT-4) no longer made sense to maintain:
-
-* it was barely used
-* it didn’t reflect the capabilities of today’s AI
-* modern agentic, reasoning-capable models require an entirely new architecture
-
-Rather than keeping outdated AI code alive, we’re **rewriting the entire AI layer** for the builder.
-
-The upcoming version will:
-
-* support **multiple AI models**
-* include at least one **free or very low-cost option**
-* offer access to advanced models like **Claude** when needed
-* introduce a **chat interface** directly in the builder, enabling visual actions and more
+[Inception](inception.md) is a separate AI product for exploring visual directions and generating web designs. Copy its output into Webstudio when you want to continue refining the design in the Builder. Inception has its own account and usage-based pricing.
## Related
-- [Inception](inception.md) – Explore Webstudio's standalone AI design exploration app
-- [Expression editor](foundations/expression-editor.md) – Write expressions and logic in Webstudio
-- [Data variables](foundations/variables.md) – Work with dynamic data and resources
-- [CMS](foundations/cms.md) – Manage content with Webstudio's built-in CMS
-- [Roadmap & Links](../basics/roadmap-and-links.md) – See what features are coming next
+- [Webstudio MCP](mcp.md) – Let an AI agent build and edit a project
+- [CLI](cli.md) – Install and run Webstudio's command-line tools
+- [Inception guide](inception.md) – Learn the Inception workflow
+- [Webstudio features](https://webstudio.is/features) – Review the current product capabilities
diff --git a/packages/cli/src/commands/api-command-docs.test.ts b/packages/cli/src/commands/api-command-docs.test.ts
index aaf2c53686..0b122e1ca4 100644
--- a/packages/cli/src/commands/api-command-docs.test.ts
+++ b/packages/cli/src/commands/api-command-docs.test.ts
@@ -269,7 +269,7 @@ test("directs agents to deferred Markdown bodies", () => {
const contents = readCliDoc(document);
expect(contents).toContain('content.mode:"markdown-body-ref"');
expect(contents).toContain("document reference");
- expect(contents).toContain("selected Markdown");
+ expect(contents).toContain("selected files");
}
const tools = createMetadataOnlyMcpAdapter().listTools();
diff --git a/packages/cli/src/commands/schema.test.ts b/packages/cli/src/commands/schema.test.ts
index 4f8336fa02..e3ab0f0a99 100644
--- a/packages/cli/src/commands/schema.test.ts
+++ b/packages/cli/src/commands/schema.test.ts
@@ -168,7 +168,7 @@ test("prints compact mcp tool summaries as json by default", () => {
inputSchema,
})
);
- expect(JSON.stringify(handshakePayload).length).toBeLessThan(215_000);
+ expect(JSON.stringify(handshakePayload).length).toBeLessThan(216_000);
expect(
JSON.stringify(
expectedTools.find(({ name }) => name === "insert-page-transfer-item")
diff --git a/packages/cli/src/content-engine-reference.ts b/packages/cli/src/content-engine-reference.ts
index 8f39bdef6c..29c63d4442 100644
--- a/packages/cli/src/content-engine-reference.ts
+++ b/packages/cli/src/content-engine-reference.ts
@@ -80,7 +80,7 @@ const contentRows = [
},
{
value: "markdown-body-ref",
- description: `Stores a reference to a Markdown body. Webstudio filters and paginates first, then reads only the selected bodies from Assets. \`maxBytes\` defaults to ${formatBytes(contentEngineLimits.hydratedFileBytes)} and cannot be set higher. The query fails if a selected source file is larger.`,
+ description: `Stores a reference to a Markdown or MDX body. Webstudio filters and paginates first, then reads only the selected bodies from Assets. \`maxBytes\` defaults to ${formatBytes(contentEngineLimits.hydratedFileBytes)} and cannot be set higher. The query fails if a selected source file is larger.`,
},
] as const satisfies readonly ReferenceRow[];
@@ -255,7 +255,10 @@ const queryLimitsTable = table({
const contentLimitsTable = table({
headings: ["Limit", "Value"],
rows: [
- ["Markdown frontmatter", formatBytes(contentEngineLimits.frontmatterBytes)],
+ [
+ "Markdown/MDX frontmatter",
+ formatBytes(contentEngineLimits.frontmatterBytes),
+ ],
["Frontmatter nesting depth", String(contentEngineLimits.frontmatterDepth)],
["Frontmatter fields", String(contentEngineLimits.frontmatterFields)],
[
@@ -300,13 +303,13 @@ export const renderContentEngineReferenceMarkdown = ({
return [
`${"#".repeat(headingLevel)} Content Engine reference`,
"",
- "Assets resources query Markdown and JSON files stored in the Assets panel. The Builder and Webstudio MCP use the same structured query contract.",
+ "Assets resources query Markdown, MDX, and JSON files stored in the Assets panel. The Builder and Webstudio MCP use the same structured query contract.",
"",
heading(1, "MCP workflow"),
"",
"Use these tools in order when creating or changing an Assets resource:",
"",
- "1. Call `get-asset-field-catalog` to inspect standard fields and the fields currently observed in Markdown frontmatter and JSON files.",
+ "1. Call `get-asset-field-catalog` to inspect standard fields and the fields currently observed in Markdown or MDX frontmatter and JSON files.",
"2. Call `validate-asset-query` to check the query structure, field paths, operators, and bounded operation counts.",
"3. Call `preview-asset-query` with concrete values and inspect its results and diagnostics.",
"4. Save the query with `create-assets-resource` or `update-assets-resource`.",
@@ -316,7 +319,7 @@ export const renderContentEngineReferenceMarkdown = ({
"",
heading(1, "Fields"),
"",
- "Every asset has the standard fields below. Markdown frontmatter and JSON root fields appear under `properties`, for example `properties.slug` or `properties.author.name`. The field catalog reports their observed types, occurrence counts, optionality, and mixed-type state. A JSON content file must contain an object at its root.",
+ "Every asset has the standard fields below. Markdown or MDX frontmatter and JSON root fields appear under `properties`, for example `properties.slug` or `properties.author.name`. The field catalog reports their observed types, occurrence counts, optionality, and mixed-type state. A JSON content file must contain an object at its root.",
"",
standardFieldsTable,
"",
@@ -368,7 +371,7 @@ export const renderContentEngineReferenceMarkdown = ({
"",
heading(1, "Asset reference metadata"),
"",
- "A plain local asset path in Markdown frontmatter or JSON properties keeps the backward-compatible URL string result. Wrap the path in an exact `$ref` object only when consumers need structured Asset Manager metadata:",
+ "A plain local asset path in Markdown or MDX frontmatter, or in JSON properties, keeps the backward-compatible URL string result. Wrap the path in an exact `$ref` object only when consumers need structured Asset Manager metadata:",
"",
"```yaml",
"featureImage:",
@@ -399,7 +402,7 @@ export const renderContentEngineReferenceMarkdown = ({
"",
renderRows(contentRows),
"",
- "Returned content has `encoding` and `text`. A range also reports its `offset`, returned `length`, and total file size. Use `markdown-body-ref` for article pages. It keeps article bodies out of the published content database and resolves relative Markdown links when the selected body is loaded.",
+ "Returned content has `encoding` and `text`. A range also reports its `offset`, returned `length`, and total file size. Use `markdown-body-ref` for Markdown or MDX article pages. It keeps article bodies out of the published content database and resolves relative links when the selected body is loaded.",
"",
heading(1, "Preview diagnostics"),
"",
@@ -415,7 +418,7 @@ export const renderContentEngineReferenceMarkdown = ({
rows: [...diagnosticRows, ...optionalDiagnosticRows],
}),
"",
- "If the merged database approaches its limit, remove duplicate reachable resources first. Then remove unused output fields or narrow the candidate documents. Prefer `markdown-body-ref` over embedded `full` content for Markdown articles.",
+ "If the merged database approaches its limit, remove duplicate reachable resources first. Then remove unused output fields or narrow the candidate documents. Prefer `markdown-body-ref` over embedded `full` content for Markdown or MDX articles.",
"",
heading(1, "Document references"),
"",
@@ -425,7 +428,7 @@ export const renderContentEngineReferenceMarkdown = ({
'{ "$ref": "[#]" }',
"```",
"",
- "Markdown references can appear in YAML frontmatter. JSON references can appear anywhere in the document. Either format can reference Markdown or JSON. References do not run inside a Markdown body.",
+ "Markdown and MDX references can appear in YAML frontmatter. JSON references can appear anywhere in the document. Any format can reference Markdown, MDX, or JSON. References do not run inside a Markdown or MDX body.",
"",
table({
headings: ["Reference", "Inserted value"],
diff --git a/packages/cli/src/docs.generated.ts b/packages/cli/src/docs.generated.ts
index bbfec222a7..3a8dd1649d 100644
--- a/packages/cli/src/docs.generated.ts
+++ b/packages/cli/src/docs.generated.ts
@@ -2,15 +2,15 @@
// Edit markdown files in src/docs instead.
export const cliDocs = {
"api-use-cases":
- '# CLI API Use Cases\n\n## Link/configure one project\n\nCommands:\n\n- webstudio init --link --json\n\nNotes:\n\n- Writes local project id and global origin/token config.\n\n## Import synced project bundle into another project\n\nCommands:\n\n- webstudio sync\n- webstudio import --to \n- MCP tool: import {"to":""}\n\nNotes:\n\n- Imports local `.webstudio/data.json` into the destination project.\n- Destination share link must allow build/import access.\n- Use `--skip-assets` only when asset rows and files should not be imported.\n\n## Identify current token\n\nCommands:\n\n- MCP tool: whoami {}\n\n## Check token permissions\n\nCommands:\n\n- webstudio permissions --json\n\n## Inspect project/build/version\n\nCommands:\n\n- MCP tool: inspect {}\n- MCP tool: snapshot {"include":["pages","instances","styles"]}\n\n## Discover CLI/API capabilities\n\nCommands:\n\n- webstudio schema api\n- webstudio schema mcp\n- webstudio man --json\n- webstudio man llm --json\n- MCP tool: meta.index {}\n- MCP tool: meta.guide {"brief":"Create a pricing page"}\n- MCP tool: meta.get-more-tools {"brief":"update-styles"}\n- webstudio mcp list-resources\n- webstudio mcp read-resource webstudio://project/guide\n- webstudio mcp read-resource webstudio://project/expressions\n\nNotes:\n\n- Use `webstudio schema mcp` for a compact machine-readable MCP tool overview. Add `--verbose` or use focused `meta.get-more-tools` calls only when exact input schemas are needed.\n- Use focused MCP tools for discovery first: `meta.index`, `meta.guide`, `meta.get-more-tools`, `components.list`, `components.summary`, `components.search`, `components.get`, `templates.list`, and `templates.get`. Protocol clients can use `resources/list` and `resources/read`; shell agents can use `webstudio mcp list-resources` and `webstudio mcp read-resource `. Read longer resources such as `webstudio://project/tools` and `webstudio://project/components` only when focused tools are insufficient.\n- `components.summary` returns counts by default; request `{"detail":"components","limit":20}` for paginated entries. Registry list tools return compact metadata, while `components.get` and `templates.get` return focused full details.\n- Read `webstudio://project/expressions` before authoring unfamiliar computed text, prop bindings, resource expressions, actions, or Collection item bindings.\n- From a shell, call one MCP tool with the shortcut form `webstudio \'\'`, for example `webstudio components.summary`. The explicit equivalent is `webstudio mcp single-op-call \'\'`. Use `--input-file` for large payloads.\n\n## Inspect external shadcn registry items\n\nCommands:\n\n- webstudio registry inspect --source https://example.com/r/registry.json --item button --json\n- webstudio registry inspect --source ./registry.json --item dialog --json\n- webstudio registry inspect --source https://example.com/r/button.json --json\n\nNotes:\n\n- Reads a local or remote registry item without installing files or changing the configured Webstudio project.\n- Returns the item name, description, package and registry dependencies, file paths/targets, available docs, and a read-only compatibility report.\n- The report explicitly says whether installation or editable-component conversion is supported, lists declared requirements and manual steps, and says when arbitrary source code was not analyzed.\n- This is an inspection step only. It does not install files or change the configured project.\n\n## Understand what MCP can do\n\nCommands:\n\n- webstudio man mcp\n- MCP tool: meta.index {}\n- MCP tool: meta.guide {"brief":"What can Webstudio MCP do?"}\n\nMCP lets agents work on one configured Webstudio project. Agents can:\n\n- Inspect the linked project, token permissions, and latest editable build.\n- Read selected project data for audits, migrations, and repair.\n- Search values and ids across every Builder namespace without sending full project data to the model.\n- Audit accessibility, security, SEO, performance settings, unused assets, ineffective Collection styles, and unused or duplicate style data.\n- Create and edit pages, folders, redirects, breakpoints, and page templates.\n- Create pages from reusable templates.\n- Update page metadata, SEO fields, auth settings, and marketplace metadata.\n- Insert components and styled JSX sections.\n- Create data-driven lists, grids, cards, and similar repeated UI from array or object data in one Collection operation.\n- Move, copy, wrap, unwrap, convert, rename, retag, and delete elements.\n- Update text, rich text, props, bindings, and actions.\n- Create and update local styles, design tokens, style sources, and CSS variables.\n- Create static data variables and JSON variables.\n- Create HTTP, GraphQL, and system resources.\n- Use system resources for sitemap, current date, and assets.\n- Bind resources to rendered data or form/action props.\n- Manage nested asset folders and upload, inspect, move, duplicate, download, replace, delete, and inspect usage for assets.\n- Publish, unpublish, inspect publish jobs, and manage custom domains.\n- Start preview, capture screenshots, compare screenshot diffs, and use OCR when installed.\n\n## Inspect and refresh MCP session cache\n\nCommands:\n\n- MCP tool: status {}\n- MCP tool: status {"verbose":true}\n- MCP tool: refresh {"namespaces":["pages","instances","styles"]}\n- MCP tool: reset-session {}\n\nNotes:\n\n- Use status before a task to understand the cached ProjectSession state.\n- Use status with `{"verbose":true}` only when debugging full namespaces, freshness, compatibility, or diagnostics.\n- Use refresh when project data may have changed outside the current MCP session.\n- Use reset-session when local cached state is corrupt or incompatible.\n\n## Visually verify rendered work with AI vision\n\nCommands:\n\n- MCP tool: preview.start {"host":"127.0.0.1","port":5173}\n- MCP tool: preview.status {}\n- MCP tool: preview.stop {}\n- MCP tool: screenshot {"path":"/","output":".webstudio/screenshots/home-current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot {"path":"/pricing","output":".webstudio/screenshots/pricing-current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot {"baseUrl":"http://127.0.0.1:5177","path":"/pricing","output":".webstudio/screenshots/pricing-current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot.diff {"baselinePath":".webstudio/screenshots/home-before.png","currentPath":".webstudio/screenshots/home-current.png","outputDir":".webstudio/screenshots/diff"}\n- MCP tool: screenshot.diff {"baselinePath":".webstudio/screenshots/home-before.png","currentPath":".webstudio/screenshots/home-current.png","outputDir":".webstudio/screenshots/diff","expectedText":["Pricing","Start free"]}\n- MCP tool: screenshot.diff {"baselinePath":".webstudio/screenshots/home-before.png","currentPath":".webstudio/screenshots/home-current.png","outputDir":".webstudio/screenshots/diff","expectedVisual":{"maxMismatchPercentage":2,"maxChangedRegions":3,"dominantColorChange":{"channel":"luminance","direction":"increase","minMagnitude":10}}}\n- MCP tool: screenshot.diff {"baselinePath":".webstudio/screenshots/pricing-before.png","currentPath":".webstudio/screenshots/pricing-current.png","outputDir":".webstudio/screenshots/diff"}\n- MCP tool: vision.install-ocr {"confirm":true}\n\nNotes:\n\n- Enter this workflow only when the user explicitly requests visual verification or opts in after being asked. Do not start preview, screenshots, diffs, OCR, or rendered audits automatically after a mutation.\n- `preview.status` reports whether generated output is `stale`. When no preview is running, `url`, `pid`, and `mode` are omitted. When present, `renderedProjectVersion` is the last project version materialized into the preview.\n- A managed `screenshot` or another `preview.start` refreshes stale generated output before capture.\n\n- After opt-in, use this so a vision-capable AI can see the generated site from the current MCP session. Use `path`; never pass a Webstudio Builder/share URL or capture Builder chrome.\n- For multi-page work, capture every changed page by `path` through the same preview server; no click navigation is required.\n- Iterative mode is the default: after MCP mutations, path screenshots ensure generated project files are current, wait for the exact session version, and perform an ordinary page reload without Vite HMR. The preview server and browser stay alive. Use `{"mode":"production"}` only for release-like verification; rendered audit does this automatically.\n- Calling `preview.start` after a committed mutation restarts a stale iterative server so external browsers and HTTP clients receive the newly generated project.\n- Do not call `preview.start` through one-shot `webstudio mcp single-op-call`: it is long-lived. From a shell, use `webstudio mcp run` with preview.start, screenshot, and preview.stop in one shared process, or use a real long-running MCP client.\n- From one-shot shell calls or another process, pass `baseUrl` with `path` to capture an already-running preview/site without generating, building, starting, or restarting preview.\n- Use preview.stop only in the same long-running MCP server or `webstudio mcp run` process that started preview. A separate one-shot `single-op-call` process does not own another process\'s preview controller.\n- Use waitForSelector when the rendered app has a reliable ready marker, waitUntil:"networkidle" for network-heavy pages, and waitForTimeout only for final visual settling.\n- The screenshot timeout bounds browser capture after the preview is ready. A timeout returns `SCREENSHOT_TIMEOUT`, resets the reusable browser session, and releases the shared preview lifecycle for cleanup.\n- Preview installs generated app dependencies under `.webstudio/preview` and reuses them across regenerations.\n- Do not add generated-preview dependencies to the repository root `package.json` or `pnpm-lock.yaml`.\n- When launcher metadata is available, Preview reuses a supported npm or pnpm launcher. Without launcher metadata, it defaults to npm.\n- If dependency installation fails, check the reported package-manager path and network configuration, then reinstall or update the Webstudio CLI if the problem persists.\n- When a baseline exists, use screenshot.diff once per baseline/current page or viewport pair to get changed regions, OCR textAnalysis, and diff artifact paths before deciding whether the result matches. Pass expectedText for explicit pass/fail current-screen text assertions with found and missing text. Pass expectedVisual for pass/fail limits on pixel mismatch percentage, changed-region count, or the overall dominant color/brightness direction.\n- If screenshot.diff reports OCR unavailable and the user agrees to install it, call vision.install-ocr {"confirm":true}; otherwise continue with pixel diff and visual inspection.\n- Compare the PNG, OCR text evidence, and diff artifacts against the user\'s intent for layout, typography, colors, spacing, imagery, and responsive framing; then iterate with focused mutations.\n- Root CLI equivalent: `webstudio screenshot --path /pricing --output pricing.png` generates a temporary production preview, captures that route, and stops the server. For repeated captures, keep `webstudio preview` running and pass its absolute URL to `webstudio screenshot`.\n\n## List pages\n\nCommands:\n\n- MCP tool: list-pages {}\n- MCP tool: list-folders {}\n\n## Read page by id\n\nCommands:\n\n- MCP tool: get-page {"pageId":""}\n\n## Read page by path\n\nCommands:\n\n- MCP tool: get-page-by-path {"path":"/pricing"}\n\n## Create page\n\nCommands:\n\n- MCP tool: create-page {"name":"Pricing","path":"/pricing"}\n- MCP tool: create-page {"name":"Pricing","path":"/pricing","title":"Pricing","meta":{"description":"Plans for teams"}}\n\nNotes:\n\n- `name`, `path`, page `title`, and metadata text fields accept plain fixed values.\n- For computed page titles or metadata, send JavaScript expression code such as `pageTitle ?? "Pricing"`.\n\n## Update page settings/metadata\n\nCommands:\n\n- MCP tool: update-page {"pageId":"","values":{"title":"Pricing","meta":{"description":"Plans","status":200}}}\n- MCP tool: update-page {"pageId":"","values":{"meta":{"auth":{"method":"basic","login":"","password":""}}}}\n\nNotes:\n\n- Page `title` and metadata text fields accept plain fixed values.\n- For computed page titles or metadata, send JavaScript expression code such as `pageTitle ?? "Pricing"`.\n- Page `status` accepts a fixed HTTP status code as a number from 200 through 599 or a JavaScript expression string for a dynamic status.\n\n## Read project settings\n\nCommands:\n\n- MCP tool: get-project-settings {}\n\nNotes:\n\n- Read `meta.agentInstructions` before making project changes. It contains the project\'s own guidance for AI agents.\n- Agent instructions are shared project guidance. Do not store credentials or other secrets there.\n\n## Update project settings\n\nCommands:\n\n- MCP tool: update-project-settings {"meta":{"siteName":"Acme"}}\n- MCP tool: update-project-settings {"meta":{"agentInstructions":"Use existing design tokens and keep product copy concise."}}\n\n## Read marketplace product\n\nCommands:\n\n- MCP tool: get-marketplace-product {}\n\n## Update marketplace product\n\nCommands:\n\n- MCP tool: update-marketplace-product {"category":"pageTemplates","name":"Acme Template","thumbnailAssetId":"asset-id","author":"Acme Studio","email":"hello@example.com","website":"https://example.com","issues":"","description":"Reusable template project for Acme landing pages."}\n\n## Submit marketplace product\n\nCommands:\n\n- MCP tool: upload-asset {"asset":{"name":"marketplace-thumbnail.png","type":"image","format":"png","meta":{"width":1200,"height":630}},"assetsDir":".webstudio/assets"}\n- MCP tool: update-marketplace-product {"category":"pageTemplates","name":"Acme Template","thumbnailAssetId":"","author":"Acme Studio","email":"hello@example.com","website":"https://example.com","issues":"","description":"Reusable template project for Acme landing pages."}\n- MCP tool: publish {"target":"production"}\n- MCP tool: submit-marketplace-product {"acknowledgePublicSubmission":true}\n\nNotes:\n\n- Wait for the production publish to complete before submitting the product for review.\n- Submission requires complete, valid marketplace metadata.\n\n## List redirects\n\nCommands:\n\n- MCP tool: list-redirects {}\n\n## Create redirect\n\nCommands:\n\n- MCP tool: create-redirect {"old":"/old","new":"/new","status":301}\n\n## Update redirect\n\nCommands:\n\n- MCP tool: update-redirect {"old":"/old","values":{"new":"/newer","status":302}}\n- MCP tool: update-redirect {"old":"/old","values":{"status":null}}\n\n## Delete redirect\n\nCommands:\n\n- MCP tool: delete-redirect {"old":"/old"}\n\n## Set redirects\n\nCommands:\n\n- MCP tool: set-redirects {"redirects":[{"old":"/old","new":"/new","status":"301"}]}\n\n## List breakpoints\n\nCommands:\n\n- MCP tool: list-breakpoints {}\n\n## Create breakpoint\n\nCommands:\n\n- MCP tool: create-breakpoint {"label":"Tablet","maxWidth":991}\n\n## Update breakpoint\n\nCommands:\n\n- MCP tool: update-breakpoint {"breakpointId":"tablet","values":{"label":"Tablet","maxWidth":1023}}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","values":{"condition":null,"minWidth":768}}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","values":{"minWidth":null,"maxWidth":null,"condition":"(hover: hover)"}}\n\n## Delete breakpoint\n\nCommands:\n\n- MCP tool: delete-breakpoint {"breakpointId":"tablet"}\n\n## Duplicate page\n\nCommands:\n\n- MCP tool: duplicate-page {"pageId":"","name":"Pricing Copy","path":"/pricing-copy"}\n- MCP tool: duplicate-page {"pageId":"","name":"Paris","path":"/paris","substitutions":{"text":{"London":"Paris"},"variables":{"city":{"type":"string","value":"Paris"}}}}\n- webstudio duplicate-page --page --name Paris --path /paris --substitutions \'{"text":{"London":"Paris"},"variables":{"city":{"type":"string","value":"Paris"}}}\' --json\n\nNotes:\n\n- Text substitutions replace exact fixed text only in the duplicated page\'s text children, string props, title, and metadata.\n- Variable substitutions are keyed by copied source-variable name and use typed variable values. The operation rejects missing or ambiguous names without committing a partial duplicate.\n- Existing expressions and cloned variable/resource references keep their remapped ids.\n\n## List page templates\n\nCommands:\n\n- MCP tool: list-page-templates {}\n\n## Create page template\n\nCommands:\n\n- MCP tool: create-page-template {"name":"Landing Template","title":"Landing"}\n\n## Update page template\n\nCommands:\n\n- MCP tool: update-page-template {"templateId":"","values":{"name":"Article Template","meta":{"description":"Reusable article layout"}}}\n\n## Delete page template\n\nCommands:\n\n- MCP tool: delete-page-template {"templateId":""}\n\n## Duplicate page template\n\nCommands:\n\n- MCP tool: duplicate-page-template {"templateId":""}\n\n## Reorder page template\n\nCommands:\n\n- MCP tool: reorder-page-template {"sourceTemplateId":"","targetTemplateId":"","position":"before"}\n\n## Create page from template\n\nCommands:\n\n- MCP tool: create-page-from-template {"templateId":"","name":"Landing","path":"/landing"}\n\n## Delete page\n\nCommands:\n\n- MCP tool: delete-page {"pageId":""}\n\n## List folders\n\nCommands:\n\n- MCP tool: list-folders {}\n- MCP tool: list-pages {}\n\n## Create folder\n\nCommands:\n\n- MCP tool: create-folder {"name":"Blog","slug":"blog"}\n\n## Update folder\n\nCommands:\n\n- MCP tool: update-folder {"folderId":"","values":{"name":"Blog","slug":"blog"}}\n\n## Delete folder\n\nCommands:\n\n- MCP tool: delete-folder {"folderId":""}\n\n## List element instances\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/","maxDepth":3}\n\n## Inspect one element instance\n\nCommands:\n\n- MCP tool: inspect-instance {"instanceId":"","include":["props","styles","children"]}\n\n## Insert authored JSX or one component template\n\nCommands:\n\n- MCP tool: insert-fragment {"parentInstanceId":"","fragment":"Product OS"}\n- MCP tool: insert-component {"parentInstanceId":"","component":"@webstudio-is/sdk-components-react-radix:Switch"}\n- MCP tool: insert-component {"parentInstanceId":"","component":"Form"}\n\nNotes:\n\n- Use MCP `insert-fragment` as the default way to author styled component trees. It converts JSX to a structured fragment before mutation.\n- Use only exact component ids returned by `components.search`, `components.get`, or `templates.get`. Never derive or guess component ids.\n- The `ws:` namespace contains specific Webstudio core components; it is not HTML-tag shorthand. Use `` for a native `div` and `` for a native form, never `` or ``.\n- For Webstudio\'s complete form structure, discover the Form component and insert its automatic template with `insert-component` using component `"Form"`.\n- MCP receives JSX as a JSON string because MCP arguments are JSON. The CLI converts it locally before the runtime mutation, so the project session receives structured Webstudio data, not JSX source.\n- In `insert-fragment` JSX, use ``ws:style={css`...`}`` for Webstudio-native CSS, or use React-style object syntax such as `style={{ padding: 24 }}` when that is simpler. Both forms create editable Webstudio style data.\n- Do not access host globals or dynamic code APIs in JSX fragments, including `process`, `globalThis`, `eval`, `Function`, or `constructor`.\n- Use Webstudio prop names such as `class` and `for`; do not use React aliases `className` or `htmlFor`.\n- Use Webstudio actions for event/action props, for example `onClick={new ActionValue(["event"], expression\\`console.log(event)\\`)}`. Do not pass JavaScript functions such as `onClick={() => ...}`.\n- Plain prop values must be JSON-compatible: `null`, strings, booleans, finite numbers, arrays, and plain objects. Do not pass `undefined`, `Symbol`, `BigInt`, `NaN`, `Infinity`, `Date`, `Map`, `Set`, class instances, or circular objects; omit the prop, use plain data, or use `expression`/`ActionValue` when the value is dynamic.\n- Template-backed components used in JSX must include required child/part components explicitly under the same parent structure as the template, for example ``.\n- Webstudio applies a registered template automatically when using `insert-component`, so composed components such as Switch include required child parts and styles.\n- Use `components.list`, `components.summary`, `components.search`, `components.get`, `templates.list`, and `templates.get` to discover known registry items, component ids, props, templates, insertability, and content model. Read `webstudio://project/components` only when those focused tools are insufficient.\n- Component/template registry items use a shadcn-compatible top-level shape plus Webstudio-specific superset metadata in `meta`. They are for Builder/MCP discovery, not a published shadcn install registry yet.\n- Known components with `contentModel.category: "none"` are not standalone-insertable; insert their root component template instead so required providers/parents are included.\n- Unknown custom component ids are a low-level extension mechanism, not a discovery fallback. Agents must not synthesize them.\n\n## Make a region editable in Content mode\n\nCommands:\n\n- MCP tool: insert-component {"parentInstanceId":"","component":"ws:block"}\n- MCP tool: inspect-instance {"instanceId":"","include":["children"]}\n\nNotes:\n\n- When a page will be handed to a Content-mode editor, wrap every region they should be able to edit in a Content Block (`ws:block`). Content-mode editors can edit text and supported props only in Content Block descendants. Content outside those blocks remains read-only, even when it looks like ordinary editable text.\n- Put reusable insertable options inside the Content Block\'s `ws:block-template` child. A template is source material, not editor content: editors cannot edit or delete it directly. When an editor inserts a template, its copy becomes a direct child of the Content Block and is editable.\n- Before handing off a page, verify with `inspect-instance` that the intended text, images, and links are inside a Content Block, and that templates include all required styling because Content-mode editors cannot use the Style panel.\n\n## Move elements\n\nCommands:\n\n- MCP tool: move-instance {"moves":"moves.json contents"}\n\nNotes:\n\n- Use `position: "end"` to append an instance. Repeating this for A and then B preserves the final order A, B.\n- A numeric `insertIndex` addresses the target parent\'s children before the moved instance is removed. Use it for exact placement; do not calculate the last index to append.\n- Moves in one `moves` array are applied sequentially in array order.\n\n## Clone element subtree\n\nCommands:\n\n- MCP tool: clone-instance {"sourceInstanceId":"","targetParentInstanceId":""}\n\n## Delete element subtree\n\nCommands:\n\n- MCP tool: delete-instance {"instanceIds":[""]}\n\n## List text/expression children\n\nCommands:\n\n- MCP tool: list-texts {"pagePath":"/"}\n\n## Update text child\n\nCommands:\n\n- MCP tool: update-text {"instanceId":"","childIndex":0,"text":"Launch faster"}\n\n## Replace bounded literal text\n\nCommands:\n\n- MCP tool: replace-text {"find":"Start free","replace":"Get started","match":"exact","pagePath":"/pricing","limit":20}\n\nNotes:\n\n- This changes only literal text children, never expression children. Scope it to pagePath or pageId and set a limit before a broad replacement.\n\n## Replace bounded static prop text\n\nCommands:\n\n- MCP tool: replace-prop-text {"find":"old.example.com","replace":"www.example.com","match":"substring","names":["href","code"],"limit":20}\n\nNotes:\n\n- This changes only static string props such as href, alt, aria-label, title, and HTML embed code. It never changes expressions, resources, actions, assets, or other dynamic bindings. Use names or instanceIds and a limit to narrow the change.\n\n## Replace bounded resource text\n\nCommands:\n\n- MCP tool: replace-resource-text {"find":"api.old.example.com","replace":"api.example.com","fields":["url"],"limit":20}\n\nNotes:\n\n- This changes resource names and fixed URL literals only. It skips dynamic URL expressions, headers, search parameters, request bodies, and GraphQL query code.\n\n## Update props\n\nCommands:\n\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: replace-prop-text {"find":"Old label","replace":"New label","names":["aria-label","title"],"limit":20}\n\nNotes:\n\n- Use this for fixed prop values such as `aria-label`, `alt`, `id`, static `href`, and other direct string/number/boolean/json prop values.\n\n## Add JSON-LD structured data\n\nCommands:\n\n- MCP tool: components.get {"component":"JsonLd"}\n- MCP tool: insert-component {"parentInstanceId":"","component":"JsonLd"}\n- MCP tool: update-props {"updates":[{"instanceId":"","name":"code","type":"string","value":"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Organization\\",\\"name\\":\\"Acme\\"}"}]}\n- MCP tool: bind-props {"bindings":[{"instanceId":"","name":"code","binding":{"type":"expression","value":"({ \'@context\': \'https://schema.org\', \'@type\': \'Article\', headline: post.title })"}}]}\n- MCP tool: audit {"scopes":["seo"],"pagePath":"/"}\n\nNotes:\n\n- Prefer placing `JsonLd` inside `HeadSlot`.\n- For fixed structured data, store `code` as a JSON object or array encoded as a compact string. The Builder formats it for editing.\n- For structured data containing runtime values, use `bind-props` with an expression that evaluates directly to an object or array. Do not call `JSON.stringify` or assemble JSON with string concatenation. Webstudio stores the expression as source text, evaluates it at runtime, and the `JsonLd` component validates and serializes the resulting value.\n- The semantic prop update rejects malformed JSON and structurally invalid fixed JSON-LD with a precise JSON path.\n- The SEO audit also warns about a missing top-level `@context`, unknown or superseded Schema.org terms, properties unsupported by the supplied type, and incompatible primitive value types.\n- Schema.org vocabulary findings are warnings because custom vocabularies and extensions remain valid. Dynamic JSON-LD is marked as skipped for rendered validation.\n- Do not use bindings just to set static text.\n\n## Delete props\n\nCommands:\n\n- MCP tool: delete-props {"deletions":"props.json contents"}\n\n## Bind props to expressions/resources/actions\n\nCommands:\n\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n\nNotes:\n\n- Use this only when the prop should remain dynamic: expression, resource, action, or an existing scoped runtime context value such as `system`.\n- For a fixed string value, use `update-props` with `type:"string"` and a direct `value` instead.\n\n## Read styles\n\nCommands:\n\n- MCP tool: get-styles {"instanceIds":[""],"includeTokens":true}\n\n## Update local styles\n\nCommands:\n\n- MCP tool: update-styles {"updates":"styles.json contents"}\n\n## Delete local styles\n\nCommands:\n\n- MCP tool: delete-styles {"deletions":"styles.json contents"}\n\n## Replace matching style values\n\nCommands:\n\n- MCP tool: replace-styles {"property":"color","fromValue":{"type":"keyword","value":"red"},"toValue":{"type":"keyword","value":"blue"}}\n\n## List design tokens\n\nCommands:\n\n- MCP tool: list-design-tokens {}\n- MCP tool: list-design-tokens {"withUsage":true}\n- MCP tool: list-design-tokens {"verbose":true}\n\nNotes:\n\n- The default response is compact and includes token id, name, declaration count, and optional usage count.\n- Use `verbose:true` only when you need the full inline style declarations.\n\n## Create design tokens\n\nCommands:\n\n- MCP tool: create-design-token {"tokens":"tokens.json contents"}\n\n## Update design token styles\n\nCommands:\n\n- MCP tool: update-design-token-styles {"designTokenId":"","updates":"styles.json contents"}\n\n## Delete design token styles\n\nCommands:\n\n- MCP tool: delete-design-token-styles {"designTokenId":"","deletions":"styles.json contents"}\n\n## Attach design token to instances\n\nCommands:\n\n- MCP tool: attach-design-token {"designTokenId":"","instanceIds":"instances.json contents"}\n\n## Detach design token from instances\n\nCommands:\n\n- MCP tool: detach-design-token {"designTokenId":"","instanceIds":"instances.json contents"}\n\n## Extract design token from local styles\n\nCommands:\n\n- MCP tool: extract-design-token {"instanceIds":[""],"name":"Brand Primary","removeLocalProps":["color"]}\n\n## List CSS variables\n\nCommands:\n\n- MCP tool: list-css-variables {"withUsage":true}\n\n## Define CSS variables\n\nCommands:\n\n- MCP tool: define-css-variable {"vars":{"--color-primary":"#2d3748","--color-accent":"#e53e3e","--space-card":"1.5rem"},"overwrite":true}\n\nNotes:\n\n- Define or overwrite multiple CSS variables atomically by including every name and value in one `vars` object.\n- Pass colors as CSS strings. Structured `hex` color components use normalized values from `0` to `1`, not `0` to `255`.\n\n## Delete CSS variables\n\nCommands:\n\n- MCP tool: delete-css-variable {"names":["--color-primary","--color-accent","--space-card"],"force":true}\n\nNotes:\n\n- Delete multiple CSS variables atomically by including every name in one `names` array. Destructive MCP calls still require the returned confirmation token before they commit.\n\n## Rewrite CSS variable references\n\nCommands:\n\n- MCP tool: rewrite-css-variable-refs {"map":"variables.json contents"}\n\n## List data variables\n\nCommands:\n\n- MCP tool: list-variables {}\n- MCP tool: list-variables {"scopeInstanceId":""}\n\nNotes:\n\n- Data variables live in the internal `dataSources` namespace.\n- For raw `snapshot`, request the public `variables` namespace rather than the internal `dataSources` name. Raw patch payloads still use `dataSources` when applying direct changes.\n- Scope variables to the instance where they should become available. Descendants can use them in expressions, and nested variables with the same name mask outer variables.\n\n## Create data variable\n\nCommands:\n\n- MCP tool: create-variable {"scopeInstanceId":"","name":"title","value":{"type":"string","value":"Hello"}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"count","value":{"type":"number","value":3}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"featured","value":{"type":"boolean","value":true}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"tags","value":{"type":"json","value":["news","product"]}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"filters","value":{"type":"json","value":{"tag":"news"}}}\n\nNotes:\n\n- Data variable values support `string`, `number`, `boolean`, and `json`. Use `json` for all arrays and objects.\n- Parameters are internal scoped runtime values provided by pages, collections, or components. They are not a public authoring surface: do not create, update, or delete parameter records. Use data variables/resources for user-authored data, and reference documented context values such as `system` only where they are already in scope.\n\n## Update data variable\n\nCommands:\n\n- MCP tool: update-variable {"dataSourceId":"","values":{"value":{"type":"json","value":{"count":1}}}}\n\n## Delete data variable\n\nCommands:\n\n- MCP tool: delete-variable {"dataSourceId":""}\n\n## List resources\n\nCommands:\n\n- MCP tool: list-resources {}\n- MCP tool: list-resources {"scopeInstanceId":""}\n\n## Create resource\n\nCommands:\n\n- MCP tool: create-resource {"resource":{"name":"Posts","method":"get","url":"https://api.example.com/posts","headers":[]}}\n- MCP tool: create-resource {"resource":{"name":"Posts","method":"get","url":"\'https://api.example.com/posts?tag=\' + filters.tag","headers":[]},"scopeInstanceId":"","dataSourceName":"posts"}\n- MCP tool: create-resource {"resource":{"name":"Filtered Posts","method":"get","url":"https://api.example.com/posts","searchParams":[{"name":"tag","value":"filters.tag"},{"name":"source","value":{"type":"literal","value":"website"}}],"headers":[{"name":"Authorization","value":"\'Bearer \' + auth.token"}]},"scopeInstanceId":"","dataSourceName":"posts"}\n- MCP tool: create-resource {"resource":{"name":"Post GraphQL","control":"graphql","method":"post","url":"https://api.example.com/graphql","headers":[{"name":"Content-Type","value":{"type":"literal","value":"application/json"}}],"body":"{ query: \'query Post($slug: String!) { post(slug: $slug) { title } }\', variables: { slug: system.params.slug } }"},"scopeInstanceId":"","dataSourceName":"post"}\n- MCP tool: create-resource {"resource":{"name":"Current Date","control":"system","method":"get","url":"/$resources/current-date","headers":[]},"scopeInstanceId":"","dataSourceName":"currentDate"}\n\nNotes:\n\n- Resource `url` accepts plain fixed URLs and paths such as `https://api.example.com/posts` and `/$resources/current-date`.\n- Resource `url` can also be a JavaScript expression when it is computed, such as `"https://api.example.com/posts?tag=" + filters.tag`.\n- Header values, search parameter values, and body accept expressions for dynamic values. For fixed text, use `{"type":"literal","value":"application/json"}`; Webstudio stores the required string expression for you.\n- Search parameter values, header values, and body expressions can read scoped variables and documented runtime context values such as `system` when they are available at the resource scope.\n- Add `scopeInstanceId` and `dataSourceName` when the resource result should be exposed as a scoped read data variable. Scoped resources are generated into the page resource `data` map and may be loaded during page rendering. Use this for read-oriented resources such as GET CMS/API data.\n- For submit/write/action resources, create the resource without `scopeInstanceId`, then bind a component prop such as a Form `action` with `bind-props` and `binding.type: "resource"`. Prop-bound resources are generated into the page resource `action` map instead of the read `data` map. Use this for POST, PUT, DELETE, webhooks, GraphQL submissions, and other explicit action flows.\n- Resource `method` can be `get`, `post`, `put`, or `delete`. Use GET for read data, POST for creates/GraphQL/webhooks/form submissions, PUT for full updates or replacements, and DELETE for deletion actions.\n- Optional `control` values are `graphql` and `system`. Use `graphql` for GraphQL-style requests, usually POST with a query body. Use `system` for built-in resources such as `"/$resources/sitemap.xml"`, `"/$resources/current-date"`, and `"/$resources/assets"` and when the resource should use the built-in `system` parameter. System fields are `system.origin`, `system.pathname`, `system.params`, and `system.search`.\n\n## Update resource\n\nCommands:\n\n- MCP tool: update-resource {"resourceId":"","values":{"url":"https://api.example.com/posts"}}\n- MCP tool: replace-resource-text {"find":"api.old.example.com","replace":"api.example.com","fields":["url"],"limit":20}\n\n## Query Markdown assets\n\nCommands:\n\n- MCP tool: get-asset-field-catalog {}\n- MCP tool: validate-asset-query {"query":{"where":{"all":[{"field":["extension"],"operator":"eq","value":"md"},{"field":["properties","draft"],"operator":"ne","value":true}]},"limit":20}}\n- MCP tool: create-assets-resource {"name":"All assets","scopeInstanceId":"","dataSourceName":"assets"}\n- MCP tool: create-assets-resource {"name":"Published posts","scopeInstanceId":"","dataSourceName":"posts","query":{"result":"many","where":{"all":[{"field":["extension"],"operator":"eq","value":{"type":"literal","value":"md"}},{"field":["properties","draft"],"operator":"ne","value":{"type":"literal","value":true}}]},"sort":[{"field":["properties","publishedAt"],"direction":"desc"}],"limit":{"type":"literal","value":20},"output":{"mode":"fields","includeMetadata":false,"fields":[["properties","title"],["properties","slug"],["properties","publishedAt"],["properties","excerpt"]]},"content":{"mode":"none"}}}\n- MCP tool: create-assets-resource {"name":"Post by slug or ID","scopeInstanceId":"","dataSourceName":"post","query":{"result":"one","where":{"all":[{"field":["extension"],"operator":"eq","value":{"type":"literal","value":"md"}},{"field":["properties","slug"],"operator":"eq","value":"system.params.slug"}]},"output":{"mode":"fields","includeMetadata":false,"fields":[["properties","title"],["properties","publishedAt"]]},"content":{"mode":"markdown-body-ref"}}}\n- MCP tool: list-assets-resources {}\n- MCP tool: get-assets-resource {"resourceId":""}\n- MCP tool: update-assets-resource {"resourceId":"","values":{"query":null}}\n- MCP tool: preview-asset-query {"query":{"result":"one","where":{"all":[{"field":["extension"],"operator":"eq","value":"md"},{"field":["properties","slug"],"operator":"eq","value":"hello-world"}]},"output":{"mode":"fields","includeMetadata":false,"fields":[["properties","title"]]},"content":{"mode":"markdown-body-ref"}}}\n\nNotes:\n\n- Read the field catalog before authoring unfamiliar queries. It includes dynamic schema-less frontmatter paths such as `properties.author.name`, observed types, optionality, and mixed-type state without downloading Markdown files.\n- Minimize the deployed content database by using `output.mode:"fields"` and selecting only fields the rendered page needs. Keep `includeMetadata:false` unless the rendered value needs file metadata such as name, path, MIME type, or creation date, and avoid `output.mode:"all"` as a convenience default. Query diagnostics are returned separately and do not require metadata output. Filters and sorting may still require their referenced fields in the database.\n- Every reachable Assets data source contributes to the shared published database. Keep one final resource per rendered query. Update an existing scoped resource rather than creating a placeholder, preview copy, or repair replacement, and remove obsolete duplicates.\n- Keep bounded overview filters, limits, and offsets literal and add a deterministic ID tie-breaker to the sort. With `content.mode:"none"`, compilation can materialize the small overview result instead of retaining its output fields across every candidate document. Use runtime expressions only for genuinely dynamic values such as the detail slug.\n- Combine filters with `where.all` (AND) and `where.any` (OR), including nested groups. Filter values, limit, and offset on a saved resource may be Webstudio expressions evaluated at render time. Preview queries use concrete JSON values.\n- Query Markdown files directly and use `content.mode:"markdown-body-ref"` when rendering their bodies. The published database retains metadata and a document reference, then fetches only the selected Markdown files from Asset storage at runtime; it does not embed their bodies. Filter and paginate before content is loaded.\n- `full` and bounded `range` continue to request embedded file bytes. Use them only when the caller requires the complete source or a byte range.\n- In Markdown, reference sibling Assets with conventional relative URLs such as `../images/hero.png`. Deferred `markdown-body-ref` content resolves matching files against the Markdown file\'s folder and emits the correct Builder or published Asset URL. Keep external URLs absolute.\n- Markdown Embed renders sanitized authored HTML for figures, captions, audio, video, and iframes. Scripts, inline event handlers, `srcdoc`, and unsafe URL protocols are removed. Executable component composition remains separate future MDX work.\n- Preview each query with concrete values before saving it. Inspect `__diagnostics__.query` for the temporary query-only footprint and `__diagnostics__.database` for the merged database built from all reachable Assets queries. Only `database.usedBytes` counts toward `database.maxBytes`; query sizes must not be summed and are not separate allowances. Compare `usedBytes`, `unboundedBytes`, and `truncated` within both scopes. A completed Markdown blog should include every source document without truncation, contain no embedded Markdown bodies, and retain only its intended materialized overview query. When merged usage approaches the limit, remove duplicate reachable resources first, then unused output fields, then narrow candidate files.\n- Use `result:"many"` for listings. It returns the ID-keyed map at `.data`, with `totalCount` and `hasMore` at `.meta`, and remains the default for existing queries. Bind a listing Collection to `posts.data`.\n- Use `result:"one"` for a unique detail route. It returns the selected item or `null` directly at `post.data`, always includes its `id`, and omits pagination. Bind components and page settings directly with expressions such as `post.data.properties.title`, `post.data.content.text`, and `post.data ? 200 : 404`. `result:"first"` and `result:"last"` also return a direct item or `null` but require explicit sorting.\n- Assets always executes a structured query. Omit `query` to use the default many-result query, which selects URL and optional image dimensions. Set `values.query:null` to restore it.\n- `create-assets-resource` and `update-assets-resource` are the semantic authoring path. Do not construct the internal query URL, headers, or body expression manually.\n- The shared metadata index is maintained automatically and is emitted only when a configured Assets resource is reachable.\n\n## Delete resource\n\nCommands:\n\n- MCP tool: delete-resource {"resourceId":""}\n\n## List assets\n\nCommands:\n\n- MCP tool: list-assets {"withUsage":true}\n- MCP tool: list-assets {"verbose":true}\n\nNotes:\n\n- Compact results include each asset\'s folder id. Use `verbose:true` to include complete records for a page of assets, or `get-asset` to read one complete record including description, folder, creation time, and image/font metadata.\n- Image asset descriptions are the default alt text for asset-backed Image components.\n- To generate missing descriptions, inspect the image in its rendered page or asset source, write a concise description of its purpose, and save it on the asset rather than duplicating it on each Image instance.\n\n## Get asset\n\nCommands:\n\n- MCP tool: get-asset {"assetId":""}\n\n## List asset folders\n\nCommands:\n\n- MCP tool: list-asset-folders {}\n\n## Create asset folder\n\nCommands:\n\n- MCP tool: create-asset-folder {"name":"Marketing"}\n- MCP tool: create-asset-folder {"name":"Photos","parentId":""}\n\n## Update asset folder\n\nCommands:\n\n- MCP tool: update-asset-folder {"folderId":"","values":{"name":"Brand"}}\n- MCP tool: update-asset-folder {"folderId":"","values":{"parentId":""}}\n- MCP tool: update-asset-folder {"folderId":"","values":{"parentId":null}}\n\nNotes:\n\n- Updating `parentId` is the folder equivalent of cut and paste. Use `null` to move a folder to Root.\n\n## Duplicate asset folder\n\nCommands:\n\n- MCP tool: duplicate-asset-folder {"folderId":""}\n- MCP tool: duplicate-asset-folder {"folderId":"","parentId":""}\n\nNotes:\n\n- Duplication recursively copies descendant folders and assets. This is the folder equivalent of copy and paste.\n\n## Delete asset folder\n\nCommands:\n\n- MCP tool: delete-asset-folder {"folderId":""}\n\nNotes:\n\n- Deleting a folder recursively deletes its descendant folders and assets.\n\n## Update asset metadata\n\nCommands:\n\n- MCP tool: update-asset {"assetId":"","values":{"description":"Team collaborating around a whiteboard"}}\n- MCP tool: update-asset {"assetId":"","values":{"meta":{"family":"Rajdhani","style":"normal","weight":600}}}\n\nNotes:\n\n- Use an empty description only when the image is intentionally decorative.\n- Updating an image asset description updates the default alt text wherever that asset is used with an asset-backed alt prop.\n- Font metadata updates merge with the detected metadata and are validated before committing; use this to correct a family, style, or weight after upload.\n\n## Generate missing image descriptions with an agent\n\nCommands:\n\n- MCP tool: audit {"scopes":["accessibility"],"verbose":true}\n- MCP tool: set-image-descriptions {"updates":[{"assetId":"hero-id","description":"Team collaborating around a whiteboard"},{"assetId":"texture-id","decorative":true}]}\n- MCP tool: audit {"scopes":["accessibility"]}\n\nNotes:\n\n- Start from `missing-image-description` findings. Inspect each image in its rendered page context before writing text.\n- The vision-capable agent generates the wording; the CLI validates and stores it but does not contain its own vision model.\n- Use `decorative:true` only when the image adds no information. This intentionally stores an empty description so later audits do not report it as missing.\n- Re-run the accessibility audit after the update. Asset-backed Image components use the saved asset description as their default alt text.\n\n## Manage fonts\n\nCommands:\n\n- MCP tool: list-fonts {"includeSystem":true}\n- MCP tool: list-assets {"type":"font"}\n- MCP tool: upload-asset {"asset":{"name":"acme-sans.woff2","type":"font","format":"woff2","meta":{"family":"Acme Sans","style":"normal","weight":400}},"assetsDir":".webstudio/assets"}\n- MCP tool: update-styles {"updates":"styles.json contents"}\n\nNotes:\n\n- Use `list-fonts` to discover uploaded families and system stacks. Upload/delete fonts through the existing asset tools, then apply a family with a `font-family` style declaration.\n\n## Upload one asset\n\nCommands:\n\n- MCP tool: upload-asset {"asset":{"name":"image.png","type":"image","format":"png","meta":{"width":1200,"height":630}},"assetsDir":".webstudio/assets"}\n- MCP tool: upload-asset {"asset":{"name":"image.png","type":"image","format":"png","folderId":"","meta":{"width":1200,"height":630}},"assetsDir":".webstudio/assets"}\n\n## Upload asset batch\n\nCommands:\n\n- MCP tool: upload-assets {"assets":[{"name":"image.png","type":"image","format":"png","meta":{"width":1200,"height":630}}],"assetsDir":".webstudio/assets"}\n\nNotes:\n\n- Multi-file uploads return `uploaded`, `failed`, and `ambiguous` lists with the\n original input index. Retry only `failed` files. A forced upload in\n `ambiguous` may already be committed; inspect the Assets list before deciding\n whether to upload it again. Successful uploads remain committed.\n\n## Duplicate asset\n\nCommands:\n\n- MCP tool: duplicate-asset {"assetId":""}\n- MCP tool: duplicate-asset {"assetId":"","folderId":""}\n- MCP tool: duplicate-asset {"assetId":"","folderId":null}\n\nNotes:\n\n- Duplication is the asset equivalent of copy and paste. Updating `folderId` is the equivalent of cut and paste; use `null` for Root.\n\n## Download asset\n\nCommands:\n\n- MCP tool: download-asset {"assetId":""}\n\n## Find asset usage\n\nCommands:\n\n- MCP tool: find-asset-usage {"assetId":""}\n\n## Replace asset references\n\nCommands:\n\n- MCP tool: replace-asset {"fromAssetId":"","toAssetId":""}\n\n## Delete assets\n\nCommands:\n\n- MCP tool: delete-asset {"assetIdsOrPrefixes":[""],"force":true}\n\n## Publish project\n\nCommands:\n\n- webstudio publish deploy --target production --json\n\n## List publishes\n\nCommands:\n\n- webstudio publish list --json\n\n## Check publish job\n\nCommands:\n\n- webstudio publish status --job --json\n\n## Unpublish\n\nCommands:\n\n- webstudio publish unpublish --target production --confirm --json\n\n## List domains\n\nCommands:\n\n- webstudio domains list --json\n\n## Create domain\n\nCommands:\n\n- webstudio domains create --domain example.com --json\n\n## Update domain\n\nCommands:\n\n- webstudio domains update --domain-id --domain www.example.com --json\n\n## Delete domain\n\nCommands:\n\n- webstudio domains delete --domain-id --confirm --json\n\n## Verify domain\n\nCommands:\n\n- webstudio domains verify --domain-id --json\n\n## Make arbitrary store-level changes\n\nCommands:\n\n- MCP tool: inspect {}\n- MCP tool: snapshot {"include":[""]}\n- MCP tool: apply-patch {"baseVersion":"","transactions":"patch.json contents"}\n\nNotes:\n\n- Use only when no semantic command exists.\n\n## Manage marketplace metadata\n\nCommands:\n\n- MCP tool: get-marketplace-product {}\n- MCP tool: update-marketplace-product {"category":"pageTemplates","name":"Acme Template","thumbnailAssetId":"asset-id","author":"Acme Studio","email":"hello@example.com","website":"https://example.com","issues":"","description":"Reusable template project for Acme landing pages."}\n- MCP tool: submit-marketplace-product {"acknowledgePublicSubmission":true}\n\nPatch namespaces:\n\n- marketplaceProduct\n\n## Search and inspect safely\n\nCommands:\n\n- webstudio search-project \'{"query":"pricing"}\'\n- MCP tool: search-project {"query":"pricing"}\n- MCP tool: search-project {"query":"api.example.com","namespaces":["resources"]}\n- MCP tool: search-project {"query":"Brand","namespaces":["styles","styleSources","styleSourceSelections"]}\n- MCP tool: list-instances {"pagePath":"/","maxDepth":5}\n- MCP tool: inspect-instance {"instanceId":"","include":["props","styles","children"]}\n- MCP tool: list-texts {"pagePath":"/"}\n- MCP tool: list-assets {"withUsage":true}\n- MCP tool: find-asset-usage {"assetId":""}\n- MCP tool: snapshot {"include":["pages","instances","props","resources","assets"]}\n\nNotes:\n\n- `search-project` is a standalone local-session command over every Builder namespace. It returns matching values with stable match ids, namespace paths, owning entities, references, and affected pages.\n- Use it when a value or id is known. Use list/get tools when the project structure or target is not known.\n- The command synchronizes its required Builder namespaces, then searches locally and returns only matches. Namespace filters limit values matched; related namespaces may still supply route and reference context, and synchronization is unchanged. This reduces data passed to the model, not the initial project-data synchronization.\n- Asset records and file metadata are searchable. Asset binary or document contents are not Builder namespace data and are not searched.\n- Values in recognized credential fields are excluded and counted in `excludedSensitiveValueCount`.\n- Use `audit` for project health findings.\n\n## Audit project quality\n\nCommands:\n\n- webstudio audit --json\n- webstudio audit --scopes accessibility --scopes seo --json\n- webstudio audit --page-path /pricing --json\n- webstudio audit --scopes accessibility --verbose --json\n- webstudio audit --rendered --page-path /pricing --json\n- webstudio audit --rendered --route-example post=/blog/hello --json\n- webstudio audit --rendered --image-domain images.example.com --json\n- MCP tool: audit {}\n- MCP tool: audit {"scopes":["accessibility","security"],"severities":["error","warning"]}\n- MCP tool: audit {"scopes":["accessibility"],"verbose":true}\n- MCP tool: audit {"scopes":["craft"],"verbose":true}\n- MCP tool: audit {"rendered":true,"verbose":true}\n\nNotes:\n\n- With no scopes, `audit` checks accessibility, security, SEO, performance settings, unused assets, ineffective Collection styles, non-GET resources exposed as render-time data, and unused or duplicate style data.\n- Craft is opt-in and read-only. Run `audit` with `scopes:["craft"]` to detect whether the project is not using Craft, partially compatible, or compatible with the versioned Craft 1.2 profile. `profileStatuses` includes the University-doc provenance and the smallest safe next action. The audit never installs Craft or changes a non-Craft project.\n- The `performance` scope reports disabled atomic CSS generation. A rendered audit also measures broken, eager below-fold, and oversized images, browser-marked render-blocking resources, and legacy font formats.\n- Rendered image and resource metrics run only when the selected scopes include `performance`; responsive layout dimensions remain available whenever `rendered:true` is requested.\n- Compact findings include stable ids, severity, message, and location. Use `--verbose` or `{"verbose":true}` for evidence, explanation, suggested remediation, skipped-check details, and manual-check workflows.\n- `summary` counts all findings before severity filtering and pagination.\n- `contractVersion` identifies the audit response contract. Handle a new value before assuming existing fields retain the same meaning.\n- Expression-, resource-, and parameter-backed values that cannot be checked reliably appear in `skippedChecks`; they are not treated as passing or failing.\n- Page filters apply to page-owned accessibility, security, and SEO checks. Asset and style usage remain project-wide to avoid false unused findings.\n- Continue paginated results with `cursor`. Restart the audit if the project version changes.\n- Verbose skipped-check and manual-check details are included on the first findings page only; their total counts remain available on every page.\n- `manualChecks` describes responsive, hierarchy, and contrast checks that require preview screenshots and vision.\n- Focused audits return only manual checks relevant to their selected scopes.\n- In a long-lived MCP session, `{"rendered":true}` reuses preview and screenshot\n tools to capture every static page at mobile, desktop, and Builder breakpoint\n edges. Compact output reports rendered check/issue/failure counts; verbose\n output includes screenshot paths and measured layout dimensions.\n- Dynamic route templates are skipped unless `--route-example =`\n (or MCP `routeExamples`) supplies a concrete path. The path must not contain\n unresolved `:` or `*` parameters.\n- Plans above 120 captures return a short-lived confirmation token. Review the\n unchanged plan, then rerun with `--confirm-large-run` and\n `--confirmation-token`.\n- Detailed rendered evidence is stored in a versioned manifest under\n `.webstudio/audits`; compact output includes its path and screenshot count.\n- Rendered checks also report broken images, eager images below the fold, and\n image sources more than 2x their rendered dimensions in both axes, including\n Webstudio instance ids and measured dimensions when available.\n- Rendered checks include sanitized Resource Timing evidence and report\n browser-marked render-blocking resources plus legacy `.ttf`, `.otf`, and\n `.woff` fonts without applying a universal transfer-size threshold.\n- Fix findings through semantic mutation commands, then rerun `audit` to confirm their deterministic finding ids disappeared.\n\n## Verify dynamic bindings\n\nCommands:\n\n- webstudio verify-bindings --json\n- MCP tool: verify-bindings {"pagePath":"/pricing"}\n- MCP tool: verify-bindings {"instanceId":"","limit":50}\n\nNotes:\n\n- Statically checks persisted text expressions, expression/action/resource/parameter props, resource expressions, and page metadata.\n- Findings distinguish invalid syntax, unknown or out-of-scope variables, stale internal data-source ids, and missing resource or parameter references.\n- Page and instance filters can be combined when the instance belongs to the selected page. Continue findings with `cursor`.\n- This operation does not resolve rendered values or execute external resources. Preview representative loading, empty, error, and populated states after static findings are fixed.\n\n## Refactor targeted content\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/"}\n- MCP tool: list-texts {"pagePath":"/"}\n- MCP tool: update-text {"instanceId":"","childIndex":0,"text":"Launch faster"}\n- MCP tool: replace-text {"find":"Old headline","replace":"New headline","match":"exact","pagePath":"/pricing","limit":20}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: update-page {"pageId":"","values":{"title":"Pricing","meta":{"description":"Plans"}}}\n- MCP tool: update-resource {"resourceId":"","values":{"url":"https://api.example.com/posts"}}\n- MCP tool: replace-asset {"fromAssetId":"","toAssetId":""}\n- MCP tool: replace-styles {"property":"color","fromValue":{"type":"keyword","value":"red"},"toValue":{"type":"keyword","value":"blue"}}\n- MCP tool: rewrite-css-variable-refs {"map":"variables.json contents"}\n\nNotes:\n\n- Use focused reads first, then mutate only matching instances, props, metadata, resource URLs, assets, or style references. Use `replace-text` for bounded literal text changes, `replace-prop-text` for bounded static prop text, `replace-resource-text` for fixed resource names/URLs, and `update-text` for one known child or expressions.\n\n## Optimize existing project\n\nCommands:\n\n- MCP tool: list-pages {}\n- MCP tool: list-folders {}\n- MCP tool: update-page {"pageId":"","values":{"title":"Pricing","meta":{"description":"Plans"}}}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: list-breakpoints {}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","values":{"maxWidth":1023}}\n- MCP tool: get-styles {"instanceIds":[""],"includeTokens":true}\n- MCP tool: update-styles {"updates":"styles.json contents"}\n- MCP tool: attach-design-token {"designTokenId":"","instanceIds":"instances.json contents"}\n- MCP tool: update-project-settings {"meta":{"siteName":"Acme"}}\n\nNotes:\n\n- Use this for SEO metadata, accessibility labels, responsive behavior, token consistency, and project settings.\n\n## Connect external data\n\nCommands:\n\n- MCP tool: create-variable {"scopeInstanceId":"","name":"title","value":{"type":"string","value":"Hello"}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"tags","value":{"type":"json","value":["news","product"]}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"filters","value":{"type":"json","value":{"tag":"news"}}}\n- MCP tool: create-resource {"resource":{"name":"Posts","method":"get","url":"https://api.example.com/posts","searchParams":[{"name":"tag","value":"filters.tag"},{"name":"source","value":{"type":"literal","value":"website"}}],"headers":[]},"scopeInstanceId":"","dataSourceName":"posts"}\n- MCP tool: create-resource {"resource":{"name":"Post GraphQL","control":"graphql","method":"post","url":"https://api.example.com/graphql","headers":[{"name":"Content-Type","value":{"type":"literal","value":"application/json"}}],"body":"{ query: \'query Post($slug: String!) { post(slug: $slug) { title } }\', variables: { slug: system.params.slug } }"},"scopeInstanceId":"","dataSourceName":"post"}\n- MCP tool: create-resource {"resource":{"name":"Current Date","control":"system","method":"get","url":"/$resources/current-date","headers":[]},"scopeInstanceId":"","dataSourceName":"currentDate"}\n- MCP tool: update-resource {"resourceId":"","values":{"url":"https://api.example.com/posts"}}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n- MCP tool: insert-fragment {"parentInstanceId":"","fragment":"{/_ collection content _/}"}\n\nNotes:\n\n- Use this for CMS sections, blog listings, Ghost/headless CMS pages, n8n-style integrations, and API URLs built from variables.\n- For read data, expose GET resources as scoped data variables with `scopeInstanceId`/`dataSourceName` and read the loaded result from the resource result wrapper, usually `.data`.\n- For writes, webhooks, GraphQL submissions, and deletes, prefer unscoped resources bound to Form `action` props so they become action resources instead of auto-loaded read resources.\n- Use direct props for fixed values and prop bindings only when a prop must read a data variable, resource, action, or documented runtime context value such as `system`.\n\n## Render an array or object as repeated content\n\nCommands:\n\n- MCP tool: insert-collection {"parentInstanceId":"","data":{"type":"expression","value":"posts.data.items"},"itemFragment":"{expression`collectionItem.title`}"}\n- MCP tool: inspect-instance {"instanceId":"","include":["props","bindings","children"]}\n\nNotes:\n\n- Use Collection whenever an array or object from a resource or data variable should render a list, grid, cards, table rows, options, tabs, or other repeated UI.\n- Pass `insert-collection` the complete array or object. Do not pass the resource response wrapper or one indexed item. External resource arrays are commonly nested under the scoped resource result\'s `data` field or deeper.\n- Pass one repeated-item Webstudio JSX root. The command creates the Collection, its private current-item/current-key parameters, the iterable binding, and descendant item bindings atomically.\n- Collection renders the item root once for every entry. Use `expression` values such as `collectionItem.title` in descendant text and props. Object iteration also exposes `collectionItemKey`.\n- Wrap multiple repeated sibling instances in one Element inside Collection.\n- For repeated Radix items such as accordion items, tabs, or menu options, bind a stable unique id or slug to every required `value` prop.\n- See the [Collection documentation](https://docs.webstudio.is/university/core-components/collection) for the equivalent Builder workflow.\n\n## Support dynamic runtime behavior\n\nCommands:\n\n- MCP tool: integrate-runtime-ui {"parentInstanceId":"","resources":[{"resource":{"name":"Seats","method":"get","url":"https://api.example.com/seats","headers":[]},"dataSourceName":"Seats","exposeAsDataSource":true}],"structure":{"type":"collection","data":{"type":"expression","value":"Seats.data"},"itemFragment":{"children":[{"type":"id","value":"seat"}],"instances":[{"type":"instance","id":"seat","component":"Text","children":[{"type":"expression","value":"collectionItem.label"}]}],"props":[],"dataSources":[],"resources":[],"styleSources":[],"styleSourceSelections":[],"styles":[],"breakpoints":[],"assets":[]}},"retainedBehavior":[{"instanceId":"","responsibility":"Seat selection behavior"}]}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n- MCP tool: create-resource {"resource":{"name":"Seats","method":"get","url":"https://api.example.com/seats","headers":[]}}\n- MCP tool: snapshot {"include":["instances","props","resources"]}\n- MCP tool: apply-patch {"baseVersion":"","transactions":"patch.json contents"}\n\nNotes:\n\n- Use `integrate-runtime-ui` to create variables/resources, insert one editable fragment or Collection, and add safe data bindings in one transaction.\n- List existing script-owned responsibilities under `retainedBehavior`. The operation preserves those instances and never evaluates or accepts replacement script bodies.\n- `unsupportedConversions` records behavior that cannot be represented safely. Dry-run returns the complete transaction and the same retained/unsupported report without changing the project.\n- New actions and HtmlEmbed scripts are intentionally rejected. Create normal editable components and data bindings; keep opaque runtime behavior in existing script instances.\n\n## Build authenticated pages\n\nCommands:\n\n- MCP tool: meta.guide {"brief":"Build a Supabase-authenticated account page","taskScope":"structural-project-change","workflow":"authenticated-page"}\n- MCP tool: create-page {"name":"Account","path":"/account"}\n- MCP tool: update-page {"pageId":"","values":{"meta":{"auth":{"method":"basic","login":"","password":""}}}}\n- MCP tool: create-resource {"resource":{"name":"Session","method":"get","url":"https://api.example.com/session","headers":[]}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"user","value":{"type":"json","value":{}}}\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n\nNotes:\n\n- Inspect and reuse the project\'s existing auth convention before authoring. Do\n not add a second provider or session model implicitly.\n- Model signed-out, loading, signed-in, and failed-auth states explicitly.\n- Never store credentials, service-role keys, refresh tokens, private session\n values, or authenticated response bodies in project data, command output,\n screenshots, agent instructions, or error reports. Privileged provider calls\n and authorization enforcement belong server-side.\n- Basic auth is semantic today. Provider-specific Supabase/Firebase setup still\n uses the existing resource, variable, prop, binding, and embed tools; there is\n no provider-specific installer.\n\n## Generate from design input\n\nCommands:\n\n- MCP tool: meta.guide {"brief":"Recreate this Figma design as a responsive page","taskScope":"visual-change","workflow":"design-input"}\n- MCP tool: create-page {"name":"Landing","path":"/landing"}\n- MCP tool: create-design-token {"tokens":"tokens.json contents"}\n- MCP tool: define-css-variable {"vars":"vars.json contents"}\n- MCP tool: list-breakpoints {}\n- MCP tool: insert-fragment {"parentInstanceId":"","fragment":"Section copy"}\n- MCP tool: update-styles {"updates":[{"instanceId":"","breakpoint":"","property":"padding-left","value":{"type":"unit","unit":"px","value":24}}]}\n- MCP tool: preview.start {"host":"127.0.0.1","port":5173}\n- MCP tool: screenshot {"path":"/landing","output":"landing-desktop.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot {"path":"/landing","output":"landing-mobile.png","viewport":{"width":390,"height":844},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot {"baseUrl":"http://127.0.0.1:5177","path":"/landing","output":"landing-desktop.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n\nNotes:\n\n- Use this after the agent can inspect the supplied design. There is no direct\n Figma, screenshot, Inception, or `design.md` import command.\n- Inspect and reuse existing variables, tokens, styles, components, assets, and\n page patterns before authoring. Build semantic editable structure rather than\n flattening the design into an image or absolute-positioned approximation.\n- Ask whether the user wants visual verification unless they explicitly requested\n it. If they decline, stop after focused reads and a static audit. If they opt\n in, verify one familiar viewport inside every distinct Builder breakpoint\n range, then run rendered audit and inspect the screenshots before completion.\n\n## Cross-project maintenance\n\nCommands:\n\n- webstudio mcp run .temp/projects.json\n- webstudio mcp run .temp/projects.json --dry-run\n- webstudio mcp run .temp/projects.json --approve-mutations --concurrency 2\n\nNotes:\n\n- Put shared `calls` and a `projects` array of independently linked project roots in the existing `mcp run` manifest. Project roots are relative to the manifest file.\n- Each project uses its own config, authentication, ProjectSession storage, checkpoint, and failure boundary. Confirmed successful calls are checkpointed. Reads can resume automatically; a mutation interrupted after dispatch is reported as ambiguous and is not replayed automatically, preventing silent duplicate writes.\n- Focus the manifest on bounded reads or audits first. Use per-call `dryRun`, global `--dry-run`, or explicitly approve committed mutations with `--approve-mutations` after reviewing the manifest.\n\n# Known CLI Gaps\n\n## Provider-specific authenticated pages\n\nMissing:\nCLI supports page basic auth and generic resources/props/embeds, but not guided Supabase/Firebase auth setup.\n\nCurrent fallback:\nCall `meta.guide` with `workflow:"authenticated-page"`, then create the\npage, resources, variables, props, bindings, and embeds with existing semantic\ntools.\n\nSuggested commands:\n\n- setup-auth-page\n\n## Generate from design input\n\nMissing:\nNo command imports Figma, screenshots, Inception output, or design.md and turns it into pages/tokens/layout.\n\nCurrent fallback:\nCall `meta.guide` with `workflow:"design-input"`, let the agent inspect the supplied\ndesign, then use semantic page, token, asset, fragment, style, preview,\nscreenshot, and audit tools. Use `apply-patch` only when no semantic operation\nfits.\n\nSuggested commands:\n\n- generate-from-design\n\n## Built-in cross-project maintenance\n\nMissing:\nPublic API and CLI intentionally operate on one configured project at a time; there is no built-in multi-project discovery or loop runner.\n\nCurrent fallback:\nRun the CLI from an external script that reconfigures one project/session at a time.\n\nSuggested commands:\n\n- none\n',
+ '# CLI API Use Cases\n\n## Link/configure one project\n\nCommands:\n\n- webstudio init --link --json\n\nNotes:\n\n- Writes local project id and global origin/token config.\n\n## Import synced project bundle into another project\n\nCommands:\n\n- webstudio sync\n- webstudio import --to \n- MCP tool: import {"to":""}\n\nNotes:\n\n- Imports local `.webstudio/data.json` into the destination project.\n- Destination share link must allow build/import access.\n- Use `--skip-assets` only when asset rows and files should not be imported.\n\n## Identify current token\n\nCommands:\n\n- MCP tool: whoami {}\n\n## Check token permissions\n\nCommands:\n\n- webstudio permissions --json\n\n## Inspect project/build/version\n\nCommands:\n\n- MCP tool: inspect {}\n- MCP tool: snapshot {"include":["pages","instances","styles"]}\n\n## Discover CLI/API capabilities\n\nCommands:\n\n- webstudio schema api\n- webstudio schema mcp\n- webstudio man --json\n- webstudio man llm --json\n- MCP tool: meta.index {}\n- MCP tool: meta.guide {"brief":"Create a pricing page"}\n- MCP tool: meta.get-more-tools {"brief":"update-styles"}\n- webstudio mcp list-resources\n- webstudio mcp read-resource webstudio://project/guide\n- webstudio mcp read-resource webstudio://project/expressions\n\nNotes:\n\n- Use `webstudio schema mcp` for a compact machine-readable MCP tool overview. Add `--verbose` or use focused `meta.get-more-tools` calls only when exact input schemas are needed.\n- Use focused MCP tools for discovery first: `meta.index`, `meta.guide`, `meta.get-more-tools`, `components.list`, `components.summary`, `components.search`, `components.get`, `templates.list`, and `templates.get`. Protocol clients can use `resources/list` and `resources/read`; shell agents can use `webstudio mcp list-resources` and `webstudio mcp read-resource `. Read longer resources such as `webstudio://project/tools` and `webstudio://project/components` only when focused tools are insufficient.\n- `components.summary` returns counts by default; request `{"detail":"components","limit":20}` for paginated entries. Registry list tools return compact metadata, while `components.get` and `templates.get` return focused full details.\n- Read `webstudio://project/expressions` before authoring unfamiliar computed text, prop bindings, resource expressions, actions, or Collection item bindings.\n- From a shell, call one MCP tool with the shortcut form `webstudio \'\'`, for example `webstudio components.summary`. The explicit equivalent is `webstudio mcp single-op-call \'\'`. Use `--input-file` for large payloads.\n\n## Inspect external shadcn registry items\n\nCommands:\n\n- webstudio registry inspect --source https://example.com/r/registry.json --item button --json\n- webstudio registry inspect --source ./registry.json --item dialog --json\n- webstudio registry inspect --source https://example.com/r/button.json --json\n\nNotes:\n\n- Reads a local or remote registry item without installing files or changing the configured Webstudio project.\n- Returns the item name, description, package and registry dependencies, file paths/targets, available docs, and a read-only compatibility report.\n- The report explicitly says whether installation or editable-component conversion is supported, lists declared requirements and manual steps, and says when arbitrary source code was not analyzed.\n- This is an inspection step only. It does not install files or change the configured project.\n\n## Understand what MCP can do\n\nCommands:\n\n- webstudio man mcp\n- MCP tool: meta.index {}\n- MCP tool: meta.guide {"brief":"What can Webstudio MCP do?"}\n\nMCP lets agents work on one configured Webstudio project. Agents can:\n\n- Inspect the linked project, token permissions, and latest editable build.\n- Read selected project data for audits, migrations, and repair.\n- Search values and ids across every Builder namespace without sending full project data to the model.\n- Audit accessibility, security, SEO, performance settings, unused assets, ineffective Collection styles, and unused or duplicate style data.\n- Create and edit pages, folders, redirects, breakpoints, and page templates.\n- Create pages from reusable templates.\n- Update page metadata, SEO fields, auth settings, and marketplace metadata.\n- Insert components and styled JSX sections.\n- Create data-driven lists, grids, cards, and similar repeated UI from array or object data in one Collection operation.\n- Move, copy, wrap, unwrap, convert, rename, retag, and delete elements.\n- Update text, rich text, props, bindings, and actions.\n- Create and update local styles, design tokens, style sources, and CSS variables.\n- Create static data variables and JSON variables.\n- Create HTTP, GraphQL, and system resources.\n- Use system resources for sitemap, current date, and assets.\n- Bind resources to rendered data or form/action props.\n- Manage nested asset folders and upload, inspect, move, duplicate, download, replace, delete, and inspect usage for assets.\n- Publish, unpublish, inspect publish jobs, and manage custom domains.\n- Start preview, capture screenshots, compare screenshot diffs, and use OCR when installed.\n\n## Inspect and refresh MCP session cache\n\nCommands:\n\n- MCP tool: status {}\n- MCP tool: status {"verbose":true}\n- MCP tool: refresh {"namespaces":["pages","instances","styles"]}\n- MCP tool: reset-session {}\n\nNotes:\n\n- Use status before a task to understand the cached ProjectSession state.\n- Use status with `{"verbose":true}` only when debugging full namespaces, freshness, compatibility, or diagnostics.\n- Use refresh when project data may have changed outside the current MCP session.\n- Use reset-session when local cached state is corrupt or incompatible.\n\n## Visually verify rendered work with AI vision\n\nCommands:\n\n- MCP tool: preview.start {"host":"127.0.0.1","port":5173}\n- MCP tool: preview.status {}\n- MCP tool: preview.stop {}\n- MCP tool: screenshot {"path":"/","output":".webstudio/screenshots/home-current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot {"path":"/pricing","output":".webstudio/screenshots/pricing-current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot {"baseUrl":"http://127.0.0.1:5177","path":"/pricing","output":".webstudio/screenshots/pricing-current.png","viewport":{"width":1440,"height":900},"waitUntil":"load","waitForTimeout":250}\n- MCP tool: screenshot.diff {"baselinePath":".webstudio/screenshots/home-before.png","currentPath":".webstudio/screenshots/home-current.png","outputDir":".webstudio/screenshots/diff"}\n- MCP tool: screenshot.diff {"baselinePath":".webstudio/screenshots/home-before.png","currentPath":".webstudio/screenshots/home-current.png","outputDir":".webstudio/screenshots/diff","expectedText":["Pricing","Start free"]}\n- MCP tool: screenshot.diff {"baselinePath":".webstudio/screenshots/home-before.png","currentPath":".webstudio/screenshots/home-current.png","outputDir":".webstudio/screenshots/diff","expectedVisual":{"maxMismatchPercentage":2,"maxChangedRegions":3,"dominantColorChange":{"channel":"luminance","direction":"increase","minMagnitude":10}}}\n- MCP tool: screenshot.diff {"baselinePath":".webstudio/screenshots/pricing-before.png","currentPath":".webstudio/screenshots/pricing-current.png","outputDir":".webstudio/screenshots/diff"}\n- MCP tool: vision.install-ocr {"confirm":true}\n\nNotes:\n\n- Enter this workflow only when the user explicitly requests visual verification or opts in after being asked. Do not start preview, screenshots, diffs, OCR, or rendered audits automatically after a mutation.\n- `preview.status` reports whether generated output is `stale`. When no preview is running, `url`, `pid`, and `mode` are omitted. When present, `renderedProjectVersion` is the last project version materialized into the preview.\n- A managed `screenshot` or another `preview.start` refreshes stale generated output before capture.\n\n- After opt-in, use this so a vision-capable AI can see the generated site from the current MCP session. Use `path`; never pass a Webstudio Builder/share URL or capture Builder chrome.\n- For multi-page work, capture every changed page by `path` through the same preview server; no click navigation is required.\n- Iterative mode is the default: after MCP mutations, path screenshots ensure generated project files are current, wait for the exact session version, and perform an ordinary page reload without Vite HMR. The preview server and browser stay alive. Use `{"mode":"production"}` only for release-like verification; rendered audit does this automatically.\n- Calling `preview.start` after a committed mutation restarts a stale iterative server so external browsers and HTTP clients receive the newly generated project.\n- Do not call `preview.start` through one-shot `webstudio mcp single-op-call`: it is long-lived. From a shell, use `webstudio mcp run` with preview.start, screenshot, and preview.stop in one shared process, or use a real long-running MCP client.\n- From one-shot shell calls or another process, pass `baseUrl` with `path` to capture an already-running preview/site without generating, building, starting, or restarting preview.\n- Use preview.stop only in the same long-running MCP server or `webstudio mcp run` process that started preview. A separate one-shot `single-op-call` process does not own another process\'s preview controller.\n- Use waitForSelector when the rendered app has a reliable ready marker, waitUntil:"networkidle" for network-heavy pages, and waitForTimeout only for final visual settling.\n- The screenshot timeout bounds browser capture after the preview is ready. A timeout returns `SCREENSHOT_TIMEOUT`, resets the reusable browser session, and releases the shared preview lifecycle for cleanup.\n- Preview installs generated app dependencies under `.webstudio/preview` and reuses them across regenerations.\n- Do not add generated-preview dependencies to the repository root `package.json` or `pnpm-lock.yaml`.\n- When launcher metadata is available, Preview reuses a supported npm or pnpm launcher. Without launcher metadata, it defaults to npm.\n- If dependency installation fails, check the reported package-manager path and network configuration, then reinstall or update the Webstudio CLI if the problem persists.\n- When a baseline exists, use screenshot.diff once per baseline/current page or viewport pair to get changed regions, OCR textAnalysis, and diff artifact paths before deciding whether the result matches. Pass expectedText for explicit pass/fail current-screen text assertions with found and missing text. Pass expectedVisual for pass/fail limits on pixel mismatch percentage, changed-region count, or the overall dominant color/brightness direction.\n- If screenshot.diff reports OCR unavailable and the user agrees to install it, call vision.install-ocr {"confirm":true}; otherwise continue with pixel diff and visual inspection.\n- Compare the PNG, OCR text evidence, and diff artifacts against the user\'s intent for layout, typography, colors, spacing, imagery, and responsive framing; then iterate with focused mutations.\n- Root CLI equivalent: `webstudio screenshot --path /pricing --output pricing.png` generates a temporary production preview, captures that route, and stops the server. For repeated captures, keep `webstudio preview` running and pass its absolute URL to `webstudio screenshot`.\n\n## List pages\n\nCommands:\n\n- MCP tool: list-pages {}\n- MCP tool: list-folders {}\n\n## Read page by id\n\nCommands:\n\n- MCP tool: get-page {"pageId":""}\n\n## Read page by path\n\nCommands:\n\n- MCP tool: get-page-by-path {"path":"/pricing"}\n\n## Create page\n\nCommands:\n\n- MCP tool: create-page {"name":"Pricing","path":"/pricing"}\n- MCP tool: create-page {"name":"Pricing","path":"/pricing","title":"Pricing","meta":{"description":"Plans for teams"}}\n\nNotes:\n\n- `name`, `path`, page `title`, and metadata text fields accept plain fixed values.\n- For computed page titles or metadata, send JavaScript expression code such as `pageTitle ?? "Pricing"`.\n\n## Update page settings/metadata\n\nCommands:\n\n- MCP tool: update-page {"pageId":"","values":{"title":"Pricing","meta":{"description":"Plans","status":200}}}\n- MCP tool: update-page {"pageId":"","values":{"meta":{"auth":{"method":"basic","login":"","password":""}}}}\n\nNotes:\n\n- Page `title` and metadata text fields accept plain fixed values.\n- For computed page titles or metadata, send JavaScript expression code such as `pageTitle ?? "Pricing"`.\n- Page `status` accepts a fixed HTTP status code as a number from 200 through 599 or a JavaScript expression string for a dynamic status.\n\n## Read project settings\n\nCommands:\n\n- MCP tool: get-project-settings {}\n\nNotes:\n\n- Read `meta.agentInstructions` before making project changes. It contains the project\'s own guidance for AI agents.\n- Agent instructions are shared project guidance. Do not store credentials or other secrets there.\n\n## Update project settings\n\nCommands:\n\n- MCP tool: update-project-settings {"meta":{"siteName":"Acme"}}\n- MCP tool: update-project-settings {"meta":{"agentInstructions":"Use existing design tokens and keep product copy concise."}}\n\n## Read marketplace product\n\nCommands:\n\n- MCP tool: get-marketplace-product {}\n\n## Update marketplace product\n\nCommands:\n\n- MCP tool: update-marketplace-product {"category":"pageTemplates","name":"Acme Template","thumbnailAssetId":"asset-id","author":"Acme Studio","email":"hello@example.com","website":"https://example.com","issues":"","description":"Reusable template project for Acme landing pages."}\n\n## Submit marketplace product\n\nCommands:\n\n- MCP tool: upload-asset {"asset":{"name":"marketplace-thumbnail.png","type":"image","format":"png","meta":{"width":1200,"height":630}},"assetsDir":".webstudio/assets"}\n- MCP tool: update-marketplace-product {"category":"pageTemplates","name":"Acme Template","thumbnailAssetId":"","author":"Acme Studio","email":"hello@example.com","website":"https://example.com","issues":"","description":"Reusable template project for Acme landing pages."}\n- MCP tool: publish {"target":"production"}\n- MCP tool: submit-marketplace-product {"acknowledgePublicSubmission":true}\n\nNotes:\n\n- Wait for the production publish to complete before submitting the product for review.\n- Submission requires complete, valid marketplace metadata.\n\n## List redirects\n\nCommands:\n\n- MCP tool: list-redirects {}\n\n## Create redirect\n\nCommands:\n\n- MCP tool: create-redirect {"old":"/old","new":"/new","status":301}\n\n## Update redirect\n\nCommands:\n\n- MCP tool: update-redirect {"old":"/old","values":{"new":"/newer","status":302}}\n- MCP tool: update-redirect {"old":"/old","values":{"status":null}}\n\n## Delete redirect\n\nCommands:\n\n- MCP tool: delete-redirect {"old":"/old"}\n\n## Set redirects\n\nCommands:\n\n- MCP tool: set-redirects {"redirects":[{"old":"/old","new":"/new","status":"301"}]}\n\n## List breakpoints\n\nCommands:\n\n- MCP tool: list-breakpoints {}\n\n## Create breakpoint\n\nCommands:\n\n- MCP tool: create-breakpoint {"label":"Tablet","maxWidth":991}\n\n## Update breakpoint\n\nCommands:\n\n- MCP tool: update-breakpoint {"breakpointId":"tablet","values":{"label":"Tablet","maxWidth":1023}}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","values":{"condition":null,"minWidth":768}}\n- MCP tool: update-breakpoint {"breakpointId":"tablet","values":{"minWidth":null,"maxWidth":null,"condition":"(hover: hover)"}}\n\n## Delete breakpoint\n\nCommands:\n\n- MCP tool: delete-breakpoint {"breakpointId":"tablet"}\n\n## Duplicate page\n\nCommands:\n\n- MCP tool: duplicate-page {"pageId":"","name":"Pricing Copy","path":"/pricing-copy"}\n- MCP tool: duplicate-page {"pageId":"","name":"Paris","path":"/paris","substitutions":{"text":{"London":"Paris"},"variables":{"city":{"type":"string","value":"Paris"}}}}\n- webstudio duplicate-page --page --name Paris --path /paris --substitutions \'{"text":{"London":"Paris"},"variables":{"city":{"type":"string","value":"Paris"}}}\' --json\n\nNotes:\n\n- Text substitutions replace exact fixed text only in the duplicated page\'s text children, string props, title, and metadata.\n- Variable substitutions are keyed by copied source-variable name and use typed variable values. The operation rejects missing or ambiguous names without committing a partial duplicate.\n- Existing expressions and cloned variable/resource references keep their remapped ids.\n\n## List page templates\n\nCommands:\n\n- MCP tool: list-page-templates {}\n\n## Create page template\n\nCommands:\n\n- MCP tool: create-page-template {"name":"Landing Template","title":"Landing"}\n\n## Update page template\n\nCommands:\n\n- MCP tool: update-page-template {"templateId":"","values":{"name":"Article Template","meta":{"description":"Reusable article layout"}}}\n\n## Delete page template\n\nCommands:\n\n- MCP tool: delete-page-template {"templateId":""}\n\n## Duplicate page template\n\nCommands:\n\n- MCP tool: duplicate-page-template {"templateId":""}\n\n## Reorder page template\n\nCommands:\n\n- MCP tool: reorder-page-template {"sourceTemplateId":"","targetTemplateId":"","position":"before"}\n\n## Create page from template\n\nCommands:\n\n- MCP tool: create-page-from-template {"templateId":"","name":"Landing","path":"/landing"}\n\n## Delete page\n\nCommands:\n\n- MCP tool: delete-page {"pageId":""}\n\n## List folders\n\nCommands:\n\n- MCP tool: list-folders {}\n- MCP tool: list-pages {}\n\n## Create folder\n\nCommands:\n\n- MCP tool: create-folder {"name":"Blog","slug":"blog"}\n\n## Update folder\n\nCommands:\n\n- MCP tool: update-folder {"folderId":"","values":{"name":"Blog","slug":"blog"}}\n\n## Delete folder\n\nCommands:\n\n- MCP tool: delete-folder {"folderId":""}\n\n## List element instances\n\nCommands:\n\n- MCP tool: list-instances {"pagePath":"/","maxDepth":3}\n\n## Inspect one element instance\n\nCommands:\n\n- MCP tool: inspect-instance {"instanceId":"","include":["props","styles","children"]}\n\n## Insert authored JSX or one component template\n\nCommands:\n\n- MCP tool: insert-fragment {"parentInstanceId":"","fragment":"Product OS"}\n- MCP tool: insert-component {"parentInstanceId":"","component":"@webstudio-is/sdk-components-react-radix:Switch"}\n- MCP tool: insert-component {"parentInstanceId":"","component":"Form"}\n\nNotes:\n\n- Use MCP `insert-fragment` as the default way to author styled component trees. It converts JSX to a structured fragment before mutation.\n- Use only exact component ids returned by `components.search`, `components.get`, or `templates.get`. Never derive or guess component ids.\n- The `ws:` namespace contains specific Webstudio core components; it is not HTML-tag shorthand. Use `` for a native `div` and `` for a native form, never `` or ``.\n- For Webstudio\'s complete form structure, discover the Form component and insert its automatic template with `insert-component` using component `"Form"`.\n- MCP receives JSX as a JSON string because MCP arguments are JSON. The CLI converts it locally before the runtime mutation, so the project session receives structured Webstudio data, not JSX source.\n- In `insert-fragment` JSX, use ``ws:style={css`...`}`` for Webstudio-native CSS, or use React-style object syntax such as `style={{ padding: 24 }}` when that is simpler. Both forms create editable Webstudio style data.\n- Do not access host globals or dynamic code APIs in JSX fragments, including `process`, `globalThis`, `eval`, `Function`, or `constructor`.\n- Use Webstudio prop names such as `class` and `for`; do not use React aliases `className` or `htmlFor`.\n- Use Webstudio actions for event/action props, for example `onClick={new ActionValue(["event"], expression\\`console.log(event)\\`)}`. Do not pass JavaScript functions such as `onClick={() => ...}`.\n- Plain prop values must be JSON-compatible: `null`, strings, booleans, finite numbers, arrays, and plain objects. Do not pass `undefined`, `Symbol`, `BigInt`, `NaN`, `Infinity`, `Date`, `Map`, `Set`, class instances, or circular objects; omit the prop, use plain data, or use `expression`/`ActionValue` when the value is dynamic.\n- Template-backed components used in JSX must include required child/part components explicitly under the same parent structure as the template, for example ``.\n- Webstudio applies a registered template automatically when using `insert-component`, so composed components such as Switch include required child parts and styles.\n- Use `components.list`, `components.summary`, `components.search`, `components.get`, `templates.list`, and `templates.get` to discover known registry items, component ids, props, templates, insertability, and content model. Read `webstudio://project/components` only when those focused tools are insufficient.\n- Component/template registry items use a shadcn-compatible top-level shape plus Webstudio-specific superset metadata in `meta`. They are for Builder/MCP discovery, not a published shadcn install registry yet.\n- Known components with `contentModel.category: "none"` are not standalone-insertable; insert their root component template instead so required providers/parents are included.\n- Unknown custom component ids are a low-level extension mechanism, not a discovery fallback. Agents must not synthesize them.\n\n## Make a region editable in Content mode\n\nCommands:\n\n- MCP tool: insert-component {"parentInstanceId":"","component":"ws:block"}\n- MCP tool: inspect-instance {"instanceId":"","include":["children"]}\n\nNotes:\n\n- When a page will be handed to a Content-mode editor, wrap every region they should be able to edit in a Content Block (`ws:block`). Content-mode editors can edit text and supported props only in Content Block descendants. Content outside those blocks remains read-only, even when it looks like ordinary editable text.\n- Put reusable insertable options inside the Content Block\'s `ws:block-template` child. A template is source material, not editor content: editors cannot edit or delete it directly. When an editor inserts a template, its copy becomes a direct child of the Content Block and is editable.\n- Before handing off a page, verify with `inspect-instance` that the intended text, images, and links are inside a Content Block, and that templates include all required styling because Content-mode editors cannot use the Style panel.\n\n## Store Content Block content in MDX\n\nCommands:\n\n- MCP tool: list-assets {"type":"file"}\n- MCP tool: upload-asset {"asset":{"name":"article.mdx","type":"file","format":"mdx","meta":{}},"assetsDir":".webstudio/assets"}\n- MCP tool: connect-content-block-source {"blockInstanceId":"","renderScope":"page:/articles/example","source":{"type":"asset","assetId":""}}\n- MCP tool: switch-content-block-source {"blockInstanceId":"","renderScope":"page:/articles/example","source":{"type":"asset","assetId":""}}\n- MCP tool: inspect-content-block-source {"blockInstanceId":"","renderScope":"page:/articles/example"}\n- MCP tool: edit-content-block-source {"blockInstanceId":"","renderScope":"page:/articles/example","source":"# Article title\\n\\nArticle body."}\n- MCP tool: update-content-block-frontmatter {"blockInstanceId":"","renderScope":"page:/articles/example","properties":{"title":"Article title","draft":false}}\n- MCP tool: reload-content-block-source {"blockInstanceId":"","renderScope":"page:/articles/example"}\n- MCP tool: migrate-content-block-template-references {"assetIds":[""],"migration":{"type":"rename","from":"Old template name","to":"New template name"}}\n- MCP tool: disconnect-content-block-source {"blockInstanceId":"","renderScope":"page:/articles/example"}\n\nNotes:\n\n- Create the local `.mdx` file under `.webstudio/assets` before calling `upload-asset`. Use the returned Asset ID when connecting it.\n- Use the Content Block source operations for connecting, switching, inspecting, editing, reloading, and disconnecting. Do not create or delete the `src` prop with generic prop tools; the source operations preserve the Body outlet and Content Block lifecycle.\n- `renderScope` is a stable key for the rendered occurrence. Use a page-based key for a direct Content Block. For a repeated Collection occurrence, use a distinct key and pass the scoped values required to resolve an expression source. For example, use `source:{"type":"expression","value":"post.assetId"}` with `variables:{"post":{"assetId":""}}`.\n- Connecting replaces existing Body content. If the result returns `requiresConfirmation:true`, report that replacement to the user and repeat the same call with `confirmReplacement:true` only after approval.\n- Prefer Markdown whenever it can represent the component and all authored properties. Use `` for a standard HTML element with authored properties that Markdown cannot express. Use `` only for a uniquely named top-level Content Block template.\n- Read the Content Block\'s Templates children before writing `ws:name`. The value must exactly match a unique top-level template instance name. Preserve unresolved names and report their diagnostics instead of deleting them.\n- When a template is renamed or deleted, use `migrate-content-block-template-references` to update a selected set of affected MDX files. The first call returns a plan. Report its changed-file, update, omission, and diagnostic counts, then repeat the exact request with its `confirmationToken` only after approval. A rename changes matching `ws:name` values; a removal deletes matching MDX elements. Invalid files remain unchanged and are reported in diagnostics.\n- `edit-content-block-source` replaces the complete MDX source. Preserve frontmatter and unrelated source when making a bounded edit.\n- `update-content-block-frontmatter` replaces the complete frontmatter mapping. Inspect the current source first and include every property that must remain.\n- Use `update-content-block-frontmatter` for MCP frontmatter edits. MDX-rendered elements are not persistent instance targets for generic `bind-props` or `update-text` calls. Preserve existing `mode:"readwrite"` bindings when encountered; they are valid only for exact direct paths into the connected document\'s frontmatter. Keep computed expressions and `$ref` values read-only.\n- Inspect every returned diagnostic. Invalid MDX is saved rather than silently repaired; preserve the source, report the source range, and fix only the requested or invalid part.\n- If an edit in a long-lived MCP session reports a conflict after another client saved the Asset, call `reload-content-block-source`, inspect the latest source, reapply the requested change, and retry. One-shot CLI calls refresh before each operation and normally cannot reproduce a stale session. Never overwrite the newer revision blindly.\n\n## Move elements\n\nCommands:\n\n- MCP tool: move-instance {"moves":"moves.json contents"}\n\nNotes:\n\n- Use `position: "end"` to append an instance. Repeating this for A and then B preserves the final order A, B.\n- A numeric `insertIndex` addresses the target parent\'s children before the moved instance is removed. Use it for exact placement; do not calculate the last index to append.\n- Moves in one `moves` array are applied sequentially in array order.\n\n## Clone element subtree\n\nCommands:\n\n- MCP tool: clone-instance {"sourceInstanceId":"","targetParentInstanceId":""}\n\n## Delete element subtree\n\nCommands:\n\n- MCP tool: delete-instance {"instanceIds":[""]}\n\n## List text/expression children\n\nCommands:\n\n- MCP tool: list-texts {"pagePath":"/"}\n\n## Update text child\n\nCommands:\n\n- MCP tool: update-text {"instanceId":"","childIndex":0,"text":"Launch faster"}\n\n## Replace bounded literal text\n\nCommands:\n\n- MCP tool: replace-text {"find":"Start free","replace":"Get started","match":"exact","pagePath":"/pricing","limit":20}\n\nNotes:\n\n- This changes only literal text children, never expression children. Scope it to pagePath or pageId and set a limit before a broad replacement.\n\n## Replace bounded static prop text\n\nCommands:\n\n- MCP tool: replace-prop-text {"find":"old.example.com","replace":"www.example.com","match":"substring","names":["href","code"],"limit":20}\n\nNotes:\n\n- This changes only static string props such as href, alt, aria-label, title, and HTML embed code. It never changes expressions, resources, actions, assets, or other dynamic bindings. Use names or instanceIds and a limit to narrow the change.\n\n## Replace bounded resource text\n\nCommands:\n\n- MCP tool: replace-resource-text {"find":"api.old.example.com","replace":"api.example.com","fields":["url"],"limit":20}\n\nNotes:\n\n- This changes resource names and fixed URL literals only. It skips dynamic URL expressions, headers, search parameters, request bodies, and GraphQL query code.\n\n## Update props\n\nCommands:\n\n- MCP tool: update-props {"updates":"props.json contents"}\n- MCP tool: replace-prop-text {"find":"Old label","replace":"New label","names":["aria-label","title"],"limit":20}\n\nNotes:\n\n- Use this for fixed prop values such as `aria-label`, `alt`, `id`, static `href`, and other direct string/number/boolean/json prop values.\n\n## Add JSON-LD structured data\n\nCommands:\n\n- MCP tool: components.get {"component":"JsonLd"}\n- MCP tool: insert-component {"parentInstanceId":"","component":"JsonLd"}\n- MCP tool: update-props {"updates":[{"instanceId":"","name":"code","type":"string","value":"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Organization\\",\\"name\\":\\"Acme\\"}"}]}\n- MCP tool: bind-props {"bindings":[{"instanceId":"","name":"code","binding":{"type":"expression","value":"({ \'@context\': \'https://schema.org\', \'@type\': \'Article\', headline: post.title })"}}]}\n- MCP tool: audit {"scopes":["seo"],"pagePath":"/"}\n\nNotes:\n\n- Prefer placing `JsonLd` inside `HeadSlot`.\n- For fixed structured data, store `code` as a JSON object or array encoded as a compact string. The Builder formats it for editing.\n- For structured data containing runtime values, use `bind-props` with an expression that evaluates directly to an object or array. Do not call `JSON.stringify` or assemble JSON with string concatenation. Webstudio stores the expression as source text, evaluates it at runtime, and the `JsonLd` component validates and serializes the resulting value.\n- The semantic prop update rejects malformed JSON and structurally invalid fixed JSON-LD with a precise JSON path.\n- The SEO audit also warns about a missing top-level `@context`, unknown or superseded Schema.org terms, properties unsupported by the supplied type, and incompatible primitive value types.\n- Schema.org vocabulary findings are warnings because custom vocabularies and extensions remain valid. Dynamic JSON-LD is marked as skipped for rendered validation.\n- Do not use bindings just to set static text.\n\n## Delete props\n\nCommands:\n\n- MCP tool: delete-props {"deletions":"props.json contents"}\n\n## Bind props to expressions/resources/actions\n\nCommands:\n\n- MCP tool: bind-props {"bindings":"bindings.json contents"}\n\nNotes:\n\n- Use this only when the prop should remain dynamic: expression, resource, action, or an existing scoped runtime context value such as `system`.\n- For a fixed string value, use `update-props` with `type:"string"` and a direct `value` instead.\n\n## Read styles\n\nCommands:\n\n- MCP tool: get-styles {"instanceIds":[""],"includeTokens":true}\n\n## Update local styles\n\nCommands:\n\n- MCP tool: update-styles {"updates":"styles.json contents"}\n\n## Delete local styles\n\nCommands:\n\n- MCP tool: delete-styles {"deletions":"styles.json contents"}\n\n## Replace matching style values\n\nCommands:\n\n- MCP tool: replace-styles {"property":"color","fromValue":{"type":"keyword","value":"red"},"toValue":{"type":"keyword","value":"blue"}}\n\n## List design tokens\n\nCommands:\n\n- MCP tool: list-design-tokens {}\n- MCP tool: list-design-tokens {"withUsage":true}\n- MCP tool: list-design-tokens {"verbose":true}\n\nNotes:\n\n- The default response is compact and includes token id, name, declaration count, and optional usage count.\n- Use `verbose:true` only when you need the full inline style declarations.\n\n## Create design tokens\n\nCommands:\n\n- MCP tool: create-design-token {"tokens":"tokens.json contents"}\n\n## Update design token styles\n\nCommands:\n\n- MCP tool: update-design-token-styles {"designTokenId":"","updates":"styles.json contents"}\n\n## Delete design token styles\n\nCommands:\n\n- MCP tool: delete-design-token-styles {"designTokenId":"","deletions":"styles.json contents"}\n\n## Attach design token to instances\n\nCommands:\n\n- MCP tool: attach-design-token {"designTokenId":"","instanceIds":"instances.json contents"}\n\n## Detach design token from instances\n\nCommands:\n\n- MCP tool: detach-design-token {"designTokenId":"","instanceIds":"instances.json contents"}\n\n## Extract design token from local styles\n\nCommands:\n\n- MCP tool: extract-design-token {"instanceIds":[""],"name":"Brand Primary","removeLocalProps":["color"]}\n\n## List CSS variables\n\nCommands:\n\n- MCP tool: list-css-variables {"withUsage":true}\n\n## Define CSS variables\n\nCommands:\n\n- MCP tool: define-css-variable {"vars":{"--color-primary":"#2d3748","--color-accent":"#e53e3e","--space-card":"1.5rem"},"overwrite":true}\n\nNotes:\n\n- Define or overwrite multiple CSS variables atomically by including every name and value in one `vars` object.\n- Pass colors as CSS strings. Structured `hex` color components use normalized values from `0` to `1`, not `0` to `255`.\n\n## Delete CSS variables\n\nCommands:\n\n- MCP tool: delete-css-variable {"names":["--color-primary","--color-accent","--space-card"],"force":true}\n\nNotes:\n\n- Delete multiple CSS variables atomically by including every name in one `names` array. Destructive MCP calls still require the returned confirmation token before they commit.\n\n## Rewrite CSS variable references\n\nCommands:\n\n- MCP tool: rewrite-css-variable-refs {"map":"variables.json contents"}\n\n## List data variables\n\nCommands:\n\n- MCP tool: list-variables {}\n- MCP tool: list-variables {"scopeInstanceId":""}\n\nNotes:\n\n- Data variables live in the internal `dataSources` namespace.\n- For raw `snapshot`, request the public `variables` namespace rather than the internal `dataSources` name. Raw patch payloads still use `dataSources` when applying direct changes.\n- Scope variables to the instance where they should become available. Descendants can use them in expressions, and nested variables with the same name mask outer variables.\n\n## Create data variable\n\nCommands:\n\n- MCP tool: create-variable {"scopeInstanceId":"","name":"title","value":{"type":"string","value":"Hello"}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"count","value":{"type":"number","value":3}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"featured","value":{"type":"boolean","value":true}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"tags","value":{"type":"json","value":["news","product"]}}\n- MCP tool: create-variable {"scopeInstanceId":"","name":"filters","value":{"type":"json","value":{"tag":"news"}}}\n\nNotes:\n\n- Data variable values support `string`, `number`, `boolean`, and `json`. Use `json` for all arrays and objects.\n- Parameters are internal scoped runtime values provided by pages, collections, or components. They are not a public authoring surface: do not create, update, or delete parameter records. Use data variables/resources for user-authored data, and reference documented context values such as `system` only where they are already in scope.\n\n## Update data variable\n\nCommands:\n\n- MCP tool: update-variable {"dataSourceId":"","values":{"value":{"type":"json","value":{"count":1}}}}\n\n## Delete data variable\n\nCommands:\n\n- MCP tool: delete-variable {"dataSourceId":""}\n\n## List resources\n\nCommands:\n\n- MCP tool: list-resources {}\n- MCP tool: list-resources {"scopeInstanceId":""}\n\n## Create resource\n\nCommands:\n\n- MCP tool: create-resource {"resource":{"name":"Posts","method":"get","url":"https://api.example.com/posts","headers":[]}}\n- MCP tool: create-resource {"resource":{"name":"Posts","method":"get","url":"\'https://api.example.com/posts?tag=\' + filters.tag","headers":[]},"scopeInstanceId":"","dataSourceName":"posts"}\n- MCP tool: create-resource {"resource":{"name":"Filtered Posts","method":"get","url":"https://api.example.com/posts","searchParams":[{"name":"tag","value":"filters.tag"},{"name":"source","value":{"type":"literal","value":"website"}}],"headers":[{"name":"Authorization","value":"\'Bearer \' + auth.token"}]},"scopeInstanceId":"","dataSourceName":"posts"}\n- MCP tool: create-resource {"resource":{"name":"Post GraphQL","control":"graphql","method":"post","url":"https://api.example.com/graphql","headers":[{"name":"Content-Type","value":{"type":"literal","value":"application/json"}}],"body":"{ query: \'query Post($slug: String!) { post(slug: $slug) { title } }\', variables: { slug: system.params.slug } }"},"scopeInstanceId":"","dataSourceName":"post"}\n- MCP tool: create-resource {"resource":{"name":"Current Date","control":"system","method":"get","url":"/$resources/current-date","headers":[]},"scopeInstanceId":"","dataSourceName":"currentDate"}\n\nNotes:\n\n- Resource `url` accepts plain fixed URLs and paths such as `https://api.example.com/posts` and `/$resources/current-date`.\n- Resource `url` can also be a JavaScript expression when it is computed, such as `"https://api.example.com/posts?tag=" + filters.tag`.\n- Header values, search parameter values, and body accept expressions for dynamic values. For fixed text, use `{"type":"literal","value":"application/json"}`; Webstudio stores the required string expression for you.\n- Search parameter values, header values, and body expressions can read scoped variables and documented runtime context values such as `system` when they are available at the resource scope.\n- Add `scopeInstanceId` and `dataSourceName` when the resource result should be exposed as a scoped read data variable. Scoped resources are generated into the page resource `data` map and may be loaded during page rendering. Use this for read-oriented resources such as GET CMS/API data.\n- For submit/write/action resources, create the resource without `scopeInstanceId`, then bind a component prop such as a Form `action` with `bind-props` and `binding.type: "resource"`. Prop-bound resources are generated into the page resource `action` map instead of the read `data` map. Use this for POST, PUT, DELETE, webhooks, GraphQL submissions, and other explicit action flows.\n- Resource `method` can be `get`, `post`, `put`, or `delete`. Use GET for read data, POST for creates/GraphQL/webhooks/form submissions, PUT for full updates or replacements, and DELETE for deletion actions.\n- Optional `control` values are `graphql` and `system`. Use `graphql` for GraphQL-style requests, usually POST with a query body. Use `system` for built-in resources such as `"/$resources/sitemap.xml"`, `"/$resources/current-date"`, and `"/$resources/assets"` and when the resource should use the built-in `system` parameter. System fields are `system.origin`, `system.pathname`, `system.params`, and `system.search`.\n\n## Update resource\n\nCommands:\n\n- MCP tool: update-resource {"resourceId":"","values":{"url":"https://api.example.com/posts"}}\n- MCP tool: replace-resource-text {"find":"api.old.example.com","replace":"api.example.com","fields":["url"],"limit":20}\n\n## Query Markdown assets\n\nCommands:\n\n- MCP tool: get-asset-field-catalog {}\n- MCP tool: validate-asset-query {"query":{"where":{"all":[{"field":["extension"],"operator":"eq","value":"md"},{"field":["properties","draft"],"operator":"ne","value":true}]},"limit":20}}\n- MCP tool: create-assets-resource {"name":"All assets","scopeInstanceId":"","dataSourceName":"assets"}\n- MCP tool: create-assets-resource {"name":"Published posts","scopeInstanceId":"","dataSourceName":"posts","query":{"result":"many","where":{"all":[{"field":["extension"],"operator":"eq","value":{"type":"literal","value":"md"}},{"field":["properties","draft"],"operator":"ne","value":{"type":"literal","value":true}}]},"sort":[{"field":["properties","publishedAt"],"direction":"desc"}],"limit":{"type":"literal","value":20},"output":{"mode":"fields","includeMetadata":false,"fields":[["properties","title"],["properties","slug"],["properties","publishedAt"],["properties","excerpt"]]},"content":{"mode":"none"}}}\n- MCP tool: create-assets-resource {"name":"Post by slug or ID","scopeInstanceId":"","dataSourceName":"post","query":{"result":"one","where":{"all":[{"field":["extension"],"operator":"eq","value":{"type":"literal","value":"md"}},{"field":["properties","slug"],"operator":"eq","value":"system.params.slug"}]},"output":{"mode":"fields","includeMetadata":false,"fields":[["properties","title"],["properties","publishedAt"]]},"content":{"mode":"markdown-body-ref"}}}\n- MCP tool: list-assets-resources {}\n- MCP tool: get-assets-resource {"resourceId":""}\n- MCP tool: update-assets-resource {"resourceId":"","values":{"query":null}}\n- MCP tool: preview-asset-query {"query":{"result":"one","where":{"all":[{"field":["extension"],"operator":"eq","value":"md"},{"field":["properties","slug"],"operator":"eq","value":"hello-world"}]},"output":{"mode":"fields","includeMetadata":false,"fields":[["properties","title"]]},"content":{"mode":"markdown-body-ref"}}}\n\nNotes:\n\n- Read the field catalog before authoring unfamiliar queries. It includes dynamic schema-less frontmatter paths such as `properties.author.name`, observed types, optionality, and mixed-type state without downloading the source files.\n- Minimize the deployed content database by using `output.mode:"fields"` and selecting only fields the rendered page needs. Keep `includeMetadata:false` unless the rendered value needs file metadata such as name, path, MIME type, or creation date, and avoid `output.mode:"all"` as a convenience default. Query diagnostics are returned separately and do not require metadata output. Filters and sorting may still require their referenced fields in the database.\n- Every reachable Assets data source contributes to the shared published database. Keep one final resource per rendered query. Update an existing scoped resource rather than creating a placeholder, preview copy, or repair replacement, and remove obsolete duplicates.\n- Keep bounded overview filters, limits, and offsets literal and add a deterministic ID tie-breaker to the sort. With `content.mode:"none"`, compilation can materialize the small overview result instead of retaining its output fields across every candidate document. Use runtime expressions only for genuinely dynamic values such as the detail slug.\n- Combine filters with `where.all` (AND) and `where.any` (OR), including nested groups. Filter values, limit, and offset on a saved resource may be Webstudio expressions evaluated at render time. Preview queries use concrete JSON values.\n- Query Markdown or MDX files directly and use `content.mode:"markdown-body-ref"` when rendering their bodies. The published database retains metadata and a document reference, then fetches only the selected files from Asset storage at runtime; it does not embed their bodies. Filter and paginate before content is loaded.\n- `full` and bounded `range` continue to request embedded file bytes. Use them only when the caller requires the complete source or a byte range.\n- In Markdown or MDX, reference sibling Assets with conventional relative URLs such as `../images/hero.png`. Deferred `markdown-body-ref` content resolves matching files against the document\'s folder and emits the correct Builder or published Asset URL. Keep external URLs absolute.\n- Markdown Embed renders sanitized authored HTML for figures, captions, audio, video, and iframes. Scripts, inline event handlers, `srcdoc`, and unsafe URL protocols are removed. It does not render Webstudio MDX elements; connect the `.mdx` file to a Content Block for that workflow.\n- Preview each query with concrete values before saving it. Inspect `__diagnostics__.query` for the temporary query-only footprint and `__diagnostics__.database` for the merged database built from all reachable Assets queries. Only `database.usedBytes` counts toward `database.maxBytes`; query sizes must not be summed and are not separate allowances. Compare `usedBytes`, `unboundedBytes`, and `truncated` within both scopes. A completed Markdown blog should include every source document without truncation, contain no embedded Markdown bodies, and retain only its intended materialized overview query. When merged usage approaches the limit, remove duplicate reachable resources first, then unused output fields, then narrow candidate files.\n- Use `result:"many"` for listings. It returns the ID-keyed map at `.data`, with `totalCount` and `hasMore` at `.meta`, and remains the default for existing queries. Bind a listing Collection to `posts.data`.\n- Use `result:"one"` for a unique detail route. It returns the selected item or `null` directly at `post.data`, always includes its `id`, and omits pagination. Bind components and page settings directly with expressions such as `post.data.properties.title`, `post.data.content.text`, and `post.data ? 200 : 404`. `result:"first"` and `result:"last"` also return a direct item or `null` but require explicit sorting.\n- Assets always executes a structured query. Omit `query` to use the default many-result query, which selects URL and optional image dimensions. Set `values.query:null` to restore it.\n- `create-assets-resource` and `update-assets-resource` are the semantic authoring path. Do not construct the internal query URL, headers, or body expression manually.\n- The shared metadata index is maintained automatically and is emitted only when a configured Assets resource is reachable.\n\n## Delete resource\n\nCommands:\n\n- MCP tool: delete-resource {"resourceId":""}\n\n## List assets\n\nCommands:\n\n- MCP tool: list-assets {"withUsage":true}\n- MCP tool: list-assets {"verbose":true}\n\nNotes:\n\n- Compact results include each asset\'s folder id. Use `verbose:true` to include complete records for a page of assets, or `get-asset` to read one complete record including description, folder, creation time, and image/font metadata.\n- Image asset descriptions are the default alt text for asset-backed Image components.\n- To generate missing descriptions, inspect the image in its rendered page or asset source, write a concise description of its purpose, and save it on the asset rather than duplicating it on each Image instance.\n\n## Get asset\n\nCommands:\n\n- MCP tool: get-asset {"assetId":""}\n\n## List asset folders\n\nCommands:\n\n- MCP tool: list-asset-folders {}\n\n## Create asset folder\n\nCommands:\n\n- MCP tool: create-asset-folder {"name":"Marketing"}\n- MCP tool: create-asset-folder {"name":"Photos","parentId":""}\n\n## Update asset folder\n\nCommands:\n\n- MCP tool: update-asset-folder {"folderId":"","values":{"name":"Brand"}}\n- MCP tool: update-asset-folder {"folderId":"","values":{"parentId":""}}\n- MCP tool: update-asset-folder {"folderId":"","values":{"parentId":null}}\n\nNotes:\n\n- Updating `parentId` is the folder equivalent of cut and paste. Use `null` to move a folder to Root.\n\n## Duplicate asset folder\n\nCommands:\n\n- MCP tool: duplicate-asset-folder {"folderId":""}\n- MCP tool: duplicate-asset-folder {"folderId":"","parentId":""}\n\nNotes:\n\n- Duplication recursively copies descendant folders and assets. This is the folder equivalent of copy and paste.\n\n## Delete asset folder\n\nCommands:\n\n- MCP tool: delete-asset-folder {"folderId":""}\n\nNotes:\n\n- Deleting a folder recursively deletes its descendant folders and assets.\n\n## Update asset metadata\n\nCommands:\n\n- MCP tool: update-asset {"assetId":"","values":{"description":"Team collaborating around a whiteboard"}}\n- MCP tool: update-asset {"assetId":"","values":{"meta":{"family":"Rajdhani","style":"normal","weight":600}}}\n\nNotes:\n\n- Use an empty description only when the image is intentionally decorative.\n- Updating an image asset description updates the default alt text wherever that asset is used with an asset-backed alt prop.\n- Font metadata updates merge with the detected metadata and are validated before committing; use this to correct a family, style, or weight after upload.\n\n## Generate missing image descriptions with an agent\n\nCommands:\n\n- MCP tool: audit {"scopes":["accessibility"],"verbose":true}\n- MCP tool: set-image-descriptions {"updates":[{"assetId":"hero-id","description":"Team collaborating around a whiteboard"},{"assetId":"texture-id","decorative":true}]}\n- MCP tool: audit {"scopes":["accessibility"]}\n\nNotes:\n\n- Start from `missing-image-description` findings. Inspect each image in its rendered page context before writing text.\n- The vision-capable agent generates the wording; the CLI validates and stores it but does not contain its own vision model.\n- Use `decorative:true` only when the image adds no information. This intentionally stores an empty description so later audits do not report it as missing.\n- Re-run the accessibility audit after the update. Asset-backed Image components use the saved asset description as their default alt text.\n\n## Manage fonts\n\nCommands:\n\n- MCP tool: list-fonts {"includeSystem":true}\n- MCP tool: list-assets {"type":"font"}\n- MCP tool: upload-asset {"asset":{"name":"acme-sans.woff2","type":"font","format":"woff2","meta":{"family":"Acme Sans","style":"normal","weight":400}},"assetsDir":".webstudio/assets"}\n- MCP tool: update-styles {"updates":"styles.json contents"}\n\nNotes:\n\n- Use `list-fonts` to discover uploaded families and system stacks. Upload/delete fonts through the existing asset tools, then apply a family with a `font-family` style declaration.\n\n## Upload one asset\n\nCommands:\n\n- MCP tool: upload-asset {"asset":{"name":"image.png","type":"image","format":"png","meta":{"width":1200,"height":630}},"assetsDir":".webstudio/assets"}\n- MCP tool: upload-asset {"asset":{"name":"image.png","type":"image","format":"png","folderId":"","meta":{"width":1200,"height":630}},"assetsDir":".webstudio/assets"}\n\n## Upload asset batch\n\nCommands:\n\n- MCP tool: upload-assets {"assets":[{"name":"image.png","type":"image","format":"png","meta":{"width":1200,"height":630}}],"assetsDir":".webstudio/assets"}\n\nNotes:\n\n- Multi-file uploads return `uploaded`, `failed`, and `ambiguous` lists with the\n original input index. Retry only `failed` files. A forced upload in\n `ambiguous` may already be committed; inspect the Assets list before deciding\n whether to upload it again. Successful uploads remain committed.\n\n## Duplicate asset\n\nCommands:\n\n- MCP tool: duplicate-asset {"assetId":""}\n- MCP tool: duplicate-asset {"assetId":"","folderId":""}\n- MCP tool: duplicate-asset {"assetId":"","folderId":null}\n\nNotes:\n\n- Duplication is the asset equivalent of copy and paste. Updating `folderId` is the equivalent of cut and paste; use `null` for Root.\n\n## Download asset\n\nCommands:\n\n- MCP tool: download-asset {"assetId":""}\n\n## Find asset usage\n\nCommands:\n\n- MCP tool: find-asset-usage {"assetId":"