mosaic-headless 1.23.1 → 1.24.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/SKILL.md +3 -3
- 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/data/slider-verification.csv +30 -19
- package/package.json +1 -1
- package/references/slider.md +39 -3
- package/scripts/check-release.mjs +1 -1
- package/sites/_moksa.py +5 -1
- package/sites/moksa.json +4829 -99
- package/tools/build_page.py +20 -2
- package/tools/verify_slider.py +63 -9
package/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: |
|
|
|
4
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 (126 node types, 191 properties, 98 style properties with 20 structured value shapes pinned down, 53 style states, 156 variants, 74 dynamic variables, 15 interaction triggers, 115 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 and its plugin data upgrade from outside the editor and holds the copy against the source tree for tree. Measured on Mosaic Pro 1.0.9: the modal (`<dialog>`), OpenStreetMap, the exit-intent and scroll-depth triggers, run rules and the memory actions all built on a live page and read back, and the 1.0.7 -> 1.0.8 -> 1.0.9 migrations driven from outside wp-admin.
|
|
5
5
|
license: "MIT"
|
|
6
6
|
author: "moksa (https://moksaweb.com)"
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.24.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Headless Mosaic
|
|
@@ -529,7 +529,7 @@ so the pattern is in the data, not just in this paragraph.
|
|
|
529
529
|
| `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 |
|
|
530
530
|
| `data/conversion-batch.csv` | 19 | **converted, built and checked live, one page after another** - every Elementor page of a production site through the converter, with per-page element and content counts |
|
|
531
531
|
| `data/token-benchmark.csv` | 6 | **measured with tiktoken** - the same six lookups priced three ways: reading the plugin source, loading every table, querying `mo.py`. 71-99.5% fewer tokens than the source and 99.6%+ fewer than the tables, which total 259,539 - never load them, query them |
|
|
532
|
-
| `data/slider-verification.csv` |
|
|
532
|
+
| `data/slider-verification.csv` | 30 | **driven live** - two sliders, one autoplaying and one a carousel: advance, arrows, bullets, keyboard, reduced motion |
|
|
533
533
|
| `data/navigation-verification.csv` | 46 | **fetched and opened live** - every menu item is a real `<a href>`, every page of the nineteen answers 200, and no page scrolls sideways at 390 / 768 / 1280 |
|
|
534
534
|
| `data/page-modal-verification.csv` | 19 | **read live** - one modal per page, and what each one's trigger, run rule, memory scope and dismissal policy actually came out as |
|
|
535
535
|
| `data/dialog-verification.csv` | 19 | **driven live** - the 1.0.9 modal, its triggers, its run rules and the memory actions, each exercised in a real browser |
|
|
@@ -805,7 +805,7 @@ post — `build_all.py` resets first for that reason.
|
|
|
805
805
|
| `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` |
|
|
806
806
|
| `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 |
|
|
807
807
|
| `theme_delete.php` | remove a theme completely through the plugin's own routine; refuses the live one |
|
|
808
|
-
| `verify_slider.py` | the slider in a real browser: does it advance, do the arrows and bullets drive it, does the keyboard, does it stop when motion is not wanted |
|
|
808
|
+
| `verify_slider.py` | the slider in a real browser: does it advance, do the arrows and bullets drive it, does the keyboard, does it stop when motion is not wanted - `--label`/`--append` put several sliders in one table, which is where a carousel and a plain slider can be held against each other |
|
|
809
809
|
| `verify_navigation.py` | a multi-page site: is every menu item a real `<a href>`, does every page answer 200 (a template that was never bound answers 406 with an empty body, which only a logged-out visitor sees), and with `--viewports` does any page scroll SIDEWAYS - the one question no per-page checker asks |
|
|
810
810
|
| `verify_dialog.py` | the 1.0.9 modal in a real browser: does it open, close, answer Esc, remember, cap - and does an OpenStreetMap carry the coordinates it was given |
|
|
811
811
|
| `verify_dialog_lab.py` | the question after "does the modal work": can three nodes be made into a bottom sheet, a side drawer, a corner notice, a full takeover and a gate with no way out - and does each one still fit at phone width, which the page's own width check cannot see |
|
|
@@ -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.24.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.24.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.24.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.24.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.24.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,
|
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
slider,check,result,detail
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
2
|
+
"hero, 4 slides, plain",HOST,PASS,"<mosaic-slider> animation=slide carousel=None, 4 slides"
|
|
3
|
+
"hero, 4 slides, plain",TRACK,PASS,<mosaic-slider-slides> aria-live=off
|
|
4
|
+
"hero, 4 slides, plain",HAS_CURRENT,PASS,slide 0 is current at rest
|
|
5
|
+
"hero, 4 slides, plain",BULLET_TEMPLATE,PASS,"4 bullets for 4 slides, all with id='sl-main-nav-dot' - one authored bullet is repeated per slide, duplicate ids included"
|
|
6
|
+
"hero, 4 slides, plain",BULLET_ARIA,PASS,"role=button tabindex=0 labels=一、輪播不是相簿, 二、四種動畫, 三、箭頭會自己消失, 四、不想動就不動 - taken from each slide's own title"
|
|
7
|
+
"hero, 4 slides, plain",ADVANCES,PASS,reached 4 of 4 slides unaided
|
|
8
|
+
"hero, 4 slides, plain",AUTOPLAY_DECLARED,PASS,data-autoplay=true delay=3600
|
|
9
|
+
"hero, 4 slides, plain",BULLET_GOES,PASS,bullet 0 -> slide 0
|
|
10
|
+
"hero, 4 slides, plain",ARROW_ENDS,PASS,"on slide 0 prev hides itself (hidden=True), next does not (hidden=False)"
|
|
11
|
+
"hero, 4 slides, plain",TRACK_LAYOUT,PASS,"grid ""slide"", every slide one track wide ([1200] vs 1200)"
|
|
12
|
+
"hero, 4 slides, plain",ARROW_ARIA,PASS,role=button tabindex=0 label='下一張投影片'
|
|
13
|
+
"hero, 4 slides, plain",NEXT,PASS,slide 0 -> 1
|
|
14
|
+
"hero, 4 slides, plain",PREV,PASS,slide 1 -> 0
|
|
15
|
+
"hero, 4 slides, plain",KEYBOARD,PASS,"focus bullet 3 taken, Enter -> slide 3"
|
|
16
|
+
"hero, 4 slides, plain",REDUCED,PASS,under prefers-reduced-motion it holds still (slide 0 -> 0)
|
|
17
|
+
"carousel, 6 slides, wraps",HOST,PASS,"<mosaic-slider> animation=slide carousel=true, 6 slides"
|
|
18
|
+
"carousel, 6 slides, wraps",TRACK,PASS,<mosaic-slider-slides> aria-live=off
|
|
19
|
+
"carousel, 6 slides, wraps",HAS_CURRENT,PASS,slide 0 is current at rest
|
|
20
|
+
"carousel, 6 slides, wraps",BULLET_TEMPLATE,PASS,"6 bullets for 6 slides, all with id='sl-carousel-nav-dot' - one authored bullet is repeated per slide, duplicate ids included"
|
|
21
|
+
"carousel, 6 slides, wraps",BULLET_ARIA,PASS,"role=button tabindex=0 labels=WEB, AI, ERP, SEO, SHOP, AUTOMATION - taken from each slide's own title"
|
|
22
|
+
"carousel, 6 slides, wraps",ADVANCES,PASS,reached 6 of 6 slides unaided
|
|
23
|
+
"carousel, 6 slides, wraps",AUTOPLAY_DECLARED,PASS,data-autoplay=true delay=2400
|
|
24
|
+
"carousel, 6 slides, wraps",BULLET_GOES,PASS,bullet 0 -> slide 0
|
|
25
|
+
"carousel, 6 slides, wraps",ARROW_ENDS,PASS,"carousel: it wraps, so neither arrow hides (prev hidden=False, next hidden=False)"
|
|
26
|
+
"carousel, 6 slides, wraps",CAROUSEL_LAYOUT,PASS,"grid ""slide"", every slide still one track wide ([1200] vs 1200) - isCarousel wraps the ends, it does not show more than one"
|
|
27
|
+
"carousel, 6 slides, wraps",ARROW_ARIA,PASS,role=button tabindex=0 label='下一張投影片'
|
|
28
|
+
"carousel, 6 slides, wraps",NEXT,PASS,slide 0 -> 1
|
|
29
|
+
"carousel, 6 slides, wraps",PREV,PASS,slide 1 -> 0
|
|
30
|
+
"carousel, 6 slides, wraps",KEYBOARD,PASS,"focus bullet 5 taken, Enter -> slide 5"
|
|
31
|
+
"carousel, 6 slides, wraps",REDUCED,PASS,under prefers-reduced-motion it holds still (slide 0 -> 0)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mosaic-headless",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"description": "AI-agent skill: build Mosaic Pro (Nextend) WordPress sites by writing the underlying data model directly - 23 custom tables, no visual editor, no DOM. Every node type, style property and node property swept against a live install and asserted on the delivered HTML and compiled CSS. Installs into Claude Code, Cursor, Codex CLI, Gemini CLI, Copilot, Continue, Windsurf and Claude.ai.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wordpress",
|
package/references/slider.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
about the component — the same kind of row the accordion probe corrected. Nested
|
|
6
6
|
the way its factories require, every piece commits and renders.
|
|
7
7
|
|
|
8
|
-
`data/slider-verification.csv`:
|
|
8
|
+
`data/slider-verification.csv`: 30 checks across two sliders, all passing.
|
|
9
9
|
|
|
10
10
|
## The shape
|
|
11
11
|
|
|
@@ -28,8 +28,24 @@ the way its factories require, every piece commits and renders.
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
`animation` is `slide` | `crossFade` | `fadeOut` | `fadeOver`. `autoplayLimit` is how
|
|
31
|
-
many rounds autoplay runs before it stops, `0` meaning no limit.
|
|
32
|
-
|
|
31
|
+
many rounds autoplay runs before it stops, `0` meaning no limit.
|
|
32
|
+
|
|
33
|
+
**`isCarousel` makes the ends wrap. It does not show more than one slide at a
|
|
34
|
+
time** — an earlier version of this page claimed both, and measuring the two side
|
|
35
|
+
by side says otherwise. `<mosaic-slider-slides>` is a CSS grid whose template is a
|
|
36
|
+
single `"slide"` area one track wide, and *every* slide sits in that one area at
|
|
37
|
+
the full track width, carousel or not:
|
|
38
|
+
|
|
39
|
+
| | plain | carousel |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `grid-template-areas` | `"slide"` | `"slide"` |
|
|
42
|
+
| `grid-template-columns` | `1240px` | `1240px` |
|
|
43
|
+
| every slide's width | 1240 | 1240 |
|
|
44
|
+
| first slide's `left` | 80 (the track's own left) | **−947** — one has already wrapped round |
|
|
45
|
+
|
|
46
|
+
So the only structural difference is that a carousel keeps a slide positioned
|
|
47
|
+
before the first one, which is both why it wraps and why neither arrow ever hides.
|
|
48
|
+
Showing several slides at once is not something this property gives you.
|
|
33
49
|
|
|
34
50
|
## Two things the markup does not announce
|
|
35
51
|
|
|
@@ -77,3 +93,23 @@ Everything is addressed by position inside the slider, for the reasons above.
|
|
|
77
93
|
"Which slide is current" is what the tool reads, because `slide` and `crossFade`
|
|
78
94
|
drive transforms and opacities completely differently and that is the one thing
|
|
79
95
|
both agree on.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Two things the component does not draw for you
|
|
99
|
+
|
|
100
|
+
**An arrow has no glyph.** `<mosaic-slider-arrow-left>` renders with empty
|
|
101
|
+
`innerHTML`, and its placement rule is `none`, so there is nowhere to put an icon
|
|
102
|
+
either. The entire appearance is the author's CSS on the element itself. The
|
|
103
|
+
two-border chevron works and needs nothing else: a ~9px box showing only
|
|
104
|
+
`border-top` and `border-right`, turned with a `rotateZ` transform entry (`45deg`
|
|
105
|
+
for next, `-135deg` for prev).
|
|
106
|
+
|
|
107
|
+
**`.m-slide-content` arrives as `display:flex` with `align-items: center`.** A
|
|
108
|
+
slide whose type should sit against the left edge has to say `alignItems:
|
|
109
|
+
"flex-start"`; without it every slide centres its own content and the result looks
|
|
110
|
+
like exactly the stock carousel you were trying not to build.
|
|
111
|
+
|
|
112
|
+
And one of layout rather than of the component: slider chrome positioned over the
|
|
113
|
+
slides (`position:absolute` bottom bar holding the bullets and arrows) will collide
|
|
114
|
+
with the slide's own text unless the slide reserves a strip of bottom padding for
|
|
115
|
+
it. Nothing warns you; the caption simply runs under the bullets.
|
|
@@ -99,7 +99,7 @@ const counts = {
|
|
|
99
99
|
"data/data-class-hierarchy.csv": 125,
|
|
100
100
|
"data/custom-fields-verification.csv": 62,
|
|
101
101
|
"data/dialog-verification.csv": 19,
|
|
102
|
-
"data/slider-verification.csv":
|
|
102
|
+
"data/slider-verification.csv": 30,
|
|
103
103
|
"data/navigation-verification.csv": 46,
|
|
104
104
|
"data/page-modal-verification.csv": 19,
|
|
105
105
|
"data/interaction-rules-verification.csv": 17,
|
package/sites/_moksa.py
CHANGED
|
@@ -248,7 +248,7 @@ def mask_line(attr, text, tag="h1", **st):
|
|
|
248
248
|
|
|
249
249
|
# ── content, all of it Moksa Web's own ───────────────────────────────────────
|
|
250
250
|
NAV = [("服務", "#services"), ("作品", "#works"),
|
|
251
|
-
("產品", "#products"), ("彈窗", "/dialogs/"),
|
|
251
|
+
("產品", "#products"), ("彈窗", "/dialogs/"), ("輪播", "/sliders/"),
|
|
252
252
|
("聯絡", "#contact")]
|
|
253
253
|
|
|
254
254
|
# key / figure / caption, read as a datasheet rather than as four big numbers
|
|
@@ -3058,6 +3058,10 @@ if __name__ == "__main__":
|
|
|
3058
3058
|
# `_moksa` (this copy is `__main__`), its own main block does not run, and the
|
|
3059
3059
|
# helpers it reads are pure functions - two copies produce identical dicts.
|
|
3060
3060
|
import _dialogs
|
|
3061
|
+
import _sliders
|
|
3062
|
+
SITE["pages"].append({"slug": "sliders", "post_id": 270,
|
|
3063
|
+
"title": "輪播實驗室",
|
|
3064
|
+
"tree": apply_type(_sliders.TREE, DISPLAY, CJK, "600")})
|
|
3061
3065
|
SITE["pages"].append({"slug": "dialogs", "post_id": 268,
|
|
3062
3066
|
"title": "彈窗實驗室",
|
|
3063
3067
|
"tree": apply_type(_dialogs.TREE, DISPLAY, CJK, "600")})
|