webcake-landing-mcp 1.0.41 → 1.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,18 @@
1
1
  [
2
+ {
3
+ "v": "1.0.43",
4
+ "d": "09/06/2026",
5
+ "type": "Changed",
6
+ "en": "The GET / web guide page has refreshed copy throughout: updated page title and meta description, simplified FAQ answers in both English and…",
7
+ "vi": "Trang hướng dẫn GET / được làm mới toàn bộ nội dung: cập nhật tiêu đề trang và meta description, đơn giản hóa câu trả lời FAQ bằng cả tiếng Anh và…"
8
+ },
9
+ {
10
+ "v": "1.0.42",
11
+ "d": "09/06/2026",
12
+ "type": "Fixed",
13
+ "en": "validate_page now raises an error when a countdown element's specials.language is set to a value outside the eight supported word-values (vietnam,…",
14
+ "vi": "validate_page nay phát lỗi khi element countdown có specials.language là giá trị nằm ngoài tám word-value được hỗ trợ (vietnam, english, filipino,…"
15
+ },
2
16
  {
3
17
  "v": "1.0.41",
4
18
  "d": "09/06/2026",
@@ -26,19 +40,5 @@
26
40
  "type": "Added",
27
41
  "en": "New add_section tool appends one or more sections to an existing page without re-sending the full source: the server fetches the current page,…",
28
42
  "vi": "Công cụ add_section mới cho phép gắn thêm một hoặc nhiều section vào trang hiện có mà không cần gửi lại toàn bộ source: server lấy trang hiện tại,…"
29
- },
30
- {
31
- "v": "1.0.37",
32
- "d": "08/06/2026",
33
- "type": "Changed",
34
- "en": "get_generation_guide now includes a HEADER section build hint directing the agent to place every header child (logo, brand text, CTA button) on a…",
35
- "vi": "get_generation_guide nay bổ sung gợi ý dựng section HEADER yêu cầu agent đặt mọi phần tử con trong header (logo, tên thương hiệu, nút CTA) trên cùng…"
36
- },
37
- {
38
- "v": "1.0.36",
39
- "d": "08/06/2026",
40
- "type": "Changed",
41
- "en": "The GET / web guide page now lists \"Claude · Codex · Cursor, etc.\" instead of only \"Claude · Cursor\" in the AI assistant flow diagram, reflecting…",
42
- "vi": "Trang hướng dẫn GET / nay hiển thị \"Claude · Codex · Cursor, v.v.\" thay vì chỉ \"Claude · Cursor\" trong sơ đồ luồng AI assistant, phản ánh danh sách…"
43
43
  }
44
44
  ]
@@ -16,8 +16,8 @@ export const MARKETING = [
16
16
  showDay: "boolean — show the days segment.",
17
17
  showSecond: "boolean — show the seconds segment.",
18
18
  showText: "boolean — show unit labels (days/hours/minutes/seconds).",
19
- language: "locale string for unit labels.",
20
- customTranslation: "object — custom unit label overrides.",
19
+ language: "unit-label locale MUST be one of: vietnam | english | filipino | khmer | lao | indonesian | thai | malay | custom. NOT a code like 'vi'/'en' (that crashes the renderer). For any other language use 'custom' + customTranslation.",
20
+ customTranslation: "object {day,hour,minute,second} of label strings used (and required) when language='custom'. e.g. {day:'Ngày',hour:'Giờ',minute:'Phút',second:'Giây'}.",
21
21
  },
22
22
  seed: (el) => {
23
23
  seedPosition(el);
@@ -25,7 +25,7 @@ export const MARKETING = [
25
25
  setStyle(el, "color", "rgba(255, 255, 255, 1)");
26
26
  setStyle(el, "background", "rgba(0, 0, 0, 1)");
27
27
  setStyle(el, "fontSize", 20);
28
- el.specials = { type: "minute", duration: "60", showDay: true, showSecond: true, showText: true, repeat: false, customize: false, customMessage: "", dailyStart: "", dailyEnd: "" };
28
+ el.specials = { type: "minute", duration: "60", language: "english", showDay: true, showSecond: true, showText: true, repeat: false, customize: false, customMessage: "", dailyStart: "", dailyEnd: "" };
29
29
  },
30
30
  },
31
31
  {
@@ -230,7 +230,7 @@
230
230
  },
