Crates.io | grimoire_css |
lib.rs | grimoire_css |
version | 1.1.0 |
source | src |
created_at | 2024-10-21 01:20:39.19191 |
updated_at | 2024-11-23 03:09:41.700077 |
description | A magical CSS system engine for all environments |
homepage | https://github.com/persevie/grimoire-css |
repository | https://github.com/persevie/grimoire-css |
max_upload_size | |
id | 1416790 |
size | 767,468 |
Grimoire CSS is a comprehensive CSS system engine crafted in Rust,
focusing on unmatched flexibility, reusable dynamic styling, and optimized performance for every environment.
Demo projects and recipes are on the way. Stay tuned for updates!
Grimoire CSS is more than just a framework - it’s your entry into a circle of developers who wield the true power of CSS. By mastering Spells and Scrolls, you’ll craft styles with precision, control, and a touch of magic. Whether you’re building responsive interfaces or optimizing for performance, Grimoire empowers you to write CSS in a way that feels both natural and powerful. Welcome to the circle, where the limits of traditional styling fade away, and the full potential of CSS is revealed.
At the heart of Grimoire CSS lies the Spell
, the foundational entity of the system. Spell
takes a different approach from traditional utility classes, like those you’d find in Tailwind. While utilities in Tailwind feel like slightly enhanced Bootstrap classes, Grimoire CSS takes things to a new level. In Tailwind, you’re expected to memorize arbitrary names like rounded-md
for border-radius: 0.375rem
- which doesn’t even make things look rounded. And then there’s tracking-tight
for letter-spacing: -0.025em
. How are you supposed to know that’s related to letter spacing?
Grimoire CSS cuts through that confusion by introducing Spell
- an approach that is both simple and infinitely flexible. At its core, a Spell
is just a CSS declaration, written in a format everyone understands: property=value
. For example, border-radius: 0.375rem
in Grimoire CSS becomes border-radius=0.375rem
. If you prefer something shorter, br=0.375rem
works too, or even br=.375rem
(yes, Grimoire CSS respects CSS's own shorthand capabilities). Unlike pre-baked utility classes, Spells
follow the natural structure of CSS: property: value
becomes component=target
.
This isn't just another syntax. It’s the whole system reimagined. You’re free to write any value in the target, whether it's custom units, functions, or even complex animations. Everything CSS supports is fair game, and all you need to do is escape spaces with underscores (_
). That’s it. Of course, we didn't stop at the basics. Spells also introduce optional enhancements: area
, focus
, and effects
, which give you deeper control over media queries, pseudo-classes, attributes, and more.
area
: You know those media queries that clutter your CSS? In Grimoire CSS, they’re handled elegantly by area
. The area
defines conditions like screen size and sits at the start of your spell, separated from the rest by double underscores (__
). For example, (width>=768px)__br=0.375rem
will activate the rule only for screens wider than 768px. Prefer a shorthand? You can use built-in names like md__br=0.375rem
. It’s still valid CSS, but with all the magic of Spell
.
focus
: Sometimes, you need more than a class or a media query. focus
lets you wrap anything - attributes, pseudo-classes, or nested selectors - inside your spell. Placed as the second part of the spell (or first if there's no area
), it’s enclosed in curly brackets. For example: {[hidden]_>_p:hover:active}color=red
becomes this CSS:
... [hidden] > p: hover:active {
color: red;
}
It’s not just readable - it’s intuitive. What you see is exactly what you get.
effects
: Sometimes, you need quick pseudo-classes without the full complexity of focus
. That’s where effects
come in. Just add pseudo-classes directly in the spell like this: hover,active:color=blue
. With effect
, you keep it compact without losing any power. Simply separate it from the component
and target
with a colon (:
).
The entire Spell
system is built on clarity and explicitness. There are no magical, arbitrary strings for targets like you find in other systems. And we don’t compromise on clarity for the sake of brevity. Targets are full, valid CSS values - because that’s how it should be. Components mirror actual CSS properties, but they can be shortened to your liking. In this way, Grimoire CSS is both a CSS declaration and a methodology. It’s so powerful because every Spell
is valid CSS - there’s no abstraction that gets in the way of what you need to achieve.
So, why call it a Spell
? Because, like magic, it’s composed of multiple elements: area
, focus
, effect
, component
, and target
. And each of these pieces works together to create something far greater than the sum of its parts. With Grimoire CSS, you’re not just writing styles - you’re casting spells. The name ‘Grimoire’ comes from ancient magical texts. Just as those books hold the knowledge to perform spells, Grimoire CSS provides you the knowledge and tools to perform CSS magic - without relying on pre-baked solutions. You’re in full control.
area__{focus}component=target
or area__effect:component=target
.-
) to separate words and underscores (_
) to escape spaces.A Scroll
is like a Spell
, but with one crucial difference - it’s something you build from scratch. Think of it as a customized collection of styles, bundled into one reusable class. Sometimes, you need to combine multiple styles into a single class for consistency, reusability, or just to make your life easier. With Scroll
, you can do just that. Combine spells, give your new creation a name, and you’ve got a Scroll
ready to use across your projects.
And here's the best part: everything you love about Spells
works seamlessly with Scrolls
too - area
, focus
, effect
, and even target
. But there’s even more: when you define a Scroll
, you can introduce variables to make your styles dynamic. Just use the $
symbol, and the target
becomes a placeholder, waiting for the actual value to be filled in. Want to create a button class that accepts variable values? No problem. Here’s an example:
"scrolls": [
{
"name": "btn",
"spells": [
"p=6px",
"br=$",
"ac=center",
"bg=none",
"bgc=$",
"cur=pointer",
"hover:bgc=$",
"active:bgc=$",
"xl__min-w=32px",
"xl__p=10px",
"xl__hover:fw=bold"
]
}
]
This btn
scroll expects four target values, and if you pass fewer or more, Grimoire CSS will kindly let you know. The targets are applied in order, giving you incredible flexibility. But we’re not done yet.
Scrolls
: The Power of CompositionOne of the most exciting aspects of Scrolls
is inheritance. Yes, you can extend a Scroll
with another Scroll
. Combine and compose them endlessly to create complex, reusable styles. Let’s take a look:
"scrolls": [
{
"name": "btn",
"spells": [
"p=6px",
"br=$",
"ac=center",
"bg=none",
"bgc=$",
"cur=pointer",
"hover:bgc=$",
"active:bgc=$",
"xl__min-w=32px",
"xl__p=10px",
"xl__hover:fw=bold"
]
},
{
"name": "danger-btn",
"extends": [
"btn"
],
"spells": [
"hover:g-anim=vibrate-3",
"anim-ic=infinite",
"c=white"
]
},
{
"name": "danger-btn-rnd",
"extends": [
"danger-btn",
"round"
],
"spells": []
},
{
"name": "round",
"spells": [
"border-radius=999999px",
"h=$",
"w=$"
]
}
]
In this example, danger-btn
extends btn
, meaning it inherits all of btn
's spells plus its own. So, danger-btn.spells
will look like btn.spells
+ danger-btn.spells
, with the parent scroll's styles taking priority at the top.
But the fun doesn’t stop there - danger-btn-rnd
extends both danger-btn
and round
. This means that danger-btn-rnd.spells
equals btn.spells
+ danger-btn.spells
+ round.spells
, combined in the correct order. And yes, the order matters. This layered inheritance allows you to build complex style structures effortlessly.
The real magic of Scrolls
lies in their unlimited possibilities. You can chain styles together, extend them endlessly, and define variables as placeholders to create flexible, reusable patterns across your entire project. With Scrolls
, Grimoire CSS goes far beyond being Yet Another CSS Framework. In fact, you could even recreate the entire structure of Tailwind or Bootstrap using nothing but the flexibility of Spells and Scrolls.
It’s pure, beautiful madness - without limits.
In Grimoire CSS, managing your projects is as flexible as the spells themselves. You define exactly which files need to be parsed (inputPaths
, supporting glob patterns) and specify where the built CSS should go (outputDirPath
).
You also have two powerful options for compiling your CSS:
For single output mode, you’ll just need to define the name of the final CSS file with singleOutputFileName
. The flexibility here allows you to control the output method depending on your project’s needs. Every project configuration contains a name
property and can include as many projects as you want. Whether you’re building a single-page application (SPA) or managing multiple projects, Grimoire CSS has you covered.
In essence, the projects section of your config is a list of projects, each with its own unique input and output settings. Here’s how that might look:
"projects": [
{
"projectName": "personal",
"inputPaths": [
"personal/src/*.tsx"
],
"outputDirPath": "personal",
"singleOutputFileName": "personal.build.css"
},
{
"projectName": "blog",
"inputPaths": [
"blog/*.html"
],
"outputDirPath": "grimoire/build/blog"
},
{
"projectName": "mix",
"inputPaths": [
"about/hero.tsx",
"blog/index.html"
],
"outputDirPath": "grimoire/build/mix",
"singleOutputFileName": "mix.css"
}
]
Grimoire CSS gives you full control over how you manage and compile your styles. You can configure projects for different output strategies depending on whether you're building large, single-page applications or static sites with multiple pages. The flexibility to switch between single or multiple output files means you’re never locked into one approach. Grimoire adapts to your needs, not the other way around.
Grimoire CSS makes it easy to define shared and critical CSS alongside your project-specific styles, allowing you to optimize how styles are applied across your entire application.
Shared CSS is exactly what it sounds like - a set of styles that you can build into a separate file and reuse across multiple projects or pages in your application. By defining shared styles, you ensure consistency and reduce repetition, improving performance and maintainability.
Critical CSS goes a step further. It automatically inlines essential styles directly into your HTML files, ensuring that key styles are loaded instantly. And here’s the clever part: if some spells are already used in your components or files, Grimoire won’t regenerate them - because they’re now part of your critical CSS. No duplicates, no unnecessary bloat - just efficient, fast-loading styles.
Both the shared
and critical
sections of the config are similar in structure. Each has:
styles
: An optional list of styles that are used in the shared or critical configuration. You can include any spells, scrolls, or even paths to existing CSS files. Grimoire will extract and optimize the content during compilation.cssCustomProperties
: An optional list of custom CSS properties, which gives you the flexibility to define your own properties and pair them with specific elements or themes.For shared CSS, you’ll define an outputPath
- the file where your shared styles will be stored. For critical CSS, you’ll define fileToInlinePaths
- a list of HTML files (or glob patterns) where these essential styles should be inlined.
Let’s take a look at some examples:
In the cssCustomProperties
section, you can define custom properties and their key-value pairs for any DOM elements in your app. Here are the key parts of this configuration:
element
: The optional DOM element associated with the CSS variable (e.g., tag
, class
, id
, or even :root
).dataParam
: The parameter name used in your CSS configuration.dataValue
: The corresponding value for that parameter.cssVariables
: A set of CSS variables and their values that will be applied to the element.Here’s how this might look in JSON:
"cssCustomProperties": [
{
"element": "body",
"dataParam": "theme",
"dataValue": "light",
"cssVariables": {
"base-bg-clr": "white"
}
},
{
"element": "body",
"dataParam": "theme",
"dataValue": "dark",
"cssVariables": {
"base-bg-clr": "black"
}
}
]
This structure allows you to define theme-specific variables, making it easier to maintain consistency across your application.
Here’s a complete example of how you might configure shared
and critical
CSS in Grimoire:
"shared": [
{
"cssCustomProperties": [],
"outputPath": "shared.css",
"styles": [
"font-size=20px"
]
}
],
"critical": [
{
"fileToInlinePaths": [
"about/*.html",
"blog/*.html"
],
"styles": [
"reset.css",
"padding=10%_24px",
"c=darkblue",
"anim-n=swing"
],
"cssCustomProperties": [
{
"element": "body",
"dataParam": "theme",
"dataValue": "light",
"cssVariables": {
"base-bg-clr": "white"
}
},
{
"element": "body",
"dataParam": "theme",
"dataValue": "dark",
"cssVariables": {
"base-bg-clr": "black"
}
}
]
}
]
In this example:
font-size=20px
) and outputs to shared.css
.about
and blog
directories, ensuring essential styles like reset.css
, padding, colors, and animations load immediately.Grimoire CSS doesn’t just help you manage your styles - it ensures that only the CSS you actually need is generated. No duplicates, no wasted space. Whether it’s shared across multiple projects or inlined for critical loading, Grimoire makes sure your CSS is lean, efficient, and optimized for performance.
Grimoire CSS doesn’t just give you the tools to build powerful styles from scratch - it also comes with a set of predefined scrolls to help you get started right away. All predefined scrolls follow the same convention: they begin with the prefix g-
. This makes it easy to distinguish built-in scrolls from the ones you define yourself.
Grimoire CSS comes loaded with hundreds of built-in animations (700+ at the moment). These animations are lightweight and efficient - they are only compiled if you actually use them. To trigger one, simply use its name in either the animation-name
or animation
CSS rule. But Grimoire CSS doesn’t stop at just applying animations; it also simplifies the process of adding associated rules.
For example, the predefined scroll g-anim
allows you to apply an animation and its associated rules at the same time. Here, g-
is the prefix, and anim
is a short version of the spell animation
. With this scroll, you can quickly inject an animation along with the necessary rules - saving time and keeping your styles clean and organized.
Even though Grimoire CSS comes packed with animations, it also gives you the power to add your own, seamlessly integrating them into your projects. It’s as simple as creating a new subfolder called animation
inside the grimoire
folder, then adding your custom CSS file using the format <name-of-animation>.css
.
Within that file, you define your animation using @keyframes
, along with any custom styles. You can also use the class placeholder GRIMOIRE_CSS_ANIMATION
to add specific styles tied to the animation itself. Let’s take a look at an example with a custom pulse animation:
@keyframes pulse {
from {
transform: scale3d(1, 1, 1);
}
50% {
transform: scale3d(1.05, 1.05, 1.05);
}
to {
transform: scale3d(1, 1, 1);
}
}
.GRIMOIRE_CSS_ANIMATION {
animation-name: pulse;
animation-timing-function: ease-in-out;
}
In this example, you’ve defined the pulse animation and set it up with ease using the GRIMOIRE_CSS_ANIMATION
placeholder. Once this file is in your project, you can invoke the pulse animation as easily as any built-in animation, giving you complete control over custom animations.
Grimoire CSS allows you to define your own variables within its settings, making your styling even more dynamic and customizable. Unlike custom properties, these variables don’t compile into shared or critical CSS. Instead, they remain in your settings and are only compiled when used - keeping your CSS clean and efficient.
You can define any value as a variable - font sizes, colors, dimensions, anything. To reference them in your styles, just add the $
symbol before the variable name (you’ll remember this from the Scroll
section). Here’s how you define and use a variable:
{
"variables": {
"hero-fs": "42px"
}
}
<h1 class="fs=$hero-fs">Hero text</h1>
In this example, the hero-fs
variable holds the value 42px
, which is then applied to the font-size
of the <h1>
element. Variables in Grimoire CSS offer a simple and effective way to maintain consistency across your styles, while keeping your code flexible and DRY (Don’t Repeat Yourself).
Grimoire CSS follows a mobile-first approach and comes with built-in responsive areas, including sm
, md
, lg
, xl
, and 2xl
. When you define a spell with one of these areas, like md__w=100px
, the spell will apply only when the screen width is equal to or greater than the specified area.
For example, md__w=100px
is equivalent to this media query:
(width>=768px)__w=100px
.
Of course, you’re not limited to the built-in areas. You can define your own media queries just as easily, like this:
(width>666px)__w=100px
With these areas, you have full control over your responsive design, but without the hassle of constantly writing and rewriting media queries.
mrs
and mfs
Grimoire CSS takes responsive design even further with built-in functions like mrs
(Make Responsive Size) and mfs
(Make Fluid Size, coming soon). These functions allow you to adapt font sizes, widths, and more based on the viewport size.
mrs
: Make Responsive SizeThis function dynamically adjusts the size of an element between a minimum and maximum value, depending on the viewport width. Here are the arguments:
min_size
: The minimum size for the element.max_size
: The maximum size for the element.min_vw
: (Optional) The minimum viewport width.max_vw
: (Optional) The maximum viewport width.<p class="fs=mrs(12px_36px_480px_1280px)">
Font size of this text will dynamically change based on the screen size
</p>
In this example, the font size will automatically adjust between 12px and 36px, depending on the screen size, with fluid adjustments in between. This makes responsive design not only easier but more precise, without the need for complex calculations or multiple breakpoints.
With Grimoire CSS, you don’t just write styles - you take control of them. By leveraging variables, responsive areas, and adaptive size functions, you can make your CSS dynamic, scalable, and ready for any device or screen size. It’s flexibility without the fuss, and it’s all built right in.
Grimoire CSS takes optimization seriously. It generates only the CSS that’s actually used, and it monitors for duplicates right from the start, ensuring no unnecessary styles sneak through. This happens at the very early stages of generation, so by the time the process finishes, you’ve got a lean, clean stylesheet.
But it doesn’t stop there. Grimoire CSS integrates LightningCSS to take your code to the next level:
.browserlistrc
file using 'defaults' if you don’t already have one.All of this happens while preserving the CSS cascade - no unintentional overwrites, no broken styles. Just clean, optimized CSS that’s ready for any environment.
Grimoire CSS is written entirely in Rust, a language designed for high performance. But we didn’t stop at Rust’s natural speed. Grimoire CSS is built with a commitment to efficiency, ensuring your CSS generation is fast, scalable, and precise.
Grimoire CSS isn’t just tied to traditional CSS, JavaScript, or HTML files. The beauty of its language-agnostic parser is that it can parse spells from any file or extension. Whether you’re working with .html
, .tsx
, .mdx
, or something else entirely, Grimoire CSS can handle it.
This means you’re not limited by file types or formats - you define the inputPaths
, and Grimoire CSS takes care of the rest. Whether your project is built with React, Vue, or something entirely different, Grimoire CSS seamlessly integrates and extracts the styles you need.
If you want to use spells outside the traditional class
or className
attributes, Grimoire CSS provides a clever solution with its template syntax: g!<spell>;
. This syntax lets you wrap your spell in a template, enabling the parser to collect spells from any text-based content.
Let’s say you have both a classic spell and a templated spell that are essentially the same. Don’t worry - Grimoire CSS is smart enough to combine them into one, as long as it doesn’t affect the CSS cascade. The result? Clean, efficient CSS output like this:
.classic,
.templated {
/* CSS declaration */
}
This flexibility means you can integrate Grimoire CSS in non-traditional environments, using it across various file types and even in plain text. It's not just tied to the web - it’s ready for any project, anywhere.
Grimoire CSS comes with a minimal but powerful CLI (Command Line Interface) that’s designed for simplicity and efficiency. Whether you’re integrating it into your build process or running it manually, the CLI gets the job done without unnecessary complexity.
There are only two commands you need to know:
init
: Initializes your Grimoire CSS configuration, either by loading an existing config or generating a new one if none is found. This is your starting point.build
: Kicks off the build process, parsing all your input files and generating the compiled CSS. If you haven’t already run init
, the build
command will handle that for you automatically.Grimoire CSS’s CLI is built for developers who want power without bloat. It’s direct, no-nonsense, and integrates smoothly into any project or bundler.
Here’s a refined version of the remaining parts, keeping the technical depth and making them more engaging and polished:
Migrating to Grimoire CSS is simple, thanks to the Grimoire CSS Transmute utility, also known as gcsst. This CLI tool takes the paths of your built CSS files (or the content of built CSS if you’re working in a web environment) and returns a transmuted.json file in the following format:
{
"classes": [
{
"name": "old-class-name",
"spells": ["spell-1", "spell-2"],
"oneliner": "spell-1 spell-2"
}
]
}
gcsst parses the existing CSS and automatically generates corresponding spells for each class. One of the standout features of gcsst is the structure of the transmuted.json file, particularly the classes property. It’s designed to look like the structure of a scroll, except for the oneliner
property. This makes it incredibly easy to create a scroll or copy-paste the single-line class into your component with minimal effort.
By simplifying the migration process, gcsst helps you move to Grimoire CSS without hassle, and you can instantly start leveraging the power of spells.
Explore the gcsst repository or try it online.
Grimoire CSS is built to integrate seamlessly into a wide range of ecosystems. It’s distributed in three ways to give you maximum flexibility:
The core of Grimoire CSS is architected entirely in Rust, ensuring top-notch performance and scalability. The main repository compiles both into a standalone executable (SEA) and a Rust crate, meaning you can use it in different environments with ease.
The grimoire-css-js
takes the core crate and wraps it into a Node.js-compatible interface, which is then compiled into an npm package. Whether you’re working with Rust, Node.js, or need a direct CLI, Grimoire CSS is ready to integrate into your workflow and bring powerful CSS management wherever you need it.
Rust crate:
If you’re using Rust, simply add Grimoire CSS to your Cargo.toml, and follow the link for documentation about crate: docs.rs.
cargo install grimoire_css
Single Executable Application (SEA):
NPM Library:
npm i @persevie/gcssjs
Once installed, you can run the following commands:
Initialize a Grimoire CSS config in your project:
grimoire_css init
or if you are using NPM library:
gcssjs init
Build your CSS using the Grimoire CSS config:
grimoire_css build
or if you are using NPM library:
gcssjs build
Grimoire CSS gives you the freedom to create styles that work exactly the way you want them to - no rigid rules or constraints. Whether you’re crafting dynamic interactions or fine-tuning layouts, Grimoire adapts to your needs, making each step straightforward and rewarding.
So, come join us. Share your work, exchange your thoughts, and help us keep pushing CSS to be more flexible and enjoyable. Together, we’re creating a space where writing styles is about mastery and craftsmanship, not about memorizing classes. Let’s see what we can build - one spell at a time.
Craft Your Code, Cast Your Spells