Components / Japan / Wagara
Wagara beta
Ten classical Japanese patterns, constructed — not pasted: seigaiha waves, asanoha hemp, shippo circles, ichimatsu checks, kikko hexagons, uroko scales, sharkskin dots, arrow feathers, fawn spots and the diamond lattice.
Seigaiha — blue ocean waves.
<div class="k-wag" data-wag>
<div class="k-wag-stage"><canvas aria-hidden="true"></canvas></div>
<div class="k-wag-bar" role="group" aria-label="Pattern">
<button class="k-wag-btn on" type="button" data-wag-p="seigaiha">青海波<small>Seigaiha</small></button>
<button class="k-wag-btn" type="button" data-wag-p="asanoha">麻の葉<small>Asanoha</small></button>
<button class="k-wag-btn" type="button" data-wag-p="shippo">七宝<small>Shippo</small></button>
<button class="k-wag-btn" type="button" data-wag-p="ichimatsu">市松<small>Ichimatsu</small></button>
<button class="k-wag-btn" type="button" data-wag-p="kikko">亀甲<small>Kikko</small></button>
<button class="k-wag-btn" type="button" data-wag-p="uroko">鱗<small>Uroko</small></button>
<button class="k-wag-btn" type="button" data-wag-p="same">鮫小紋<small>Same</small></button>
<button class="k-wag-btn" type="button" data-wag-p="yagasuri">矢絣<small>Yagasuri</small></button>
<button class="k-wag-btn" type="button" data-wag-p="kanoko">鹿の子<small>Kanoko</small></button>
<button class="k-wag-btn" type="button" data-wag-p="hishi">菱<small>Hishi</small></button>
<button class="k-wag-btn k-wag-tone" type="button" data-wag-tone>Tone: Paper</button>
</div>
<p class="k-wag-cap">Seigaiha — blue ocean waves.</p>
</div>/* KATA Wagara — classical patterns, constructed. */
.k-wag{font-family:var(--k-font)}
.k-wag-stage{border-radius:14px;overflow:hidden;border:1px solid var(--k-line)}
.k-wag canvas{display:block;width:100%;height:228px}
.k-wag-bar{display:flex;gap:8px;flex-wrap:wrap;margin-top:11px;align-items:center}
.k-wag-btn{border:1px solid var(--k-line);background:var(--k-bg);color:var(--k-ink-2);font-family:inherit;font-size:12.5px;font-weight:550;padding:7px 13px;border-radius:99px;cursor:pointer}
.k-wag-btn small{color:var(--k-ink-3);font-weight:500;margin-inline-start:5px}
.k-wag-btn.on{background:var(--k-ink);color:var(--k-bg);border-color:var(--k-ink)}
.k-wag-btn.on small{color:var(--k-zinc-400)}
.k-wag-tone{margin-inline-start:auto;color:var(--k-accent-ink);border-color:var(--k-accent-bg)}
.k-wag-cap{font-size:12.5px;color:var(--k-ink-3);margin-top:9px}
// KATA Wagara — ten patterns, drawn from their constructions.
document.querySelectorAll('[data-wag]').forEach(function (root) {
var canvas = root.querySelector('canvas');
var ctx = canvas.getContext('2d');
var DPR = Math.min(3, window.devicePixelRatio || 1);
var cap = root.querySelector('.k-wag-cap');
var cs = getComputedStyle(root);
var V = function (n) { return cs.getPropertyValue(n).trim(); };
var TONES = [
{ bg: V('--k-bg'), fg: V('--k-ink'), mid: V('--k-zinc-400'), soft: V('--k-zinc-200'), name: 'Paper' },
{ bg: V('--k-zinc-950'), fg: V('--k-zinc-200'), mid: V('--k-zinc-500'), soft: V('--k-zinc-800'), name: 'Ink' },
{ bg: V('--k-zinc-950'), fg: V('--k-accent'), mid: V('--k-zinc-500'), soft: V('--k-zinc-800'), name: 'Night' }
];
var CAPS = {
seigaiha: 'Seigaiha — blue ocean waves. Concentric arcs, each row offset by half a fan; a wish for calm seas and a long life.',
asanoha: 'Asanoha — the hemp leaf. Six-fold geometry from a hexagon\u2019s triangles; hemp grows fast and straight, so the pattern guards children.',
shippo: 'Shippo — seven treasures. Equal circles overlapping by a quarter, each petal a treasure, the whole an unbroken wish for harmony.',
ichimatsu: 'Ichimatsu — the checkered pattern named for the kabuki actor Sanogawa Ichimatsu. The nested band is the one the KATA mark wears.',
kikko: 'Kikko — the tortoiseshell. Hexagons from the turtle\u2019s shell; the tortoise lives ten thousand years, so the pattern is worn for a long life.',
uroko: 'Uroko — scales. Overlapping triangles of fish and dragon scale; what sheds its skin sheds misfortune with it.',
same: 'Samekomon — sharkskin. Dots riding the arcs of scales, dyed so fine it counted as plain cloth under Edo sumptuary law — luxury hiding in the dots.',
yagasuri: 'Yagasuri — the arrow feather. An arrow once shot never returns, so the pattern rides wedding kimono: go, and do not come back.',
kanoko: 'Kanoko — the fawn\u2019s spots. Shibori dots pinched and dyed one by one, named for the dapples down a young deer\u2019s back.',
hishi: 'Hishi — the diamond. The floating leaf of the water caltrop, squared into a lattice that crosses the whole cloth.'
};
var pattern = 'seigaiha', tone = 0, W, H;
function seigaiha(t) {
var s = 30;
var rows = Math.ceil(H / (s * .5)) + 2;
for (var r = rows; r >= -1; r--) {
var y = r * s * .5 + s * .5;
var off = (r % 2) * s;
for (var x = -s + off; x < W + s; x += s * 2) {
for (var k = 4; k >= 1; k--) {
ctx.beginPath();
ctx.arc(x, y, s * k / 4, Math.PI, 0);
ctx.closePath();
ctx.fillStyle = k % 2 ? t.bg : t.soft;
if (k === 4) ctx.fillStyle = t.bg;
ctx.fill();
ctx.strokeStyle = k % 2 ? t.fg : t.mid;
ctx.lineWidth = 1.2;
ctx.stroke();
}
}
}
}
function asanoha(t) {
var R = 25, dx = Math.sqrt(3) * R, dy = 1.5 * R;
ctx.lineWidth = 1.1;
var row = 0;
for (var y = -R; y < H + R; y += dy, row++) {
for (var x = -dx; x < W + dx; x += dx) {
var cx = x + (row % 2 ? dx / 2 : 0), cy = y;
var v = [];
for (var k = 0; k < 6; k++) { var a = Math.PI / 3 * k - Math.PI / 2; v.push([cx + R * Math.cos(a), cy + R * Math.sin(a)]); }
for (var k2 = 0; k2 < 6; k2++) {
var A = v[k2], B = v[(k2 + 1) % 6];
var mx = (A[0] + B[0] + cx) / 3, my = (A[1] + B[1] + cy) / 3;
ctx.strokeStyle = t.mid;
ctx.beginPath(); ctx.moveTo(cx, cy); ctx.lineTo(A[0], A[1]); ctx.stroke();
ctx.beginPath(); ctx.moveTo(A[0], A[1]); ctx.lineTo(B[0], B[1]); ctx.stroke();
ctx.strokeStyle = t.fg;
[[A, B], [B, [cx, cy]], [[cx, cy], A]].forEach(function (pr) {
ctx.beginPath(); ctx.moveTo(mx, my); ctx.lineTo(pr[0][0], pr[0][1]); ctx.stroke();
});
var mAB = [(A[0] + B[0]) / 2, (A[1] + B[1]) / 2], mBc = [(B[0] + cx) / 2, (B[1] + cy) / 2], mCa = [(cx + A[0]) / 2, (cy + A[1]) / 2];
ctx.beginPath(); ctx.moveTo(mAB[0], mAB[1]); ctx.lineTo(mBc[0], mBc[1]); ctx.lineTo(mCa[0], mCa[1]); ctx.closePath(); ctx.stroke();
}
}
}
}
function shippo(t) {
var R = 21;
ctx.lineWidth = 1.2; ctx.strokeStyle = t.mid;
for (var y = 0; y < H + R; y += R) for (var x = 0; x < W + R; x += R) {
ctx.beginPath(); ctx.arc(x, y, R, 0, 7); ctx.stroke();
}
ctx.fillStyle = t.fg;
for (var y2 = 0; y2 < H + R; y2 += R) for (var x2 = 0; x2 < W + R; x2 += R) {
ctx.beginPath(); ctx.arc(x2, y2, 1.6, 0, 7); ctx.fill();
}
}
function ichimatsu(t) {
var s = 27;
for (var y = 0; y < H - 40; y += s) for (var x = 0; x < W; x += s) {
if (((x / s) + (y / s)) % 2 === 0) { ctx.fillStyle = t.fg; ctx.globalAlpha = .85; ctx.fillRect(x, y, s, s); }
}
ctx.globalAlpha = 1;
var s2 = 6.75, y0 = H - 40;
ctx.fillStyle = t.soft; ctx.fillRect(0, y0, W, 40);
for (var yy = y0; yy < H; yy += s2) for (var xx = 0; xx < W; xx += s2) {
if (((xx / s2) + ((yy - y0) / s2)) % 2 === 0) { ctx.fillStyle = t.fg; ctx.fillRect(xx, yy, s2, s2); }
}
}
function kikko(t) {
var R = 22, dx = Math.sqrt(3) * R, dy = 1.5 * R;
ctx.lineWidth = 1.2;
var row = 0;
for (var y = -R; y < H + R; y += dy, row++) {
for (var x = -dx; x < W + dx; x += dx) {
var cx = x + (row % 2 ? dx / 2 : 0), cy = y;
[1, .58].forEach(function (sc, i) {
ctx.beginPath();
for (var k = 0; k < 6; k++) {
var a = Math.PI / 3 * k - Math.PI / 2, px = cx + R * sc * Math.cos(a), py = cy + R * sc * Math.sin(a);
if (k === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py);
}
ctx.closePath();
ctx.strokeStyle = i === 0 ? t.fg : t.mid;
ctx.stroke();
});
}
}
}
function uroko(t) {
var s = 30, h = s * .87;
ctx.lineWidth = 1.2;
var row = 0;
for (var y = h; y < H + h; y += h, row++) {
for (var x = -s; x < W + s; x += s) {
ctx.beginPath();
ctx.moveTo(x, y); ctx.lineTo(x + s / 2, y - h); ctx.lineTo(x + s, y); ctx.closePath();
ctx.fillStyle = row % 2 ? t.bg : t.soft;
ctx.fill();
ctx.strokeStyle = t.fg;
ctx.stroke();
}
}
}
function same(t) {
var R = 18;
ctx.fillStyle = t.fg;
var rows = Math.ceil(H / (R * .62)) + 2;
for (var r = rows; r >= -1; r--) {
var y = r * R * .62 + R;
var off = (r % 2) * R;
for (var x = -R + off; x < W + R; x += R * 2) {
[1, .6].forEach(function (sc) {
var Rk = R * sc, stepA = 5.6 / Rk;
for (var a = Math.PI; a <= Math.PI * 2 + .001; a += stepA) {
ctx.beginPath(); ctx.arc(x + Rk * Math.cos(a), y + Rk * Math.sin(a), 1.35, 0, 7); ctx.fill();
}
});
ctx.beginPath(); ctx.arc(x, y, 1.35, 0, 7); ctx.fill();
}
}
}
function yagasuri(t) {
var w = 24, h = 46;
var row = 0;
for (var y = -h; y < H + h; y += h * .8, row++) {
for (var x = 0; x < W + w; x += w) {
var cx = x + (row % 2 ? w / 2 : 0), cy = y;
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(cx + w * .4, cy + h * .34);
ctx.lineTo(cx + w * .13, cy + h * .34);
ctx.lineTo(cx + w * .13, cy + h);
ctx.lineTo(cx, cy + h * .7);
ctx.lineTo(cx - w * .13, cy + h);
ctx.lineTo(cx - w * .13, cy + h * .34);
ctx.lineTo(cx - w * .4, cy + h * .34);
ctx.closePath();
ctx.fillStyle = row % 2 ? t.mid : t.fg;
ctx.globalAlpha = .88;
ctx.fill();
ctx.globalAlpha = 1;
}
}
}
function kanoko(t) {
var s = 23;
var row = 0;
for (var y = s / 2; y < H + s; y += s, row++) {
for (var x = s / 2 + (row % 2 ? s / 2 : 0); x < W + s; x += s) {
ctx.beginPath(); ctx.arc(x, y, 8, 0, 7); ctx.strokeStyle = t.soft; ctx.lineWidth = 3.4; ctx.stroke();
ctx.beginPath(); ctx.arc(x, y, 4.4, 0, 7); ctx.strokeStyle = t.fg; ctx.lineWidth = 1.5; ctx.stroke();
ctx.beginPath(); ctx.arc(x, y, 1.5, 0, 7); ctx.fillStyle = t.fg; ctx.fill();
}
}
}
function hishi(t) {
var s = 25;
ctx.lineWidth = 1.1; ctx.strokeStyle = t.mid;
ctx.beginPath();
for (var d = -H; d < W + H; d += s) { ctx.moveTo(d, 0); ctx.lineTo(d + H, H); }
for (var d2 = 0; d2 < W + 2 * H; d2 += s) { ctx.moveTo(d2, 0); ctx.lineTo(d2 - H, H); }
ctx.stroke();
ctx.fillStyle = t.fg;
for (var gy = 0; gy <= H + s; gy += s) for (var gx = 0; gx <= W + s; gx += s) {
var px = gx + ((gy / s) % 2 ? 0 : 0), py = gy;
ctx.save(); ctx.translate(px, py); ctx.rotate(Math.PI / 4); ctx.fillRect(-2.1, -2.1, 4.2, 4.2); ctx.restore();
}
}
function draw() {
var t = TONES[tone];
W = canvas.clientWidth; H = canvas.clientHeight;
canvas.width = W * DPR; canvas.height = H * DPR; ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
ctx.fillStyle = t.bg; ctx.fillRect(0, 0, W, H);
({ seigaiha: seigaiha, asanoha: asanoha, shippo: shippo, ichimatsu: ichimatsu, kikko: kikko, uroko: uroko, same: same, yagasuri: yagasuri, kanoko: kanoko, hishi: hishi })[pattern](t);
cap.textContent = CAPS[pattern];
}
root.querySelectorAll('[data-wag-p]').forEach(function (b) {
b.addEventListener('click', function () {
root.querySelectorAll('[data-wag-p]').forEach(function (x) { x.classList.remove('on'); });
b.classList.add('on');
pattern = b.getAttribute('data-wag-p');
draw();
});
});
root.querySelector('[data-wag-tone]').addEventListener('click', function () { tone = (tone + 1) % TONES.length; this.textContent = 'Tone: ' + TONES[tone].name; draw(); });
window.addEventListener('resize', draw);
draw();
});
Installation
CLI
node kata-ui.mjs add wagara
Writes the part’s CSS and JS into your project. New to the CLI? See the CLI doc.
Manual
- Load
tokens.cssonce, before any part. - Copy the CSS tab into your stylesheet.
- Copy the HTML where it belongs. The part has a script — include it after the markup; it initializes itself.
Usage
Each pattern is drawn from its real geometry by the script — seigaiha as concentric arcs on a half-offset grid, asanoha as the true six-fold hemp construction, shippo as equal overlapping circles, kikko as nested hexagons, samekomon as dots riding the scale arcs, yagasuri as the arrow-feather silhouette. Three tones (paper, ink, night) and all colors come from the token set on purpose: the patterns are classical, the palette stays the house’s. Use them as section textures, empty-state skies, and the inside of covers.
Accessibility
Pattern is texture: the canvas is aria-hidden and any text over it must pass contrast on the flat tone color alone, pattern removed. Under prefers-reduced-motion nothing changes — patterns were always still.
Anatomy
The public surface of this part, read from its own source. Class names are the API — the CSS tab above is the full contract.
.k-wag | class |
.k-wag-stage | class |
.k-wag-bar | class |
.k-wag-btn | class |
.on | class |
.k-wag-tone | class |
.k-wag-cap | class |
data-wag | data hook |
data-wag-p | data hook |
data-wag-tone | data hook |
aria-hidden | ARIA |
aria-label | ARIA |
Related parts
Hanko beta
A vermillion seal that stamps: the shu-iro signature for approvals, authorship and things that are done.
Kintsugi Card beta
A status card repaired in gold: the cracks of an incident, drawn as kintsugi veins that mend on arrival.
Noren beta
A noren curtain as a section divider: three hanging panels that sway, and part when you reach for them.
Tategaki beta
Vertical Japanese text, set properly: shuhari — obey the form, break the form, leave the form — as an editorial monument.