Write TypeScript functions in your CSS. Compose reusable directives that generate declarations, selectors, animations, and more at build time.
• ⚡ Zero Runtime — Compiles to CSS at build time via lightningcss. No client JavaScript added.
• 🖊️ CSS Native — Feels like writing plain CSS.
• 🎨 Rich Helpers — Built-in backgrounds, colors, math, transforms, borders, and layout helpers.
• 🔌 Extensible — Custom directives with defineHelper. Schema validation, aliases, and root-level CSS generation.
• 🏗️ Vite Plugin — Drop-in integration with HMR, @import inlining, and automatic directive loading.
• 🛡️ Schema Validated — Runtime argument validation with valibot. Clear error messages on misuse.
• 🏷️ Custom Properties — Emit --var declarations and @property rules automatically.
bun add @subwaytime/tscss
# or
npm install @subwaytime/tscss
# or
pnpm add @subwaytime/tscss
# or
yarn add @subwaytime/tscssAdd the plugin to your vite.config.ts:
import { defineConfig } from 'vite';
import { tscss } from '@subwaytime/tscss/vite';
export default defineConfig({
plugins: [
tscss(),
],
});Now use tscss directives in your CSS:
.test {
@paper(50px);
color: @mix(red, blue, 50);
border-radius: @perfectBorder(inner, 1rem, 0.25rem);
}The plugin automatically inlines @import statements, resolves custom directives, and provides HMR for directive files.
.test {
@paper(50px); /* blueprint grid */
@grid(20px); /* line grid */
@dotPattern(10px); /* dot pattern */
@checkerboard(20px); /* checkerboard */
@verticalLines(20px); /* vertical stripes */
@horizontalLines(20px); /* horizontal stripes */
}.test {
color: @mix(red, blue, 50);
color: @lighten(#333, 20);
color: @darken(#fff, 10);
color: @opacity(red, 50);
color: @complement(red);
color: @black(#ff0000, 30);
color: @white(#ff0000, 30);
color: @tint(#333, 20);
color: @saturate(red, 50);
color: @grayscale(#ff0000);
}.test {
font-size: @pxToRem(16px);
width: @lerp(0px, 100px, 0.5);
margin: @negate(1rem);
@ratio(100px, 200px);
color: @toOklch(#ff0000);
color: @toOklab(#ff0000);
color: @toRgb(#ff0000);
color: @toHsl(#ff0000);
color: @toHwb(#ff0000);
}.btn {
@perfectBorder(inner, 1rem, 0.25rem);
}
.grid {
@autoGrid(200px, 3);
}import { cssVar } from '@subwaytime/tscss/directives';
const primary = cssVar('primary');
// @primary(blue) → --primary: blue
const size = cssVar({
name: 'size',
transform: (v) => `calc(${v} / 16px * 1rem)`,
});
// @size(16px) → --size: calc(16px / 16px * 1rem)
const typedColor = cssVar({
name: 'primary',
typed: { syntax: '<color>', inherits: false, initialValue: 'blue' },
});
// @primary(red) → @property --primary { ... } + --primary: redconst bg = declaration('background', (args) =>
`linear-gradient(${args[0]}, transparent)`
);
// .test { @bg(red); } → background: linear-gradient(red, transparent);const hover = selector(() => '&:hover');
// .btn { @hover() { color: red; } } → .btn:hover { color: red; }const mobile = media('(max-width: 768px)');
// @mobile { padding: 1rem; } → @media (max-width: 768px) { padding: 1rem; }const fadeIn = keyframes('fadeIn', {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
});
// animation: @fadeIn 0.3s ease → @keyframes fadeIn { ... }const myFont = fontFace({ src: "url('/font.woff2')", family: 'MyFont' });
// @myFont → @font-face { ... } + font-family: MyFont;import { defineHelper } from '@subwaytime/tscss/directives';
const hero = defineHelper({
property: 'background',
value: (args) => `linear-gradient(${args[0] || 'red'}, blue)`,
});
// .test { @hero; } → background: linear-gradient(red, blue);Custom directives support schema validation, aliases, spawn for root-level CSS generation (e.g., @keyframes, @font-face), and .value composition.
All helpers accept natural CSS syntax without quotes:
.test {
color: @mix(red, blue, 50);
color: @mix('red', 'blue', '50');
width: @lerp(0px, 100px, 0.5);
background: @black(var(--origin), 30);
}Load custom directives from a directory:
import { defineConfig } from 'vite';
import { tscss } from '@subwaytime/tscss/vite';
export default defineConfig({
plugins: [
tscss({
directives: './src/css-directives',
include: /\.css$/,
exclude: /node_modules/,
}),
],
});The plugin loads .ts and .js files from the specified directory and makes them available as directives in your CSS.
bun install
bun test
bun run bundleMIT © 2026-PRESENT Leon Langer