File: /home/primrwxj/thezonalhouse.info/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Design Description → CSS</title>
<style>
:root { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
body { margin: 24px; max-width: 980px; }
h1 { font-size: 20px; margin: 0 0 10px; }
p { margin: 0 0 16px; color: #444; }
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
textarea, pre {
width: 100%;
border: 1px solid #ddd;
border-radius: 12px;
padding: 12px;
font-size: 14px;
line-height: 1.4;
box-sizing: border-box;
background: #fff;
}
textarea { min-height: 190px; }
pre { min-height: 190px; overflow: auto; background: #fafafa; }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
button {
border: 1px solid #ddd;
background: #fff;
padding: 10px 12px;
border-radius: 12px;
cursor: pointer;
font-weight: 600;
}
button:hover { background: #f6f6f6; }
.hint { font-size: 12px; color: #555; }
.pill { font-size: 12px; background: #f1f1f1; padding: 4px 8px; border-radius: 999px; }
</style>
</head>
<body>
<h1>Design Description → Clean CSS</h1>
<p>Type a UI description (e.g., “modern card, rounded corners, soft shadow, centered, max width 420px, blue accent”).</p>
<div class="grid">
<div>
<textarea id="desc" placeholder="Describe your design..."></textarea>
<div class="row">
<button id="gen">Generate CSS</button>
<button id="copy">Copy CSS</button>
<span class="pill" id="status">Ready</span>
</div>
<div class="hint">
Try: <code>glassmorphism card, blur background, white text, gradient button, large radius</code><br/>
Or: <code>minimal navbar, sticky top, subtle border, spaced links</code>
</div>
</div>
<div>
<pre id="out">/* Your CSS will appear here */</pre>
</div>
</div>
<script>
/**
* Tiny rule-based "design description -> CSS" generator.
* - Detects intent (card/button/navbar/form/layout)
* - Applies consistent defaults
* - Extracts simple values (colors, widths, padding)
*/
const KEYWORDS = {
// Components / intent
card: ["card", "panel", "surface", "tile"],
button: ["button", "cta", "call to action"],
navbar: ["navbar", "nav", "navigation", "header bar", "top bar"],
form: ["form", "input", "textfield", "text field", "search"],
hero: ["hero", "banner", "header section"],
// Styles
modern: ["modern", "clean", "sleek"],
minimal: ["minimal", "simple", "plain"],
rounded: ["rounded", "radius", "pill", "curved"],
shadow: ["shadow", "elevation", "depth"],
border: ["border", "outlined", "stroke"],
glass: ["glass", "glassmorphism", "frosted"],
gradient: ["gradient"],
dark: ["dark", "dark mode"],
light: ["light", "bright", "white background"],
center: ["center", "centered", "align center", "middle"],
fullwidth: ["full width", "full-width", "100%", "stretch"],
responsive: ["responsive", "mobile", "fluid"],
};
const NAMED_COLORS = {
blue: "#2563eb",
indigo: "#4f46e5",
purple: "#7c3aed",
pink: "#db2777",
red: "#dc2626",
orange: "#ea580c",
amber: "#d97706",
yellow: "#ca8a04",
green: "#16a34a",
teal: "#0f766e",
cyan: "#0891b2",
slate: "#334155",
gray: "#6b7280",
black: "#111827",
white: "#ffffff",
};
function hasAny(text, words) {
const t = text.toLowerCase();
return words.some(w => t.includes(w));
}
function pickIntent(text) {
const t = text.toLowerCase();
const intents = [];
for (const [intent, words] of Object.entries(KEYWORDS)) {
if (["card","button","navbar","form","hero"].includes(intent) && hasAny(t, words)) intents.push(intent);
}
// Default to card if nothing specified
return intents.length ? intents : ["card"];
}
function extractHexColor(text) {
const m = text.match(/#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b/);
return m ? (m[0].length === 4 ? expandHex(m[0]) : m[0].toLowerCase()) : null;
}
function expandHex(h) {
// #abc -> #aabbcc
return "#" + h[1]+h[1] + h[2]+h[2] + h[3]+h[3];
}
function extractNamedColor(text) {
const t = text.toLowerCase();
for (const name of Object.keys(NAMED_COLORS)) {
const re = new RegExp("\\b" + name + "\\b", "i");
if (re.test(t)) return NAMED_COLORS[name];
}
return null;
}
function extractSize(text, label) {
// examples:
// "max width 420", "max-width: 420px", "width 600px", "padding 16"
const t = text.toLowerCase();
const patterns = {
maxWidth: [
/max[-\s]?width[:\s]+(\d+)(px|rem|em|%)?/i,
/max[-\s]?w(?:idth)?\s+(\d+)(px|rem|em|%)?/i,
],
width: [
/(^|\b)width[:\s]+(\d+)(px|rem|em|%)?/i,
/\bw\s+(\d+)(px|rem|em|%)?/i,
],
padding: [
/padding[:\s]+(\d+)(px|rem|em)?/i,
/\bp\s+(\d+)(px|rem|em)?/i,
],
radius: [
/radius[:\s]+(\d+)(px|rem|em)?/i,
/border[-\s]?radius[:\s]+(\d+)(px|rem|em)?/i,
],
};
const pats = patterns[label] || [];
for (const pat of pats) {
const m = t.match(pat);
if (m) {
// pick groups depending on pattern
const num = m[m.length - 2] ?? m[1];
const unit = m[m.length - 1] ?? "px";
const n = parseInt(num, 10);
if (Number.isFinite(n)) return `${n}${unit || "px"}`;
}
}
return null;
}
function tone(text) {
const t = text.toLowerCase();
const isDark = hasAny(t, KEYWORDS.dark);
const isLight = hasAny(t, KEYWORDS.light);
if (isDark && !isLight) return "dark";
if (isLight && !isDark) return "light";
// default: light
return "light";
}
function buildDesignSystem(text) {
const t = text.toLowerCase();
const accent = extractHexColor(text) || extractNamedColor(text) || "#2563eb";
const mode = tone(text);
// Defaults
let bg = mode === "dark" ? "#0b1220" : "#ffffff";
let surface = mode === "dark" ? "rgba(255,255,255,0.06)" : "#ffffff";
let textColor = mode === "dark" ? "#e5e7eb" : "#0f172a";
let muted = mode === "dark" ? "rgba(229,231,235,0.72)" : "#475569";
let border = mode === "dark" ? "rgba(255,255,255,0.10)" : "rgba(15,23,42,0.12)";
// Glass overrides
const glass = hasAny(t, KEYWORDS.glass);
if (glass) {
surface = mode === "dark" ? "rgba(255,255,255,0.07)" : "rgba(255,255,255,0.65)";
border = mode === "dark" ? "rgba(255,255,255,0.14)" : "rgba(15,23,42,0.10)";
}
// Sizes
const maxW = extractSize(text, "maxWidth") || "520px";
const pad = extractSize(text, "padding") || "16px";
const rad = extractSize(text, "radius") || (hasAny(t, KEYWORDS.rounded) ? "18px" : "12px");
// Shadow intensity
const wantsShadow = hasAny(t, KEYWORDS.shadow);
const shadow = wantsShadow
? (mode === "dark"
? "0 12px 30px rgba(0,0,0,0.45)"
: "0 12px 30px rgba(2,6,23,0.12)")
: "none";
return { accent, mode, bg, surface, textColor, muted, border, maxW, pad, rad, shadow, glass };
}
function cssForCard(ds, text) {
const t = text.toLowerCase();
const centered = hasAny(t, KEYWORDS.center);
const wantsBorder = hasAny(t, KEYWORDS.border) || ds.glass;
return `
/* CARD */
.card {
background: ${ds.surface};
color: ${ds.textColor};
border: ${wantsBorder ? `1px solid ${ds.border}` : "none"};
border-radius: ${ds.rad};
padding: ${ds.pad};
box-shadow: ${ds.shadow};
max-width: ${ds.maxW};
${centered ? "margin: 0 auto;" : ""}
${ds.glass ? "backdrop-filter: blur(12px);" : ""}
}
.card__title { font-size: 18px; font-weight: 700; margin: 0 0 8px; }
.card__text { color: ${ds.muted}; margin: 0; line-height: 1.55; }
`.trim();
}
function cssForButton(ds, text) {
const t = text.toLowerCase();
const pill = t.includes("pill") || t.includes("pill-shaped");
const gradient = hasAny(t, KEYWORDS.gradient);
const bg = gradient
? `linear-gradient(135deg, ${ds.accent}, rgba(255,255,255,0))`
: ds.accent;
return `
/* BUTTON */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 10px 14px;
border-radius: ${pill ? "999px" : "14px"};
border: 1px solid rgba(255,255,255,0.0);
background: ${bg};
color: #fff;
font-weight: 700;
text-decoration: none;
cursor: pointer;
transition: transform 120ms ease, filter 120ms ease, box-shadow 120ms ease;
box-shadow: 0 10px 22px rgba(2,6,23,0.18);
}
.btn:hover { transform: translateY(-1px); filter: brightness(1.02); }
.btn:active { transform: translateY(0px); filter: brightness(0.98); }
.btn:focus { outline: 2px solid rgba(37,99,235,0.35); outline-offset: 2px; }
`.trim();
}
function cssForNavbar(ds, text) {
const t = text.toLowerCase();
const sticky = t.includes("sticky");
const wantsBorder = hasAny(t, KEYWORDS.border);
return `
/* NAVBAR */
.navbar {
${sticky ? "position: sticky; top: 0; z-index: 50;" : ""}
background: ${ds.bg};
color: ${ds.textColor};
border-bottom: ${wantsBorder ? `1px solid ${ds.border}` : "none"};
}
.navbar__inner {
max-width: 1100px;
margin: 0 auto;
padding: 12px 16px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.navbar__brand { font-weight: 800; letter-spacing: -0.02em; }
.navbar__links { display: flex; gap: 14px; flex-wrap: wrap; }
.navbar a { color: inherit; text-decoration: none; opacity: 0.9; }
.navbar a:hover { opacity: 1; text-decoration: underline; }
`.trim();
}
function cssForForm(ds, text) {
const t = text.toLowerCase();
const pill = t.includes("pill");
return `
/* FORM / INPUT */
.input {
width: 100%;
padding: 10px 12px;
border-radius: ${pill ? "999px" : "12px"};
border: 1px solid ${ds.border};
background: ${ds.mode === "dark" ? "rgba(255,255,255,0.03)" : "#fff"};
color: ${ds.textColor};
outline: none;
transition: box-shadow 120ms ease, border-color 120ms ease;
}
.input::placeholder { color: ${ds.mode === "dark" ? "rgba(229,231,235,0.55)" : "rgba(71,85,105,0.75)"}; }
.input:focus {
border-color: ${ds.accent};
box-shadow: 0 0 0 4px rgba(37,99,235,0.15);
}
.label { font-size: 13px; font-weight: 700; margin-bottom: 6px; display: inline-block; }
.formRow { display: grid; gap: 8px; }
`.trim();
}
function cssForHero(ds, text) {
const t = text.toLowerCase();
const gradient = hasAny(t, KEYWORDS.gradient);
const heroBg = gradient
? `linear-gradient(135deg, ${ds.accent}, ${ds.mode === "dark" ? "#0b1220" : "#ffffff"})`
: ds.bg;
return `
/* HERO */
.hero {
padding: 56px 16px;
background: ${heroBg};
color: ${ds.textColor};
}
.hero__inner {
max-width: 1100px;
margin: 0 auto;
display: grid;
gap: 14px;
}
.hero__title { font-size: clamp(26px, 4vw, 44px); font-weight: 900; margin: 0; letter-spacing: -0.03em; }
.hero__subtitle { margin: 0; color: ${ds.muted}; max-width: 64ch; line-height: 1.55; }
`.trim();
}
function generateCSS(description) {
const ds = buildDesignSystem(description);
const intents = pickIntent(description);
const base = `
/* =========
BASE TOKENS
========= */
:root {
--accent: ${ds.accent};
--bg: ${ds.bg};
--text: ${ds.textColor};
--muted: ${ds.muted};
--border: ${ds.border};
}
/* =========
PAGE BASE
========= */
.page {
background: var(--bg);
color: var(--text);
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
line-height: 1.45;
}
`.trim();
const blocks = [base];
if (intents.includes("card")) blocks.push(cssForCard(ds, description));
if (intents.includes("button")) blocks.push(cssForButton(ds, description));
if (intents.includes("navbar")) blocks.push(cssForNavbar(ds, description));
if (intents.includes("form")) blocks.push(cssForForm(ds, description));
if (intents.includes("hero")) blocks.push(cssForHero(ds, description));
// Helpful layout utilities (only if asked)
const t = description.toLowerCase();
if (hasAny(t, KEYWORDS.center) || hasAny(t, KEYWORDS.responsive) || hasAny(t, KEYWORDS.fullwidth)) {
blocks.push(`
/* UTILITIES */
.container { max-width: 1100px; margin: 0 auto; padding: 0 16px; }
.stack { display: grid; gap: 12px; }
.center { display: grid; place-items: center; }
`.trim());
}
return blocks.join("\n\n");
}
// UI
const desc = document.getElementById("desc");
const out = document.getElementById("out");
const status = document.getElementById("status");
document.getElementById("gen").addEventListener("click", () => {
const text = desc.value.trim();
if (!text) {
out.textContent = "/* Please type a design description first. */";
status.textContent = "Needs description";
return;
}
out.textContent = generateCSS(text);
status.textContent = "Generated";
});
document.getElementById("copy").addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(out.textContent);
status.textContent = "Copied";
} catch {
status.textContent = "Copy failed";
}
});
// Nice starter
desc.value = "Modern card, rounded corners, soft shadow, centered, max width 460px, blue accent. Include a gradient button.";
out.textContent = generateCSS(desc.value);
</script>
</body>
</html>