231
231
  "specials": {
232
232
  "type": "object",
233
- "description": "Type-specific content/config. The user-visible CONTENT lives here, NOT in styles. Open object; key fields by type: section{globalSection,globalSectionName,custom_class,imageCompression}; text-block{text(HTML),tag}; list-paragraph{text(<li>..)}; image-block{src,resize}; button{text,required,format,connectedSurvey}; video{typeVideo,video_cdn,img,autoReplay}; gallery{media[]}; form{field_type,form_type,sheetOrder,validate,submit_success,fb_event_type,fb_conversion_value,fb_tracking_currency,tiktok_conversion_value,tiktok_tracking_currency}; input/textarea/select/checkbox/radio/address/...{field_name,field_placeholder,field_type,required,options}; countdown{type,duration,startTime,endTime,showDay,showSecond,showText,language,customTranslation}; survey{options[{id,image,title,value,field_name}],type,multiOption,selectedBackground,selectedBorder}; list-product{format_title,numerical_order,remain_quantity_text}.",
233
+ "description": "Type-specific content/config. The user-visible CONTENT lives here, NOT in styles. Open object; key fields by type: section{globalSection,globalSectionName,custom_class,imageCompression}; text-block{text(HTML),tag}; list-paragraph{text(<li>..)}; image-block{src,resize}; button{text,required,format,connectedSurvey}; video{typeVideo,video_cdn,img,autoReplay}; gallery{media[]}; form{field_type,form_type,sheetOrder,validate,submit_success,fb_event_type,fb_conversion_value,fb_tracking_currency,tiktok_conversion_value,tiktok_tracking_currency}; input/textarea/select/checkbox/radio/address/...{field_name,field_placeholder,field_type,required,options}; countdown{type,duration,startTime,endTime,showDay,showSecond,showText,language(vietnam|english|filipino|khmer|lao|indonesian|thai|malay|custom — NOT a locale code; 'custom' uses customTranslation),customTranslation{day,hour,minute,second}}; survey{options[{id,image,title,value,field_name}],type,multiOption,selectedBackground,selectedBorder}; list-product{format_title,numerical_order,remain_quantity_text}.",
234
234
  "additionalProperties": true,
235
235
  "properties": {
236
236
  "text": { "type": "string", "description": "text-block/button label/list-paragraph (may contain HTML)." },
@@ -36,6 +36,11 @@ const OPTION_NAME_FIELDS = new Set(["select", "radio", "checkbox-group"]);
36
36
  // field_placeholder throws "Cannot read properties of undefined (reading 'replace')"
37
37
  // and the whole page fails to render.
38
38
  const PLACEHOLDER_REQUIRED_FIELDS = new Set(["select", "country-select", "group-select-item"]);
39
+ // countdown's renderer indexes a fixed `lang` table by specials.language and then
40
+ // destructures the result: `const [d,h,m,s] = lang[language]`. Any value outside
41
+ // this set (e.g. a locale code like "vi"/"en") yields undefined → "is not iterable"
42
+ // and the whole page fails to render. 'custom' instead reads specials.customTranslation.
43
+ const COUNTDOWN_LANGUAGES = new Set(["vietnam", "english", "filipino", "khmer", "lao", "indonesian", "thai", "malay", "custom"]);
39
44
  // Fixed canvas reference (matches vocab CANVAS) used for the layout/bounds check.
40
45
  const CANVAS_DESKTOP = 960;
41
46
  const CANVAS_MOBILE = 420;
@@ -149,6 +154,15 @@ export function validatePage(input) {
149
154
  });
150
155
  }
151
156
  }
157
+ // countdown.language must be a key the renderer's lang table knows (or 'custom');
158
+ // anything else (e.g. a locale code "vi"/"en") crashes the renderer with
159
+ // "is not iterable" when it destructures lang[language].
160
+ if (type === "countdown") {
161
+ const lang = node.specials?.language;
162
+ if (typeof lang === "string" && !COUNTDOWN_LANGUAGES.has(lang)) {
163
+ errors.push(`${path} (countdown): specials.language="${lang}" is not supported and crashes the renderer. Use one of: ${[...COUNTDOWN_LANGUAGES].join(", ")} (use "custom" + specials.customTranslation for other languages).`);
164
+ }
165
+ }
152
166
  // collect events
