Category Overview
AI Section Skills
Build custom JoonWeb (.jw) sections and layouts using conversational AI models, ChatGPT, Claude, and Cursor.
AI Section Skills Overview
Build custom JoonWeb (.jw) sections and layouts using conversational AI models, ChatGPT, Claude, and Cursor.
3 Endpoints / Guides
•
Official Developer Specification
AI Section Studio & Universal Skills
Build Custom .jw Sections with AI
Use our official jw-theme-sections skill to generate responsive, error-free storefront sections in ChatGPT, Claude, Cursor, and AI coding agents.
1. Select Your AI Platform
ChatGPT Workflow: Click "1-Click Launch in ChatGPT" below to open ChatGPT with the pre-loaded prompt and skill context. Alternatively, create a Custom GPT with the system instructions below.
1-Click Skill Installation (Run in Terminal)
Recommended
Run in your theme project root to download the complete skill so @jw-theme works instantly
$
mkdir -p .cursor/rules && curl -s https://joonweb.dev/skills/jw-theme-sections/SKILL.md > .cursor/rules/jw-theme.mdc
Auto-indexed by Cursor v0.42+ (no restart required)
Enables @jw-theme in Composer & Chat
View Raw SKILL.md
2. Choose a Section Example / Preset
Switch presets to test different prompt types & outputs
Ready-to-Run Prompt
Hero Banner
You are an Expert JoonWeb Theme Developer. Follow the official JoonWeb section specifications from:
https://joonweb.dev/skills/jw-theme-sections/SKILL.md
Generate a production-ready Hero Banner section in .jw format with:
- Top comment: {# Copy and paste this code directly into the JoonWeb Theme Editor (.jw file) #}
- Strict file order: Variables {% set %} -> <style> -> <section> -> <script> -> {% rules %}
- Scoped CSS under {{ S }} MUST be placed BEFORE <section>
- Conditionals using != '' or 'is not empty' (never != blank)
- Outer wrapper with data-bl="{{ site ? 0 : 1 }}", data-xx="1", and background{{ sc }}
- Editable blocks using data-jw-block
- Valid schema types only (radio yes/no, quickEditor, text, image_picker, range)
- Append {"type": "themes"} and {"type": "apps"} to schema blocks
- Populated presets with realistic default blocks (NEVER include themes or apps in presets)
- Right above rules schema comment: {# Do not change if you don't know #}
- No bulky or decorative divider comments
Expected .jw File Structure (Pure JW Language + Bootstrap 5.3 + Populated Presets)
{# Copy and paste this code directly into the JoonWeb Theme Editor (.jw file) #}
{% set ss = section.settings %}
{% set S = '#jw-section-' ~ section.id %}
{% set sc = (section.colors | default('5')) | replace({ 'background': '' }) %}
{% set bg_col = ss.customBg == 'yes' ? ss.bgColor | default('') : '' %}
{% set text_col = ss.customText == 'yes' ? ss.textColor | default('') : '' %}
{% set card_bg = ss.customCardBg == 'yes' ? ss.cardBgColor | default('') : '' %}
{% set card_tx = ss.customCardText == 'yes' ? ss.cardTextColor | default('') : '' %}
{% set width_map = { "full-width": "full-width", "container": "container", "container-fluid": "container-fluid" } %}
{% set width = width_map[ss.sectionWidth] ?? 'container' %}
{% set v = ss.image is iterable ? (ss.image.src ?? ss.image.url ?? ss.image.value ?? '') : (ss.image ?? '') %}
{% set img = v != '' ? ((v starts with 'http' or v starts with '/' or v starts with 'data:') ? v : v | asset_url) : '' %}
<style>
{{ S }} {
padding-top: var(--pad-t);
padding-bottom: var(--pad-b);
position: relative;
overflow: hidden;
}
{{ S }} .hb-badge {
background: rgba(59, 130, 246, 0.12);
color: #2563eb;
border: 1px solid rgba(59, 130, 246, 0.25);
font-size: 0.75rem;
letter-spacing: 0.05em;
}
{{ S }} .hb-img {
aspect-ratio: 4 / 3;
object-fit: cover;
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
{{ S }} .hb-media-wrap:hover .hb-img {
transform: scale(1.03);
}
{{ S }}.hb-ccbg .hb-card { background: var(--ccbg) !important; }
{{ S }}.hb-cctx .hb-card { color: var(--cctx) !important; }
@media (max-width: 749.98px){
{{ S }} {
padding-top: calc(var(--pad-t) * 0.7);
padding-bottom: calc(var(--pad-b) * 0.7);
}
}
/* Builder Overrides */
{{ S }}[data-bl="1"] .hb-img { transform: none !important; }
@media (prefers-reduced-motion: reduce){
{{ S }} * { animation: none !important; transition: none !important; }
}
</style>
<section
id="jw-section-{{ section.id }}"
class="hb background{{ sc }} {{ card_bg != '' ? 'hb-ccbg' : '' }} {{ card_tx != '' ? 'hb-cctx' : '' }}"
data-xx="1" data-bl="{{ site ? 0 : 1 }}"
style="{{ bg_col != '' ? 'background:' ~ bg_col ~ ';' : '' }} {{ text_col != '' ? 'color:' ~ text_col ~ ';' : '' }} {{ card_bg != '' ? '--ccbg:' ~ card_bg ~ ';' : '' }} {{ card_tx != '' ? '--cctx:' ~ card_tx ~ ';' : '' }} --pad-t: {{ ss.pad_top | default(80) }}px; --pad-b: {{ ss.pad_bottom | default(80) }}px;">
<div class="{{ width }}" data-id="{{ section.id }}">
<div class="row align-items-center g-5 {{ ss.reverse_mobile == 'yes' ? 'flex-column-reverse flex-lg-row' : '' }}">
<div class="col-12 col-lg-6">
<div class="hb-content text-{{ ss.alignment | default('left') }}">
{% for block in section.blocks ?? [] %}
{% set b = block.settings %}
{% switch block.type %}
{% case "badge" %}
<div class="hb-blk mb-3" data-jw-block>
<span class="badge rounded-pill px-3 py-2 text-uppercase fw-bold hb-badge">
{{ b.text | default('New Season') }}
</span>
</div>
{% case "heading" %}
<div class="hb-blk mb-3" data-jw-block>
<h1 class="display-4 fw-bold mb-0 lh-tight hb-title fontStyle1">
{{ (b.text ?? 'Digital Storefront Innovation') | raw }}
</h1>
</div>
{% case "text" %}
<div class="hb-blk mb-4" data-jw-block>
<div class="lead mb-0 hb-desc fontStyle7">
{{ (b.content ?? '<p>High-converting, responsive storefront architecture built natively with JW Language.</p>') | raw }}
</div>
</div>
{% case "buttons" %}
<div class="hb-blk mb-4" data-jw-block>
<div class="d-flex flex-wrap gap-3 align-items-center {{ ss.alignment == 'center' ? 'justify-content-center' : '' }}">
{% set btn1_url = b.btn1_link is iterable ? (b.btn1_link.url ?? '') : (b.btn1_link ?? '') %}
{% if btn1_url != '' %}
<a href="{{ btn1_url }}" class="btn btn-primary px-4 py-3 rounded-pill fw-bold shadow-sm">
<span>{{ b.btn1_text | default('Explore Catalog') }}</span>
<i class="bi bi-arrow-right ms-2"></i>
</a>
{% endif %}
{% set btn2_url = b.btn2_link is iterable ? (b.btn2_link.url ?? '') : (b.btn2_link ?? '') %}
{% if btn2_url != '' %}
<a href="{{ btn2_url }}" class="btn btn-outline-secondary px-4 py-3 rounded-pill fw-bold">
<span>{{ b.btn2_text | default('Learn More') }}</span>
</a>
{% endif %}
</div>
</div>
{% default %}
{{ render_block(block) }}
{% endswitch %}
{% endfor %}
</div>
</div>
<div class="col-12 col-lg-6">
<div class="hb-media-wrap position-relative">
{% if img != '' %}
<div class="hb-img-frame rounded-4 overflow-hidden shadow-lg">
<img src="{{ img }}" alt="{{ ss.heading | default('Hero Banner') | striptags }}" class="img-fluid w-100 hb-img" loading="lazy" onerror="this.onerror=null;this.src='https://images.unsplash.com/photo-1441986300917-64674bd600d8?auto=format&fit=crop&w=1200&q=80';">
</div>
{% else %}
<div class="hb-placeholder rounded-4 d-flex align-items-center justify-content-center text-muted p-5 bg-light">
<i class="bi bi-image fs-1 me-2"></i>
<span>Select an image in section settings</span>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</section>
<script>
(function () {
function init(sec) {
if (sec._hbInit) return;
sec._hbInit = true;
var bl = sec.getAttribute('data-bl') === '1';
if (bl) return;
}
function scan() { document.querySelectorAll('[data-xx="1"]').forEach(init); }
if (window.JWHeroBanner) { window.JWHeroBanner.scan(); return; }
window.JWHeroBanner = { scan: scan };
if (document.readyState !== 'loading') scan();
else document.addEventListener('DOMContentLoaded', scan);
})();
</script>
{# Do not change if you don't know #}
{% rules %}
{
"name": "Hero Banner",
"settings": [
{ "type": "select", "id": "sectionWidth", "label": "Container Width", "options": [
{ "value": "container", "label": "Container" },
{ "value": "container-fluid", "label": "Container Fluid" },
{ "value": "full-width", "label": "Full Width" }
], "default": "container" },
{ "type": "select", "id": "alignment", "label": "Alignment", "options": [
{ "value": "left", "label": "Left" },
{ "value": "center", "label": "Center" }
], "default": "left" },
{ "type": "radio", "id": "reverse_mobile", "label": "Reverse on Mobile", "options": [
{ "value": "yes", "label": "Yes" }, { "value": "no", "label": "No" }
], "default": "no" },
{ "type": "image_picker", "id": "image", "label": "Hero Image" },
{ "type": "range", "id": "pad_top", "label": "Top Spacing", "min": 20, "max": 160, "step": 5, "unit": "px", "default": 80 },
{ "type": "range", "id": "pad_bottom", "label": "Bottom Spacing", "min": 20, "max": 160, "step": 5, "unit": "px", "default": 80 },
{ "type": "header", "content": "Custom Colors" },
{ "type": "radio", "id": "customBg", "label": "Custom Background", "options": [
{ "value": "yes", "label": "On" }, { "value": "no", "label": "Off" }
], "default": "no" },
{ "type": "color_background", "id": "bgColor", "label": "Background Color" },
{ "type": "radio", "id": "customText", "label": "Custom Text Color", "options": [
{ "value": "yes", "label": "On" }, { "value": "no", "label": "Off" }
], "default": "no" },
{ "type": "color", "id": "textColor", "label": "Text Color" }
],
"blocks": [
{ "type": "badge", "name": "Badge Pill", "settings": [{ "type": "text", "id": "text", "label": "Text", "default": "New Arrival" }] },
{ "type": "heading", "name": "Heading", "settings": [{ "type": "text", "id": "text", "label": "Heading", "default": "Next-Generation Digital Storefronts" }] },
{ "type": "text", "name": "Description", "settings": [{ "type": "quickEditor", "id": "content", "label": "Content", "default": "<p>Build high-converting storefronts with JW Language architecture.</p>" }] },
{ "type": "buttons", "name": "Buttons", "settings": [
{ "type": "text", "id": "btn1_text", "label": "Primary Button Text", "default": "Shop New Arrivals" },
{ "type": "url", "id": "btn1_link", "label": "Primary Button Link" }
] },
{ "type": "themes" },
{ "type": "apps" }
],
"presets": [
{
"name": "Hero Banner",
"category": "Hero",
"settings": { "colors": "5", "alignment": "left", "pad_top": 80, "pad_bottom": 80 },
"blocks": [
{ "type": "badge", "settings": { "text": "✨ Spring 2026 Collection" } },
{ "type": "heading", "settings": { "text": "Next-Generation Digital Storefronts" } },
{ "type": "text", "settings": { "content": "<p>Build high-converting storefronts with JW Language architecture.</p>" } },
{ "type": "buttons", "settings": { "btn1_text": "Shop New Arrivals" } }
]
}
]
}
{% endrules %}
Alternative: Manual .cursorrules File Configuration
If you prefer creating a rule file manually instead of running the 1-click terminal install command, save this snippet into .cursorrules in your project root:
# JoonWeb Theme Developer Rules
When generating or modifying .jw sections:
1. Reference Skill: https://joonweb.dev/skills/jw-theme-sections/SKILL.md
2. Framework: Bootstrap 5.3 + Bootstrap Icons + jQuery (Never Tailwind CSS).
3. Syntax: Pure JW Language ({% if %}, {% elseif %}, {% else %}, {% endif %}, {% for %}).
4. Scoped CSS: <style> targeting {{ S }} placed BEFORE <section>.
5. Schema: Always provide valid JSON {% rules %} ... {% endrules %} with fully populated presets.
6. Auto-Suggest: Search endpoints must integrate debounced /suggestions.json?q={query}&limit=8.
Available Resources & Endpoints
Last updated: Oct 12, 2026