Install
$ agentstack add skill-yizhian-aniya-studio-grapesjs-html-compliance ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
GrapesJS HTML Compliance
HTML generated for GrapesJS runs inside an isolated iframe with a fixed 1920x1080 canvas. The editor manages slide visibility via CssComposer, strips ` tags outside custom-code blocks, and extracts ` to its style manager. This skill defines the constraints that keep generated HTML compatible with this environment.
Part 0: Compliant HTML Skeleton
Start every deck from this minimal, correct skeleton. Customize styles and content; keep the structure intact.
/* Navigation control styles (counter, dots, progress bar, buttons) */
/* Font family declarations — aniyaFonts auto-loads from Google Fonts */
body { margin: 0; padding: 0; background: #000; }
#nav-controls { position: absolute; bottom: 20px; right: 20px; z-index: 10; }
(function() {
// Keyboard navigation (← → arrows, Space to advance)
// Click/tap on left/right edges as fallback
// Slide counter (current / total)
// Progress bar and dot indicators
// localStorage persistence for current slide
})();
Key points:
- First
.slidehardcodesclass="active"— not added by JS - All slides use explicit
width: 1920px; height: 1080px; overflow: hidden - All `
inside` - Opacity/transform-based slide transitions are allowed (they work in preview).
The platform's scoped shell handles editor slide visibility.
- No
position: fixed— chrome elements useposition: absoluteinside the
1920×1080 stage. Combined with scaleDeck() this is functionally equivalent to fixed positioning in preview. (S6 enforced.)
- No viewport units (
vw/vh) for layout containers. - No
@importor `` for fonts — the aniyaFonts plugin auto-loads from
Google Fonts. The platform injects font `` tags during serialization.
Part 0b: Using Design Skills
Design skills are design directories, not code templates. When a design skill is loaded, extract its design DNA and apply it to the compliant skeleton above. The compliance skill has authority over design skills when they conflict.
Extract (keep these)
- Color tokens: All
:rootCSS custom properties and their hex values. Note accent constraints (e.g., "single accent under 5% per slide"). - Typography system: Font family names and role assignments (display/body/mono). The aniyaFonts plugin auto-loads any Google Font declared via
font-family. Extractfont-familyvalues (e.g.,'Newsreader','JetBrains Mono') — these are safe. Also extract weight constraints, italic/uppercase rules, type scale ratios, letter-spacing values. - Layout archetypes: The slide type taxonomy and internal compositions (grid ratios, card structures, metric layouts, decorative elements).
- Visual style rules: Constraints and banned patterns (no border-radius, no shadows, no gradients, single accent, monospace-only body, etc.).
- Content structure: Deck rhythm rules, slide ordering conventions, slide count guidance.
Editor Canvas Constraints (these break in the GrapesJS editor iframe)
position: fixed— relative to iframe viewport, not 1920×1080 canvas.
Use position: absolute inside .slide or 1920px stage. Combined with scaleDeck(), this is functionally identical to fixed positioning in preview. (S6 enforced.)
- Viewport units (
vw/vh) — iframe viewport ≠ canvas. Use px for
.slide containers. Fluid typography (clamp()) inside slides is acceptable.
- Scripts execute only in preview — custom-code blocks show placeholder
in editor canvas. All scripts MUST be inside ``.
Publish Document Capabilities (allowed in the full HTML)
- Slide visibility — opacity/transform transitions work in preview/export.
The editor's scoped shell CSS does not affect the published document.
position: absolutechrome — nav bars, dots, progress bars placed with
position: absolute inside the 1920px stage work correctly in both editor and preview. Combined with scaleDeck() they behave like fixed elements. Note: position: fixed is blocked by S6 — use absolute instead.
scaleDeck()— include in custom-code for viewport-adaptive scaling.- Font loading — declare via
font-familyonly. The platform injects
Google Fonts ` tags during serialization. Do NOT write ` tags yourself.
Discard (these break in GrapesJS)
position: fixed— blocked by S6; useposition: absoluteinstead.- Font LOADING mechanisms (but KEEP font NAMES):
- Strip:
@import url('https://fonts.googleapis.com/...')— blocked by S7 - Strip: `` — agent must not write
- Strip: `` for font domains — blocked by S7
- Strip:
@font-face { src: url('https://...') }— blocked by S7 - Keep:
font-family: 'Font Name', fallback— aniyaFonts auto-loads from Google Fonts - Keep: System font stacks (they need no loading) —
-apple-system, BlinkMacSystemFont, ...
- Other external resources — `
,,url('https://...')in CSS (exceptdata:` URIs which are safe). Platform-injected Google Fonts links are exempt. pointer-events: noneandoverflow: hiddenon body/html
Apply
Build each slide from the compliant skeleton, styled with the extracted design DNA. Use px-based dimensions on .slide containers. Chrome elements (page numbers, brand marks, slide labels) are part of slide content, not fixed overlays.
Part 1: Architecture Overview
GrapesJS renders content in an isolated iframe with a fixed 1920x1080 canvas. Key facts:
- The editor sets
overflow: hidden !importanton `and` — no body-level scrolling - Slide visibility in the editor canvas is managed by a scoped shell CSS rule (
html[data-aniya-editor] .slide:not(.active) { display: none !important; }). In published documents (which lackdata-aniya-editor), the author's own visibility rules (opacity, transform) take effect. - `
tags are stripped on import unless inside` - `` tags are extracted to CssComposer on import
- Custom components use
data-gjs-typeattribute (data-gjs-type="custom-code") - Charts: layout charts (KPIs, bar comparisons, data grids, progress bars) use pure div + CSS; complex geometry (pie, radar, line) uses inline ``
- No bare `
tags —` elements get split into individually-selectable components; use div grid instead
For detailed architecture reference, see references/grapesjs-architecture.md.
Part 2: Mandatory Constraints
2.1 Structure
- Canvas size: All
.slidemust have explicitwidth: 1920px; height: 1080px - No
position: fixed: Fixed positioning is relative to the iframe viewport, not the canvas. Useposition: absoluteinside.slideor 1920px stage instead. Combined with scaleDeck(), this is functionally identical to fixed positioning in preview. (S6 enforced.) - Viewport containers use
position: relative:#stage,#presentation,#scale-wrapmust useposition: relative - Explicit
.slidestructure: Every slide is `` - First slide hardcodes
active: The first.slideelement in HTML source must includeclass="... active"(e.g., ``). Do not rely on JS to add it — custom-code scripts do not execute in the editor canvas. - Slide overflow: All
.slidemust useoverflow: hidden(notoverflow-y: autoorscroll)
2.2 Scripts
- Scripts in custom-code only: All `
tags must be inside` — otherwise stripped on import - Charts: div+CSS or inline SVG:
- Layout charts (KPIs, bar comparisons, data grids, progress bars) → pure div + CSS (flex/grid + inline width%)
- Data tables → div grid (no bare `
—` gets split into separate components) - Complex geometry (pie, radar, line) → inline ``
- Chart containers should use
class="chart"for easy selection
- No inline event handlers:
onclick,onload,onerror,onmouseoveretc. are stripped by the editor
2.3 Styles
- Prefer inline styles: Use element
styleattributes — most reliable - **`
in**: All style rules inblocks — extracted to CssComposer on import. Do NOT define.slide:not(.active) { display: none !important; }` — the platform provides the scoped equivalent. Opacity/transform-based visibility rules are acceptable. - No author-level
!important: Generates thousands of duplicate rules on re-render. The platform's scoped shell (html[data-aniya-editor] .slide:not(.active) { display: none !important; }) is a platform-reserved rule — do NOT repeat or override it in your HTML. - No CSS-in-JS: Silently fails in the iframe (styled-components, emotion, etc.)
2.4 SVG
- SVG in containers: Wrap each chart in a container div (e.g., ``) for easy selection
- SVG uses
viewBox: All `elements useviewBox`, not fixed pixel dimensions - SVG uses native elements only: `
,,,` — no HTML divs inside SVG
2.5 Resources
- No external CDN resources: No
http://orhttps://URLs insrc,href,url(), or@import. Exception:data:URIs are safe. Platform-injected Google Fonts links (fonts.googleapis.com,fonts.gstatic.com) are exempt — the Agent must NOT write these itself. - Fonts via
font-familyonly: Any Google Font works — declare withfont-family: 'Font Name', fallbackin CSS. The aniyaFonts plugin auto-loads them. Do NOT use@import url()or `tags to load fonts..slidecraft/available_fonts.json` is a convenience reference, not a whitelist.
2.6 Five Universal Failure Patterns
These patterns appear in design skill examples and cause failures in GrapesJS:
| # | Pattern | Why It Fails | Correct Approach | |---|---------|-------------|-----------------| | 1 | Viewport units (vw, vh, %) | iframe viewport ≠ 1920x1080 canvas | px-based dimensions on .slide containers | | 2 | Custom visibility (opacity:0, visibility:hidden) | In editor: display:none overrides it via scoped shell. In publish: transitions work. | Default to opacity:1; animate only on :hover or in preview. Opacity/transform transitions on .slide are allowed. | | 3 | Zero-dimension wrappers with overflow:hidden | Absolutely-positioned children don't expand parent | Explicit width/height on all wrapper containers | | 4 | Animation starting at opacity:0 | Animations don't run in editor mode, content stays invisible | Default to opacity:1; animate only on :hover or in preview | | 5 | Flex children with percentage heights | Undefined height on flex container collapses children | Use explicit px heights or flex ratios instead of percentages |
Part 3: Self-Check Checklist
After generating HTML, check every item:
- [ ] Starts with ``
- [ ] `
and` tags present and complete - [ ] All
.slidehave explicitwidth: 1920px; height: 1080px - [ ] All
.slideuseoverflow: hidden(notoverflow-y: autoorscroll) - [ ] All `
inside` - [ ] First
.slideelement includesclass="slide active"(hardcoded, not from JS) - [ ] No bare `` tags (use div grid for table layouts)
- [ ] Charts use div+CSS (layout) or inline SVG (complex geometry); SVG uses
viewBoxand is wrapped in a container div - [ ] Viewport containers (
#stage/#presentation/#scale-wrap) useposition: relative - [ ] No
position: fixed(S6 enforced — useposition: absoluteinstead) - [ ] No external resource URLs (check all
src,hrefattributes; fonts viafont-familydeclaration only). Platform-injected Google Fonts links are exempt. - [ ] No inline event handlers (
onclick/onload/onerroretc.) - [ ] No unclosed tags (`
/` count matches, etc.) - [ ] No unclosed CSS comments
/* ...(will freeze the editor) - [ ] No
.slide:not(.active) { display: none !important; }— platform provides scoped equivalent. Opacity/transform visibility rules (for publish mode transitions) are allowed.
Part 4: Common Pitfalls
| Pitfall | Consequence | Correct Approach | |---------|------------|-----------------| | ` outside custom-code | Scripts stripped on import | Wrap in | | in custom-code | Normalized to CssComposer on import (fallback; don't rely on it) | Place styles in | | position: fixed | Element positioned relative to iframe viewport, not canvas (S6 enforced) | Use position: absolute relative to .slide or 1920px stage. scaleDeck() makes this visually identical to fixed in preview. | | Unclosed CSS comment / | **Editor freezes** | Ensure every / has a matching / | | Repeated !important | Thousands of duplicate CSS rules generated | Use more specific selectors; platform scoped shell html[data-aniya-editor] .slide:not(.active){display:none!important} is reserved | | Chart container without explicit size | Chart renders at 0×0 | Set explicit width and height on container | | CSS-in-JS | Silently fails in iframe | Use inline style or | | External CDN references | Resource load failure (S7 enforced) | Inline all resources (SVG, data: URIs); fonts via font-family. Platform-injected Google Fonts links are exempt. | | elements | Known custom-code plugin bug | Avoid | | on event attributes | Stripped by editor | Use addEventListener in custom-code scripts | | Bare tags | split into separate selectable components | Use div grid for table layouts | | First slide active via JS | Editor canvas shows blank | Hardcode class="slide active" in HTML source | | opacity:0 on .slide | In editor: display:none overrides it via scoped shell. In publish: transitions work. | Default to opacity:1; animate only on :hover or in preview. Opacity/transform transitions on .slide are allowed. | | writefile to fix violations | fileexists error, destroys editor state | Always use readfile then editfile` |
Part 5: Mandatory Audit Workflow
After generating or editing HTML, follow this exact sequence. Do NOT skip steps.
- Read:
read_filethe HTML file to get current content andread_mtime_unix_ns. - Check: Go through every item in Part 3's self-check checklist against the file content.
- Record: Note each violation with its line number and the fix needed.
- Fix: Use
edit_fileto fix one violation at a time. CRITICAL: Never usewrite_fileon an existing file — it will fail withfile_existsand destroys GrapesJS editor state. - Re-verify: After fixing, the platform re-checks automatically. Repeat the readfile → editfile cycle until the checklist is fully clean.
Gate: Do not declare the task complete until all 15 checklist items pass.
When NOT to Apply This Skill
- Standalone browser HTML: If the output is viewed directly in a browser (not GrapesJS), use standard web practices instead.
- Print-only decks: If the output is for print/PDF, viewport constraints and script rules are irrelevant.
- Non-HTML output: This skill only applies to
.htmlfiles destined for GrapesJS import.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: yizhian
- Source: yizhian/Aniya-Studio
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.