GemDesign Prototyping
Use the
CLI to create, save, and modify high-fidelity prototype pages on the GemDesign platform. You generate HTML following the GemDesign Page Spec, validate it, then save via CLI.
When to Invoke
- User wants to create a UI prototype or design a page
- User has a requirements document and wants batch page generation
- User wants to modify an existing GemDesign page
- User wants to view existing GemDesign pages
Prerequisites
CRITICAL: Step 1, Step 2, and Step 2.5 MUST be executed strictly in order BEFORE starting any Workflow. Each step MUST fully complete before proceeding to the next. Do NOT skip, parallelize, or advance until the current step is confirmed successful.
IMPORTANT — Step 3 timing: Step 3 (Start the Local Server) is NOT executed immediately after login. It MUST be executed INSIDE a Workflow, AFTER the app is created or reused (i.e., after
/
+
), and BEFORE any page generation. Starting the server before the app exists is a violation — the server serves pages from the project subdirectory derived from the app, so the app must exist first.
Step 1: Verify & Install GemDesign CLI (MUST complete before Step 2)
ALWAYS verify CLI installation and version first before doing any other work. This step is a hard gate — no other operations (
,
,
,
, etc.) may run until this step is confirmed complete.
-
Check if CLI is installed:
bash
npm list -g @gemdesign-ai/cli
- If the command returns version info (e.g., ), CLI is installed - proceed to step 2.
- If the command returns empty or error (e.g., or ), CLI is NOT installed. Run:
bash
npm install -g @gemdesign-ai/cli
Wait for the installation to finish, then re-verify with npm list -g @gemdesign-ai/cli
. Do NOT proceed until re-verification confirms the installed version.
-
Check if CLI is latest version (only after step 1 confirms CLI is installed):
bash
npm outdated -g @gemdesign-ai/cli
- If the command returns empty or shows , CLI is up-to-date - this step is complete, proceed to Step 2.
- If the command shows version info with different and values, CLI is outdated. Update to latest:
bash
npm update -g @gemdesign-ai/cli
Wait for the update to finish, then re-verify with npm outdated -g @gemdesign-ai/cli
. Do NOT proceed until re-verification confirms the CLI is up-to-date.
After this step is confirmed complete, the
command is available globally at the latest version.
Only then may you advance to Step 2.
Step 2: Verify Login (MUST complete after Step 1, before any Workflow)
ALWAYS verify login status after Step 1 is complete. Run this command:
- If it succeeds (returns user info), the user is logged in — proceed to a Workflow (A/B/C). Step 3 (local server) will be executed INSIDE the workflow, after the app is created/reused.
- If it fails (returns an error like "token 无效" or "未提供 token"), the user is NOT authenticated. You MUST:
- Tell the user: if they don't have an account or token yet, go to https://design.gemcoder.com to register an account and get an API token. The token retrieval path is: log in to the platform -> click 个人中心 (Personal Center) -> get the MCP 令牌 (MCP token).
- Ask the user for their API token (use tool to prompt the user to input their token).
- Once the user provides their token, automatically run the login command for them:
bash
gemdesign auth login --token <user_provided_token>
- Re-verify with to confirm login succeeded.
- If login still fails, repeat from step 2 (ask the user to provide their token again).
- Only proceed to a Workflow after login is confirmed.
HARD GATE: Until login is confirmed via
, you MUST NOT perform ANY page-generation work — this includes CLI commands (
,
,
,
) AND local file operations (writing
, streaming write, creating the
directory). Local HTML generation is NOT a workaround for the login gate; a page can only be saved to the platform by an authenticated user, so generating it before login is wasted work. If login fails, stop and resolve authentication first — do not start writing any HTML.
Step 2.5: Configure htmlWorkdir and Clean Up (MUST complete after Step 2, before any Workflow)
After login is confirmed, configure the HTML working directory (
) and then clean up stale empty project directories left over from previous interrupted sessions. Both operations MUST complete before starting any Workflow (in particular, before
), because
needs
to be configured first in order to scan it.
-
Configure htmlWorkdir (run once, persists across sessions):
CRITICAL - sync-creates the local project folder under , and validates before launching. If
is not configured,
skips local folder creation (returns a
), and
returns
{"success":false,"error":"未配置 htmlWorkdir,请先执行 gemdesign server workdir --path <path> 设置 HTML 工作目录"}
and refuses to start. This prevents the background process's cwd from mismatching the actual HTML generation directory, which would cause fileWatcher to miss
changes and the canvas to stay blank ("page generated but canvas not showing").
bash
gemdesign server workdir --path ./output
- Relative paths are resolved against the current working directory to an absolute path.
- Verify with (no flags) - returns
{"success":true,"htmlWorkdir":"<absolute path>"}
.
- If htmlWorkdir is already configured (returns a non-empty ), skip this step.
-
Clean up empty project directories (MUST run AFTER step 1, because
scans
which must be configured first):
- The command scans the configured (the directory) for project subdirectories (named ).
- It deletes:
- Empty project directories: project subdirectories that contain zero files (created by but never had a page saved — e.g., the session was interrupted).
- Orphaned streaming files: files left over from streaming write that was started but never completed.
- Returns JSON:
{"success":true,"message":"清理完成:删除 N 个空项目目录,清理 M 个遗留文件","removedDirs":[...],"removedLocks":[...]}
- This step is non-blocking: cleanup failures do not prevent proceeding to a Workflow. The command always returns unless an unexpected error occurs.
Step 3: Start the Local Server (MUST complete after app is created/reused, before any page generation)
CRITICAL - HARD GATE: You MUST open the browser in this step. This is NON-NEGOTIABLE and MUST NOT be skipped, deferred, or treated as optional. Generating any page before the browser is open is a SERIOUS VIOLATION - the user needs the real-time preview surface to see pages as they are generated. You MUST actively open the browser yourself using your platform's built-in browser/preview tool (see step 3 below for the fallback strategy). Do NOT just output a URL in chat text and wait for the user to click it — you MUST programmatically open the browser.
TIMING — Execute INSIDE a Workflow, NOT immediately after login. Step 3 is invoked from within Workflow A/B/C (see each workflow's "Start the local server" step), AFTER the app has been created or reused via
/
and confirmed via
. Do NOT start the server right after Step 2 (login) — the server serves pages from the project subdirectory derived from the app (
<projectDir> = {projectName}__{appuuid}
), so the app must exist first. Starting the server before the app exists is a violation.
After Step 1 (CLI installed), Step 2 (Login verified), AND the app is created/reused (inside a Workflow) are all confirmed complete, start the local server for real-time streaming preview.
The local server provides real-time streaming preview of HTML pages as they are being generated. The server is built into the CLI and managed via the
commands. The server runs on port
by default; if that port is occupied it auto-retries the next available port (up to
).
-
Ensure htmlWorkdir is configured (MUST complete before
in a Workflow, and before
):
htmlWorkdir is configured in Step 2.5 (persists across sessions).
sync-creates the local project folder under
, and
validates
before launching — if it is not configured,
skips local folder creation (returns a
) and
refuses to start, causing fileWatcher to miss
changes and the canvas to stay blank ("page generated but canvas not showing").
If Step 2.5 was skipped (e.g. resuming a session), verify now:
(no flags) returns
{"success":true,"htmlWorkdir":"<absolute path>"}
. If it returns an empty
, run
gemdesign server workdir --path ./output
before proceeding.
-
Stop any previously running server (MANDATORY before every
, CANNOT be skipped):
CRITICAL — 执行 之前必须先执行 终止之前启动的服务,无论应用是新建还是复用都不可跳过。这确保 fileWatcher 绑定到正确的项目目录,避免残留进程干扰新会话。
HARD GATE - 严禁跳过此步:无论你认为当前是否已有服务在运行,都必须执行
命令。禁止以"服务器未运行"、"上一次会话已启动"、"浏览器预览已打开"、"为了节省时间"等任何理由跳过 stop。必须以
的实际返回结果作为唯一判定依据。
- 返回
{"success":true,"message":"本地服务已停止"}
表示已停止,继续下一步。
- 返回
{"success":false,"error":"未发现运行中的本地服务"}
表示无运行中的服务,忽略此错误继续下一步。
- 必须等待上述命令返回结果后才能进入第 2 步。在 stop 命令未返回前,不得执行任何 操作。
-
Start the local server using the CLI command:
必须在执行此命令前先完成上一步的 ,不得在未停止旧服务的情况下直接 start。
HARD GATE - 顺序约束:
必须在
命令返回结果(成功或"未发现运行中的本地服务"错误)之后才能执行。严禁以下行为:
- 将 与 并行执行(例如在同一个并行工具调用批次中);
- 在 命令尚未返回结果时就发起 ;
- 先执行 再执行 ;
- 因为"觉得没必要 stop"而跳过 stop 直接 start。
正确顺序:执行
-> 等待命令返回结果 -> 执行
。这是不可逆的串行依赖关系。
- If the server starts successfully, the command returns JSON:
{"success":true,"port":<port>,"url":"http://localhost:<port>"}
- If the server fails to start, the command returns JSON with an error:
{"success":false,"error":"<error message>"}
- On error: Read the error message carefully. Common errors:
- : The CLI installation is incomplete — reinstall the CLI.
- : Possible port conflict or config file error — check .
- Record the from the success response for subsequent steps.
-
Check server status (optional, for debugging):
Returns:
{"success":true,"status":"running","port":<port>,"url":"http://localhost:<port>"}
or
{"success":true,"status":"stopped"}
-
Open the preview (MANDATORY — HARD GATE, DO NOT SKIP): After the server is confirmed running (the
command returned success), you MUST open the browser and navigate to the service page named
GemDesign设计器 (URL:
- use the port from the
response).
This step is NON-NEGOTIABLE. Do NOT proceed to any page generation workflow (Workflow A/B/C) until the browser is open at
. The server being up is NOT the same as the preview being open - the user must SEE the preview surface in the browser.
DO NOT just output a URL in chat text. You MUST use a tool to actually open the browser. Outputting something like "服务器启动成功!请在浏览器中打开
http://localhost:4056" is a VIOLATION — the browser must be opened programmatically, not by asking the user to click a link.
How to open the browser — use the following methods in priority order:
Try the following methods in priority order. Use the FIRST one that is available and succeeds. If a method fails, skip it and try the next:
| Priority | Method | How to use |
|---|
| 1 | Your platform's built-in browser/preview tool | You MUST check what browser/preview tools are available on your current agent platform and use the most appropriate one. Different platforms provide different built-in tools — use whichever one your platform offers. Examples of platform-specific tools: Trae provides and the MCP's ; Cursor provides its own preview mechanism; other platforms may have equivalent tools. The key requirement is: you MUST use a tool to programmatically open the browser, not just output a URL in chat. Navigate to using the tool. |
| 2 | OS default browser command | If no built-in browser/preview tool is available (or it failed), open the default browser via OS command: Windows start http://localhost:<port>/
, macOS open http://localhost:<port>/
, Linux xdg-open http://localhost:<port>/
. |
| 3 | Tell the user to open the URL | If ALL above methods fail or are unavailable, as a last resort, clearly tell the user: "请在浏览器中打开 http://localhost:<port>/ 查看设计器预览" and wait for the user to confirm before proceeding. |
How to find your platform's built-in tool: Check your available tools list — look for tools with names like
,
,
,
, or similar. Any tool that can open a URL in a browser panel qualifies. Use it with the URL
.
Ensuring success:
- If the highest-priority method returned an error or you're unsure whether it succeeded, immediately fall back to the next method in the table.
- After opening the browser, verify the server is still accessible by re-checking the debug endpoint (
http://localhost:<port>/api/local/stream/debug
returns 200).
- Only proceed to page generation after you have made a best-effort attempt to open the browser using at least one available method.
After the preview is open, you may proceed to page generation workflows.
CRITICAL - The browser is opened EXACTLY ONCE, only here in Step 3. Once the browser is open at
(the designer SPA root), you MUST NEVER open the browser again — not during page generation (Workflows A/B/C), not during modification flows, not to "refresh" or "show" a generated page. The designer SPA stays open for the entire session; generated HTML is loaded into an iframe INSIDE the designer via SSE (see "Streaming Write Workflow"), NOT by navigating the browser to a new URL.
Opening the browser again will navigate it away from the designer to whatever URL you passed — this OVERWRITES the designer with the generated HTML (or a 404), destroying the preview surface the user needs. The URL used to open the browser MUST ALWAYS be the designer root URL
— NEVER a path to a generated
file (e.g.
http://localhost:<port>/output/<projectDir>/<pageuuid>.html
), NEVER a page-specific URL. Generated pages have no direct browser URL; they are only viewable through the designer's iframe via SSE.
CLI Command Reference
Server Management
bash
gemdesign server start [--port <port>] # 启动本地设计器服务(默认端口 4056)
gemdesign server stop # 停止本地设计器服务
gemdesign server status # 查看服务运行状态
gemdesign server workdir --path <path> # 保存 HTML 工作目录(htmlWorkdir,相对路径基于当前目录解析为绝对路径)
gemdesign server workdir # 查看当前 htmlWorkdir
gemdesign server workdir --clear # 清除 htmlWorkdir 配置
gemdesign server cleanup # 清理空项目目录和遗留的流式文件
server workdir 保存 HTML 工作目录到
的
字段。本地服务启动后通过 fileWatcher 监听此目录下的
文件变更,并经 SSE 推送到浏览器画布。
会在此目录下同步创建项目子目录 ,
也会在启动前校验 htmlWorkdir 是否已配置--未配置时
跳过本地目录创建(返回
),
拒绝启动并返回错误提示,避免后台进程 cwd 与实际 HTML 生成目录不一致导致"页面生成但画布不显示"。建议在登录后、
之前执行一次
gemdesign server workdir --path ./output
(路径通常是
,即页面 HTML 的根目录)。配置一次后持久化,后续无需重复设置。
server start 以后台进程方式启动本地服务。
执行 之前必须先执行 终止之前的服务,不得在未停止旧服务的情况下直接 start。
严禁跳过(即使你认为没有运行中的服务也必须执行该命令),且
必须等 命令返回结果后才能执行——禁止将两者并行执行、或在 stop 未返回时就发起 start。启动成功返回含
和
的 JSON;失败返回含
的 JSON,需仔细阅读错误信息诊断并修复后再重试(重试前同样要先 stop)。
server stop stops the running server. On Windows, uses
to terminate the process tree. Returns error if no server is running or if the process cannot be terminated — 此时该错误可忽略(表示本就无运行中的服务),但仍视为 stop 步骤已执行完成,可继续 start。
server status returns the current status (
or
), port, and URL if running.
Authentication
bash
gemdesign auth login --token <token> # Configure API token
gemdesign auth whoami # Verify identity
App Management
bash
gemdesign app create --name "MyApp" [--type web|app] [--width <px>] [--height <px>] [--workdir <path>] # Create new app (sync-creates local project folder under htmlWorkdir), --type defaults to web
gemdesign app list # List all apps
gemdesign app info [--appuuid <id>] # App details
gemdesign app use --appuuid <id> # Switch current default app
app create 画布尺寸:
/
用于指定画布像素尺寸。不传时按
取默认值:
-> 1920×1080,
-> 440×956。传入的尺寸会随应用信息同步到本地设计器画布(覆盖默认值)。示例:
gemdesign app create --name "PadApp" --type app --width 768 --height 1024
。
CRITICAL - MUST run BEFORE :
成功后会在
下
同步创建本地项目子目录 (与
命令的命名规范一致),后续页面 HTML 直接写入该目录,local-server 也据此扫描项目。因此
gemdesign server workdir --path <path>
必须在 之前执行(或通过
在创建应用时一并指定,效果等同于先
再
)。若未配置
,应用仍会在服务端创建成功,但本地目录创建会被跳过,并在返回结果中以
提示。
appuuid priority:
flag >
(set by
/
) >
env
Once you run
or
, subsequent
commands don't need
.
IMPORTANT: Always check
BEFORE creating a new app. Reuse existing apps to keep all pages in the same project folder. Only create a new app when the user explicitly asks for one.
CRITICAL - Never create duplicate apps: Never call
more than once in a single session/task. If you have already run
in this session, you MUST NOT run it again — even if a later workflow step or retry seems to require app setup. Instead, reuse the existing app by running
to find it, then
gemdesign app use --appuuid <id>
. Creating a second app leaves the first one empty and orphaned on the platform.
CRITICAL - Restart the server around every or : 正确顺序为:
-> (等待 stop 命令返回结果) -> (确保
已配置) ->
/
->
。该顺序由 workflow 步骤强制执行,不要作为独立序列重复执行。
执行 之前必须先执行 终止之前的服务,无论应用是新建还是复用,否则旧服务的 fileWatcher 仍绑定在前一个 app 的
,新页面不会推送到画布。
这一步严禁跳过(即使你认为没有运行中的服务也必须执行),且
必须等 命令返回结果后才能执行,禁止并行执行或先 start 后 stop。
IMPORTANT - Output app info to user: After selecting/switching/creating an app (i.e., after any
,
, or
call that establishes the working app), you MUST clearly tell the user in your text response which app is now the active target for page generation. At minimum, output the
app name and
appuuid (and ideally the computed
). This ensures the user always knows which app pages will be generated/modified in, and can interrupt if the wrong app was picked. See the "Output current app info to user" step in each workflow for the exact format.
CRITICAL - App type determines page type: Apps have a type -
(桌面端) or
(移动端) - returned by
as the
field.
When generating new pages, the page type MUST match the app type: a
app can only contain
pages (desktop layout, wide screen), and an
app can only contain
pages (mobile layout, narrow screen). Before generating any HTML, check the app's
from
and design the page accordingly. Do NOT generate a desktop-width page for an
type app, or a mobile-width page for a
type app.
Style Search (optional helper)
bash
gemdesign style search --keywords "科技,深蓝,企业" --limit 5 # Search styles
gemdesign style get --id <styleId> --format html # Get full style
Style search is optional. You can also design styles yourself or use other UI design skills.
Page - View
bash
gemdesign page list [--appuuid <id>] # List pages
gemdesign page get --pageuuid <id> --file ./output/<projectDir>/<id>.html # Get page HTML (auto-creates projectDir)
gemdesign page doc get --pageuuid <id> --file ./output/<projectDir>/<id>.md # Get requirement doc
Page - Create (streaming mode)
bash
gemdesign page create --pageuuid <readable-id> --name "<pageName>" # Create page + enter streaming mode
signals the local server to start streaming mode for this page, enabling real-time HTML preview as you write to the
file. This command should be called BEFORE writing the HTML file, and the streaming mode is automatically ended when
completes.
Page - Save (with validation)
bash
gemdesign page save --pageuuid <id> --file ./output/<projectDir>/<id>.html # Update existing
gemdesign page save --new --pageuuid <readable-id> --name "Login" --file ./output/<projectDir>/<readable-id>.html # Create new
gemdesign page doc save --pageuuid <id> --file ./doc.md # Save requirement doc
automatically validates the HTML against the GemDesign Page Spec before uploading. After a successful save, it automatically ends streaming mode, triggering the browser to fetch the final render.
saves an agent-generated requirement document to the platform.
for : Use a human-readable id (e.g. filename without
). Ensure uniqueness within the app. This id is used directly as
in navigation elements - no need to change them after saving.
Project subdirectory: Always use
in paths. The CLI is idempotent - if the path already contains
, it won't duplicate it. See "Local File Management" for details.
Validate Only
bash
gemdesign validate --file ./page.html # Validate without saving
Local File Management
For every page, save HTML files locally under
, organized by project subdirectory:
| File | Purpose | How to generate |
|---|
./output/<projectDir>/<pageuuid>.html
| Page HTML (contains DSL, for editing and saving) | The file you generate and write |
Project subdirectory naming:
<projectDir> = {projectName}__{appuuid}
- comes from (illegal filesystem chars removed, whitespace collapsed to )
- Empty falls back to ; empty falls back to
- Examples: , ,
- Directory creation: This subdirectory is sync-created by under (requires configured first via ); / also create it idempotently when writing files.
How to write files:
- Always use
./output/<projectDir>/<pageuuid>.html
in all file paths, whether writing files directly or passing to CLI commands.
- The CLI is idempotent: if the path already contains , it will NOT duplicate it. You can safely pass
./output/CRM系统__abc-123/home.html
to or without worrying about nesting.
- Compute first: Run -> get and -> compute
<projectDir> = {projectName}__{appuuid}
(sanitize projectName).
- Validate before creating files: Ensure is non-empty and matches
{nonEmptyName}__{nonEmptyUuid}
. If or is empty/undefined, re-run . Never create files with an empty or partial (e.g. or ) - this creates orphaned unnamed directories.
The local server automatically serves pages from the project subdirectory path.
Streaming Write Workflow (Real-time Display)
When generating HTML pages, use the streaming write workflow to enable real-time display in the browser. The GemDesign local server watches for file changes and pushes incremental content to the browser via Server-Sent Events (SSE).
CRITICAL — Do NOT open the browser again during streaming write (or at any point after Step 3). The designer SPA (already open in the browser from Step 3) watches for
file changes and auto-loads the generated HTML into its inner iframe via SSE. You do NOT need to "open" or "refresh" anything — just write the files and the designer updates itself in real time. Navigating the browser to the generated
URL (e.g. via a preview tool or OS browser command with a page-specific URL) will OVERWRITE the designer with the generated HTML and break the preview surface. The only valid URL for opening the browser is the designer root
, and even that should NOT be re-used after Step 3.
How It Works
The CLI automatically manages the streaming lifecycle for you. The
command starts streaming mode, and
automatically ends it. The browser receives incremental HTML as you append to the
file:
- → browser enters streaming mode for that page
- Append to → browser receives incremental HTML and re-renders in real-time
- → browser fetches the complete HTML and switches to final render
Steps
For each page you generate, follow this workflow instead of writing the complete HTML in one shot:
-
Compute path:
htmlPath = ./output/<projectDir>/<pageuuid>.html
-
Create the page (enter streaming mode):
bash
gemdesign page create --pageuuid <pageuuid> --name "<pageName>"
This signals the local server to start streaming mode for this page. The browser will enter streaming mode and prepare to receive incremental HTML.
-
Write the HTML file (append-only after the first write, NEVER overwrite with shorter content):
- You may write the HTML in one shot or in multiple appends — the local server detects file changes and pushes each append to the browser in real-time.
- The HTML must be a complete document: + (with all dependencies and styles) + + .
- If writing in multiple appends, ensure the first write includes the tag so the browser can start rendering immediately (the browser only renders after appears).
CRITICAL RULES:
- Always append to the file after the first write. Never overwrite with shorter content during streaming — this triggers a event and forces the browser to re-render from scratch.
- If you must rewrite from scratch, delete the file first, then start over.
- The first write creates the file (length goes from 0 to N), subsequent writes append (length goes from N to N+M).
- No delays or chunk-size limits: Write as fast as you like, in any size. The local server pushes every file change to the browser within ~10ms.
- Clean up on failure: If streaming write fails or is interrupted, delete any partial file for that page. You can also run to clean up orphaned files and empty project directories.
-
Validate the HTML:
bash
gemdesign validate --file ./output/<projectDir>/<pageuuid>.html
If validation fails, fix the HTML and re-validate. The browser continues to show the streaming state, giving immediate feedback on fixes.
-
Save to platform:
bash
gemdesign page save --new --pageuuid <pageuuid> --name "<pageName>" --file ./output/<projectDir>/<pageuuid>.html
When the save completes, the CLI automatically ends streaming mode. The browser fetches the complete HTML and switches to the final render.
Example (Streaming Write for a "home" page)
bash
# 1. Create the page (enter streaming mode)
gemdesign page create --pageuuid home --name "首页"
# 2. Write the HTML file (one shot or multiple appends — your choice)
# Use Write tool to create ./output/MyApp__abc-123/home.html with the complete HTML:
# <!DOCTYPE html><html><head>...<script src="tailwind"></script>...</head><body>...content...</body></html>
# Or write in multiple appends (ensure first write includes <body> tag).
# 3. Validate
gemdesign validate --file ./output/MyApp__abc-123/home.html
# Fix any validation errors and re-validate before proceeding
# 4. Save to platform (automatically ends streaming mode)
gemdesign page save --new --pageuuid home --name "首页" --file ./output/MyApp__abc-123/home.html
Workflows
PRECONDITION FOR ALL WORKFLOWS: Step 1 (CLI installed & up-to-date), Step 2 (Login verified via
), AND Step 2.5 (htmlWorkdir configured + cleanup) MUST be confirmed complete BEFORE starting any workflow. If login is not confirmed, do NOT generate HTML, do NOT create
files, do NOT start streaming write - stop and resolve authentication first. Step 3 (local server running AND browser preview opened) is NOT executed before starting a workflow — it is executed INSIDE each workflow, AFTER the app is created/reused (and
confirms
), and BEFORE any page generation. This applies to Workflow A, B, and C alike.
Workflow A: Batch Generation from Requirements
- Complete Prerequisites: Ensure Step 1 (CLI install/update), Step 2 (Login), AND Step 2.5 (htmlWorkdir configured + cleanup) are confirmed complete before proceeding. Step 3 (local server + browser preview) is NOT done here — it is executed in step 5 below, AFTER the app is created/reused.
- Ensure app exists (reuse first!):
- Ensure htmlWorkdir is configured (MUST complete before ): htmlWorkdir was configured in Step 2.5 (persists across sessions). Verify with (no flags); if it returns an empty , run
gemdesign server workdir --path ./output
first. This MUST be done before so that synchronously creates the local project folder under .
- Run to check existing apps
- If apps already exist: Run
gemdesign app use --appuuid <id>
to set the target app as default. Do NOT create a new app unless the user explicitly asks for a new one.
- If no apps exist: Run
gemdesign app create --name "<AppName>" [--type web|app] [--width <px>] [--height <px>] [--workdir <path>]
to create one (default type is ; default canvas size: -> 1920×1080, -> 440×956). sync-creates the local project folder under (pass to set it in one step). After creating, immediately run to confirm the app exists and record its appuuid. Do NOT run again for any reason in this session. 之前运行中的服务会在步骤 5 的 中统一终止。
- CRITICAL - No duplicate apps: If you already ran earlier in this session (even in a previous workflow attempt), do NOT run it again. Reuse the existing app via + . Creating a second app leaves the first one empty and orphaned.
- CRITICAL: All pages in the same batch MUST go into the same app. Reusing an existing app prevents pages from being scattered across different project folders.
- Get project directory name:
- Run to get and
- Compute
<projectDir> = {projectName}__{appuuid}
(remove illegal chars from projectName, collapse whitespace to )
- Example: project name "电商 App" with appuuid "abc-123" →
<projectDir> = "电商_App__abc-123"
- Output current app info to user (CRITICAL — user must know which app pages will be generated into):
- Before generating any HTML, clearly tell the user in your text response which app you are generating pages into. At minimum, output:
- App name ( from )
- App UUID ( from )
- App type ( from - for 桌面端, for 移动端)
- Project directory ( computed in step 3)
- Page count to be generated in this batch (from step 7 analysis)
- Example output format:
📦 当前应用信息
- 应用名称:电商 App
- 应用 ID:abc-123
- 应用类型:app(移动端)
- 项目目录:电商_App__abc-123
- 本次将生成页面数:5
- Type matching: The value determines the page layout you MUST follow. Generate (desktop, wide-screen) pages for apps, (mobile, narrow-screen) pages for apps. Do NOT mix types - a web app cannot contain app pages, and vice versa.
- If the user did not explicitly specify an app and you reused an existing app, also tell the user which app was selected (e.g. "已复用现有应用:电商 App") so they can interrupt if it's the wrong one.
- Pause-friendly: This is informational only - no user reply is required unless the user wants to switch apps. Continue to the next step immediately after outputting.
- Start the local server (Step 3): Now that the app exists and is computed, execute Step 3 (see the "Step 3: Start the Local Server" section above) — 必须先执行 终止之前的服务(无论应用是新建还是复用,也无论之前是否已运行服务,均不可跳过此步),必须等 命令返回结果(确认已停止或无运行中的服务)之后,才能执行 启动本地服务,并仅打开一次浏览器到设计器 。记录 返回的 供后续步骤使用。这是 HARD GATE:服务未运行或浏览器预览未打开前,不得进入任何页面生成。
- CRITICAL - 严禁跳过 这一步:即使你认为当前会话中没有运行中的服务,也必须执行 命令并以命令返回结果为准。禁止以"服务器已在运行"、"上一次 workflow 已启动"、"浏览器预览已打开"等理由跳过 stop。stop 返回
{"success":false,"error":"未发现运行中的本地服务"}
时表示无服务可停,此时可继续下一步 start。
- CRITICAL - 必须等 执行完成后再执行:禁止将 stop 和 start 并行执行、或先 start 后 stop。 的前置条件是 已返回结果。
- Never open the browser with a generated-page URL (e.g.
http://localhost:<port>/output/<projectDir>/<pageuuid>.html
) - that overwrites the designer with the generated HTML and destroys the preview surface.
- Search style (optional):
gemdesign style search --keywords "电商,现代,简洁"
→ select one → gemdesign style get --id <id>
- Analyze requirements: Read the requirements doc, break down into individual pages. Assign each page a readable (e.g. , , ).
- Generate design system page (only for newly created apps): If a new app was created in step 2 (not reused), generate a design system page as the visual style baseline before generating business pages. All subsequent business pages should follow this style. Determine the design system type based on from , and generate the page following the type table and page structure in the dedicated "Design System Page Spec" section below. The pageuuid is fixed as and is NOT counted as a business page. You MUST save the design system page to the platform (not just write it locally) - otherwise it will not appear in the app and cannot serve as the style baseline. Use the Streaming Write Workflow with these explicit steps (same create-validate-save process as business pages):
- Create page (enter streaming mode):
gemdesign page create --pageuuid design-system --name "设计系统"
- Write the HTML file to
./output/<projectDir>/design-system.html
(follow the Design System Page Spec; pageuuid is )
- Validate:
gemdesign validate --file ./output/<projectDir>/design-system.html
(fix errors and re-validate)
- Save to platform (MANDATORY - do NOT skip):
gemdesign page save --new --pageuuid design-system --name "设计系统" --file ./output/<projectDir>/design-system.html
(uploads the design system page into the app so it persists on the platform and shows up in ; automatically ends streaming mode)
- Verify it was saved: (confirm appears in the list)
If the app was reused (switched via in step 2), skip this step AND skip step 9.
- Design System Review Gate (CRITICAL — only when step 8 generated a design system page): Before generating any business page, you MUST apply the "Design System Review Gate" rules (see that section below). Evaluate the continue conditions; if none apply, STOP and ask the user for confirmation/feedback on the design system using the format specified in that section. Do not proceed to step 10 until the design system is confirmed by the user or a continue condition is met. If the app was reused (step 8 was skipped), skip this step too.
- For each page (use Streaming Write Workflow above for real-time display):
- Generate HTML following the Page Spec below (incorporate style if available). Use the assigned as in navigation elements. All business pages MUST follow the style baseline established (and, if applicable, confirmed) in the design system page.
- Use streaming write (see "Streaming Write Workflow" section for details):
- Create page (enter streaming mode):
gemdesign page create --pageuuid <pageuuid> --name "页面名"
- Write the HTML file to:
./output/<projectDir>/<pageuuid>.html
(create the directory if it doesn't exist; use the computed in step 3)
- Validate:
gemdesign validate --file ./output/<projectDir>/<pageuuid>.html
- Fix any validation errors, re-validate
- Save to platform:
gemdesign page save --new --pageuuid <pageuuid> --name "页面名" --file ./output/<projectDir>/<pageuuid>.html
(uploads to platform, automatically ends streaming mode)
- Verify:
- Output designer link (MANDATORY - output ONCE, only after ALL pages are generated): After ALL pages in the batch are generated, validated, and saved (i.e., after step 10's loop is fully complete and step 11 verification passes), you MUST output a clickable link in your text response so the user can easily open the designer to view the final result. The link MUST be:
- Name: (exact text, do NOT change or translate)
- URL: (use the port recorded from Step 3's response)
- Format (markdown link):
[gemdesign 设计器](http://localhost:<port>)
- Example:
[gemdesign 设计器](http://localhost:4056)
CRITICAL - Do NOT output this link after each individual page in step 10. Output it exactly ONCE, at the very end of the entire batch, after every page has been generated and saved. Outputting the link after each page clutters the conversation and violates the "all pages complete" requirement.
Note: This is the ONLY exception to the "do not output URLs in chat text" rule in Step 3. Step 3's rule prohibits outputting a URL instead of programmatically opening the browser during setup. This step is different - it runs AFTER all page generation is complete, and outputs a text link for the user to click at their discretion (e.g. if they closed the browser or want to reopen the designer). This is NOT an automatic browser open action - it is a markdown link in your final summary.
Workflow B: Conversational Generation
When user asks for a page in conversation:
- Complete Prerequisites: Ensure Step 1 (CLI install/update), Step 2 (Login), AND Step 2.5 (htmlWorkdir configured + cleanup) are confirmed complete before proceeding. Step 3 (local server + browser preview) is NOT done here — it is executed in step 5 below, AFTER the app is created/reused.
- Ensure app exists (reuse first!):
- Ensure htmlWorkdir is configured (MUST complete before ): htmlWorkdir was configured in Step 2.5 (persists across sessions). Verify with (no flags); if it returns an empty , run
gemdesign server workdir --path ./output
first. This MUST be done before so that synchronously creates the local project folder under .
- Run to check existing apps
- If apps already exist: Run
gemdesign app use --appuuid <id>
to set the target app as default. Do NOT create a new app unless the user explicitly asks for a new one.
- If no apps exist: Run
gemdesign app create --name "<AppName>" [--type web|app] [--width <px>] [--height <px>] [--workdir <path>]
to create one (default type is ; default canvas size: -> 1920×1080, -> 440×956). sync-creates the local project folder under (pass to set it in one step). After creating, immediately run to confirm the app exists and record its appuuid. Do NOT run again for any reason in this session. 之前运行中的服务会在步骤 5 的 中统一终止。
- CRITICAL - No duplicate apps: If you already ran earlier in this session (even in a previous workflow attempt), do NOT run it again. Reuse the existing app via + . Creating a second app leaves the first one empty and orphaned.
- CRITICAL: All pages MUST go into the same app. Reusing an existing app prevents pages from being scattered across different project folders.
- Get project directory name:
- Run to get and
- Compute
<projectDir> = {projectName}__{appuuid}
(remove illegal chars from projectName, collapse whitespace to )
- Output current app info to user (CRITICAL — user must know which app the page will be generated into):
- Before generating any HTML, clearly tell the user in your text response which app you are generating the page into. At minimum, output:
- App name ( from )
- App UUID ( from )
- App type ( from - for 桌面端, for 移动端)
- Project directory ( computed in step 3)
- Example output format:
📦 当前应用信息
- 应用名称:电商 App
- 应用 ID:abc-123
- 应用类型:app(移动端)
- 项目目录:电商_App__abc-123
- Type matching: The value determines the page layout you MUST follow. Generate (desktop, wide-screen) pages for apps, (mobile, narrow-screen) pages for apps. Do NOT mix types - a web app cannot contain app pages, and vice versa.
- If the user did not explicitly specify an app and you reused an existing app, also tell the user which app was selected (e.g. "已复用现有应用:电商 App") so they can interrupt if it's the wrong one.
- Pause-friendly: This is informational only — no user reply is required unless the user wants to switch apps. Continue to the next step immediately after outputting.
- Start the local server (Step 3): Now that the app exists and is computed, execute Step 3 (see the "Step 3: Start the Local Server" section above) — 必须先执行 终止之前的服务(无论应用是新建还是复用,也无论之前是否已运行服务,均不可跳过此步),必须等 命令返回结果(确认已停止或无运行中的服务)之后,才能执行 启动本地服务,并仅打开一次浏览器到设计器 。记录 返回的 供后续步骤使用。这是 HARD GATE:服务未运行或浏览器预览未打开前,不得进入任何页面生成。
- CRITICAL - 严禁跳过 这一步:即使你认为当前会话中没有运行中的服务,也必须执行 命令并以命令返回结果为准。禁止以"服务器已在运行"、"上一次 workflow 已启动"、"浏览器预览已打开"等理由跳过 stop。stop 返回
{"success":false,"error":"未发现运行中的本地服务"}
时表示无服务可停,此时可继续下一步 start。
- CRITICAL - 必须等 执行完成后再执行:禁止将 stop 和 start 并行执行、或先 start 后 stop。 的前置条件是 已返回结果。
- Never open the browser with a generated-page URL (e.g.
http://localhost:<port>/output/<projectDir>/<pageuuid>.html
) - that overwrites the designer with the generated HTML and destroys the preview surface.
- Generate design system page (only for newly created apps): If a new app was created in step 2 (not reused), generate a design system page as the visual style baseline before generating business pages. All subsequent business pages should follow this style. Determine the design system type based on from , and generate the page following the type table and page structure in the dedicated "Design System Page Spec" section below. The pageuuid is fixed as and is NOT counted as a business page. You MUST save the design system page to the platform (not just write it locally) - otherwise it will not appear in the app and cannot serve as the style baseline. Use the Streaming Write Workflow with these explicit steps (same create-validate-save process as business pages):
- Create page (enter streaming mode):
gemdesign page create --pageuuid design-system --name "设计系统"
- Write the HTML file to
./output/<projectDir>/design-system.html
(follow the Design System Page Spec; pageuuid is )
- Validate:
gemdesign validate --file ./output/<projectDir>/design-system.html
(fix errors and re-validate)
- Save to platform (MANDATORY - do NOT skip):
gemdesign page save --new --pageuuid design-system --name "设计系统" --file ./output/<projectDir>/design-system.html
(uploads the design system page into the app so it persists on the platform and shows up in ; automatically ends streaming mode)
- Verify it was saved: (confirm appears in the list)
If the app was reused (switched via in step 2), skip this step AND skip step 7.
- Design System Review Gate (CRITICAL — only when step 6 generated a design system page): Apply the "Design System Review Gate" rules (see that section below). If no continue condition applies, STOP and ask the user for confirmation/feedback before proceeding. Do not proceed to step 8 until the design system is confirmed or a continue condition is met. If the app was reused (step 6 was skipped), skip this step too.
- Determine a readable (e.g. filename without , unique within the app)
- Generate HTML following the Page Spec, using as in navigation elements. Follow the style baseline established (and, if applicable, confirmed) in the design system page.
- Use streaming write (see "Streaming Write Workflow" section):
- Create page (enter streaming mode):
gemdesign page create --pageuuid <pageuuid> --name "<pageName>"
- Write the HTML file to
./output/<projectDir>/<pageuuid>.html
(create the directory if it doesn't exist; use the computed in step 3)
gemdesign validate --file ./output/<projectDir>/<pageuuid>.html
- Fix errors if any, re-validate
gemdesign page save --new --pageuuid <pageuuid> --name "<pageName>" --file ./output/<projectDir>/<pageuuid>.html
(uploads to platform, automatically ends streaming mode)
- Describe the result to the user
- Output designer link (MANDATORY - output ONCE, only after ALL page work is complete): After the page is generated, validated, and saved, you MUST output a clickable link in your text response so the user can easily open the designer. The link MUST be:
- Name: (exact text, do NOT change or translate)
- URL: (use the port recorded from Step 3's response)
- Format (markdown link):
[gemdesign 设计器](http://localhost:<port>)
- Example:
[gemdesign 设计器](http://localhost:4056)
CRITICAL - Output this link exactly ONCE, at the very end of the workflow. Do NOT output it after each intermediate step. This is a text link for the user to click at their discretion, NOT an automatic browser open action. See Workflow A step 12 for the full rationale on why this does not conflict with Step 3's "do not output URLs in chat" rule.
When user requests modifications:
gemdesign page get --pageuuid <id> --file ./output/<projectDir>/<id>.html
to retrieve HTML+DSL for editing
- Modify the HTML (adjust DOM, add/remove interaction DSL, update jsHandle)
- For substantial modifications, use the Streaming Write Workflow: rewrite the HTML (delete the old file first if starting fresh, or append if only adding)
gemdesign validate --file ./output/<projectDir>/<id>.html
- Fix errors if any, re-validate
gemdesign page save --pageuuid <id> --file ./output/<projectDir>/<id>.html
- If requirement doc needs updating:
gemdesign page doc save --pageuuid <id> --file <updated-doc.md>
Workflow C: Modify Existing Page
- Complete Prerequisites: Ensure Step 1 (CLI install/update), Step 2 (Login), AND Step 2.5 (htmlWorkdir configured + cleanup) are confirmed complete before proceeding. Step 3 (local server + browser preview) is NOT done here — it is executed in step 4 below, AFTER confirms .
- Get project directory name: Run → compute
<projectDir> = {projectName}__{appuuid}
(remove illegal chars from projectName, collapse whitespace to )
- Output current app info to user (CRITICAL — user must know which app the page being modified belongs to):
- Before modifying any HTML, clearly tell the user in your text response which app the target page belongs to. At minimum, output:
- App name ( from )
- App UUID ( from )
- App type ( from - for 桌面端, for 移动端)
- Project directory ( computed in step 2)
- Example output format:
📦 当前应用信息
- 应用名称:电商 App
- 应用 ID:abc-123
- 应用类型:app(移动端)
- 项目目录:电商_App__abc-123
- Type matching: The value determines the page layout you MUST follow. Generate (desktop, wide-screen) pages for apps, (mobile, narrow-screen) pages for apps. Do NOT mix types - a web app cannot contain app pages, and vice versa.
- This confirms to the user that the modification will land in the correct app, especially when multiple apps exist. If the user wanted a different app, they can interrupt here to switch via .
- Pause-friendly: This is informational only — no user reply is required unless the user wants to switch apps. Continue to the next step immediately after outputting.
- Start the local server (Step 3): Now that the app exists and is computed, execute Step 3 (see the "Step 3: Start the Local Server" section above) — 必须先执行 终止之前的服务(无论应用是新建还是复用,也无论之前是否已运行服务,均不可跳过此步),必须等 命令返回结果(确认已停止或无运行中的服务)之后,才能执行 启动本地服务,并仅打开一次浏览器到设计器 。记录 返回的 供后续步骤使用。这是 HARD GATE:服务未运行或浏览器预览未打开前,不得进入任何页面修改。
- CRITICAL - 严禁跳过 这一步:即使你认为当前会话中没有运行中的服务,也必须执行 命令并以命令返回结果为准。禁止以"服务器已在运行"、"上一次 workflow 已启动"、"浏览器预览已打开"等理由跳过 stop。stop 返回
{"success":false,"error":"未发现运行中的本地服务"}
时表示无服务可停,此时可继续下一步 start。
- CRITICAL - 必须等 执行完成后再执行:禁止将 stop 和 start 并行执行、或先 start 后 stop。 的前置条件是 已返回结果。
- Never open the browser with a generated-page URL (e.g.
http://localhost:<port>/output/<projectDir>/<pageuuid>.html
) - that overwrites the designer with the generated HTML and destroys the preview surface.
- -> find the target page
gemdesign page get --pageuuid <id> --file ./output/<projectDir>/<id>.html
-> retrieve HTML+DSL for editing
- Analyze HTML structure and interactions
- Modify HTML as needed
- For substantial modifications, use the Streaming Write Workflow (see above): rewrite the HTML
gemdesign validate --file ./output/<projectDir>/<id>.html
- Fix errors if any, re-validate
gemdesign page save --pageuuid <id> --file ./output/<projectDir>/<id>.html
- If requirement doc needs updating:
gemdesign page doc save --pageuuid <id> --file <updated-doc.md>
- Output designer link (MANDATORY - output ONCE, only after ALL page work is complete): After the page is modified, validated, and saved, you MUST output a clickable link in your text response so the user can easily open the designer to view the updated result. The link MUST be:
- Name: (exact text, do NOT change or translate)
- URL: (use the port recorded from Step 3's response)
- Format (markdown link):
[gemdesign 设计器](http://localhost:<port>)
- Example:
[gemdesign 设计器](http://localhost:4056)
CRITICAL - Output this link exactly ONCE, at the very end of the workflow. Do NOT output it after each intermediate step. This is a text link for the user to click at their discretion, NOT an automatic browser open action. See Workflow A step 12 for the full rationale on why this does not conflict with Step 3's "do not output URLs in chat" rule.
Design System Page Spec
When the app is newly created, generate a design system page (with pageuuid fixed as
) before generating business pages, serving as the visual style baseline for the app. All subsequent business pages should follow the colors, border radii, shadows, and component styles established in this design system. The design system page also follows the GemDesign Page Specification (see below), including tech stack rules, CSS rules, Lite-Interaction DSL, etc.
Type Determination
Determine the design system type based on the
field returned by
:
| pageScene | Design System Type | Core Objective |
|---|
| Mobile C-end experience-driven | Create a consumer-facing, experience-and-emotion-driven mobile app UI design system showcase page. Showcase common interaction patterns and visual components of C-end apps, emphasizing content consumption, social interaction, and personalized experience. The page uses a mobile-width layout directly (no phone frame/外框 wrapper), presenting the mobile app interface as-is. |
| Enterprise admin function-driven | Create a function-driven, enterprise/admin-management-oriented Web UI design system showcase page. Showcase common framework structures, data operations, and form input components of admin systems, emphasizing information density, operational efficiency, and status feedback. The page uses a full-width admin layout, simulating a real admin management system interface. |
| Other | Flexible analysis | Analyze the most suitable design system type based on requirements, and design flexibly using the Header + Design Tokens + Components basic structure. |
Page Structure — Type (Mobile C-end)
Header
- Include system logo/icon, system name (Chinese), and brief description
- Use dark or brand-color background with white text
- Fixed at top or as a page-top banner
Section 1: Design Tokens
- Section title style: Use a left-side colored border bar (, using the style's primary color) + large title + tag badge combination
- Color system: Use color swatch cards to display primary, secondary, functional, and neutral colors, with Hex values and usage notes
- Border radius & shadows: Use physicalized blocks to display shadow effects at different levels, large radius specs (e.g. 16px/24px), soft shadows or diffuse glow
Section 2: Components
- Media Cards: Image-text cards (large image mode), masonry/waterfall cards, video/live cover containers
- Social Elements: User avatars, like/favorite/comment icons (with micro-interaction styles), follow buttons
- Interactive Containers: Bottom sheet panels (Bottom Sheet/Drawer), Toast notifications (shown only as style effect displays within containers — do NOT simulate real popup effects fixed in page layout)
- Navigation: Immersive top bar (transparent gradient), bottom navigation bar (icon + text, with selected-state animation hints)
- Empty/Loading: Loading placeholders (Skeleton), empty-state illustration placeholders
Page Structure — Type (Enterprise Admin)
Header
- Include system logo/icon, system name (Chinese), and brief description
- Use dark or brand-color background with white text
- Fixed at top or as a page-top banner
Section 1: Design Tokens
- Section title style: Use a left-side colored border bar (, using the style's primary color) + large title + tag badge combination
- Color system: Use color swatch cards to display primary, secondary, functional, and neutral colors, with Hex values and usage notes
- Typography hierarchy: Display H1-H4, Body, and Caption level comparisons within cards, with font/size/weight annotations
- Border radius & shadows: Use physicalized blocks to display shadow effects at different levels
Section 2: Components
- Use grid layout (
grid-cols-1 lg:grid-cols-2/3
) to organize component displays
- Structure/Shell: Sidebar nav items (selected/hover), top breadcrumb, Page Header
- Data Display: Data tables (header, zebra striping, row hover, pagination), Tab pages, Tags (Tag/Badge), key-value pair lists
- Form Elements: Input boxes (Input), dropdown selects (Select), checkboxes/radio buttons (Checkbox/Radio), switches (Switch) — must include default, Hover, Focus, and Error states
- Actions: Action buttons (Primary, Secondary, Ghost, Icon Button)
- Feedback/Overlays: Global messages (Message), notifications (Notification), dialogs (Modal/Dialog, shown as example displays — do NOT use full-screen modals), loading states (Skeleton/Spinner)
Page Structure — Other Types
Follow the Header + Design Tokens + Components basic structure, and determine suitable components and visual style based on requirements analysis.
Design System Review Gate (CRITICAL)
When the design system page is generated (newly created apps only), you MUST apply this review gate before generating any business page. This gate does not apply to reused apps (which skip design system generation) or to Workflow C (modify existing page).
Why this gate exists (first principles)
The design system page is a high-leverage decision point. It locks in the colors, typography, shadows, radii, and component styles that every subsequent business page will inherit. Two properties make the moment right after its generation a natural checkpoint:
-
Asymmetric error cost. A wrong style decision made here propagates to every business page generated afterward. Correcting it after N pages exist means reworking N pages; correcting it immediately costs one round-trip with the user. The expected cost of skipping the gate grows linearly with page count, while the cost of pausing is constant and tiny.
-
Information-state flip. Before generation, the agent can only infer the user's visual preference from the requirements doc — an uncertain state. After generation, the user can see a concrete proposal rendered in the browser — a certain state. This is the first moment the user possesses actionable information to confirm or redirect. Capturing that signal here yields maximum value: it is the cheapest point in the whole workflow to correct course.
Decision rule — stop or continue?
After the design system page is generated, validated, and saved, evaluate the continue conditions below. The default is STOP and ask; you may only continue without asking if at least one continue condition is clearly met.
Continue conditions (any ONE is sufficient to skip the pause and proceed directly to business pages):
| # | Condition | Why it's safe to continue |
|---|
| C1 | The user explicitly specified the visual style in their original request (e.g. specific brand colors, "深蓝科技风", "参考某App的样式", a mood-board, a hex code) | The style direction is already locked by the user — there is no information gap for the gate to close. |
| C2 | The user ran + earlier in this session AND the design system page faithfully reflects that selected style | The user pre-signaled their preference through an explicit selection action; the design system is executing that choice, not proposing a new one. |
| C3 | The user explicitly waived the review (e.g. "不用确认,直接全部生成", "全自动跑完", "不要中途停") | The user has voluntarily forfeited the checkpoint. Respect their stated preference. |
If NO continue condition applies → you MUST stop. This is the default and the most common case for a freshly created app driven only by a requirements document.
When you stop — what to present
Do not merely announce "设计系统已生成". Present a decision-ready summary so the user can confirm or redirect with minimal effort:
- Style decisions made — primary/secondary colors (with hex), overall direction (e.g. 科技感/温暖/极简), key component treatments (card radius, shadow style, button style). Be concrete, not vague.
- Reasoning link — connect the decisions back to the requirements (e.g. "基于需求文档中'面向年轻人的社交平台'定位,主色选用高饱和的紫色…").
- Explicit ask — use the tool to structure the choice. Suggested options:
- "确认,继续生成业务页面"
- "调整配色方案"
- "调整整体风格方向"
- (the user can also type a custom response via "其他")
After the user responds
- User confirms → proceed to business page generation, treating the confirmed design system as the locked style baseline for all pages.
- User requests adjustments -> modify the design system page first (edit -> validate -> save), then either re-present (if the change is major/subjective, e.g. a pivot from "科技蓝" to "温暖橙") or proceed (if the change is minor and clearly resolved, e.g. a single hex value tweak). Use judgment here. The "save" step here means re-running
gemdesign page save --pageuuid design-system --file ./output/<projectDir>/design-system.html
(NO flag - the page already exists on the platform from step 7/5; would error on duplicate pageuuid). Confirm the update with .
- Never start business pages until the design system is either (a) confirmed by the user or (b) covered by a continue condition above.
GemDesign Page Specification
You MUST follow this spec when generating HTML. The
command checks all these rules.
Overview
A GemDesign page = HTML(DOM) + TailwindCSS(style) + Lite-Interaction DSL(interaction).
Tech Stack Rules
Allowed: HTML native tags, TailwindCSS (via
tag), CSS (
), Font Awesome, ECharts
Forbidden: Any JS framework (Vue/React/jQuery), hand-written DOM JS (except jsHandle), CSS Hack,
unit
Only Two Types of Scripts Allowed
<script id="interaction-data">
— Lite-Interaction JSON string (interaction logic)
<script id="funcName">function funcName(event){...}</script>
— jsHandle custom function
Dependencies
html
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- ECharts (only when using charts): -->
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
<!-- ECharts China map (only when using china map): -->
<script src="https://cdn.jsdmirror.com/npm/echarts/map/js/china.js"></script>
Layout Rules
- Use TailwindCSS for layout component classes.
- Prefer flexbox layout; Flexbox, padding, and gap are the core tools for interface layout.
- Block elements can be used for simple elements (text, decorative images), but NOT for layout. All elements default to the box model.
- Fixed elements (sidebars, nav bars) must have explicit height/width; content area needs matching padding.
- Masks and modals/drawers must be nested. The mask/overlay layer MUST have a semi-transparent background color (e.g. ), and the inner modal/drawer content container MUST have an opaque background color (e.g. ) - a transparent content container is a SERIOUS VIOLATION, as it lets the mask color bleed through.
- When centering elements, absolutely do NOT use or - you MUST use flex layout's and on the parent element.
CSS Rules
Rule 1: No unit
Forbidden: the
unit, any Tailwind CSS class containing
, and any class containing
(e.g.
).
Rule 2: HIGHEST-LEVEL RED LINE - ABSOLUTELY NO Margin
The entire page is ABSOLUTELY FORBIDDEN from using ANY margin! This includes native CSS and ALL Tailwind class names with margin semantics! The model is highly prone to habitually using margin for "icon spacing" and "element top/bottom spacing" - you MUST overcome this habit!
If your output code contains ANY of the following prefixes (positive OR negative), it is a SERIOUS VIOLATION:
- (e.g. , )
- (e.g. )
- (e.g. , , )
- (e.g. )
- (e.g. , )
- (e.g. )
- (e.g. )
- / (the underlying implementation is also margin, ABSOLUTELY forbidden)
Mandatory alternatives - for the scenarios you are most prone to violating:
-
❌ Violation habit 1 (icon and text spacing):
<i class="fas fa-edit mr-1"></i>编辑
-
✅ Correct practice 1 (use flex + gap):
<div class="flex items-center gap-1"><i class="fas fa-edit"></i><span>编辑</span></div>
-
❌ Violation habit 2 (title/paragraph bottom spacing):
<h3 class="mb-4">标题</h3><form>...</form>
-
✅ Correct practice 2 (parent flex + gap):
<div class="flex flex-col gap-4"><h3>标题</h3><form>...</form></div>
-
❌ Violation habit 3 (center alignment):
or
-
✅ Correct practice 3 (parent centering): use
flex justify-center items-center
on the parent element
Lite-Interaction DSL (Core)
All interactions are declared in
<script id="interaction-data">
as a JSON array wrapped in backticks.
typescript
interface TriggerEvent {
original: string; // Selector: #id or .class only
trigger: 'click' | 'mouseover' | 'mouseenter' | 'mouseleave' | 'mousedown' | 'mouseup';
actions: Action[];
}
interface Action {
operation: 'show' | 'hide' | 'openModal' | 'closeModal' | 'addClass' | 'removeClass' | 'openPage' | 'back' | 'openLink' | 'jsHandle';
target?: string; // Required for show/hide/addClass/removeClass. #id only, multiple: "#id1,#id2"
params?: string; // addClass/removeClass: class names (comma-separated); openPage: pageUuid; openLink: URL. Forbidden for jsHandle. Must be a plain string, no code/variables.
funcName?: string; // Only for jsHandle
operationTitle?: string; // Required for jsHandle/addClass/removeClass (2-8 Chinese chars)
animation?: string; // Animation effect name
animationTime?: number; // Animation duration in seconds
delayTime?: number; // Delay before execution in seconds
}
Selector Rules (CRITICAL)
| Rule | Detail |
|---|
| and | Only or — NO attribute selectors () |
| Single element only — no multiple selectors |
| Multiple IDs allowed: — NO allowed |
| If element only has data attributes | You MUST add an to it, then use in DSL |
Operation Priority
- / — preferred for opening/closing modals
- / — CSS changes
- — page navigation (params must be pageUuid string only)
- — go back
- — only when above can't satisfy the requirement
jsHandle Rules
- Each function in its own tag
- Script MUST match function name exactly
- Only one parameter:
- No API calls inside
html
<script id="tabSwitchXxx">
function tabSwitchXxx(event) {
// full implementation
}
</script>
Page Navigation
For navigation elements, add
AND
to the HTML tag. The
value MUST match the
you pass to
:
html
<!-- If you will save this target page with: page save --new --pageuuid home --name "首页" -->
<a id="nav-home" data-uuid="home" href="javascript:void(0);">首页</a>
Do NOT add openPage events in interaction-data for these — they are auto-generated.
Image Placeholders
Use placeholder URLs, the platform replaces them with real images:
html
<img src="./api/searchImage?query=premium laptop on white background&width=400&height=400" class="w-full h-full object-cover" />
Button Rules
- ALL buttons must have
- NO
- Use
href="javascript:void(0);"
for links, never
Design Constraints
- Shadows: Use diffuse shadows:
shadow-[0_8px_30px_rgba(0,0,0,0.04)]
, not short dark shadows
- Native controls: No or radio buttons for option switching — use capsule segmented controls
- Horizontal scroll: Hide scrollbar with
- Modals/masks/drawers: Add class by default; use nested structure. The mask/overlay layer MUST have a semi-transparent background color (e.g. ), and the inner modal/drawer content container MUST have an opaque background color (e.g. ). A transparent content container is a SERIOUS VIOLATION - the mask color will bleed through and the popup content area will appear as the mask color. Example:
html
<div id="modalMask" class="modal-mask hidden fixed inset-0 bg-black/50 flex justify-center items-center z-50">
<div class="bg-white rounded-lg p-6">
<!-- Modal content - inner container MUST have bg-white or other opaque color -->
</div>
</div>
- CSS override: When status class (like ) overrides component class, combine in stylesheet:
.modal-mask.hidden { display: none; }
— do NOT use
Script Order
- TailwindCSS (in )
- ECharts dependency (in , optional)
- configuration
- ECharts config scripts (
<script id="echarts_*" type="echarts">
, optional)
- jsHandle function scripts (, optional)
- MUST be the last tag
Complete Page Template
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: { primary: '#1890ff' }
}
}
};
</script>
<style>
.modal-mask.hidden { display: none; }
</style>
</head>
<body>
<div id="app">
<!-- Page DOM -->
</div>
<!-- jsHandle functions (optional) -->
<!-- <script id="funcName">function funcName(event) {...}</script> -->
<!-- Interaction DSL (MUST be last script) -->
<script id="interaction-data">
`
[
{
"original": "#elementId",
"trigger": "click",
"actions": [
{ "operation": "show", "target": "#targetId" }
]
}
]
`
</script>
</body>
</html>
Validation Rules Summary
| # | Rule | What it checks |
|---|
| 1 | interaction_data_exists | <script id="interaction-data">
present |
| 2 | dsl_json_valid | Content is valid JSON array |
| 3 | selector_exists | All original/target selectors exist in DOM |
| 4 | selector_format | Only #id and .class, no attribute selectors |
| 5 | original_single | original has only one selector |
| 6 | target_no_class | target uses only #id, no .class |
| 7 | jshandle_func_match | Each funcName has matching |
| 8 | script_id_funcname_match | script id equals function name |
| 9 | button_type | All buttons have type="button", no type="submit" |
| 10 | no_vh | No vh unit in classes or styles |
| 11 | no_hash_href | No href="#" |
| 12 | image_url_format | Placeholder image URLs use ./api/searchImage?query=...&width=...&height=...
with numeric width/height, no spaces around |
| 13 | data_uuid_complete | Tags with data-uuid also have id |
| 14 | interaction_data_last | interaction-data is the last script tag |
Tips
- Always validate before saving — catches errors early
- For batch generation, validate each page individually before saving
- Save HTML locally for every page:
./output/<projectDir>/<pageuuid>.html
for editing and saving to the platform. Always compute <projectDir> = {projectName}__{appuuid>
first via . The CLI is idempotent - passing a path that already contains will not duplicate it.
- When creating a new page, pass a readable (e.g. , ) - use the same value as in navigation elements, so you don't need to update them after saving
- Use
gemdesign page get --file <path>
to retrieve editable HTML+DSL before modifying
- The full page spec is available at in the CLI project directory