153
167
  if (Array.isArray(node.events)) {
154
168
  for (const ev of node.events) {
package/dist/web-guide.js CHANGED
@@ -78,14 +78,14 @@ function tile(name) {
78
78
  // ── i18n: per-language SEO metadata ───────────────────────────────────────────
79
79
  const META = {
80
80
  vi: {
81
- title: "Webcake Landing MCP — AI dựng landing page Webcake bằng lời nói",
82
- desc: "MCP server cho phép AI (Claude, Cursor, Windsurf…) dựng, kiểm tra và lưu thẳng landing page Webcake từ một câu tả. Không kéo-thả, không viết JSON, kết nối một lần là xong.",
81
+ title: "Webcake Landing MCP — AI tự dựng landing page Webcake cho bạn",
82
+ desc: "Bạn chỉ cần tả bằng lời, AI (Claude, Cursor, Windsurf…) sẽ tự dựng, tự kiểm tra và lưu landing page Webcake cho bạn. Không cần kéo-thả, không cần biết code, kết nối một lần là xong.",
83
83
  keywords: "Webcake, landing page, MCP, Model Context Protocol, AI, Claude, Cursor, Windsurf, tạo landing page bằng AI, no-code, COD, lead generation",
84
84
  locale: "vi_VN",
85
85
  },
86
86
  en: {
87
- title: "Webcake Landing MCP — let AI build Webcake landing pages from a sentence",
88
- desc: "An MCP server that lets AI (Claude, Cursor, Windsurf…) build, validate and save Webcake landing pages straight from a plain-language description. No drag-and-drop, no JSON, connect once.",
87
+ title: "Webcake Landing MCP — let AI build Webcake landing pages for you",
88
+ desc: "Just describe it in plain words and AI (Claude, Cursor, Windsurf…) builds, checks and saves a Webcake landing page for you. No drag-and-drop, no coding connect once and you're set.",
89
89
  keywords: "Webcake, landing page, MCP, Model Context Protocol, AI, Claude, Cursor, Windsurf, AI website builder, no-code, COD, lead generation",
90
90
  locale: "en_US",
91
91
  },
@@ -95,210 +95,210 @@ const FAQ = {
95
95
  vi: [
96
96
  {
97
97
  q: "Webcake Landing MCP là gì?",
98
- a: "Một MCP server dạy AI cách dựng trọn cấu trúc nguồn của landing page Webcake từ yêu cầu bằng lời, kiểm tra hợp lệ rồi lưu về tài khoản Webcake của bạn. Server lo phần khó; bạn chỉ mô tả và duyệt.",
98
+ a: " một công cụ giúp AI (như Claude, Cursor) tự dựng landing page Webcake cho bạn từ một câu tả, tự kiểm tra rồi lưu vào tài khoản Webcake của bạn. Công cụ lo phần khó; bạn chỉ cần mô tả và xem lại.",
99
99
  },
100
100
  {
101
101
  q: "Tôi có cần biết lập trình không?",
102
- a: "Không. Bạn chỉ cần mô tả trang bằng ngôn ngữ tự nhiên trong AI (Claude, Cursor…). AI dùng các tool của server để dựng đúng hình element thật của Webcake.",
102
+ a: "Không. Bạn chỉ cần mô tả trang bằng lời, ngay trong ứng dụng AI bạn đang dùng. Mọi phần kỹ thuật để công cụ tự lo.",
103
103
  },
104
104
  {
105
105
  q: "Có miễn phí không?",
106
- a: "Có. Server nguồn mở miễn phí. Bạn chỉ cần một tài khoản Webcake để lưu trang; các tool tham chiếu + kiểm tra còn chạy được mà không cần token.",
106
+ a: "Có. Công cụ miễn phí nguồn mở. Bạn chỉ cần một tài khoản Webcake để lưu trang.",
107
107
  },
108
108
  {
109
- q: "Dùng được với AI/IDE nào?",
110
- a: "Claude Desktop, Claude Code, Cursor, Windsurf, Augment (VS Code), Codex, và claude.ai trên web hay bất kỳ client nào hỗ trợ Model Context Protocol.",
109
+ q: "Dùng được với ứng dụng nào?",
110
+ a: "Claude (máy tính, web, Claude Code), Cursor, Windsurf, Augment, Codex — bất kỳ ứng dụng AI nào hỗ trợ chuẩn kết nối MCP.",
111
111
  },
112
112
  {
113
- q: "Token của tôi có an toàn không?",
114
- a: "Có. Token chỉ là của riêng bạn, gửi qua header hoặc link nhân, không lưu lại; mọi thao tác ghi đều mặc định xem trước (dry-run) trước khi thực sự lưu.",
113
+ q: "Thông tin của tôi có an toàn không?",
114
+ a: "Có. đăng nhập là của riêng bạn không bị lưu lại. Ngoài ra, mỗi lần lưu trang công cụ đều cho bạn xem trước, chắc chắn rồi mới thực hiện.",
115
115
  },
116
116
  ],
117
117
  en: [
118
118
  {
119
119
  q: "What is Webcake Landing MCP?",
120
- a: "An MCP server that teaches AI how to build the full source structure of a Webcake landing page from a plain-language request, validate it, then save it to your Webcake account. The server does the hard part; you just describe and review.",
120
+ a: "It's a tool that lets AI (like Claude or Cursor) build a Webcake landing page for you from a single description, check it, then save it to your Webcake account. The tool does the hard part; you just describe and review.",
121
121
  },
122
122
  {
123
123
  q: "Do I need to know how to code?",
124
- a: "No. You just describe the page in natural language in your AI (Claude, Cursor…). The AI uses the server's tools to build against Webcake's real element model.",
124
+ a: "No. You just describe the page in plain words, right inside the AI app you already use. The tool handles all the technical parts.",
125
125
  },
126
126
  {
127
127
  q: "Is it free?",
128
- a: "Yes. The server is open-source and free. You only need a Webcake account to save pages; the reference and validation tools work without a token.",
128
+ a: "Yes. The tool is free and open-source. You only need a Webcake account to save pages.",
129
129
  },
130
130
  {
131
- q: "Which AI / IDEs work with it?",
132
- a: "Claude Desktop, Claude Code, Cursor, Windsurf, Augment (VS Code), Codex, and claude.ai on the web or any client that supports the Model Context Protocol.",
131
+ q: "Which apps work with it?",
132
+ a: "Claude (desktop, web, Claude Code), Cursor, Windsurf, Augment, Codex — and any AI app that supports the MCP connection standard.",
133
133
  },
134
134
  {
135
- q: "Is my token safe?",
136
- a: "Yes. The token is yours alone, sent via a header or your personal link and never stored; and every write defaults to a preview (dry-run) before anything is actually saved.",
135
+ q: "Is my information safe?",
136
+ a: "Yes. Your login code is yours alone and is never stored. On top of that, every save shows you a preview first, so nothing happens until you're sure.",
137
137
  },
138
138
  ],
139
139
  };
140
140
  const T = {
141
141
  vi: {
142
- sub: "Cho AI dựng & sửa landing page Webcake bằng lời nói",
143
- running: "Server đang chạy",
144
- leadPre: "Bạn gõ yêu cầu, AI (Claude, Cursor…) dựng nguyên cái landing page rồi ",
142
+ sub: "Để AI tự dựng & sửa landing page Webcake cho bạn, chỉ bằng lời nói",
143
+ running: "Đang hoạt động",
144
+ leadPre: "Bạn gõ yêu cầu, AI (như Claude, Cursor…) tự dựng cả trang landing page rồi ",
145
145
  leadGrad: "lưu thẳng vào tài khoản Webcake",
146
- leadPost: " của bạn. Không kéo thả, không cài server — kết nối một lần là xong.",
146
+ leadPost: " của bạn. Không cần kéo thả, không cần cài đặt phức tạp — kết nối một lần là xong.",
147
147
  ctaStart: "Bắt đầu kết nối",
148
- ctaStar: "Star trên GitHub",
149
- flowH2: " hình hoạt động",
148
+ ctaStar: "Tặng sao trên GitHub",
149
+ flowH2: "Mọi thứ diễn ra thế nào",
150
150
  flow: [
151
- { icon: "bulb", t: "Bạn", s: "ý tưởng" },
152
- { icon: "brain", t: "Trợ lý AI", s: "Claude · Codex · Cursor,etc..." },
153
- { icon: "server", t: "MCP", s: "webcake-landing" },
154
- { icon: "window", t: "WebCake", s: "trang thật" },
151
+ { icon: "bulb", t: "Bạn", s: "ý tưởng của bạn" },
152
+ { icon: "brain", t: "Trợ lý AI", s: "Claude · Cursor · Codex…" },
153
+ { icon: "server", t: "Webcake MCP", s: "cầu nối thông minh" },
154
+ { icon: "window", t: "Webcake", s: "trang web thật" },
155
155
  ],
156
- flowCap: "Bạn tả bằng lời → AI học hình thật từ MCP MCP dựng JSON + kiểm tra → lưu thành trang thật trên WebCake. Bạn nhận link, mở editor, publish.",
157
- howH2: "Cách hoạt động",
156
+ flowCap: "Bạn nói ý tưởng → AI hiểu cách Webcake hoạt độngtự dựng trang tự kiểm tra → trang được lưu thật vào Webcake. Bạn nhận link, mở lên xem và đăng trang.",
157
+ howH2: " sao bạn không cần biết kỹ thuật",
158
158
  how: [
159
159
  {
160
160
  icon: "brain",
161
- t: "AI học hình thật",
162
- d: 'Danh mục element, <code class="inl">specials</code>, hệ toạ độ sự kiện của Webcake lấy trực tiếp qua các tool của server.',
161
+ t: "AI lo phần dựng trang",
162
+ d: "AI tự sắp xếp chữ, hình ảnh, nút bấm, biểu mẫu… theo đúng chuẩn của Webcake. Bạn không phải đụng tới.",
163
163
  },
164
164
  {
165
165
  icon: "check2",
166
- t: "Server lo phần khó",
167
- d: "Dựng JSON nguồn, kiểm tra hợp lệ (validate) rồi lưu trang về backend Webcake — bạn khỏi đụng schema.",
166
+ t: "Hệ thống tự kiểm tra",
167
+ d: "Trang được dựng kiểm tra tự động trước khi lưu, nên hiếm khi lỗi — bạn không cần biết gì về kỹ thuật.",
168
168
  },
169
169
  {
170
170
  icon: "edit",
171
- t: "Bạn chỉ duyệt",
172
- d: "Mở trang trong editor Webcake, chỉnh vài chỗ nếu thích, lưu lại để render xong.",
171
+ t: "Bạn chỉ việc xem lại",
172
+ d: "Mở trang trong trình chỉnh sửa Webcake, sửa vài chỗ nếu thích, bấm lưu trang hiển thị. Vậy là xong.",
173
173
  },
174
174
  ],
175
- buildH2: "Bạn dựng được những gì",
175
+ buildH2: "Bạn thể tạo những gì",
176
176
  uses: [
177
177
  {
178
178
  icon: "magnet",
179
- t: "Trang thu lead",
180
- e: '"Trang waitlist cho SaaShero, 3 lợi ích, form thu email."',
179
+ t: "Trang thu khách tiềm năng",
180
+ e: '"Trang đăng ký nhận tin cho ứng dụng phần đầu nổi bật, 3 lợi ích, ô nhập email."',
181
181
  },
182
182
  {
183
183
  icon: "cart",
184
- t: "Bán hàng COD / online",
185
- e: '"Trang một sản phẩm — gallery, giá, biến thể, form đặt hàng có giỏ."',
184
+ t: "Bán hàng (COD / online)",
185
+ e: '"Trang bán một sản phẩm — ảnh, giá, lựa chọn mẫu mã, form đặt hàng."',
186
186
  },
187
187
  {
188
188
  icon: "ticket",
189
- t: "Sự kiện / webinar",
190
- e: '"Trang đăng ký — đếm ngược, agenda, form đăng ký."',
189
+ t: "Sự kiện / hội thảo",
190
+ e: '"Trang đăng ký tham gia đồng hồ đếm ngược, lịch trình, form đăng ký."',
191
191
  },
192
192
  {
193
193
  icon: "mail",
194
194
  t: "Thiệp mời",
195
- e: '"Thiệp cưới — tên, ngày, bản đồ, form RSVP."',
195
+ e: '"Thiệp cưới — tên cô dâu chú rể, ngày giờ, bản đồ, form xác nhận tham dự."',
196
196
  },
197
197
  {
198
198
  icon: "phone",
199
- t: "Quảng app",
200
- e: '"Mockup điện thoại, danh sách tính năng, nút App Store + Google Play."',
199
+ t: "Giới thiệu ứng dụng",
200
+ e: '"Ảnh điện thoại, danh sách tính năng, nút tải trên App Store Google Play."',
201
201
  },
202
202
  {
203
203
  icon: "flame",
204
- t: "Flash sale",
205
- e: '"Đồng hồ đếm ngược to, lưới sản phẩm giảm giá, nút Mua dính."',
204
+ t: "Sale chớp nhoáng",
205
+ e: '"Đồng hồ đếm ngược cỡ lớn, lưới sản phẩm giảm giá, nút Mua luôn nổi."',
206
206
  },
207
207
  ],
208
208
  connectH2: "Kết nối — chọn 1 trong 2 cách",
209
- m1Tag: "Cách ① · npx — chạy trên máy bạn",
210
- m1Sub: "Hợp khi dùng nhân, muốn toàn quyền. Cần cài Node.js 18+.",
209
+ m1Tag: "Cách ① · Cài trên máy của bạn",
210
+ m1Sub: "Phù hợp khi bạn tự dùng muốn chủ động. Cần sẵn Node.js (một phần mềm miễn phí giúp chạy lệnh).",
211
211
  m1Steps: [
212
- '<b>Cài Node.js 18+</b> nếu chưa có. Kiểm tra bằng <code class="inl">node -v</code>; chưa có thì tải <b>nodejs.org</b>.',
213
- "<b>Mở Terminal chạy:</b><pre>npx -y webcake-landing-mcp install</pre>",
214
- '<b>Làm theo hỏi đáp:</b> chọn môi trường (<code class="inl">prod</code>) → đăng nhập Webcake qua trình duyệt (hoặc dán JWT) → chọn IDE (Claude Desktop / Cursor / Claude Code…).',
215
- '<b>Khởi động lại IDE</b> thấy <code class="inl">webcake-landing</code> trong danh sách MCP xong.',
212
+ "<b>Cài Node.js</b> (miễn phí) nếu máy chưa có tải tại <b>nodejs.org</b>. Đây là phần mềm giúp máy chạy được công cụ ở bước sau.",
213
+ "<b>Mở Terminal</b> (cửa sổ gõ lệnh — trên Mac tìm “Terminal”, trên Windows tìm “Command Prompt”), dán dòng dưới đây rồi nhấn Enter:<pre>npx -y webcake-landing-mcp install</pre>",
214
+ '<b>Làm theo hướng dẫn hiện ra:</b> chọn <code class="inl">prod</code> → đăng nhập Webcake bằng trình duyệt → chọn ứng dụng AI bạn đang dùng (Claude, Cursor…).',
215
+ '<b>Mở lại ứng dụng AI.</b> Thấy chữ <code class="inl">webcake-landing</code> xuất hiện đã kết nối thành công.',
216
216
  ],
217
- m1Note: "Muốn cấu hình mọi IDE một phát:",
218
- m2Tag: "Cách ② · URL remote — không cần cài gì",
219
- m2Sub: "Hợp khi máy không Node.js, dùng theo nhóm, hoặc dùng claude.ai trên web.",
217
+ m1Note: "Muốn cài cho tất cả ứng dụng cùng lúc, dùng dòng lệnh này:",
218
+ m2Tag: "Cách ② · Dùng link — không cần cài gì",
219
+ m2Sub: "Phù hợp khi máy không cài được phần mềm, dùng theo nhóm, hoặc dùng Claude trên web (claude.ai).",
220
220
  m2Steps: [
221
- '<b>Lấy link nhân</b> (đã gắn sẵn token) — mở trang sau rồi bấm <b>Copy</b>:<a class="btn" href="{REMOTE}">Mở {REMOTE_HOST} {ARROW}</a>',
222
- '<b>Mở phần thêm connector</b> trong client:<br>• claude.ai: <i>Settings → Connectors → Add custom connector</i><br>• Cursor / Claude Code: mở file <code class="inl">.mcp.json</code>',
223
- "<b>Dán link</b> vừa copy ( dạng):<pre>{ENDPOINT}?jwt=&lt;TOKEN&gt;</pre>",
224
- "<b>Bấm Add</b> (hoặc lưu file) đợi kết nối xong. Icon Webcake xanh hiện lên chạy được.",
221
+ '<b>Lấy link riêng của bạn</b> (đã gắn sẵn mã đăng nhập) — mở trang dưới đây rồi bấm <b>Copy</b>:<a class="btn" href="{REMOTE}">Mở {REMOTE_HOST} {ARROW}</a>',
222
+ '<b>Vào nơi thêm kết nối</b> trong ứng dụng:<br>• claude.ai: <i>Settings → Connectors → Add custom connector</i><br>• Cursor / Claude Code: mở file <code class="inl">.mcp.json</code>',
223
+ "<b>Dán link</b> bạn vừa copy (trông giống như):<pre>{ENDPOINT}?jwt=&lt;MÃ CỦA BẠN&gt;</pre>",
224
+ "<b>Bấm Add</b> (hoặc lưu file) rồi chờ một chút. Khi biểu tượng Webcake chuyển xanh là dùng được.",
225
225
  ],
226
- m2Note: "⚠️ Link chứa token nhân — coi như mật khẩu, đừng chia sẻ, luôn dùng HTTPS.",
227
- afterH2: "Sau khi kết nối, bạn nói được",
226
+ m2Note: "⚠️ Link chứa đăng nhập riêng của bạn hãy coi như mật khẩu, đừng chia sẻ cho ai.",
227
+ afterH2: "Kết nối xong, bạn chỉ cần nói",
228
228
  examples: [
229
229
  {
230
230
  icon: "wand",
231
- t: '"Dựng landing bán khoá học, tông xanh, có form đăng ký + nút Zalo."',
231
+ t: '"Dựng trang bán khóa học, tông màu xanh, có form đăng ký nút Zalo."',
232
232
  },
233
233
  {
234
234
  icon: "edit",
235
- t: "\"Mở trang <i>sale-hè</i>, đổi tiêu đề thành 'Giảm 50%', nút sang màu đỏ.\"",
235
+ t: "\"Mở trang <i>sale-hè</i>, đổi tiêu đề thành 'Giảm 50%', đổi nút sang màu đỏ.\"",
236
236
  },
237
237
  {
238
238
  icon: "clock",
239
- t: '"Thêm section đếm ngược + 3 testimonial vào cuối trang."',
239
+ t: '"Thêm phần đếm ngược 3 lời nhận xét của khách vào cuối trang."',
240
240
  },
241
241
  ],
242
242
  newH2: "Có gì mới",
243
243
  newBadge: "MỚI",
244
- clMore: "Xem toàn bộ changelog",
244
+ clMore: "Xem tất cả thay đổi",
245
245
  faqH2: "Câu hỏi thường gặp",
246
- starH2: "Thấy hữu ích? Thả cho dự án một star",
247
- starP: "Đây là dự án mã nguồn mở — mỗi star là một liều động viên giữ phát triển và giúp người khác tìm thấy nó.",
248
- starBtn: "Star trên GitHub",
246
+ starH2: "Thấy hữu ích? Tặng dự án một ngôi sao nhé",
247
+ starP: "Đây là dự án miễn phí, mã nguồn mở — mỗi ngôi sao là một lời động viên để dự án tiếp tục phát triển và giúp nhiều người biết đến hơn.",
248
+ starBtn: "Tặng sao trên GitHub",
249
249
  footGuide: "Hướng dẫn",
250
250
  switchLabel: "English",
251
251
  },
252
252
  en: {
253
- sub: "Let AI build & edit Webcake landing pages from plain words",
254
- running: "Server is running",
255
- leadPre: "You type a request, AI (Claude, Cursor) builds the whole landing page and ",
253
+ sub: "Let AI build & edit your Webcake landing pages, just by talking to it",
254
+ running: "Up and running",
255
+ leadPre: "You type what you want, AI (like Claude or Cursor) builds the whole landing page and ",
256
256
  leadGrad: "saves it straight to your Webcake account",
257
- leadPost: ". No drag-and-drop, no server to host — connect once and you're set.",
257
+ leadPost: ". No drag-and-drop, no complicated setup — connect once and you're done.",
258
258
  ctaStart: "Get connected",
259
259
  ctaStar: "Star on GitHub",
260
- flowH2: "How it flows",
260
+ flowH2: "How it all happens",
261
261
  flow: [
262
262
  { icon: "bulb", t: "You", s: "your idea" },
263
- { icon: "brain", t: "AI assistant", s: "Claude · Codex · Cursor,etc..." },
264
- { icon: "server", t: "MCP", s: "webcake-landing" },
265
- { icon: "window", t: "WebCake", s: "a real page" },
263
+ { icon: "brain", t: "AI assistant", s: "Claude · Cursor · Codex…" },
264
+ { icon: "server", t: "Webcake MCP", s: "the smart bridge" },
265
+ { icon: "window", t: "Webcake", s: "a real page" },
266
266
  ],
267
- flowCap: "You describe it in words → the AI learns the real model from the MCP the MCP builds the JSON + validatesit's saved as a real WebCake page. You get a link, open the editor, publish.",
268
- howH2: "How it works",
267
+ flowCap: "You say your idea → the AI learns how Webcake worksit builds the page and checks it the page is saved for real in Webcake. You get a link, open it, and publish.",
268
+ howH2: "Why you don't need to be techy",
269
269
  how: [
270
270
  {
271
271
  icon: "brain",
272
- t: "AI learns the real model",
273
- d: "Webcake's element catalog, <code class=\"inl\">specials</code>, coordinate system and events pulled straight from this server's tools.",
272
+ t: "AI does the building",
273
+ d: "The AI arranges the text, images, buttons and forms the way Webcake expects. You never have to touch any of it.",
274
274
  },
275
275
  {
276
276
  icon: "check2",
277
- t: "The server does the hard part",
278
- d: "Builds the source JSON, validates it, then saves the page to the Webcake backendyou never touch the schema.",
277
+ t: "It checks itself",
278
+ d: "Every page is built and checked automatically before it's saved, so things rarely breakno technical know-how needed.",
279
279
  },
280
280
  {
281
281
  icon: "edit",
282
282
  t: "You just review",
283
- d: "Open the page in the Webcake editor, tweak if you like, save to render done.",
283
+ d: "Open the page in the Webcake editor, tweak anything you like, hit save and it goes live. That's it.",
284
284
  },
285
285
  ],
286
286
  buildH2: "What you can build",
287
287
  uses: [
288
288
  {
289
289
  icon: "magnet",
290
- t: "Lead-gen page",
291
- e: '"A SaaS waitlist — hero, 3 benefits, an email-capture form."',
290
+ t: "Lead-capture page",
291
+ e: '"A waitlist for an app a bold header, 3 benefits, an email box."',
292
292
  },
293
293
  {
294
294
  icon: "cart",
295
- t: "COD / online store",
296
- e: '"A one-product page — gallery, price, variations, an order form with cart."',
295
+ t: "Sell products (COD / online)",
296
+ e: '"A one-product page — photos, price, options, an order form."',
297
297
  },
298
298
  {
299
299
  icon: "ticket",
300
300
  t: "Event / webinar",
301
- e: '"A registration page — countdown, agenda, sign-up form."',
301
+ e: '"A sign-up page — a countdown, the agenda, a registration form."',
302
302
  },
303
303
  {
304
304
  icon: "mail",
@@ -308,38 +308,38 @@ const T = {
308
308
  {
309
309
  icon: "phone",
310
310
  t: "App promo",
311
- e: '"Phone mockups, feature list, App Store + Google Play buttons."',
311
+ e: '"Phone photos, a feature list, App Store and Google Play buttons."',
312
312
  },
313
313
  {
314
314
  icon: "flame",
315
315
  t: "Flash sale",
316
- e: '"A big countdown, a discounted product grid, a sticky Buy button."',
316
+ e: '"A big countdown, a grid of discounted products, a Buy button that follows you."',
317
317
  },
318
318
  ],
319
319
  connectH2: "Connect — pick one of two ways",
320
- m1Tag: "Way ① · npx — runs on your machine",
321
- m1Sub: "Best for personal use and full control. Needs Node.js 18+.",
320
+ m1Tag: "Way ① · Install on your computer",
321
+ m1Sub: "Best when it's just for you and you want full control. Needs Node.js (a free program that runs commands).",
322
322
  m1Steps: [
323
- '<b>Install Node.js 18+</b> if you don\'t have it. Check with <code class="inl">node -v</code>; otherwise grab it from <b>nodejs.org</b>.',
324
- "<b>Open a terminal and run:</b><pre>npx -y webcake-landing-mcp install</pre>",
325
- '<b>Follow the prompts:</b> pick an environment (<code class="inl">prod</code>) → sign in to Webcake in the browser (or paste a JWT) pick your IDE (Claude Desktop / Cursor / Claude Code…).',
326
- '<b>Restart your IDE</b> see <code class="inl">webcake-landing</code> in the MCP list and you\'re done.',
323
+ "<b>Install Node.js</b> (free) if you don't have it get it at <b>nodejs.org</b>. It's the program that lets your computer run the tool in the next step.",
324
+ "<b>Open a terminal</b> (the command window — “Terminal” on Mac, “Command Prompt” on Windows), paste the line below and press Enter:<pre>npx -y webcake-landing-mcp install</pre>",
325
+ '<b>Follow the prompts:</b> choose <code class="inl">prod</code> → sign in to Webcake in your browser pick the AI app you use (Claude, Cursor…).',
326
+ '<b>Reopen your AI app.</b> When you see <code class="inl">webcake-landing</code> listed, you\'re connected.',
327
327
  ],
328
- m1Note: "Configure every IDE at once:",
329
- m2Tag: "Way ② · Remote URL — nothing to install",
330
- m2Sub: "Best when you have no Node.js, work in a team, or use claude.ai on the web.",
328
+ m1Note: "Set it up for every app at once with this command:",
329
+ m2Tag: "Way ② · Use a link — nothing to install",
330
+ m2Sub: "Best when you can't install software, work in a team, or use Claude on the web (claude.ai).",
331
331
  m2Steps: [
332
- '<b>Get your personal link</b> (token baked in) — open the page below and hit <b>Copy</b>:<a class="btn" href="{REMOTE}">Open {REMOTE_HOST} {ARROW}</a>',
333
- '<b>Open the add-connector area</b> in your client:<br>• claude.ai: <i>Settings → Connectors → Add custom connector</i><br>• Cursor / Claude Code: open <code class="inl">.mcp.json</code>',
334
- "<b>Paste the link</b> you copied (looks like):<pre>{ENDPOINT}?jwt=&lt;TOKEN&gt;</pre>",
335
- "<b>Hit Add</b> (or save the file) wait for it to connect done. A green Webcake icon means it's live.",
332
+ '<b>Get your personal link</b> (your login is built in) — open the page below and hit <b>Copy</b>:<a class="btn" href="{REMOTE}">Open {REMOTE_HOST} {ARROW}</a>',
333
+ '<b>Go to where you add a connection</b> in your app:<br>• claude.ai: <i>Settings → Connectors → Add custom connector</i><br>• Cursor / Claude Code: open <code class="inl">.mcp.json</code>',
334
+ "<b>Paste the link</b> you just copied (it looks like):<pre>{ENDPOINT}?jwt=&lt;YOUR CODE&gt;</pre>",
335
+ "<b>Hit Add</b> (or save the file) and wait a moment. When the Webcake icon turns green, you're good to go.",
336
336
  ],
337
- m2Note: "⚠️ The link carries your personal token — treat it like a password, never share it, always use HTTPS.",
338
- afterH2: "Once connected, you can say",
337
+ m2Note: "⚠️ The link contains your personal login code — treat it like a password and never share it.",
338
+ afterH2: "Once connected, just say",
339
339
  examples: [
340
340
  {
341
341
  icon: "wand",
342
- t: '"Build a landing page to sell a course, green theme, a sign-up form + a Zalo button."',
342
+ t: '"Build a page to sell a course, green theme, with a sign-up form and a Zalo button."',
343
343
  },
344
344
  {
345
345
  icon: "edit",
@@ -347,15 +347,15 @@ const T = {
347
347
  },
348
348
  {
349
349
  icon: "clock",
350
- t: '"Add a countdown section + 3 testimonials to the bottom of the page."',
350
+ t: '"Add a countdown and 3 customer reviews to the bottom of the page."',
351
351
  },
352
352
  ],
353
353
  newH2: "What's new",
354
354
  newBadge: "NEW",
355
- clMore: "See full changelog",
355
+ clMore: "See all changes",
356
356
  faqH2: "FAQ",
357
- starH2: "Find it useful? Drop the project a star",
358
- starP: "It's an open-source project — every star keeps it moving and helps others discover it.",
357
+ starH2: "Find it useful? Give the project a star",
358
+ starP: "It's a free, open-source project — every star is a little encouragement to keep it growing and helps more people find it.",
359
359
  starBtn: "Star on GitHub",
360
360
  footGuide: "Docs",
361
361
  switchLabel: "Tiếng Việt",
@@ -456,7 +456,7 @@ export function guideHtml(origin, lang = "vi") {
456
456
  <html lang="${L}"><head>
457
457
  <meta charset="utf-8">
458
458
  <meta name="viewport" content="width=device-width,initial-scale=1">
459
- <script>(function(){try{var t=localStorage.getItem('wc-theme');if(t==='dark'||t==='light')document.documentElement.setAttribute('data-theme',t);}catch(e){}try{if('scrollRestoration' in history)history.scrollRestoration='manual';}catch(e){}})();</script>
459
+ <script>(function(){document.documentElement.classList.add('js');try{var t=localStorage.getItem('wc-theme');if(t==='dark'||t==='light')document.documentElement.setAttribute('data-theme',t);}catch(e){}try{if('scrollRestoration' in history)history.scrollRestoration='manual';}catch(e){}})();</script>
460
460
  <title>${m.title}</title>
461
461
  <meta name="description" content="${m.desc}">
462
462
  <meta name="keywords" content="${m.keywords}">
@@ -692,10 +692,14 @@ export function guideHtml(origin, lang = "vi") {
692
692
  .flow .wire .pkt{display:none}
693
693
  }
694
694
  @media(prefers-reduced-motion:no-preference){
695
- @supports (animation-timeline:view()){
696
- .reveal{animation:rise linear both;animation-timeline:view();animation-range:entry 0% entry 32%}
697
- @keyframes rise{from{opacity:0;transform:translateY(30px)}to{opacity:1;transform:none}}
698
- }
695
+ /* One-shot reveal: JS adds .in the first time an element scrolls into view and
696
+ never removes it. Gated on .js so content is always visible without
697
+ JavaScript. We deliberately DON'T use a scroll-driven (animation-timeline)
698
+ reveal here — that ties opacity to scroll position and fades content back
699
+ out when you scroll up, which reads as the page flickering. */
700
+ .js .reveal{opacity:0;transform:translateY(24px);
701
+ transition:opacity .6s ease,transform .6s cubic-bezier(.2,.7,.2,1)}
702
+ .js .reveal.in{opacity:1;transform:none}
699
703
  .hero-in{animation:rise2 .8s cubic-bezier(.2,.7,.2,1) both}
700
704
  @keyframes rise2{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:none}}
701
705
  }
@@ -843,6 +847,20 @@ export function guideHtml(origin, lang = "vi") {
843
847
  window.addEventListener('beforeunload',saveScroll);
844
848
  window.addEventListener('pagehide',saveScroll);
845
849
 
850
+ // One-shot reveal-on-scroll. Each .reveal fades in once when it enters the
851
+ // viewport and then keeps its class forever — replacing the old scroll-driven
852
+ // CSS reveal that re-ran (and flickered) when scrolling back up. Falls back to
853
+ // showing everything if IntersectionObserver is missing.
854
+ var reveals=[].slice.call(document.querySelectorAll('.reveal'));
855
+ if(window.IntersectionObserver&&reveals.length){
856
+ var io=new IntersectionObserver(function(entries){
857
+ entries.forEach(function(en){if(en.isIntersecting){en.target.classList.add('in');io.unobserve(en.target);}});
858
+ },{rootMargin:'0px 0px -8% 0px'});
859
+ reveals.forEach(function(el){io.observe(el);});
860
+ }else{
861
+ reveals.forEach(function(el){el.classList.add('in');});
862
+ }
863
+
846
864
  // Enable smooth scrolling only after the browser has restored scroll position
847
865
  // on (re)load — applying it globally animates that restore into a jerky scroll.
848
866
  window.addEventListener('load',function(){requestAnimationFrame(function(){html.classList.add('smooth');});});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcake-landing-mcp",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "MCP server exposing Webcake landing-page element schemas + AI usage hints, and persisting LLM-generated page sources to a Webcake backend.",
5
5
  "mcpName": "io.github.vuluu2k/webcake-landing-mcp",
6
6
  "type": "module",
@@ -14,10 +14,15 @@
14
14
  "engines": {
15
15
  "node": ">=18"
16
16
  },
17
+ "author": "vuluu2k (https://github.com/vuluu2k)",
18
+ "homepage": "https://mcp.toolvn.io.vn",
17
19
  "repository": {
18
20
  "type": "git",
19
21
  "url": "git+https://github.com/vuluu2k/webcake-landing-mcp.git"
20
22
  },
23
+ "bugs": {
24
+ "url": "https://github.com/vuluu2k/webcake-landing-mcp/issues"
25
+ },
21
26
  "scripts": {
22
27
  "build": "node scripts/gen-changelog.mjs && tsc && node scripts/copy-assets.mjs",
23
28
  "start": "node dist/index.js",