Low-code Front-end Design & Development Platform
Front-end development platform, with a visual builder and headless content modelling capabilities. Static website creation, and UI development tools.
翻譯準備中
글래스모피즘과 블러 효과를 조합한 웹·앱 공용 디자인 시스템 · 카페인 팔레트, 반응형 그리드, React·Svelte · A web & app design system combining glassmorphism and blur · made by caffeinecat
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
글래스모피즘과 블러 효과를 조합한, 웹·앱 공용 디자인 시스템 — 블러레마와 카페인 팔레트 A web & app design system that combines glassmorphism with blur — Blurema crema and caffeine palettes 미리보기 Preview · 브랜드북 Brand book · npm blurssism은 우유 거품 같은 크림색 바탕 위에 젖빛 크레마 블러레마(Blurema)를 필요한 곳에만 띄우는 디자인 시스템입니다. 유리 표현은 Apple Liquid Glass와 Samsung One UI에서 영감을 받았고, 색은 카페인에서 가져왔으며, 한국어 화면을 기준으로 만들었습니다.檢視完整 README ↗
blurssism은 브랜드 성격이 뚜렷한 웹 화면을 위한 디자인 시스템입니다. 우유 거품 같은 크림색 바탕 위에 젖빛 크레마 **블러레마(Blurema)**를 필요한 곳에만 띄웁니다. 유리 표현은 Apple Liquid Glass와 Samsung One UI에서 영감을 받았고, 색은 카페인에서 가져왔으며, 한국어 화면을 기준으로 만들었습니다. 콘텐츠·프로필·설정·랜딩 화면에 맞고, 정보 밀도가 높은 업무 화면에서는 간격과 버튼 위계를 별도로 조정해야 합니다.
원칙
paper)와 먹(ink). 강조색은 10% 이내.들어 있는 것
off · 기본 on · 데스크톱 rich(더 깊은 블러와 두 겹 그림자). 데스크톱 모드와 포인터 빛은 개발자가 켜고 끌 수 있음<script>, 안 쓰는 컴포넌트는 번들러가 버림)와 Svelte 5, 또는 CSS 클래스(bl-*)만으로도. 토스트 매니저, 로케일(setLocale("en")), 제어·비제어 겸용probe), 개발 중 검사(auditCrema(): 블러 예산·primary 개수·강조색 면적 추정·팔레트 하나). 면적 검사는 단색과 토큰 색이 들어간 그라디언트를 보수적으로 세며 사진·외부 이미지는 육안 확인이 필요합니다.자세한 비교는 브랜드북에 있어요.
npm install @caffeinecatkr/blurssism
모든 페이지에 뷰포트 메타 태그가 있어야 반응형이 작동합니다: <meta name="viewport" content="width=device-width, initial-scale=1">
import { Button, PalettePicker, Container, Grid, Card } from "@caffeinecatkr/blurssism";
import "@caffeinecatkr/blurssism/fonts.css"; // 글꼴(CDN). 직접 호스팅하면 빼도 됩니다
import "@caffeinecatkr/blurssism/tokens.css";
import "@caffeinecatkr/blurssism/bundle.css";
export default function App() {
return (
<Container className="bl-root">
<PalettePicker />
<Grid columns={{ xs: 1, md: 2, lg: 3 }}>
<Card title="오늘의 원두" body="에티오피아 예가체프" />
</Grid>
<Button variant="primary" icon="plus">새로 만들기</Button>
</Container>
);
}
Next.js App Router에서는 CSS를 app/layout.jsx에서 불러옵니다. 컴포넌트는 서버 컴포넌트 파일에서 import해 그릴 수 있지만(패키지에 "use client"가 들어 있음), 함수 props(onClick, Table의 render·format 등)는 서버 컴포넌트에서 넘길 수 없으니 그런 부분은 "use client" 파일 안에서 씁니다. → examples/nextjs · examples/vite-react
<script>
import { Button, PalettePicker, TextField, Dialog, breakpoint } from "@caffeinecatkr/blurssism/svelte";
import "@caffeinecatkr/blurssism/fonts.css";
import "@caffeinecatkr/blurssism/tokens.css";
import "@caffeinecatkr/blurssism/bundle.css";
let email = $state("");
let open = $state(false);
const bp = breakpoint();
</script>
<PalettePicker />
<TextField label="이메일" bind:value={email} />
<Button variant="primary" onclick={() => (open = true)}>열기</Button>
<Dialog bind:open title="저장할까요?">
<Button variant="ghost" size="md" onclick={() => (open = false)}>취소</Button>
</Dialog>
{#if bp.current === "xs"}<p>폰 화면이에요</p>{/if}
입력 요소는 bind:value·bind:checked·bind:open을 지원하고, 슬롯 대신 스니펫({#snippet actions()}…{/snippet})을 씁니다. Svelte 5.20 이상이 필요합니다. → examples/sveltekit
Button의 기본형은 ghost입니다. 화면의 핵심 행동 하나에만 variant="primary"를 명시하세요. 예전에 variant를 생략해 강조 버튼을 만들었다면 해당 버튼에 variant="primary"를 추가해야 합니다.
글꼴: Blurssism Sans(UI)와 Blurssism Serif(명조)를 씁니다. 이름만 blurssism이고 실체는 Pretendard(© Kil Hyung-jin)와 Gowun Batang(© The Gowun Batang Project Authors)에서 KS X 1001 한글 2350자와 영문·숫자·기호만 남긴 사본입니다(OFL 규정상 수정본은 원래 이름을 쓸 수 없어 바꿨습니다). 파일이 작습니다(Sans 가변 450KB, Serif 400·700 합쳐 383KB). 모든 한글이 한 글꼴로 보이길 바라면 fonts.dynamic.css를 대신 불러오세요. 원본 글꼴을 동적 서브셋으로 받아 11,172자 전부 같은 글꼴이고 쓰인 글자 조각만 받습니다(jsDelivr + Google Fonts 필요). 2350자 밖의 드문 글자(똠, 햏 등)는 시스템 글꼴로 보입니다. OFL 예약 이름 때문에 이름을 바꿨습니다. fonts.css는 같은 버전의 글꼴 파일을 jsDelivr에서 불러옵니다. CDN 없이 쓰려면(CSP·사내망·오프라인) fonts.css 자리에 fonts.local.css를 불러오면 끝입니다. 패키지에 든 글꼴 파일(dist/fonts/, SIL OFL)을 쓰고, Vite·Next.js·SvelteKit은 글꼴 파일을 알아서 함께 내보냅니다. 번들러 없이 쓰면 dist/fonts.local.css와 dist/fonts/ 폴더를 같은 자리에 올립니다. 다른 글꼴로 바꾸려면 --font-sans·--font-serif를 덮어씁니다.
import "@caffeinecatkr/blurssism/fonts.local.css"; // fonts.css 대신
React와 Svelte는 같은 CSS와 같은 함수 모듈(/utils)을 써서, 어느 쪽에서 applyBrandColor()나 applyCremaPreference()를 불러도 상태가 하나입니다. 이름이 다른 곳은 프레임워크 관례를 따른 것입니다.
| React | Svelte | |
|---|---|---|
| 이벤트 | onChange, onClick, onClose | onchange, onclick, onclose |
| 양방향 값 | value + onChange (Chip은 defaultSelected로 스스로) | bind:value, bind:checked, bind:selected, bind:open |
| Table 칸 | format(행) 글자, render(행) 노드 | format(행) 글자, cell 스니펫 |
| Tooltip | 자식에 aria-describedby 자동 연결 | 스니펫이 받은 id를 직접 붙임 |
Checkbox label | 글자 또는 노드 | 글자 또는 스니펫 |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@caffeinecatkr/blurssism/dist/fonts.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@caffeinecatkr/blurssism/dist/tokens.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@caffeinecatkr/blurssism/dist/bundle.css">
<body class="bl-root">
<div class="bl-container">
<header class="bl-navbar bl-crema"><p class="bl-navbar-title">설정</p></header>
<div class="bl-grid"><div class="bl-span-4 bl-span-lg-8">본문</div><div class="bl-span-4">옆</div></div>
<button class="bl-btn bl-btn-primary">저장하기</button>
</div>
</body>
<html data-palette="matcha" data-theme="dark">
data-palette | 이름 | 느낌 |
|---|---|---|
black | 블랙 (기본) | 블랙커피의 검정 채움과 캐러멜빛 글자 강조 |
espresso | 에스프레소 | 볶은 원두의 갈색과 크레마 |
matcha | 말차 | 녹차의 차분한 초록 |
chai | 차이 | 향신료 밀크티의 주황 |
coldbrew | 콜드브루 | 차갑게 우린 커피의 깊은 남색 |
mocha | 모카 | 초콜릿과 장미빛 코코아 |
classic | 클래식 | 자두색 |
blue | 블루 | 링크와 버튼에서 가장 익숙한 파랑 |
indigo | 인디고 | SaaS와 개발 도구에서 흔한 남보라 |
violet | 바이올렛 | 창작 도구와 커뮤니티의 보라 |
teal | 틸 | 헬스케어와 핀테크의 청록 |
emerald | 에메랄드 | 결제와 성장 서비스의 선명한 초록 |
pink | 핑크 | 커머스와 뷰티의 분홍 |
graphite | 그래파이트 | 색 없이 먹색 하나로 쓰는 단색 |
배경은 <html data-background="white">(아래 "배경색"). 코드로는 setPalette("chai"), setTheme("dark" | "light" | "system"). 테마를 지정하지 않으면 시스템 설정을 따릅니다. 사용자의 선택을 저장하는 것은 앱 몫입니다. <PalettePicker group="web" />처럼 한 묶음만 보일 수도 있습니다.
| 단계 | 너비 | 그리드 | 거터 · 여백 |
|---|---|---|---|
xs | 0–599 | 4열 | 16 · 16 |
sm | 600–767 | 8열 | 16 · 24 |
md | 768–1119 | 8열 | 24 · 32 |
lg | 1120–1439 | 12열 | 24 · 40 |
xl | 1440+ | 12열 | 32 · 48 |
Container/.bl-container로 폭을 맞추고, Grid columns={{ xs: 1, md: 2, lg: 3 }} 또는 .bl-grid + .bl-span-md-6으로 배치합니다.TabBar. md 미만에서는 Dialog가 아래 시트 모양이 되고 제목이 자동으로 작아짐.NavBar 링크가 나타나고 TabBar는 스스로 숨음(hideFrom={false}로 계속 보이기).useBreakpoint(), Svelte breakpoint(), 공통 getBreakpoint()·isAtLeast("md").전체 규칙은 브랜드북의 반응형 절에 있습니다.
// tailwind.config.js — tokens.css도 함께 불러오세요
module.exports = { presets: [require("@caffeinecatkr/blurssism/tailwind")] };
bg-paper, text-accent, rounded-full, backdrop-blur-md, 그리고 같은 브레이크포인트(sm: md: lg: xl:)를 씁니다.
| 1.x | 2.0 | 왜 |
|---|---|---|
primary 버튼 = ink 채움, accent 버튼 = 강조색 채움 | primary = 강조색(accent) 채움. accent는 primary의 별칭 | 블랙 팔레트에서 둘이 같은 검정이었고, 규칙상 둘을 나란히 두지 않으므로 하나로 합침 |
블랙 팔레트 accent-ink = 검정 | 캐러멜빛(#653819 · 다크 #e2ab7a) | 링크·활성 탭 글자가 본문과 같은 색이라 구분되지 않았음 |
타입 클래스 .body .label .caption .display .title-1 … | .bl-body .bl-label … (접두어) | 소비자 CSS와 충돌. 값은 새 변수 --text-body-size·-line·-weight·-tracking으로도 나옴 |
| 데스크톱 모드 포인터 빛 기본 켜짐, 블러 40/64px | 포인터 빛 기본 꺼짐({ pointerLight: true }), 블러 32/48px | 마우스가 움직일 때마다 블러 면을 다시 칠해 블러 예산 취지와 어긋남 |
| 크레마 결·띠 진함 | 결 알파 .46→.26(다크 .24→.16), 띠 42→30%, 채움 틴트 20→12% | 매트한 판처럼 보여 흐린 유리로 되돌림. 대비 검사 108,522개 그대로 통과 |
React 컴포넌트에 ref 불가 | Button·IconButton·Chip·TextField(input)·Select(select)·Checkbox(input)·Switch·RadioGroup·ListItem·Container·Grid가 forwardRef | react-hook-form register, 프로그램적 포커스 |
1.4의 glass 이름(.bl-glass*, data-glass, --glass-*, applyGlassPreference() 등)은 2.0에서 제거됐어요. 1.5~1.6의 별칭 표대로 crema 이름으로 바꾸면 되고, 화면에 남은 .bl-glass·data-glass는 auditCrema()가 찾아 줘요.
| 1.4까지 (2.0에서 제거됨) | 1.5부터 |
|---|---|
.bl-glass · .bl-glass-thick · .bl-glass-lite | .bl-crema · .bl-crema-thick · .bl-crema-lite |
.bl-btn-glass, variant="glass" | .bl-btn-crema, variant="crema" |
<html data-glass="off|on|rich"> | <html data-crema="off|on|rich"> |
applyGlassPreference() · setGlassMode() · getGlassMode() · shouldReduceGlass() | applyCremaPreference() · setCremaMode() · getCremaMode() · shouldReduceCrema() |
GlassMode · GlassOptions (타입) | CremaMode · CremaOptions |
--glass-fill · --glass-fill-strong · --glass-stroke · --glass-tint-accent | --crema-fill · --crema-fill-strong · --crema-stroke · --crema-tint-accent |
--glass-edge · --glass-crema · --glass-grain · --glass-light · --crema(1.4의 띠 색) | --crema-edge · --crema-band · --crema-grain · --crema-light · --crema-tint |
--shadow-glass · --glass-saturate | --shadow-crema · --crema-saturate |
import { applyBrandColor } from "@caffeinecatkr/blurssism"; // Svelte는 ".../svelte", 바닐라는 ".../utils"
const palette = applyBrandColor("#ff5a1f"); // <html data-palette="brand">
palette.warnings.forEach((w) => console.warn(w.message));
바탕과 글자는 그대로 두고 강조색 묶음만 만듭니다. 흰 글자가 안 읽히는 밝은 색은 필요한 만큼만 어둡게 맞추고 원래 색은 장식색으로 남기며, 상태색과 헷갈리는 색은 경고합니다. 서버 렌더링에서는 paletteToCss(createPalette("#ff5a1f"))를 <style>에 넣고, 터미널에서는 npx @caffeinecatkr/blurssism palette "#ff5a1f"로 CSS를 받습니다.
<html data-background="white"> <!-- cream(기본) · white · gray -->
import { setBackground, applyBackgroundColor } from "@caffeinecatkr/blurssism"; // Svelte는 ".../svelte", 바닐라는 ".../utils"
setBackground("gray");
const bg = applyBackgroundColor("#f5f0ff"); // <html data-background="custom">
bg.warnings.forEach((w) => console.warn(w.message));
바탕 묶음(paper·paper-raised·paper-sunken·line)만 바꾸고 글자·강조·상태색은 그대로 둡니다. 크레마(블러레마)의 우유 거품 채움과 거품 결도 바탕을 따라가서, 흰·회색 바탕 위에서는 무채색 크레마가 됩니다. 채움은 팔레트·브랜드색의 장식색도 조금(crema-fill-tint) 머금어요. 색 하나를 주면 카드·눌린 면·구분선을 같은 색조로 만들고, 글자와 모든 내장 팔레트가 읽히지 않으면 바탕을 필요한 만큼만 밝게(다크는 어둡게) 옮기며, 보조 글자색이 모자라면 조금 진하게 맞춥니다. 밝은 색은 라이트 바탕이 되고 다크 바탕은 같은 색조로 만들어요. 다크 바탕을 따로 정하려면 applyBackgroundColor("#ffffff", { dark: "#101010" }). 서버 렌더링에서는 backgroundToCss(createBackground("#f5f0ff"))를 <style>에 넣습니다. 브랜드색 팔레트를 함께 쓰면 createPalette(color, { background: bg })로 그 바탕에서 대비를 맞춥니다. 크레마 띠는 팔레트를 따라갑니다.
import { applyCremaPreference } from "@caffeinecatkr/blurssism";
applyCremaPreference(); // 기기에 맞춰 off · on · rich 자동
applyCremaPreference({ rich: false }); // 데스크톱 모드 끄기
applyCremaPreference({ rich: true }); // 데스크톱 모드 항상 켜기
| 모드 | 언제 | 블러 예산 |
|---|---|---|
off | 저사양·데이터 절약·투명도 줄이기 | 0 (불투명) |
on | 기본, 모바일 | 화면당 3개 |
rich | 1120px 이상 + 마우스 + 넉넉한 기기 | 화면당 6개, 블러 32/48px, 더 비치는 크레마, 두 겹 그림자. 포인터를 따라오는 캐러멜빛은 { pointerLight: true }로 켬 |
반복 목록 안에서는 .bl-crema-lite(MediaCard는 lite), 블러 반경은 애니메이션하지 않습니다. 크레마 안의 아이콘 버튼과 다이얼로그 뒤 scrim은 블러를 걸지 않습니다.
import { auditCrema } from "@caffeinecatkr/blurssism";
if (import.meta.env.DEV) auditCrema(); // 블러 예산, primary 개수, 강조색 면적 추정, 영역별 팔레트, 옛 glass 이름을 검사
저사양 기준은 applyCremaPreference({ minMemory: 4, minCores: 4 })로 바꿀 수 있어요(기본: 메모리 4GB 미만, 메모리를 알려 주지 않는 브라우저에서는 코어 2개 이하면 off). { probe: true }를 주면 블러 면을 실제로 그려 프레임 시간을 재고 느리면 off로 바꿔요.
import { ToastProvider, useToast, Sheet, setLocale } from "@caffeinecatkr/blurssism";
setLocale("en"); // 컴포넌트 문구(오류 접두어, 달력, 메뉴 이름 등). 기본 "ko". 일부만 덮어쓴 객체도 됨
<ToastProvider>{app}</ToastProvider> // 앱 루트
const toast = useToast(); toast.show({ message: "저장했어요", tone: "positive" }); // 최대 3개, 4초, 마우스를 올리면 멈춤
<Sheet open={open} onClose={() => setOpen(false)} title="공유">…</Sheet> // open을 주면 모달(손잡이 끌어내려 닫기)
Svelte는 toast.show() + <Toaster />, bind:open, locale.current. Switch·SegmentedControl·TabBar·RadioGroup·Tabs·Accordion·Pagination·Popover·Menu는 value를 주면 제어, defaultValue를 주면 스스로 바뀌어요.
bundle.css는 @layer blurssism 안에 있어서 소비자 CSS가 명시도와 상관없이 이겨요. 전역 리셋은 @layer reset, blurssism;처럼 앞 계층에 두세요. 치수는 --bl-btn-h·--bl-field-h·--bl-card-pad·--bl-dialog-w 같은 컴포넌트 변수로, 글자는 --text-body-size 같은 타입 변수로 영역마다 덮어쓸 수 있어요. Tailwind 프리셋은 bg-accent/50 같은 투명도 수정자를 지원해요(tokens.css의 --accent-rgb).
blurssism is a design system for brand-led web interfaces. It floats crema — Blurema, a frosted, milk-tinted surface topped with a caramel crema band — only where it's needed, over a calm cream background. The look is inspired by Apple Liquid Glass and Samsung One UI, the colors come from caffeine, and Korean typography is the default. It suits content, profile, settings, and landing screens; dense work interfaces need their own spacing and action hierarchy.
Principles
paper) and ink (ink). Accent colors stay under 10%.What's inside
off for low-end devices, on by default, and rich for desktop (deeper blur and layered shadows). Desktop mode and the optional pointer light are up to the developer.<script>; tree-shakeable) and Svelte 5, or use the CSS classes (bl-*) alone. Toast manager, locale (setLocale("en")), controlled and uncontrolled inputs.probe), plus dev-time audits (auditCrema(): blur budget, primary count, estimated accent area, one palette per screen). The area estimate counts solid fills and gradients containing token colors conservatively; inspect photos and external images visually.npm install @caffeinecatkr/blurssism
Responsive behavior requires a viewport meta tag on every page: <meta name="viewport" content="width=device-width, initial-scale=1">
import { Button, PalettePicker, Container, Grid, Card } from "@caffeinecatkr/blurssism";
import "@caffeinecatkr/blurssism/fonts.css"; // web fonts from a CDN; drop it if you self-host
import "@caffeinecatkr/blurssism/tokens.css";
import "@caffeinecatkr/blurssism/bundle.css";
In the Next.js App Router, import the CSS in app/layout.jsx. Components can be rendered from server component files (the package ships "use client"), but function props such as onClick or a Table column's render/format can't cross the server boundary, so use those inside a "use client" file. See examples/nextjs and examples/vite-react.
Button defaults to ghost. Set variant="primary" explicitly for the screen's one main action. If earlier code relied on an omitted variant for a filled button, add variant="primary" there.
<script>
import { Button, PalettePicker, TextField, breakpoint } from "@caffeinecatkr/blurssism/svelte";
import "@caffeinecatkr/blurssism/fonts.css";
import "@caffeinecatkr/blurssism/tokens.css";
import "@caffeinecatkr/blurssism/bundle.css";
let email = $state("");
const bp = breakpoint();
</script>
<PalettePicker />
<TextField label="Email" bind:value={email} />
Fonts: Blurssism Sans (UI) and Blurssism Serif. They are Pretendard and Gowun Batang cut down to the 2,350 KS X 1001 Hangul syllables plus Latin, digits and common symbols (Sans 450KB variable, Serif 400 and 700 383KB); rarer syllables fall back to system fonts. The copies are renamed because of the OFL Reserved Font Name. fonts.css loads the same version's font files from jsDelivr. To skip the CDN (CSP, intranet, offline), import fonts.local.css in its place and you're done: it uses the font files shipped in the package (dist/fonts/, SIL OFL), and Vite, Next.js and SvelteKit emit them for you. Without a bundler, serve dist/fonts.local.css next to the dist/fonts/ folder. To use other fonts, override --font-sans and --font-serif.
Inputs support bind:value, bind:checked and bind:open. Use snippets ({#snippet actions()}…{/snippet}) instead of slots. Requires Svelte 5.20+. See examples/sveltekit.
Set <html data-palette="matcha" data-theme="dark">, or call setPalette("chai") / setTheme("dark" | "light" | "system"). Without a theme, the system setting is followed. Persisting the user's choice is up to your app. Use <PalettePicker group="web" /> to show one group only.
| Step | Width | Grid | Gutter · margin |
|---|---|---|---|
xs | 0–599 | 4 col | 16 · 16 |
sm | 600–767 | 8 col | 16 · 24 |
md | 768–1119 | 8 col | 24 · 32 |
lg | 1120–1439 | 12 col | 24 · 40 |
xl | 1440+ | 12 col | 32 · 48 |
Container / .bl-container for width, and Grid columns={{ xs: 1, md: 2, lg: 3 }} or .bl-grid with .bl-span-md-6 for layout.TabBar. Below md, Dialog turns into a bottom sheet and headings shrink automatically. From lg up, NavBar links appear and the TabBar hides itself (pass hideFrom={false} to keep it).useBreakpoint() (React), breakpoint() (Svelte), or getBreakpoint() / isAtLeast("md").module.exports = { presets: [require("@caffeinecatkr/blurssism/tailwind")] };
Also load tokens.css. The sm: / md: / lg: / xl: breakpoints match blurssism.
import { ToastProvider, useToast, Sheet, setLocale } from "@caffeinecatkr/blurssism";
setLocale("en"); // component copy (error prefix, calendar, menu names). Default "ko"; partial overrides accepted
<ToastProvider>{app}</ToastProvider>
useToast().show({ message: "Saved", tone: "positive" }); // up to 3 stacked, 4s, pauses on hover
<Sheet open={open} onClose={close} title="Share">…</Sheet> // with `open` it is a modal with drag-to-close
Svelte: toast.show() + <Toaster />, bind:open, locale.current. Switch, SegmentedControl, TabBar, RadioGroup, Tabs, Accordion, Pagination, Popover and Menu are controlled with value or uncontrolled with defaultValue. bundle.css lives in @layer blurssism, so unlayered consumer CSS wins regardless of specificity (put global resets in an earlier layer). Sizes are component variables (--bl-btn-h, --bl-field-h, --bl-card-pad, --bl-dialog-w), type is --text-*, and the Tailwind preset supports opacity modifiers (bg-accent/50).
primary buttons are filled with accent (was ink); variant="accent" is now an alias of primary. The black palette's accent-ink (links, active labels) is caramel so it differs from body text..bl-body, .bl-title-1, …) and the scale is exposed as --text-{name}-size/-line/-weight/-tracking, which components read.{ pointerLight: true }); rich blur is 32/48px.Button, IconButton, Chip, TextField (input), Select (select), Checkbox (input), Switch, RadioGroup, ListItem, Container and Grid forward refs..bl-glass* → .bl-crema*, variant="glass" → "crema", data-glass → data-crema, applyGlassPreference / setGlassMode / getGlassMode / shouldReduceGlass → applyCremaPreference / setCremaMode / getCremaMode / shouldReduceCrema, and --glass-* → --crema-* (--glass-crema → --crema-band, --shadow-glass → --shadow-crema). auditCrema() reports leftover .bl-glass / data-glass on the page.import { applyBrandColor } from "@caffeinecatkr/blurssism";
const palette = applyBrandColor("#ff5a1f"); // sets <html data-palette="brand">
Pass one color and blurssism builds the accent set for light and dark, tuned to pass WCAG contrast, while the paper and ink stay the same. Colors too bright for white text are darkened just enough, and the original is kept as the decoration color. You get warnings for colors that look like status colors. For SSR, use paletteToCss(createPalette(color)); from a terminal, npx @caffeinecatkr/blurssism palette "#ff5a1f".
import { setBackground, applyBackgroundColor } from "@caffeinecatkr/blurssism";
setBackground("white"); // <html data-background="white"> — cream (default) · white · gray
const bg = applyBackgroundColor("#f5f0ff"); // any color, sets <html data-background="custom">
Only the surface set (paper, paper-raised, paper-sunken, line) changes, and the crema fill and foam grain follow it (neutral crema on white or gray). From one color blurssism derives the card, sunken and divider colors for light and dark, nudges the paper just enough for ink, status colors and every built-in palette to pass contrast, and darkens the secondary text if needed. Pass { dark: "#101010" } to set the dark paper yourself. For SSR, use backgroundToCss(createBackground(color)); pair it with a brand palette via createPalette(color, { background: bg }).
applyCremaPreference() picks off (low-end devices, data saver, reduced transparency), on (default, 3 crema surfaces per screen) or rich, a desktop mode for 1120px+ screens with a mouse and capable hardware (6 per screen, 32/48px blur, layered shadows; pass { pointerLight: true } for a caramel light that follows the pointer). Turn desktop mode off with applyCremaPreference({ rich: false }), force it with { rich: true }, or use setCremaMode("off" | "on" | "rich" | "auto"). Use .bl-crema-lite inside repeated lists and never animate the blur radius. During development, auditCrema() warns when a screen goes over the blur budget or shows more than one primary button. Since 1.5 the code names are crema too (bl-crema, data-crema, applyCremaPreference); the 1.4 glass names keep working as aliases until 2.0.
The full rules are in the brand book (Korean).
질문, 제안, 협업 문의는 [email protected](caffeinecat)으로 보내 주세요. 버그는 GitHub 이슈에 남겨 주시면 가장 빨리 볼 수 있어요. Questions, ideas or collaboration: [email protected] (caffeinecat). Please report bugs on GitHub Issues.
logos/): 권리 보유 / all rights reserved — logos/LICENSE.mddist/fonts/에 원본 라이선스와 함께 들어 있습니다 / Subsets of Pretendard and Gowun Batang under SIL OFL 1.1, renamed per the Reserved Font Name; the woff2 files ship in dist/fonts/ with their licenses.원본은 src/에 있습니다: 토큰 src/tokens.json, 스타일 src/bundle.css, React src/core.js, Svelte src/svelte/, 공통 함수 src/utils.js.
npm install 후 npm run build로 dist/와 svelte/를 만들고, npm run check로 대비(크레마 위 포함), Svelte·React 타입, 서버 렌더링, 동작·접근성 테스트를 검사합니다. 질감이나 간격을 바꿨다면 npm run visual로 114개 화면을 기준 이미지와 비교하고, 의도한 변화면 npm run visual:update로 기준을 갱신합니다(처음 한 번 npx playwright install chromium). 같은 검사가 GitHub Actions에서도 돕니다.
Sources live in src/. After npm install, run npm run build to generate dist/ and svelte/, and npm run check to verify contrast (including text on crema), Svelte and React types, and server rendering. CI runs the same checks.