mosaic-headless 1.15.1 → 1.16.0
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.
- package/README.ja.md +15 -8
- package/README.ko.md +14 -7
- package/README.md +14 -7
- package/README.zh-TW.md +13 -7
- package/SKILL.md +193 -28
- package/assets/templates/platforms/claude-ai.json +1 -1
- package/assets/templates/platforms/claude-code.json +1 -1
- package/assets/templates/platforms/codex-cli.json +1 -1
- package/assets/templates/platforms/copilot.json +1 -1
- package/assets/templates/platforms/gemini-cli.json +1 -1
- package/bin/check-release.mjs +63 -2
- package/data/accordion-verification.csv +8 -0
- package/data/browser-verification.csv +147 -0
- package/data/conversion-verification.csv +10 -0
- package/data/design-audit-acknowledged.csv +2 -0
- package/data/design-audit.csv +2 -0
- package/data/intro-verification.csv +17 -15
- package/data/loop-verification.csv +29 -0
- package/data/node-type-notes.csv +7 -1
- package/data/rwd-verification.csv +43 -0
- package/data/style-value-shapes.csv +3 -0
- package/data/theme-zip-verification.csv +23 -0
- package/package.json +1 -1
- package/sites/_moksa.py +594 -61
- package/sites/moksa.json +712 -2
- package/tools/from_elementor.py +507 -0
- package/tools/probe_accordion.py +161 -0
- package/tools/theme_delete.php +63 -0
- package/tools/theme_export.php +4 -2
- package/tools/theme_zip.py +222 -0
- package/tools/theme_zip_compare.php +112 -0
- package/tools/verify_browser.py +3 -3
- package/tools/verify_conversion.py +295 -0
- package/tools/verify_intro.py +17 -6
- package/tools/verify_loop.py +386 -0
package/README.ja.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# mosaic-headless
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/mosaic-headless)
|
|
4
|
+
|
|
3
5
|
[Mosaic Pro](https://mosaicbuilder.com)(Nextend)のサイトを、データモデルを直接書いて
|
|
4
6
|
構築・変更する — ビジュアルエディタも DOM も使わない。
|
|
5
7
|
|
|
@@ -21,9 +23,12 @@ fractional-index の文字列。エディタはこのモデルの一クライア
|
|
|
21
23
|
`data/` を引くこと。**
|
|
22
24
|
|
|
23
25
|
しかも grep ではなく `mo.py` で引く。grep は打った質問には答えるが、本当に抱えている
|
|
24
|
-
質問には答えない。`accordion-content` を grep
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
質問には答えない。`accordion-content` を grep すればその型が存在することは分かる。
|
|
27
|
+
スイープ表は BROKE_PAGE だと言う — 置けば公開ページ全体が 54 バイトのエラー文字列に
|
|
28
|
+
なる。どちらも本当で、どちらも間違った答えだ。行の横の注記は、その文字列が「親がない」
|
|
29
|
+
ことを名指ししていること、`accordion > accordion-item` の下に入れ子にすれば commit も
|
|
30
|
+
描画も通り、キーボードで操作できる開閉 UI までついてくることを言っている。
|
|
31
|
+
`mo.py type` はその三つを一度に見せる。
|
|
27
32
|
|
|
28
33
|
```bash
|
|
29
34
|
python tools/mo.py type accordion-content # 1 つの型を、全ライブスイープに接続して表示
|
|
@@ -60,14 +65,16 @@ URL に対応するテンプレなし HTTP 406、未ログインには空の b
|
|
|
60
65
|
| **ノードタイプ** | 122 / 122。1 ドキュメントにつき 1 タイプで commit → 描画 → 断言 → 削除。70 RENDERED、30 COMMITTED、15 COMMIT_5xx、7 BROKE_PAGE |
|
|
61
66
|
| **スタイルプロパティ** | 98 / 98 を実ページに書き、コンパイル済み CSS と照合:58 COMPILED、18 ABSENT、21 SKIPPED |
|
|
62
67
|
| **ノードプロパティ** | 181 / 181 を、各プロパティ自身の validator chain から導いた値で再測定:35 APPLIED、42 NO_EFFECT、55 NO_HOST、47 SKIPPED |
|
|
63
|
-
| **レスポンシブ** | 2 サイト計
|
|
68
|
+
| **レスポンシブ** | 2 サイト計 731 件の `_t`/`_m` 宣言を、サイトが実際に配信したスタイルシートに対して 1 件ずつ断言 — 全件検証済み |
|
|
64
69
|
| **コンポーネント** | コンポーネント機構を端から端まで実行し **8 / 8**:カテゴリ配下に作成、ドキュメントを heal、書き込み可能な instance 経由でツリーを投入、読み取り専用の方は同じ書き込みを拒否(ネガティブコントロール)、最後に 2 つのインスタンスが 1 つの定義から描画 |
|
|
65
70
|
| **スタイル状態** | 53 状態のうち 52 を実ページに書き、テーブルが約束するセレクタと照合:**36 件が完全一致**、12 件 NO_HOST、3 件 SKIPPED、1 件 BROKE_PAGE。どの要素にも使えるグローバル 7 状態はすべて検証済み |
|
|
66
71
|
| **インタラクション** | JS アニメーション経路を、ネガティブコントロール付きで保存行を読み戻しながら検証:`propertyMetas` は**受理され保存される**。プロパティ値は依然としてバインドされないが、その境界は厳密になった |
|
|
67
|
-
| **入場アニメーション** |
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
72
|
+
| **入場アニメーション** | 単調時計でページ読み込み後の 15 時点をサンプリングし 8 項目を断言 — 再生されること、アニメーションする `@property` カウンタが 100 に達すること、ベールがヒットテストから外れること、ビューポート内に opacity 0 のまま取り残された要素がないこと、実際のクリックが文書に届くこと、`prefers-reduced-motion` ではベールがそもそも存在しないこと、そして全てが落ち着いた後もなお動いているものがあること。文書の初回レイアウトを待ってから始まるため、アニメーションの全くないページに対して遅れフレームは 1 つだけ |
|
|
73
|
+
| **常時アニメーション** | 隅で刷り続け、タップすると拡大する版 — **28 項目**:一時停止したタイムラインをスクラブして周期性を証明、5 つの幅 × 25 のスクロール位置でテキスト*と*操作要素の遮蔽を「決して読めない」を失敗条件として計測、ポインタでも Enter でも開くこと、reduced motion では静止すること。Mosaic 自身のアコーディオンの上に構築 |
|
|
74
|
+
| **アコーディオン** | `accordion-item` と `accordion-content` はスイープ表では BROKE_PAGE。ファクトリが要求する通りに入れ子にすれば commit も描画も通る、**7 件中 7 件**。注記はその行の横にある |
|
|
75
|
+
| **ブラウザ** | 配信された 2 ページを Chromium の 3 つのビューポートで計算スタイル 3,988 件読み取り:2,929 件が一致、912 件は比較不能として明示、**上書き 0 件** |
|
|
76
|
+
| **デザイン監査** | コントラスト、フォントフォールバック、CJK の字送り、横溢れ、テキストの切れ、1 行の文字数 — ブラウザ上で実行、**指摘 26 件、すべて理由付きで裁定済み** — 理由のない容認はリリースゲートが拒否する |
|
|
77
|
+
| **テーマの書き出し/読み込み** | 経路は二つ、どちらも往復検証済み。`theme_export.php` は WP-CLI で行を JSON として移し、id は不変、コピーはバイト単位で同一のページを配信。`theme_zip.py` は Mosaic **自身**の ZIP 書き出し/読み込みをそのマイルストーン・プロトコルで駆動する — 読み込みは `--activate` を付けない限りテストモードに入る、既定がライブサイトの切り替えだからだ — そして **22 項目**でコピーを元とツリー単位で突き合わせる:全テーブル一致、68,337 のノード id を保持、override ノードは再採番、足りない 1 行はツリー走査が運ぶべきでない孤児 |
|
|
71
78
|
| **実測** | REST ルート 114、element class 151、条件サブジェクト 59、23 テーブル / 206 カラム |
|
|
72
79
|
|
|
73
80
|
`SKIPPED`、`NO_HOST`、`INCONCLUSIVE` を合格率に混ぜることは決してしない。
|
package/README.ko.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# mosaic-headless
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/mosaic-headless)
|
|
4
|
+
|
|
3
5
|
[Mosaic Pro](https://mosaicbuilder.com)(Nextend) 사이트를 데이터 모델에 직접 써서
|
|
4
6
|
구축하고 수정한다 — 비주얼 에디터도, DOM도 쓰지 않는다.
|
|
5
7
|
|
|
@@ -22,8 +24,11 @@ fractional-index 문자열이다. 에디터는 이 모델의 한 클라이언트
|
|
|
22
24
|
|
|
23
25
|
그리고 grep이 아니라 `mo.py`로 찾을 것. grep은 입력한 질문에 답할 뿐, 실제로 품고 있는
|
|
24
26
|
질문에는 답하지 않는다. `accordion-content`를 grep하면 그 타입이 존재한다는 것은 알 수
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
있다. 스윕 표는 BROKE_PAGE라고 말한다 — 하나 배치하면 공개 페이지 전체가 54바이트 에러
|
|
28
|
+
문자열이 된다. 둘 다 사실이고, 둘 다 틀린 답이다. 행 옆의 메모는 그 문자열이 "부모가
|
|
29
|
+
없다"를 지목한다는 것, `accordion > accordion-item` 아래에 중첩하면 commit도 렌더링도
|
|
30
|
+
되고 키보드로 조작 가능한 펼침 UI까지 따라온다는 것을 말한다. `mo.py type`은 그 셋을
|
|
31
|
+
한 번에 보여준다.
|
|
27
32
|
|
|
28
33
|
```bash
|
|
29
34
|
python tools/mo.py type accordion-content # 타입 하나를 모든 라이브 스윕과 연결해 출력
|
|
@@ -60,14 +65,16 @@ URL에 맞는 템플릿 없음 HTTP 406, 로그인하지 않은 사용자
|
|
|
60
65
|
| **노드 타입** | 122 / 122. 문서 하나당 타입 하나로 commit → 렌더 → 단언 → 삭제. 70 RENDERED, 30 COMMITTED, 15 COMMIT_5xx, 7 BROKE_PAGE |
|
|
61
66
|
| **스타일 속성** | 98 / 98을 실제 페이지에 쓰고 컴파일된 CSS와 대조: 58 COMPILED, 18 ABSENT, 21 SKIPPED |
|
|
62
67
|
| **노드 속성** | 181 / 181을 각 속성 자신의 validator chain에서 도출한 값으로 재측정: 35 APPLIED, 42 NO_EFFECT, 55 NO_HOST, 47 SKIPPED |
|
|
63
|
-
| **반응형** | 두 사이트 합쳐
|
|
68
|
+
| **반응형** | 두 사이트 합쳐 731개의 `_t`/`_m` 선언을, 사이트가 실제로 내보낸 스타일시트에 대해 하나씩 단언 — 전부 검증됨 |
|
|
64
69
|
| **컴포넌트** | 컴포넌트 체계를 끝까지 구동해 **8 / 8**: 카테고리 아래 생성, 문서 heal, 쓰기 가능한 instance로 트리 주입, 읽기 전용 쪽은 같은 쓰기를 거부(음성 대조군), 마지막으로 인스턴스 2개가 정의 하나로 렌더링 |
|
|
65
70
|
| **스타일 상태** | 53개 상태 중 52개를 실제 페이지에 쓰고 표가 약속한 셀렉터와 대조: **36개가 정확히 일치**, 12개 NO_HOST, 3개 SKIPPED, 1개 BROKE_PAGE. 어떤 요소에나 쓸 수 있는 전역 7개 상태는 전부 검증됨 |
|
|
66
71
|
| **인터랙션** | JS 애니메이션 경로를 음성 대조군과 함께, 저장된 행을 되읽으며 검증: `propertyMetas`는 **수용되고 저장된다**. 속성 값은 여전히 바인딩되지 않지만 그 경계는 이제 정확하다 |
|
|
67
|
-
| **인트로 애니메이션** | 페이지 로드 후
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
72
|
+
| **인트로 애니메이션** | 단조 시계로 페이지 로드 후 15개 시점을 샘플링해 8가지를 단언 — 재생될 것, 애니메이션되는 `@property` 카운터가 100에 도달할 것, 베일이 히트 테스트에서 빠질 것, 뷰포트 안에 opacity 0으로 갇힌 요소가 없을 것, 실제 클릭이 문서에 닿을 것, `prefers-reduced-motion`에서는 베일이 아예 존재하지 않을 것, 그리고 모든 것이 가라앉은 뒤에도 여전히 움직이는 것이 있을 것. 문서의 첫 레이아웃을 기다린 뒤 시작하므로, 애니메이션이 전혀 없는 페이지 대비 늦은 프레임은 하나뿐 |
|
|
73
|
+
| **상시 애니메이션** | 구석에서 계속 자기를 찍어내고 탭하면 확대되는 판 — **28개 검사**: 일시정지한 타임라인을 스크럽해 주기성 증명, 다섯 폭 × 스물다섯 스크롤 지점에서 텍스트*와* 컨트롤의 가림을 "결코 읽을 수 없음"을 실패 조건으로 측정, 포인터와 Enter 양쪽으로 열림, reduced motion에서는 정지. Mosaic 자체 아코디언 위에 구축 |
|
|
74
|
+
| **아코디언** | `accordion-item`과 `accordion-content`는 스윕 표에서 BROKE_PAGE. 팩토리가 요구하는 대로 중첩하면 commit과 렌더링이 되며, **7건 중 7건**. 메모는 이제 그 행 옆에 있다 |
|
|
75
|
+
| **브라우저** | 전달된 두 페이지를 Chromium의 세 가지 뷰포트에서 계산 스타일 3,988건 판독: 2,929건 일치, 912건은 비교 불가로 명시, **덮어쓰기 0건** |
|
|
76
|
+
| **디자인 감사** | 명암비, 폰트 폴백, CJK 자간, 가로 넘침, 텍스트 잘림, 한 줄 글자 수 — 브라우저에서 실행, **지적 26건, 모두 서면으로 판정** — 이유 없는 승인은 릴리스 게이트가 거부한다 |
|
|
77
|
+
| **테마 내보내기/가져오기** | 두 경로, 모두 왕복 검증. `theme_export.php`는 WP-CLI로 행을 JSON으로 옮기며 id는 그대로, 사본은 바이트 단위로 동일한 페이지를 제공. `theme_zip.py`는 Mosaic **자체**의 ZIP 내보내기/가져오기를 그 마일스톤 프로토콜로 구동한다 — 가져오기는 `--activate`가 없으면 테스트 모드에 놓이는데, 기본값이 라이브 사이트 전환이기 때문이다 — 그리고 **22개 검사**로 사본을 원본과 트리 단위로 대조한다: 모든 테이블 일치, 68,337개 노드 id 유지, override 노드는 재발급, 빠진 한 행은 트리 순회가 가져가면 안 되는 고아 |
|
|
71
78
|
| **실측** | REST 라우트 114개, element class 151개, 조건 주체 59개, 23개 테이블 / 206개 컬럼 |
|
|
72
79
|
|
|
73
80
|
`SKIPPED`, `NO_HOST`, `INCONCLUSIVE`를 합격률에 섞는 일은 결코 없다.
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# mosaic-headless
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/mosaic-headless)
|
|
4
|
+
|
|
3
5
|
Build and modify [Mosaic Pro](https://mosaicbuilder.com) (Nextend) sites by writing
|
|
4
6
|
the data model directly — no visual editor, no DOM.
|
|
5
7
|
|
|
@@ -22,8 +24,11 @@ from memory. Look it up in `data/`.**
|
|
|
22
24
|
|
|
23
25
|
And look it up with `mo.py`, not grep. Grep answers the question you typed; it does
|
|
24
26
|
not answer the question you have. Ask grep about `accordion-content` and it confirms
|
|
25
|
-
the type exists.
|
|
26
|
-
|
|
27
|
+
the type exists. The sweep says BROKE_PAGE: place one and the whole public page
|
|
28
|
+
becomes a 54-byte error string. Both true, both the wrong answer — the note beside
|
|
29
|
+
the row says that string names a missing parent, and that nested under
|
|
30
|
+
`accordion > accordion-item` the type commits, renders, and hands you a
|
|
31
|
+
keyboard-operable disclosure. `mo.py type` shows all three at once.
|
|
27
32
|
|
|
28
33
|
```bash
|
|
29
34
|
python tools/mo.py type accordion-content # one type, joined to every live sweep
|
|
@@ -61,14 +66,16 @@ factories, so Pro types register and render regardless.
|
|
|
61
66
|
| **node types** | 122 / 122 swept one per document, committed → rendered → asserted → deleted: 70 RENDERED, 30 COMMITTED, 15 COMMIT_5xx, 7 BROKE_PAGE |
|
|
62
67
|
| **style properties** | 98 / 98 written to a live page and checked against the compiled CSS: 58 COMPILED, 18 ABSENT, 21 SKIPPED |
|
|
63
68
|
| **node properties** | 181 / 181 re-probed with a value shaped by each property's own validator chain: 35 APPLIED, 42 NO_EFFECT, 55 NO_HOST, 47 SKIPPED |
|
|
64
|
-
| **responsive** |
|
|
69
|
+
| **responsive** | 731 `_t`/`_m` declarations across two sites asserted against the stylesheet the site actually served — all verified |
|
|
65
70
|
| **components** | the component system driven end to end, **8 of 8**: created under a category, document healed, tree filled through the writable instance, the read-only one refused the same write as a negative control, and two instances on a page rendering one definition twice |
|
|
66
71
|
| **style states** | 52 of the 53 states written to a live page and matched against the selector the table promises: **36 compiled exactly**, 12 NO_HOST, 3 SKIPPED, 1 BROKE_PAGE. All seven globally usable states verified |
|
|
67
72
|
| **interactions** | the JS animation path probed with negative controls and the row read back: `propertyMetas` **is** accepted and stored; the property values still do not bind, and the boundary is now exact |
|
|
68
|
-
| **entrance animation** | the page-load sequence sampled at
|
|
69
|
-
| **
|
|
70
|
-
| **
|
|
71
|
-
| **
|
|
73
|
+
| **entrance animation** | the page-load sequence sampled at fifteen timestamps on a monotonic clock and asserted on eight counts — it plays, its animated `@property` counter reaches 100, the veil leaves hit-testing, nothing in the viewport is stranded at opacity 0, a real click reaches the document, under `prefers-reduced-motion` the veil never exists, and something is still moving once everything has settled. Costs one late frame over a page with no animation at all, because it waits for the document's first layout |
|
|
74
|
+
| **perpetual animation** | a corner plate that keeps printing itself and opens to full size when tapped, **28 checks**: periodicity proved by scrubbing a paused timeline, occlusion of text *and* controls at five widths and twenty-five scroll stops with "never readable" as the failing condition, opened by pointer and by Enter, still under reduced motion. Built on Mosaic's own accordion |
|
|
75
|
+
| **accordion** | `accordion-item` and `accordion-content` sit in the sweep table as BROKE_PAGE; nested as their factory requires they commit and render, **7 of 7**. The note now lives beside the row |
|
|
76
|
+
| **browser** | 3,988 computed-style readings on two delivered pages in Chromium at three viewports: 2,929 compared and agreed, 912 not-comparable and labelled, **0 overridden** |
|
|
77
|
+
| **design audit** | contrast, font fallback, CJK tracking, overflow, clipped text, line measure — run in the browser, **26 findings, every one ruled on in writing** — an acknowledgement without a reason is refused by the release gate |
|
|
78
|
+
| **theme export/import** | two paths, both round-tripped. `theme_export.php` moves rows as JSON over WP-CLI, ids intact, and the copy served byte-identical pages. `theme_zip.py` drives Mosaic's **own** ZIP export/import over its milestone protocol — import lands in test mode unless told `--activate`, because the default is to switch the live site — and **22 checks** hold the copy against the source tree for tree: every table equal, 68,337 node ids kept, override nodes re-keyed, the one missing row an orphan no tree-walk should carry |
|
|
72
79
|
| **measured live** | 114 REST routes, 151 element classes, 59 condition subjects, 23 tables / 206 columns |
|
|
73
80
|
|
|
74
81
|
`SKIPPED`, `NO_HOST` and `INCONCLUSIVE` are never folded into a pass rate. A sweep
|
package/README.zh-TW.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# mosaic-headless
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/mosaic-headless)
|
|
4
|
+
|
|
3
5
|
直接寫入資料模型來建置與修改 [Mosaic Pro](https://mosaicbuilder.com)(Nextend)網站——
|
|
4
6
|
不開視覺編輯器,不碰 DOM。
|
|
5
7
|
|
|
@@ -18,8 +20,10 @@ Mosaic 把一個頁面放在 **23 張自訂資料表**裡,不在 `post_content
|
|
|
18
20
|
**絕不憑印象寫節點型別、屬性名稱、列舉值、樣式鍵或 Free/Pro 的判斷。到 `data/` 裡查。**
|
|
19
21
|
|
|
20
22
|
而且要用 `mo.py` 查,不要用 grep。grep 回答你打出來的問題,不回答你真正的問題:
|
|
21
|
-
問它 `accordion-content
|
|
22
|
-
|
|
23
|
+
問它 `accordion-content`,它確認這個型別存在;掃描表則說 BROKE_PAGE——放一個下去,
|
|
24
|
+
整個公開頁面會變成一段 54 bytes 的錯誤字串。兩個都是真的,也都是錯的答案:列旁邊的
|
|
25
|
+
註記說那段字串指名的是「缺少父層」,而照 `accordion > accordion-item` 嵌套後它能寫入、
|
|
26
|
+
能渲染,還免費送你一個鍵盤可操作的展開元件。`mo.py type` 一次把三者都給你。
|
|
23
27
|
|
|
24
28
|
```bash
|
|
25
29
|
python tools/mo.py type accordion-content # 一個型別,接上所有線上掃描結果
|
|
@@ -53,14 +57,16 @@ commit 時 PHP fatal HTTP 500 (122 種型別裡有 15 種,光放在 div
|
|
|
53
57
|
| **節點型別** | 122 / 122,一份文件一種型別:寫入 → 渲染 → 斷言 → 刪除。70 RENDERED、30 COMMITTED、15 COMMIT_5xx、7 BROKE_PAGE |
|
|
54
58
|
| **樣式屬性** | 98 / 98 寫進真實頁面並對照編譯後的 CSS:58 COMPILED、18 ABSENT、21 SKIPPED |
|
|
55
59
|
| **節點屬性** | 181 / 181,用每個屬性自己的 validator chain 推導出的值重測:35 APPLIED、42 NO_EFFECT、55 NO_HOST、47 SKIPPED |
|
|
56
|
-
| **響應式** | 兩個站共
|
|
60
|
+
| **響應式** | 兩個站共 731 條 `_t`/`_m` 宣告,對照網站實際送出的樣式表逐條斷言——全數通過 |
|
|
57
61
|
| **元件系統** | 完整驅動過一遍,**8 / 8**:在分類下建立、文件 heal、透過可寫的 instance 填入內容、唯讀的那個作為負對照組確實拒絕同一個寫入,最後兩個實例在頁面上由同一份定義渲染兩次 |
|
|
58
62
|
| **樣式狀態** | 53 個狀態中的 52 個寫進真實頁面,對照表格承諾的選擇器逐一比對:**36 個完全吻合**、12 個 NO_HOST、3 個 SKIPPED、1 個 BROKE_PAGE。七個可用於任何元素的狀態全數驗證 |
|
|
59
63
|
| **互動動畫** | 帶負對照組並讀回儲存列來探測 JS 動畫路徑:`propertyMetas` **確實**會被接受並儲存;屬性值仍然無法綁定,但界線現在很精確 |
|
|
60
|
-
| **入口動畫** |
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
+
| **入口動畫** | 以單調時鐘在載入後十五個時間點取樣、做八項斷言——它有播、被動畫的 `@property` 計數器跑到 100、遮罩退出點擊判定、視窗內沒有任何內容卡在 opacity 0、真實點擊落在文件上、`prefers-reduced-motion` 下遮罩根本不存在、而一切靜止後仍有東西在動。相較於完全沒有動畫的同一頁只多掉一幀,因為它會等文件第一次排版做完才開始 |
|
|
65
|
+
| **永續動畫** | 右下角一塊不斷自我印刷、點了會放大的版子,**28 項檢查**:暫停時間軸逐格比對證明週期性、在五個寬度、二十五個捲動停點量文字*與*控制項的遮擋、以「永遠讀不到」為失敗條件、用指標和 Enter 都能打開、reduced motion 下靜止。建在 Mosaic 自己的 accordion 上 |
|
|
66
|
+
| **accordion** | `accordion-item` 與 `accordion-content` 在掃描表裡是 BROKE_PAGE;照工廠要求的方式嵌套後能寫入、能渲染,**7 之 7**。註記現在就在那一列旁邊 |
|
|
67
|
+
| **瀏覽器** | 在 Chromium 三個視窗寬度上對兩個交付頁面做 3,988 次計算樣式讀取:2,929 條比對相符、912 條標為無法比對、**0 條被覆蓋** |
|
|
68
|
+
| **設計稽核** | 對比度、字體回退、CJK 字距、水平溢出、文字裁切、每行字數——在瀏覽器裡跑,**26 項發現,每一項都有書面裁定**——沒寫理由的 acknowledge 會被發布閘門拒絕 |
|
|
69
|
+
| **主題匯出/匯入** | 兩條路徑,都來回驗證過。`theme_export.php` 用 WP-CLI 把資料列搬成 JSON、ID 原封不動,副本送出的頁面逐位元組相同。`theme_zip.py` 走 Mosaic **自己**的 milestone 協定驅動 ZIP 匯出匯入——匯入預設進 test mode,要 `--activate` 才上線,因為它的預設是直接把 live 站切過去——並以 **22 項檢查**逐表、逐樹比對副本與來源:每張表相等、68,337 個節點 ID 保留、override 節點重新發 ID,唯一少的一列是走樹本來就不該帶的孤兒 |
|
|
64
70
|
| **線上量測** | 114 條 REST 路由、151 個 element class、59 個條件主體、23 張表 / 206 個欄位 |
|
|
65
71
|
|
|
66
72
|
`SKIPPED`、`NO_HOST`、`INCONCLUSIVE` 永遠不併進通過率。
|
package/SKILL.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "mosaic-headless"
|
|
3
3
|
description: |
|
|
4
|
-
Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface with `mo.py`, which joins every source table to the live sweeps so a lookup leads with the measured verdict rather than the declaration (122 node types, 181 properties, 98 style properties with 20 structured value shapes pinned down, 53 style states, 151 element classes, 74 dynamic variables, 12 interaction triggers, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, the design-token and element-class layers verified against compiled CSS, the @VAR() dynamic language verified against rendered output, nine designed pages built through the tables themselves, and the delivered
|
|
4
|
+
Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface with `mo.py`, which joins every source table to the live sweeps so a lookup leads with the measured verdict rather than the declaration (122 node types, 181 properties, 98 style properties with 20 structured value shapes pinned down, 53 style states, 151 element classes, 74 dynamic variables, 12 interaction triggers, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, the design-token and element-class layers verified against compiled CSS, the @VAR() dynamic language verified against rendered output, nine designed pages built through the tables themselves, and the delivered pages re-read in Chromium at three viewports so a rule that is present, correct and still wrong cannot pass. Drives Mosaic's own theme export/import from outside the editor and holds the copy against the source tree for tree.
|
|
5
5
|
license: "MIT"
|
|
6
6
|
author: "moksa (https://moksaweb.com)"
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.16.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Headless Mosaic
|
|
@@ -23,9 +23,14 @@ from memory. Look it up in `data/`.**
|
|
|
23
23
|
|
|
24
24
|
And look it up with `mo.py`, not with grep. Grep answers the question you typed;
|
|
25
25
|
it does not answer the question you have. Ask grep about `accordion-content` and it
|
|
26
|
-
confirms the type exists.
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
confirms the type exists. The sweep table says BROKE_PAGE: place one and the entire
|
|
27
|
+
public page becomes a 54-byte error string. Both are true, and both are the wrong
|
|
28
|
+
answer - the note beside the row says the string is `AccordionItemElementMResource
|
|
29
|
+
instance required`, that this is a type committed without the parent its factory
|
|
30
|
+
needs, and that nested under `accordion > accordion-item` it commits, renders and
|
|
31
|
+
gives you a keyboard-operable disclosure for free. `mo.py type` shows all three in
|
|
32
|
+
one answer. Grep shows one, the CSV shows two, and the skill was itself wrong about
|
|
33
|
+
this type for a week.
|
|
29
34
|
|
|
30
35
|
```bash
|
|
31
36
|
python tools/mo.py stats # the surface, and what is unsafe
|
|
@@ -123,6 +128,12 @@ NODE SWEEP 122 of 122 node types, ONE PER DOCUMENT, committed then rendered th
|
|
|
123
128
|
COMMIT_5xx 15 PHP fatal on commit
|
|
124
129
|
BROKE_PAGE 7 committed, then the whole page died
|
|
125
130
|
Free 74: 43/22/6/3. Pro 48: 27/8/9/4. data/node-verification.csv
|
|
131
|
+
Three of the non-rendering outcomes are artefacts of the sweep's own
|
|
132
|
+
method - one type per document, under a plain div - and not of the
|
|
133
|
+
type: `component-instance` (needs `component-instance/<id>`),
|
|
134
|
+
`accordion-item` and `accordion-content` (need their parent). Each is
|
|
135
|
+
proven to work as built, and `data/node-type-notes.csv` says so
|
|
136
|
+
beside the row. The sweep verdict stands; the note is what to read.
|
|
126
137
|
|
|
127
138
|
STYLE the states[state][breakpoint][property] shape confirmed by writing it
|
|
128
139
|
and reading back the compiled CSS; 20 of 22 structured value shapes
|
|
@@ -170,29 +181,97 @@ INTERACTION the JS animation path, probed with negative controls and the row re
|
|
|
170
181
|
written straight into the table with caches flushed.
|
|
171
182
|
data/interaction-verification.csv
|
|
172
183
|
|
|
173
|
-
INTRO the page-load sequence - an ukiyo-e sheet printing itself
|
|
174
|
-
|
|
175
|
-
true against the kento marks - sampled at
|
|
176
|
-
|
|
177
|
-
and
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
INTRO the page-load sequence - an ukiyo-e sheet printing itself eleven
|
|
185
|
+
carved blocks at a time, each impression landing out of register and
|
|
186
|
+
easing true against the kento marks - sampled at fifteen timestamps
|
|
187
|
+
on a monotonic clock (the first version scheduled against the previous
|
|
188
|
+
sample and drifted fourteen seconds) and asserted on eight counts: it
|
|
189
|
+
plays, the animated `@property` counter reaches 100, the veil leaves
|
|
190
|
+
hit-testing, no in-viewport content is stranded at opacity 0 (elements
|
|
191
|
+
waiting on a scroll timeline are exempt, and a `position:fixed` one
|
|
192
|
+
was the case that showed the exemption had to be by timeline and not
|
|
193
|
+
by position), a real click reaches the document, under
|
|
194
|
+
`prefers-reduced-motion` the veil never exists and nothing is
|
|
195
|
+
invisible at 120ms, plus AMBIENT, which counts how many elements still
|
|
196
|
+
move with no input once everything has settled. Every other motion
|
|
197
|
+
check here fires on an EVENT; a page can pass all of them and be
|
|
198
|
+
completely static the moment you stop scrolling. Also measured, with
|
|
199
|
+
CPU-time counters rather than frame timing, which proved unusable:
|
|
200
|
+
the sequence costs one late frame over a page with no animation in it,
|
|
201
|
+
because it no longer starts until the document's own first layout is
|
|
202
|
+
done. All pass. data/intro-verification.csv
|
|
203
|
+
|
|
204
|
+
LOOP 28 assertions about the one animation nothing else here can see: the
|
|
205
|
+
ukiyo-e plate that keeps printing itself in the corner of the page,
|
|
206
|
+
forever, with no input, and that opens to full size when tapped. Its
|
|
207
|
+
eleven moving parts are SVG groups inside a raw-HTML `code` node, so no
|
|
208
|
+
checker that walks the spec tree knows they exist. RUNS reads them on the clock across a full period; each part is
|
|
209
|
+
then proved periodic by PAUSING its animation and scrubbing
|
|
210
|
+
`currentTime` to T and T + one period (14s), past the stagger, which
|
|
211
|
+
is the only way to compare a compositor-driven transform exactly.
|
|
212
|
+
CLEAR is the one that found a real defect: a fixed decoration is
|
|
213
|
+
opaque, and on a full-bleed page no rectangle anywhere along the right
|
|
214
|
+
edge misses text at every scroll offset - so the test is not "never
|
|
215
|
+
overlaps" but "never makes anything unreadable", per element, at five
|
|
216
|
+
widths and twenty-five scroll stops.
|
|
217
|
+
It caught three footer links buried at the position a reader cannot
|
|
218
|
+
scroll past. Once the plate became a control, REACHABLE holds links and
|
|
219
|
+
buttons to the same rule - swallowing a click is worse than covering a
|
|
220
|
+
word - and OPENS/CLOSES/KEYBOARD check the enlarged view on the
|
|
221
|
+
delivered page, including that Enter works on it. Five widths from 390
|
|
222
|
+
up. data/loop-verification.csv
|
|
223
|
+
|
|
224
|
+
CONVERSION an Elementor page turned into a Mosaic spec and built, then checked
|
|
225
|
+
against its own source: every text string, every image, every link
|
|
226
|
+
target, every h1-h6 level. 5 of 5 on a page with 16 images and 21
|
|
227
|
+
links. Scope was decided by counting a real site rather than by
|
|
228
|
+
taste - across 19 Elementor pages and 3,292 element instances,
|
|
229
|
+
container/heading/text-editor/button/html/icon-list/divider/image
|
|
230
|
+
are 99.6% of everything present, and the long tail (loop-grid, form,
|
|
231
|
+
posts, countdown, third-party addons) is dynamic: a query and a
|
|
232
|
+
server-side action have no node to become. Those are reported per
|
|
233
|
+
element with a reason, never dropped, and `--strict` refuses to
|
|
234
|
+
write a spec while any remain. The verifier earned its place twice
|
|
235
|
+
over: it caught the converter writing `url` onto `text` and `image`
|
|
236
|
+
nodes, which only `button`, `menu-link`, `wysiwyg-link` and
|
|
237
|
+
`dropdown-toggle` declare - 19 of 21 link targets accepted, stored
|
|
238
|
+
and silently emitting no anchor, this platform's signature failure -
|
|
239
|
+
and it caught two bugs in ITSELF that had blamed the converter.
|
|
240
|
+
Then the converted page went through the skill's own suites like any
|
|
241
|
+
other: 96 responsive declarations verified, 5,595 computed values
|
|
242
|
+
with 0 overridden, and a design audit of 49 CONTRAST findings -
|
|
243
|
+
every one traced back to a colour the Elementor source declared,
|
|
244
|
+
none introduced by the conversion. That split is a check of its own,
|
|
245
|
+
FIDELITY, and the inherited defects are recorded beside it as still
|
|
246
|
+
real: a 3.19:1 label is 3.19:1 whoever wrote it. 8 of 8.
|
|
247
|
+
data/conversion-verification.csv
|
|
248
|
+
|
|
249
|
+
ACCORDION 7 checks that resolve a wrong entry in this skill's own tables.
|
|
250
|
+
`accordion-item` and `accordion-content` are recorded BROKE_PAGE, which
|
|
251
|
+
is true and misleading in exactly the way `component-instance` was:
|
|
252
|
+
the failure is `AccordionItemElementMResource instance required`, i.e.
|
|
253
|
+
committed without the parent the factory needs. Nested properly they
|
|
254
|
+
commit, render, and emit `<dl><div class=AccordionItem><dt tabindex=0
|
|
255
|
+
aria-expanded><dd>` - which is why the worked example's enlargeable
|
|
256
|
+
plate is built on it instead of on a checkbox, and gets keyboard
|
|
257
|
+
operation and a screen-reader state for nothing. The negative control
|
|
258
|
+
asks the placement guard rather than committing, because the first
|
|
259
|
+
version of the probe destroyed the positive result it had just
|
|
260
|
+
produced. data/accordion-verification.csv
|
|
261
|
+
|
|
262
|
+
BROWSER 3,988 computed-style readings on the delivered pages in Chromium, at
|
|
188
263
|
three viewports: every declared property vs `getComputedStyle` on the
|
|
189
264
|
node it targets. 2,929 compared and agreed, 912 not-comparable and
|
|
190
265
|
labelled as such, 0 overridden. Plus a design audit that only a browser
|
|
191
266
|
can run - font fallback, tracking against script, text contrast,
|
|
192
|
-
horizontal overflow, clipped text, line measure -
|
|
267
|
+
horizontal overflow, clipped text, line measure - 26 findings, every
|
|
268
|
+
one ruled on in writing. Two pages: the homepage, and a WooCommerce
|
|
269
|
+
My Account page whose UI arrives through one `code` node running a
|
|
270
|
+
shortcode - which is also the measurement that shows the property
|
|
271
|
+
sweep's NO_EFFECT on `processShortcodes` was the sweep, not the flag.
|
|
193
272
|
data/browser-verification.csv, data/design-audit.csv
|
|
194
273
|
|
|
195
|
-
RWD
|
|
274
|
+
RWD 731 responsive declarations across two sites asserted against the
|
|
196
275
|
stylesheet the site actually served - each `_t`/`_m` property matched
|
|
197
276
|
to its element's generated class inside that breakpoint's own media
|
|
198
277
|
query. All verified; the checker is itself checked against a poisoned
|
|
@@ -332,16 +411,20 @@ so the pattern is in the data, not just in this paragraph.
|
|
|
332
411
|
| `data/property-verification.csv` | 170 | **probed live** — per-property effect on markup vs CSS, with unprovable enums marked INCONCLUSIVE |
|
|
333
412
|
| `data/node-property-verification.csv` | 181 | **swept live** — each property probed with a value shaped by its own validator chain, on a type that declares it |
|
|
334
413
|
| `data/style-verification.csv` | 98 | **swept live** — every style property written to a page and checked against the compiled CSS, with its group beside the result |
|
|
335
|
-
| `data/rwd-verification.csv` |
|
|
336
|
-
| `data/browser-verification.csv` |
|
|
337
|
-
| `data/design-audit-acknowledged.csv` |
|
|
338
|
-
| `data/design-audit.csv` |
|
|
414
|
+
| `data/rwd-verification.csv` | 731 | **checked live** - every `_t`/`_m` declaration vs the served stylesheet, with status per row |
|
|
415
|
+
| `data/browser-verification.csv` | 3988 | **computed in Chromium** - declared vs `getComputedStyle` at three viewports, `not-comparable` labelled per row |
|
|
416
|
+
| `data/design-audit-acknowledged.csv` | 3 | reviewed findings that will not be fixed, each with a written reason. An acknowledgement without a reason is a suppression wearing a better name, and the release gate refuses one |
|
|
417
|
+
| `data/design-audit.csv` | 26 | **computed in Chromium** - contrast, font fallback, CJK tracking, overflow, measure. Empty means it ran and found nothing |
|
|
339
418
|
| `data/data-class-hierarchy.csv` | 121 | source - every data class and its parent, so a type's inherited properties can be resolved |
|
|
340
419
|
| `data/style-state-verification.csv` | 52 | **swept live** - each state written on a host of its own type and matched against its promised selector |
|
|
341
420
|
| `data/component-verification.csv` | 8 | **driven live** - the component lifecycle, each step asserted against the row or the delivered HTML |
|
|
342
|
-
| `data/
|
|
421
|
+
| `data/loop-verification.csv` | 28 | **measured live** - a perpetual animation: periodicity by scrubbing a paused timeline, per-element occlusion of both text and controls at five widths, and the enlarged view opened by pointer and by keyboard |
|
|
422
|
+
| `data/accordion-verification.csv` | 7 | **driven live** - the accordion family nested the way its factory requires, against the guard that refuses it unparented. Resolves two BROKE_PAGE rows |
|
|
423
|
+
| `data/conversion-verification.csv` | 8 | **converted then checked live** - an Elementor page rebuilt as Mosaic and held against its source (text, images, links, heading levels), then put through rwd, browser and the design audit with every finding classified inherited-or-introduced |
|
|
424
|
+
| `data/theme-zip-verification.csv` | 22 | **round-tripped live** - Mosaic's own ZIP export imported in test mode and compared to its source, table by table and tree by tree |
|
|
425
|
+
| `data/node-type-notes.csv` | 8 | where a sweep outcome is true but misleading on its own, why. Surfaced by `mo.py type` |
|
|
343
426
|
| `data/interaction-verification.csv` | 7 | **probed live** - interaction animation shapes, with negative controls and the stored row beside the payload |
|
|
344
|
-
| `data/intro-verification.csv` |
|
|
427
|
+
| `data/intro-verification.csv` | 8 + 15 | **sampled live** - the entrance sequence over fifteen timestamps on a monotonic clock, plus the eight assertions about it |
|
|
345
428
|
| `data/element-classes.csv` | 151 | **live** — the built-in class metas; their IDs are what an `elementClass` record must use |
|
|
346
429
|
| `data/dynamic-variables.csv` | 74 | source — every `@VAR('ns/name')` expression, by namespace |
|
|
347
430
|
| `data/evaluator-functions.csv` | 19 | source — the `@` functions with their arity |
|
|
@@ -400,6 +483,33 @@ and rewrite nothing but the theme, which means no id remapping and nothing left
|
|
|
400
483
|
dangling. Round-tripped and verified: a full theme exported, re-imported as a copy,
|
|
401
484
|
and the copy served byte-identical pages.
|
|
402
485
|
|
|
486
|
+
Mosaic also has its own: `POST /theme/<id>/export` and `POST /theme/import/upload`
|
|
487
|
+
(or `/import/download` from a URL), plus `/duplicate` on themes, masters, templates,
|
|
488
|
+
components and style guides. The native export is a ZIP with the theme's
|
|
489
|
+
attachments inside, produced by a chunked, lock-protected milestone flow — you POST
|
|
490
|
+
repeatedly with `milestoneID` to step it through collect → compress → download — and
|
|
491
|
+
it is gated on admin capability only, not on a licence. It moves a whole theme, never
|
|
492
|
+
a single page. `tools/theme_zip.py` drives both directions from outside the editor.
|
|
493
|
+
Two things about the import that the route list does not tell you: with no
|
|
494
|
+
`themeActivateMode` it defaults to `live` and switches every visitor to the imported
|
|
495
|
+
theme (the tool sends `test`, Mosaic's admin-only preview, unless `--activate`); and a
|
|
496
|
+
milestone must be called until it answers `isCompleted:true` - stop one call early,
|
|
497
|
+
as the first version of the tool did after its last upload chunk, and that
|
|
498
|
+
milestone's batch bookkeeping is left in the lock for the NEXT milestone to read as
|
|
499
|
+
its own, which is how `extract` came to skip creating its directories and fail on
|
|
500
|
+
the first nested file with "Could not copy file".
|
|
501
|
+
|
|
502
|
+
Round-tripped and measured (`data/theme-zip-verification.csv`, 22 checks): export,
|
|
503
|
+
import in test mode, compare. Every scoped table equal; 68,337 of 68,337 nodes
|
|
504
|
+
outside overrides keep their ids; the 1,024 override nodes are re-keyed, with their
|
|
505
|
+
`originalID` re-pointed at the re-keyed component internals; the live theme
|
|
506
|
+
untouched. The node table came back one row short, and that row is the difference
|
|
507
|
+
between the two tools in one line: an orphan `div` with no parent, left by an
|
|
508
|
+
interrupted build, which a tree-walking import correctly does not carry and a
|
|
509
|
+
row-copying one (`theme_import.php`) would. `theme_export.php` exists because a
|
|
510
|
+
2 MB JSON of rows is easier to diff, version and reason about than a ZIP, and
|
|
511
|
+
because it needs nothing but WP-CLI; the ZIP is what the editor's buttons speak.
|
|
512
|
+
|
|
403
513
|
`copy_styles.py` pushes one node's style onto others by attrID or prefix, optionally
|
|
404
514
|
only certain `state.breakpoint` slices, and shows the diff before writing.
|
|
405
515
|
|
|
@@ -429,6 +539,29 @@ post — `build_all.py` resets first for that reason.
|
|
|
429
539
|
number is not stable. The sibling `M_EL_<Type>` class is.
|
|
430
540
|
- **`body{opacity:0}`** — the theme reveals itself from JavaScript. Screenshot tooling
|
|
431
541
|
must let scripts run or it captures a blank page.
|
|
542
|
+
- **Two themes can carry the same name, and only the ACTIVE one is bound to
|
|
543
|
+
anything.** Every write to `theme/<themeID>/...` succeeds against an inactive
|
|
544
|
+
theme - master, nodes, components, tokens, all of it - and then
|
|
545
|
+
`createManualTemplate` answers `Master not found`, because it resolves the theme
|
|
546
|
+
from the request, not from your URL. Read the active theme's id off
|
|
547
|
+
`wp theme list --status=active` (`mosaic-1-1-<themeID>`) before building.
|
|
548
|
+
- **Page caches stack.** The demo host ran Varnish AND Breeze; purging Varnish
|
|
549
|
+
changed nothing because Breeze still had the old document. `build_site.py`
|
|
550
|
+
fetches the plain URL and a cache-busted one at the same moment and reports
|
|
551
|
+
STALE CACHE when they differ by more than a percent - believe it, then find
|
|
552
|
+
every layer. `wp breeze purge --cache=all` was the one that mattered.
|
|
553
|
+
- **A `code` node is a wrapper, not a splice.** `insertLocation:"inPlace"` puts your
|
|
554
|
+
markup INSIDE `<div class="M_EL_Code">`, one level down - so a sibling combinator
|
|
555
|
+
from injected HTML to a Mosaic node never matches, and a control you inject has
|
|
556
|
+
to be styled through its own ancestors or through `:has()`. The native accordion
|
|
557
|
+
avoided the question entirely.
|
|
558
|
+
- **`section` arrives with 80px of top and bottom padding.** Measured on a node
|
|
559
|
+
whose spec set neither; between a masthead and the block below it that is a
|
|
560
|
+
160px hole. Set `paddingTop`/`paddingBottom` explicitly when a section's rhythm
|
|
561
|
+
is meant to come from its contents.
|
|
562
|
+
- **The front page 301s.** When a post is `page_on_front`, its own permalink
|
|
563
|
+
(`/moksa/`) redirects to `/`; a fetch that does not follow redirects reads 0
|
|
564
|
+
bytes and looks like an outage.
|
|
432
565
|
|
|
433
566
|
## Rendered-tag facts you would otherwise guess wrong
|
|
434
567
|
|
|
@@ -438,6 +571,18 @@ post — `build_all.py` resets first for that reason.
|
|
|
438
571
|
`<mosaic-tabs>`, `<mosaic-accordion>`, `<mosaic-vimeo>`, `<mosaic-youtube>` and
|
|
439
572
|
friends. A selector written against `div`/`nav` misses all of them.
|
|
440
573
|
- **`icon` renders inline `<svg>`.**
|
|
574
|
+
- **Only four types take a `url`**: `button`, `menu-link`, `wysiwyg-link`,
|
|
575
|
+
`dropdown-toggle`. Put one on a `text` or an `image` and it is accepted, stored,
|
|
576
|
+
and emits no anchor whatsoever. To make anything else clickable, WRAP it in a
|
|
577
|
+
`menu-link` - that type takes `children: rule=any` and becomes a real `<a href>`
|
|
578
|
+
as soon as it has a `url` (`target="_blank"` included; both probed).
|
|
579
|
+
- **An image's attachment-protocol path is relative to the UPLOADS directory.**
|
|
580
|
+
`wp-attachment://image/<id>/<size>/2026/09/pic.png` resolves, and carries the
|
|
581
|
+
attachment's `width`/`height` onto the tag. Give it the full
|
|
582
|
+
`wp-content/uploads/2026/09/pic.png` - the obvious guess - and Mosaic prefixes
|
|
583
|
+
the uploads base a second time, serving a broken `src` with no error and no
|
|
584
|
+
dimensions. A plain `https://` URL also works, and is the right fallback for an
|
|
585
|
+
image that is not an attachment on this site.
|
|
441
586
|
|
|
442
587
|
## Tools
|
|
443
588
|
|
|
@@ -449,6 +594,10 @@ post — `build_all.py` resets first for that reason.
|
|
|
449
594
|
| `verify_rwd.py` | does every `_t`/`_m` declaration reach the served stylesheet? |
|
|
450
595
|
| `verify_browser.py` | does the **browser** compute what the stylesheet promised - and does the result pass a design audit? |
|
|
451
596
|
| `verify_intro.py` | does the page-load animation play, and - the part that matters - does it END and hand the page back? |
|
|
597
|
+
| `verify_loop.py` | a decoration that runs forever: does it loop (paused-timeline scrub), does it bury text or controls anywhere a reader can rest, does it open by pointer and by keyboard, is it still under reduced motion? |
|
|
598
|
+
| `probe_accordion.py` | the accordion family nested as its factory requires, plus the guard's refusal of the bare node - the probe that corrected two rows of this skill's own tables |
|
|
599
|
+
| `from_elementor.py` | an Elementor `_elementor_data` tree -> a Mosaic page spec, with every element it cannot convert reported by name and reason (`--strict` to refuse a lossy spec) |
|
|
600
|
+
| `verify_conversion.py` | did the conversion carry the page? every source string, image, link and heading level looked for on the delivered Mosaic page |
|
|
452
601
|
| `sweep_node_types.py` | commit every node type one per document and assert the delivered HTML |
|
|
453
602
|
| `sweep_style_properties.py` | write every style property and check the compiled CSS |
|
|
454
603
|
| `sweep_node_properties.py` | probe every node property with a value from its own validator chain |
|
|
@@ -456,6 +605,9 @@ post — `build_all.py` resets first for that reason.
|
|
|
456
605
|
| `sweep_components.py` | build a component, instance it twice, and prove one definition served both |
|
|
457
606
|
| `sweep_interactions.py` | which interaction animation shapes survive to the frontend payload |
|
|
458
607
|
| `theme_export.php` / `theme_import.php` | move a whole theme across installs, ids intact |
|
|
608
|
+
| `theme_zip.py` | drive Mosaic's OWN export/import - the ZIP the editor makes, attachments included, over the milestone protocol; import lands in test mode unless told `--activate` |
|
|
609
|
+
| `theme_zip_compare.php` | hold an imported copy against its source, tree for tree - every scoped table, the (parentType, type) shape, which ids survive, and orphans named rather than counted |
|
|
610
|
+
| `theme_delete.php` | remove a theme completely through the plugin's own routine; refuses the live one |
|
|
459
611
|
| `copy_styles.py` | push one node's style onto others, by attrID or prefix |
|
|
460
612
|
| `bootstrap_probe_theme.php` | a licence-free scratch theme |
|
|
461
613
|
| `mint_session.php` | a matching cookie + `wp_rest` nonce from WP-CLI |
|
|
@@ -487,8 +639,21 @@ python tools/sweep_style_properties.py --config sweep.json --page moksa --csv da
|
|
|
487
639
|
python tools/sweep_node_properties.py --config sweep.json --page moksa --csv data/node-property-verification.csv
|
|
488
640
|
python tools/sweep_style_states.py --config sweep.json --post 20 --slug probe-lab --csv data/style-state-verification.csv
|
|
489
641
|
python tools/sweep_interactions.py --config sweep.json --post 20 --slug probe-lab --csv data/interaction-verification.csv
|
|
642
|
+
python tools/verify_loop.py --url https://site/ --window mk-loop --toggle mk-plate-title --panel mk-plate-item \
|
|
643
|
+
--parts ukw-sky,ukw-sun,ukw-fuji,ukw-mist,ukw-sea,ukw-crest,ukw-boat,ukw-wave,ukw-claw,ukw-swell,ukw-key,mk-loop-seal \
|
|
644
|
+
--period 14000 --csv data/loop-verification.csv
|
|
645
|
+
python tools/probe_accordion.py --config sweep.json --post 20 --slug probe-lab --csv data/accordion-verification.csv
|
|
646
|
+
python tools/from_elementor.py --data _elementor_data.json --out spec.json --report conv.csv --uploads-base https://site/wp-content/uploads --slug converted --post 208
|
|
647
|
+
python tools/verify_rwd.py --config c.json --site spec.json --csv rwd.csv
|
|
648
|
+
python tools/verify_browser.py --config c.json --site spec.json --csv browser.csv --audit audit.csv
|
|
649
|
+
python tools/verify_conversion.py --data _elementor_data.json --url https://site/converted/ --report conv.csv --prefix p2360 --rwd rwd.csv --browser browser.csv --audit audit.csv --csv data/conversion-verification.csv
|
|
490
650
|
wp eval-file tools/theme_export.php active > theme.json
|
|
491
651
|
wp eval-file tools/theme_import.php theme.json "Copy" rebind activate
|
|
652
|
+
python tools/theme_zip.py export --config c.json --out theme.zip
|
|
653
|
+
python tools/theme_zip.py import --config c.json --zip theme.zip # test mode
|
|
654
|
+
python tools/theme_zip.py import --config c.json --zip theme.zip --activate # goes live
|
|
655
|
+
wp eval-file tools/theme_zip_compare.php <source> <copy> theme-zip-verification.csv
|
|
656
|
+
wp eval-file tools/theme_delete.php <copy>
|
|
492
657
|
python tools/probe.py --config lab.json --cases cases.json # ad-hoc measurement
|
|
493
658
|
python tools/check_placement_predicts.py
|
|
494
659
|
```
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "moksa (https://moksaweb.com)",
|
|
23
|
-
"version": "1.
|
|
23
|
+
"version": "1.16.0"
|
|
24
24
|
},
|
|
25
25
|
"loaderBehaviour": "Upload via Settings -> Skills -> Upload. Claude.ai parses SKILL.md frontmatter and surfaces the skill in your library. The extraction tool (extract-block-schema.php) needs a live WP-CLI connection and won't run in the sandbox; use it from a local terminal against your own site instead.",
|
|
26
26
|
"uploadSteps": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "moksa (https://moksaweb.com)",
|
|
23
|
-
"version": "1.
|
|
23
|
+
"version": "1.16.0"
|
|
24
24
|
},
|
|
25
25
|
"loaderBehaviour": "Auto-loads on session start when SKILL.md frontmatter parses successfully.",
|
|
26
26
|
"verified": true,
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "moksa (https://moksaweb.com)",
|
|
23
|
-
"version": "1.
|
|
23
|
+
"version": "1.16.0"
|
|
24
24
|
},
|
|
25
25
|
"loaderBehaviour": "Confirmed (2026-07-11): Codex CLI natively supports the SKILL.md spec. Place SKILL.md under .codex/skills/<name>/ (project) or ~/.codex/skills/<name>/ (personal) and Codex loads the name+description at session start, then the full body on demand. A parallel, broader convention .agents/skills/ (searched from cwd up to repo root, then ~/.agents/skills/) also exists across multiple tools - if your Codex CLI version prioritizes that path instead, mirror the same SKILL.md there.",
|
|
26
26
|
"verified": true,
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "moksa (https://moksaweb.com)",
|
|
23
|
-
"version": "1.
|
|
23
|
+
"version": "1.16.0"
|
|
24
24
|
},
|
|
25
25
|
"loaderBehaviour": "CHANGED as of 2026-07-11: GitHub Copilot added a proper '.github/skills/' Agent Skills directory (December 2025), alongside the older single-file .github/copilot-instructions.md convention. This config targets the new skills-directory form. If your Copilot version predates this (pre Dec 2025), use the instructions-append fallback instead (see fallback below).",
|
|
26
26
|
"fallback": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "moksa (https://moksaweb.com)",
|
|
23
|
-
"version": "1.
|
|
23
|
+
"version": "1.16.0"
|
|
24
24
|
},
|
|
25
25
|
"loaderBehaviour": "CHANGED as of 2026-07-11: Gemini CLI now natively supports the same SKILL.md standard as Claude Code and Codex CLI - the same directory-based skill works unmodified. Gemini CLI discovers skills in this precedence order: built-in, extension skills, ~/.gemini/skills/ (personal), .gemini/skills/ (project, shared via version control). At session start Gemini injects each discovered skill's name+description into the system prompt and calls activate_skill when a task matches.",
|
|
26
26
|
"verified": true,
|