docs v0.1
Magic Formula
+ Simplicity of plain HTML, JS, CSS
+ Flexibility of modular components
+ Stability of precompiled languages
=MAGIC.
essencekit turns pure creativity into precise reality.
Installation
Prerequisites
Ensure your system has:
- Node.js
- npm
- git
Quick Start
git clone git@github.com:essencekit/essencekit.git
cd essencekit
npm install && npm link
essencekit build
Your generated site will appear in the Pub folder.
Directory Structure
- App → Application files: components, overrides, global config
- Core → The heart of the project
- Pub → Rendered static files per environment
Component System
To create a component, simply add a new folder and HTML file under App/Components
. Each component can have unlimited sub‑components.
Component structure example:
App/
└── Components/
└── SomeComponent/
├── SubComponent/
│ └── OneMoreComponent.html
├── SomeComponent.html
├── AnotherComponent.html
└── config.json
Components can extend others by specifying a parent in config.json.
State
essencekit provides simple state management for handling both global and local states easily.
Global State Example
A minimal global state for theme switching:
<button id="toggle-theme">Toggle Theme</button>
<script>
window.addEventListener('globalStateReady', () => {
document.getElementById('toggle-theme').onclick = () => {
const newTheme = globalState.getState().theme === 'dark' ? 'light' : 'dark';
globalState.setState({ theme: newTheme });
document.body.setAttribute('data-theme', newTheme);
};
});
</script>
Local State Example
Local state for managing interactive elements:
<form id="chat-form">
<input name="prompt" placeholder="Your message..." />
<button type="submit">Send</button>
</form>
<div id="response"></div>
<script type="module">
import State from '@ASSETS@/State/Manager.js';
const chatForm = document.getElementById('chat-form');
const chatState = new State({ messages: [] });
chatForm.onsubmit = (e) => {
e.preventDefault();
const prompt = e.target.prompt.value;
chatState.setState({
messages: [...chatState.getState().messages, prompt],
});
document.getElementById('response').innerText = 'Sent: ' + prompt;
e.target.prompt.value = '';
};
</script>
Preserving State Across Pages
You can persist state using localStorage
, ensuring state continuity between page loads:
// Saving state to localStorage
localStorage.setItem('chatMessages', JSON.stringify(chatState.getState().messages));
// Loading state from localStorage
const savedMessages = JSON.parse(localStorage.getItem('chatMessages') || '[]');
const chatState = new State({ messages: savedMessages });
Use these minimal states to keep interactions clear, responsive, and maintainable.
Template Engine
1. Call a component – pass it whatever data you need
@{SomeComponent, {"someKey": "data"}}
2. Inside SomeComponent
you can access that key (or any config value) with:
@[someKey]
3. Chain another component – a component can invoke another component the same way:
@{AnotherComponent}
Conditional & loops:
@if(some.condition)
...
@else
...
@endif
@each(item in some.list)
...
@end
Project Lifecycle
To build and deploy your essencekit site, run:
essencekit build
This compiles and outputs the generated website into the Pub/dev
folder by default.
Namespaces and Strict Mode
To deploy with specific configurations, use namespaces (like prod
):
essencekit build prod
Using the prod
namespace activates strict mode, preventing deployments with rule violations. The build will halt on errors, ensuring your production environment remains stable.
Custom post‑processing is supported. Minification is enabled by default.
The final result is a fully static site composed of HTML, JS, and CSS.
Rules
Rules in essencekit ensure best practices, consistency, and stability across your project. Rules are defined under the App/Rules
directory and configured within your App/config.json
:
Configuration Example (App/config.json
):
{
"rules": {
"enabled": true,
"strict": true,
"sources": [
"Rules/customRules.js"
]
}
}
Rule Definition Example (App/Rules/customRules.js
):
export default [
{
name: 'title-required',
description: 'Component config must have a title.',
check(html, component) {
if (!component?.config?.title) {
return `Missing title in component: ${component.name}`;
}
}
}
];
Each rule consists of:
- name: Short identifier for the rule.
- description: Explanation of the rule’s purpose.
- check: Function to validate the rule; returns an error message when conditions fail.
Use strict mode to enforce compliance during production builds, keeping your deployments safe and consistent.
You can skip rules entirely if they're not needed for your project.
PostProcess
Post‑processing in essencekit optimizes the final HTML output. Minification is enabled by default, but you can add custom steps as needed.
Post‑processors live under App/PostProcess
and are configured in App/config.json
.
Configuration Example (App/config.json
):
{
"postProcess": {
"enabled": true,
"sources": [
"PostProcess/smila.js"
]
}
}
PostProcessor Example (App/PostProcess/smila.js
):
export default function (html) {
// Insert a smiley just before the closing tag
return html.replace('</body>', '😊</body>');
}
Use post‑processors to keep your builds clean, performant, and optimized for production.
Playground
Explore essencekit features with examples in the repository's App
folder. Deploy and test freely.
Configuration Levels
Configurations hierarchy:
.env
→ API keysApp/config.json
→ Global settings- Component
config.json
→ Scoped settings
.env Configuration
Set API keys here. Copy .env.example
to .env
to start configuring your API keys.
Global Config
Example (App/config.json
):
{
"rules": {
"enabled": true,
"strict": true,
"sources": [
"essencekit-rules-basic",
"Rules/customRules.js",
"Rules/htmlLintRules.js"
]
},
"auth": {
"endpoint": "http://localhost:3000/api/auth/login"
},
"apiGroups": {
"main": "https://jsonplaceholder.typicode.com",
"openai": "https://api.openai.com/v1"
},
"apiAuth": {
"openai": {
"type": "Bearer",
"token": "OPENAI_KEY"
}
}
}
Component Config
Example (App/Components/Index/config.json
):
{
"extends": "BasePage",
"title": "essencekit Home Page",
"description": "Minimalist web framework focused on speed, simplicity, and fun.",
"render": true,
"auth": true,
"api": [
{
"dataGroup": "main",
"dataSource": "/posts",
"postType": true,
"postName": "sendPost"
}
]
}
Only components with render: true
are rendered. It is possible to skip config.json
altogether and simply call the component from another component.
API System
Global Configuration
Define your APIs in the global configuration file: App/config.json
{
"apiGroups": {
"openai": "https://api.openai.com/v1",
"main": "https://jsonplaceholder.typicode.com"
},
"apiAuth": {
"openai": {
"type": "Bearer",
"token": "OPENAI_KEY"
}
}
}
Component Configuration
Use APIs within your components by defining them in your component config:
GET Example
{
"api": [
{
"dataGroup": "main",
"dataSource": "/posts",
"getType": "static",
"injectAs": "posts"
}
]
}
Template Usage:
@if(posts.length)
<ul>
@each(post in posts)
<li>@[post.title]</li>
@end
</ul>
@else
<p>No posts available.</p>
@endif
POST Example
Define the POST endpoint in your component config:
{
"extends": "BasePage",
"title": "essencekit Home Page",
"description": "essencekit is a minimalist web framework focused on speed, simplicity, and fun.",
"render": true,
"auth": true,
"api": [
{
"dataGroup": "main",
"dataSource": "/posts",
"postType": true,
"postName": "sendBlessing"
}
]
}
Template usage with a form:
<form onsubmit="essenceAPI.sendBlessing({
title: this.title.value,
message: this.message.value,
userId: 1}).then(res => console.log('✅ Sent:', res)); return false;">
<input name="title" placeholder="Type a title..." />
<input name="message" placeholder="Type a blessing..." />
<button type="submit">Bless essencekit</button>
</form>
Future Implementation
Currently, only getType: "static"
is implemented.
Soon, getType: "dynamic"
will allow personalized refetching of data upon reload or after a defined expiration period without needing to redeploy the application.
Naming Conventions
- Classes: UpperCamelCase (
Renderer
) - Functions/Utilities: lowerCamelCase (
generateClientPost
)
Monorepo as Launchpad
The entire essencekit ecosystem begins in a unified monorepo — a springboard for rapid development, seamless iteration, and tight integration. This setup accelerates early momentum and simplifies contributions. As the project evolves, the community will vote on whether to keep it unified or modularize into separate packages. The structure adapts to growth — not the other way around.
Routing
essencekit doesn't include built‑in routing, giving you full control to integrate your server’s rewrite rules. A dedicated router package might come later.
Overriding Principle
essencekit allows overriding core classes effortlessly: simply mirror the class path inside the App folder and modify imports. Maintain the same namespace but use your custom logic.
Example:
Original:
Core/Compiler/Renderer.js
Override:
App/Compiler/Renderer.js
Currently, only the Renderer class is override‑ready. More extensibility options are on the way.
Authentication Demo
To test authentication with the Auth component, set up the demo auth server — or use your own.
- Next.js auth demo: essencekit-auth-demo
- Follow repo README for setup instructions.
AI Workflows (Coming Soon)
Stay tuned for AI‑driven workflows.
Philosophy & Community
essencekit is community‑driven:
- Documentation is a knowledge base, not just a manual.
- Everyone is encouraged to share solutions and best practices.
- Your input shapes essencekit’s evolution.
Check and contribute to essencekit’s future: GitHub Issues
Contact us through our social networks for support.
And One More Thing...
All documentation is a suggestion, not a rulebook.
Experiment, explore, and share your insights on Twitter, Reddit, or GitHub.