What pattern() is
MODERN SYSTEM · 1.2.4
pattern() registers a description + a template (CSS or FSCSS).
Elsewhere in the same compile unit, a plain line of text is scored against those descriptions.
The best hit at or above the pattern’s threshold is expanded in place.
Unlike @define (exact name + args), patterns are intent-based.
From 1.2.4, templates can also pull values out of the caller’s phrase with
@match(regex) — so patterns behave like parameterized helpers without a formal signature.
Semantic match
Word overlap / similarity — not only exact strings
Threshold
Per-pattern minimum score (0–1); default 1 if omitted
@match
Capture groups from the call phrase into the template
Compile-time
CLI or runtime expand once — no browser NLP cost in production CSS
@match against that line → emit CSS/FSCSS.
Install
npm install fscss@1.2.4
<script src="https://cdn.jsdelivr.net/npm/fscss@1.2.4/runtime.min.js" defer></script>
Use 1.2.4+ for improved matching, balanced-paren @match, and safer regex checks.
Creating & calling patterns
1 Declare
pattern()pattern(threshold: "description in plain language", `
/* template: CSS and/or FSCSS */
`)
- threshold — optional; omit → defaults to
1(strict) - description — words used for similarity scoring
- template — prefer backticks so quotes inside CSS are free
2 Call
Write a line without typical CSS structure ({ } ; alone as pure CSS). That line is treated as a phrase and compared to descriptions.
pattern(0.5: "Hello World card", `
border-radius: 12px;
padding: 24px;
background: linear-gradient(135deg, #667eea, #764ba2);
color: #fff;
box-shadow: 0 8px 24px rgba(0,0,0,0.25);
`)
.card {
hello world card
}
The phrase sits inside a selector (property pattern) or alone (block pattern — see below).
Thresholds & sensitive patterns
How strict should a listener be?
sensitivitySimilarity is word-based (case-insensitive). A phrase must score ≥ threshold and beat other candidates.
| Threshold | Behavior | Use for |
|---|---|---|
1 (default) |
Near-exact description | Short / generic phrases (“dark button”) |
0.7–0.9 |
Strict but forgiving typos/order | Named components |
0.4–0.6 |
Looser intent match | Longer descriptions with optional words |
≤ 0.35 |
Very open — easy collisions | Rare; keep descriptions unique |
Sensitive (high)
pattern(0.9: "primary cta button solid", `
background: #4f46e5;
color: #fff;
border-radius: 8px;
`)
/* Only close paraphrases of that phrase fire */
Open (lower)
pattern(0.5: "Beautiful card", `
background: #06f;
`)
/* "beautiful card", "a beautiful card panel" may match */
@match — parameters from the phrase
Parameterized patterns without formal args
@match
Inside a template, @match(regex) runs against the caller’s phrase (not the description).
The first defined capturing group is used; if none, the full match.
Parentheses in the regex are supported via balanced scanning (inner ) won’t truncate the directive).
pattern(0.6: "rounded primary button with color: white, bg: red", `
background: @match(background:?\s([#\w\d-_]+)) @match(bg:?\s([#\w\d-_]+));
color: @match(color:?\s([#\w\d-_]+)) @match(text:?\s([#\w\d-_]+));
border-radius: 25px;
padding: 10px 20px;
border: 2px solid;
font-weight: 700;
`)
.primary {
rounded primary button with color: #0BCEAE, background: midnightblue
}
Designing “inputs”
- Put stable keywords in the description (for scoring).
- Put variable slots in the call phrase and harvest with
@match. - Offer alternate labels in one pattern:
bg:andbackground:,color:andtext:. - If a match fails, the insertion is empty (unless strict mode is enabled in the engine options).
pattern(0.35: "create sales array value: 0,", `
@arr @match(create\s([\w-_]+))[
@match(data:?\s([\d\, \s]+))@match(value:?\s([\d\, \s]+))
]
`)
create sample array value: 77, 7, 66, 78, 16
/* → @arr sample[ 77, 7, 66, 78, 16 ] when groups resolve */
Property patterns vs block patterns
Property
Phrase inside a rule → declarations merge into that rule.
.btn {
rounded primary button
}
Block
Phrase alone → full constructs (@keyframes, top-level FSCSS, etc.).
pattern(0.7: "animated keyframe for spin", `
@keyframes spin {
to { transform: rotate(360deg); }
}
`)
an Animated keyframes for spin
Patterns that emit FSCSS
Arrays, modules, st-core
Templates are not limited to plain CSS. They can expand to @arr, @import, or module calls — then the rest of the pipeline runs as usual.
@import((*) from st-core@v2)
@st-root()
pattern(0.35: "create sales array value: 0,", `
@arr @match(create\s([\w-_]+))[
@match(data:?\s([\d\, \s]+))@match(value:?\s([\d\, \s]+))
]
`)
pattern(0.50: "render sales chart with st-core ", `
@st-chart-fill(.fill, @match(st-core\s([\w-_]+))@match(render\s([\w-_]+)))
@st-chart-line(.line, @match(st-core\s([\w-_]+))@match(render\s([\w-_]+)))
.chart {
@st-chart-points(@match(st-core\s([\w-_]+))@match(render\s([\w-_]+)))
}
`)
create sample array value: 77, 7, 66, 78, 16
render sample chart with st-core
.chart {
width: 300px;
height: 200px;
position: relative;
border: 1px solid var(--st-muted);
border-radius: var(--st-radius-md);
background: var(--st-surface);
}
Description words (“create”, “render”, “st-core”) drive matching;
@match binds the name token (sample) into array and chart helpers.
Safe @match regexes
1.2.4 rejects dangerous or invalid sources before new RegExp:
- Nested quantifiers such as
(a+)+ - Hostile repeated alternation forms
- Overlong sources (sanity cap)
- Invalid syntax → clear compile error
Prefer simple character classes and one clear capturing group per @match.
Advanced recipes
Library file of patterns
/* _patterns.fscss — import into apps */
pattern(0.75: "glass panel elevated", `
background: color-mix(in srgb, #fff 12%, transparent);
backdrop-filter: blur(12px);
border: 1px solid rgba(255,255,255,0.12);
border-radius: 16px;
`)
pattern(0.8: "muted label uppercase", `
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--st-muted, #64748b);
`)
Ship next to modules so teams type intent instead of copying declarations.
Multiple @match fallbacks
Chain alternate labels so authors can say bg: or background::
background: @match(background:?\s([#\w]+)) @match(bg:?\s([#\w]+));
Whichever group hits the phrase contributes; the other stays empty.
pattern vs @define
| @define | pattern() |
|---|---|
Exact name @name(args) |
Fuzzy phrase match |
@use(param) formal params |
@match from free text |
| Best for APIs & modules | Best for intent, demos, authoring UX |
Best practices
Distinct descriptions
Avoid two patterns that share the same core words at low thresholds
Tune thresholds
Short phrases → high threshold; long unique blurbs → can go lower
One capture per concern
Keep @match regexes small and readable
Backtick templates
CSS can contain ' and " freely
npm install fscss@1.2.4 ·
CDN https://cdn.jsdelivr.net/npm/fscss@1.2.4/runtime.min.js