@newlogic-digital/core 4.0.0-rc.8 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { styleText } from 'node:util'
4
+ import { getPackageInfo } from 'vituum/utils/common.js'
5
+
6
+ const { name } = getPackageInfo(new URL('../package.json', import.meta.url).href)
7
+ const [command] = process.argv.slice(2)
8
+
9
+ if (command === 'postinstall') {
10
+ await import('../src/createEslintStylisticConfig.js')
11
+ await import('../src/linkAgentSkills.js')
12
+ }
13
+ else {
14
+ console.error(`${styleText(['cyan', 'bold'], name)} ${styleText('red', `Unknown command "${command ?? ''}".`)}`)
15
+ process.exitCode = 1
16
+ }
package/index.js CHANGED
@@ -25,6 +25,7 @@ const defaultOptions = {
25
25
  assets: [
26
26
  './src/styles/*.{css,pcss,scss,sass,less,styl,stylus}',
27
27
  './src/scripts/*.{js,ts,mjs}',
28
+ './src/assets/**/*',
28
29
  ],
29
30
  pages: [
30
31
  './src/pages/**/*.{json,latte,twig,liquid,njk,hbs,pug,html}',
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@newlogic-digital/core",
3
3
  "type": "module",
4
- "version": "4.0.0-rc.8",
4
+ "version": "4.0.0",
5
5
  "main": "index.js",
6
+ "bin": {
7
+ "newlogic-core": "./bin/newlogic-core.js"
8
+ },
6
9
  "author": "New Logic Studio s.r.o.",
7
10
  "description": "Set of tools that can be used to create modern web applications",
8
11
  "license": "MIT",
9
12
  "scripts": {
10
- "postinstall": "node ./src/createEslintStylisticConfig.js",
11
13
  "tsc": "tsc",
12
14
  "oxlint": "oxlint",
13
15
  "oxlint-fix": "oxlint --fix",
@@ -16,30 +18,43 @@
16
18
  },
17
19
  "dependencies": {
18
20
  "@minify-html/node": "^0.18.1",
19
- "@newlogic-digital/vite-plugin-heroicons": "^1.1.0",
21
+ "@newlogic-digital/vite-plugin-heroicons": "^1.1.1",
20
22
  "@stylistic/eslint-plugin": "^5.10",
21
23
  "@stylistic/stylelint-config": "^4.0.0",
22
- "@vituum/vite-plugin-css-inline": "^2.0.0",
23
- "@vituum/vite-plugin-latte": "^2.0.0",
24
- "@vituum/vite-plugin-send": "^2.0.0",
24
+ "@vituum/vite-plugin-css-inline": "^2.0.2",
25
+ "@vituum/vite-plugin-latte": "^2.0.2",
26
+ "@vituum/vite-plugin-send": "^2.0.1",
25
27
  "browserslist": "^4.28.1",
26
28
  "browserslist-to-esbuild": "^2.1.1",
27
29
  "lightningcss": "^1.32.0",
30
+ "npm-check-updates": "^19.6.5",
28
31
  "oxlint": "^1.56.0",
29
32
  "stylelint-config-standard": "^40.0.0",
30
- "vituum": "^2.0.0"
33
+ "vituum": "^2.0.1"
34
+ },
35
+ "peerDependencies": {
36
+ "@tailwindcss/vite": "4.2.2",
37
+ "@vituum/vite-plugin-twig": "^2.0.1",
38
+ "vite": "^8.0.1"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "@vituum/vite-plugin-twig": {
42
+ "optional": true
43
+ },
44
+ "@tailwindcss/vite": {
45
+ "optional": true
46
+ }
31
47
  },
32
48
  "devDependencies": {
33
- "@tailwindcss/vite": "0.0.0-insiders.d24b112",
34
49
  "@types/node": "^25.5",
35
- "@vituum/vite-plugin-twig": "^2.0.0",
36
- "rolldown": "^1.0.0-rc.9",
37
- "typescript": "^5",
38
- "vite": "^8.0.0"
50
+ "rolldown": "^1.0.0-rc.10",
51
+ "typescript": "^5"
39
52
  },
40
53
  "files": [
54
+ "bin",
41
55
  "icons",
42
56
  "latte",
57
+ "skills",
43
58
  "src",
44
59
  "types",
45
60
  "eslint-stylistic.json",
@@ -0,0 +1,246 @@
1
+ ---
2
+ name: figma-implement-design
3
+ description: Translate Figma nodes into production-ready code with 1:1 visual fidelity using the Figma MCP workflow (design context, screenshots, assets, and project-convention translation). Trigger when the user provides Figma URLs or node IDs, or asks to implement designs or components that must match Figma specs. Requires a working Figma MCP server connection.
4
+ ---
5
+
6
+ # Implement Design
7
+
8
+ ## Overview
9
+
10
+ This skill provides a structured workflow for translating Figma designs into production-ready code with pixel-perfect accuracy. It ensures consistent integration with the Figma MCP server, proper use of design tokens, and 1:1 visual parity with designs.
11
+
12
+ ## Prerequisites
13
+
14
+ - Figma MCP server must be connected and accessible
15
+ - User must provide a Figma URL in the format: `https://figma.com/design/:fileKey/:fileName?node-id=1-2`
16
+ - `:fileKey` is the file key
17
+ - `1-2` is the node ID (the specific component or frame to implement)
18
+ - **OR** when using `figma-desktop` MCP: User can select a node directly in the Figma desktop app (no URL required)
19
+ - Project should have an established design system or component library (preferred)
20
+
21
+ ### Step 1: Get Node ID
22
+
23
+ #### Option A: Parse from Figma URL
24
+
25
+ When the user provides a Figma URL, extract the file key and node ID to pass as arguments to MCP tools.
26
+
27
+ **URL format:** `https://figma.com/design/:fileKey/:fileName?node-id=1-2`
28
+
29
+ **Extract:**
30
+
31
+ - **File key:** `:fileKey` (the segment after `/design/`)
32
+ - **Node ID:** `1-2` (the value of the `node-id` query parameter)
33
+
34
+ **Note:** When using the local desktop MCP (`figma-desktop`), `fileKey` is not passed as a parameter to tool calls. The server automatically uses the currently open file, so only `nodeId` is needed.
35
+
36
+ **Example:**
37
+
38
+ - URL: `https://figma.com/design/kL9xQn2VwM8pYrTb4ZcHjF/DesignSystem?node-id=42-15`
39
+ - File key: `kL9xQn2VwM8pYrTb4ZcHjF`
40
+ - Node ID: `42-15`
41
+
42
+ #### Option B: Use Current Selection from Figma Desktop App (figma-desktop MCP only)
43
+
44
+ When using the `figma-desktop` MCP and the user has NOT provided a URL, the tools automatically use the currently selected node from the open Figma file in the desktop app.
45
+
46
+ **Note:** Selection-based prompting only works with the `figma-desktop` MCP server. The remote server requires a link to a frame or layer to extract context. The user must have the Figma desktop app open with a node selected.
47
+
48
+ ### Step 2: Fetch Design Context
49
+
50
+ Run `get_design_context` with the extracted file key and node ID.
51
+
52
+ ```
53
+ get_design_context(fileKey=":fileKey", nodeId="1-2")
54
+ ```
55
+
56
+ This provides the structured data including:
57
+
58
+ - Layout properties (Auto Layout, constraints, sizing)
59
+ - Typography specifications
60
+ - Color values and design tokens
61
+ - Component structure and variants
62
+ - Spacing and padding values
63
+
64
+ **If the response is too large or truncated:**
65
+
66
+ 1. Run `get_metadata(fileKey=":fileKey", nodeId="1-2")` to get the high-level node map
67
+ 2. Identify the specific child nodes needed from the metadata
68
+ 3. Fetch individual child nodes with `get_design_context(fileKey=":fileKey", nodeId=":childNodeId")`
69
+ 4. Run `get_variable_defs(fileKey=":fileKey", nodeId="1-2")` to get the variable definitions for the child nodes
70
+
71
+ ### Step 3: Resolve Code Connect Mappings
72
+
73
+ Run `get_code_connect_map` on the same top-level node before implementation starts.
74
+
75
+ ```
76
+ get_code_connect_map(fileKey=":fileKey", nodeId="1-2")
77
+ ```
78
+
79
+ This step is mandatory for a correct design-system handoff.
80
+
81
+ **Interpretation rules:**
82
+
83
+ - If `nodeId="1-2"` is a page, frame, or large section, treat the returned map as the authoritative list of mapped descendant components that MUST be preserved in the final handoff.
84
+ - Do NOT assume the explicit `CodeConnectSnippet` wrappers shown in `get_design_context` are the full list. A page-level `get_code_connect_map` may return many more mapped descendants.
85
+ - `CodeConnectSnippet` wrapper elements are never part of final code. Use only the inner snippet or the actual mapped component in the codebase.
86
+ - Do NOT rename Code Connect classes, collapse modifier classes into new aliases, or replace mapped snippet APIs with custom helper classes just because the implementation is standalone or the classes do not exist yet. Implement the missing styles behind the mapped contract instead.
87
+ - If you must diverge from the mapped markup or class API for technical reasons, STOP and get explicit user approval first. Explain the exact incompatibility and the minimal required deviation.
88
+
89
+ ### Step 3: Capture Visual Reference
90
+
91
+ Run `get_screenshot` with the same file key and node ID for a visual reference.
92
+
93
+ ```
94
+ get_screenshot(fileKey=":fileKey", nodeId="1-2")
95
+ ```
96
+
97
+ This screenshot serves as the source of truth for visual validation. Keep it accessible throughout implementation.
98
+
99
+ ### Step 4: Download Assets
100
+
101
+ Download any assets (images, icons, SVGs) returned by the Figma MCP server, BUT ONLY if the user specifically asks, otherwise skip this step.
102
+
103
+ **IMPORTANT:** Follow these asset rules:
104
+
105
+ - NEVER invent, redraw, approximate, reconstruct, or substitute assets that already exist in the Figma payload. If Figma provides an icon, SVG, image, or vector, use that original asset or exact markup. If you are about to replace an existing asset ALWAYS STOP AND ASK the user first.
106
+ - If the original Figma code already contains the asset markup, preserve or translate that exact asset instead of recreating it by hand.
107
+ - Assets are served through the Figma MCP server's built-in assets endpoint
108
+ - If the user or other skill specifies to use placeholder assets, or icon packs, follow the provided guidelines and do NOT use figma assets.
109
+ - If an asset URL or payload cannot be consumed in the target runtime, treat that as a blocker for exact fidelity. Report the failure clearly and ask the user before recreating, approximating, or substituting the asset.
110
+
111
+ ### Step 5: Translate to Project Conventions
112
+
113
+ Translate the Figma output into this project's framework, styles, and conventions.
114
+
115
+ **Key principles:**
116
+
117
+ - Treat the Figma MCP output (typically React + Tailwind) as a representation of design and behavior, not as final code style
118
+ - Treat Code Connect mappings as authoritative handoff requirements, not optional hints
119
+ - Review that the Tailwind utility classes are using the latest Tailwind conventions and patterns (MUST be version 4 and above)
120
+ - Always use Tailwind CSS v4. If the project does not already have a Tailwind build pipeline, use the browser build from `https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4`. Do NOT use the legacy `https://cdn.tailwindcss.com` script.
121
+ - Reuse existing components (buttons, inputs, typography, icon wrappers) instead of duplicating functionality
122
+ - Search the codebase for mapped component sources before falling back to raw snippets
123
+ - Use the project's color system, typography scale, and spacing tokens consistently
124
+ - Respect existing routing, state management, and data-fetch patterns
125
+ - Preserve the original Figma layout and DOM structure as closely as possible. Do NOT redesign, simplify, restructure, or "improve" the layout unless responsiveness, technical constraints, or an explicit user request requires it.
126
+ - Responsiveness is the default exception: adapt layout only as much as needed for smaller breakpoints while keeping the desktop structure faithful to the original frame.
127
+ - If you are about to make a large structural change, invent missing structure, or replace original layout patterns with new ones, STOP and ASK the user first.
128
+ - If Code Connect provides raw HTML class contracts instead of framework components, preserve those contracts in the final output. Add CSS/Tailwind support for them if needed, but do not silently translate them into a different API.
129
+
130
+ ### Step 6: Achieve 1:1 Visual Parity
131
+
132
+ Strive for pixel-perfect visual parity with the Figma design.
133
+
134
+ **Guidelines:**
135
+
136
+ - Prioritize Figma fidelity to match designs exactly
137
+ - Avoid hardcoded values - use design tokens from Figma where available
138
+ - When conflicts arise between design system tokens and Figma specs, prefer design system tokens but adjust spacing or sizes minimally to match visuals
139
+ - Follow WCAG requirements for accessibility
140
+ - Add component documentation as needed
141
+
142
+ ### Step 7: Validate Against Figma
143
+
144
+ Before marking complete, validate the final UI against the Figma screenshot.
145
+
146
+ **Validation checklist:**
147
+
148
+ - [ ] Layout matches (spacing, alignment, sizing)
149
+ - [ ] Typography matches (font, size, weight, line height)
150
+ - [ ] Colors match exactly
151
+ - [ ] Interactive states work as designed (hover, active, disabled)
152
+ - [ ] Responsive behavior follows Figma constraints
153
+ - [ ] Assets render correctly
154
+ - [ ] Every descendant returned by `get_code_connect_map` on the top-level node is represented in the final code
155
+ - [ ] Accessibility standards met
156
+
157
+ ### Step 8: Validate Against Browser
158
+
159
+ Use the /agent-browser skill if exists to validate the final UI in the browser.
160
+
161
+ - If the skill does not exist, skip this step.
162
+ - If the skill command fails, ask the user to manually validate the UI in the browser and skip this step.
163
+
164
+ ## Implementation Rules
165
+
166
+ ### Component Organization
167
+
168
+ - Place UI components in the project's designated design system directory
169
+ - Follow the project's component naming conventions
170
+ - Avoid inline styles unless truly necessary for dynamic values
171
+
172
+ ### Design System Integration
173
+
174
+ - ALWAYS use components from the project's design system when possible
175
+ - ALWAYS preserve mapped Code Connect components in the final handoff when they exist
176
+ - When using mapped Code Connect snippets directly, preserve their public contract exactly: same tags, same classes, same attributes, same variant/modifier naming.
177
+ - Map Figma design tokens to project design tokens
178
+ - When a matching component exists, extend it rather than creating a new one
179
+ - Document any new components added to the design system
180
+ - If any workaround would change assets, mapped component contracts, markup structure, or visual composition in a way that is not explicitly present in Figma, STOP and get user approval first.
181
+
182
+ ## Examples
183
+
184
+ ### Example 1: Implementing a Button Component
185
+
186
+ User says: "Implement this Figma button component: https://figma.com/design/kL9xQn2VwM8pYrTb4ZcHjF/DesignSystem?node-id=42-15"
187
+
188
+ **Actions:**
189
+
190
+ 1. Parse URL to extract fileKey=`kL9xQn2VwM8pYrTb4ZcHjF` and nodeId=`42-15`
191
+ 2. Run `get_design_context(fileKey="kL9xQn2VwM8pYrTb4ZcHjF", nodeId="42-15")` and `get_code_connect_map(fileKey="kL9xQn2VwM8pYrTb4ZcHjF", nodeId="42-15")`
192
+ 3. Run `get_screenshot(fileKey="kL9xQn2VwM8pYrTb4ZcHjF", nodeId="42-15")` for visual reference
193
+ 4. Download any button icons from the assets endpoint
194
+ 5. Check if project has existing button component
195
+ 6. If yes, extend it with new variant; if no, create new component using project conventions
196
+ 7. Map Figma colors to project design tokens (e.g., `primary-500`, `primary-hover`)
197
+ 8. Validate against screenshot for padding, border radius, typography
198
+
199
+ **Result:** Button component matching Figma design, integrated with project design system.
200
+
201
+ ### Example 2: Building a Dashboard Layout
202
+
203
+ User says: "Build this dashboard: https://figma.com/design/pR8mNv5KqXzGwY2JtCfL4D/Dashboard?node-id=10-5"
204
+
205
+ **Actions:**
206
+
207
+ 1. Parse URL to extract fileKey=`pR8mNv5KqXzGwY2JtCfL4D` and nodeId=`10-5`
208
+ 2. Run `get_metadata(fileKey="pR8mNv5KqXzGwY2JtCfL4D", nodeId="10-5")` to understand the page structure
209
+ 3. Identify main sections from metadata (header, sidebar, content area, cards) and their child node IDs
210
+ 4. Run `get_design_context(fileKey="pR8mNv5KqXzGwY2JtCfL4D", nodeId=":childNodeId")` and `get_code_connect_map(fileKey="pR8mNv5KqXzGwY2JtCfL4D", nodeId=":childNodeId")` for each major section
211
+ 5. Run `get_screenshot(fileKey="pR8mNv5KqXzGwY2JtCfL4D", nodeId="10-5")` for the full page
212
+ 6. Download all assets (logos, icons, charts)
213
+ 7. Build layout using project's layout primitives
214
+ 8. Implement each section using existing components where possible
215
+ 9. Validate responsive behavior against Figma constraints
216
+
217
+ ### Code Quality
218
+
219
+ - Avoid hardcoded values - extract to constants or design tokens
220
+ - Keep components composable and reusable
221
+
222
+ ## Best Practices
223
+
224
+ ### Always Start with Context
225
+
226
+ Never implement based on assumptions. Always fetch `get_design_context`, `get_code_connect_map` and `get_screenshot` first.
227
+
228
+ ### Original Assets First
229
+
230
+ If Figma already provides an asset, vector, or exact SVG/code representation, use that original source. Do NOT redraw icons, invent substitute artwork, or replace provided assets with lookalikes.
231
+
232
+ ### Incremental Validation
233
+
234
+ Validate frequently during implementation, not just at the end. This catches issues early.
235
+
236
+ ### Ask Before Large Inventions
237
+
238
+ If the implementation required inventing significant structure, changing layout patterns, or making large visual/architectural decisions that were not explicitly requested, STOP and ask the user before proceeding.
239
+
240
+ ### Reuse Over Recreation
241
+
242
+ Always check for existing components before creating new ones. Consistency across the codebase is more important than exact Figma replication.
243
+
244
+ ### Design System First
245
+
246
+ When in doubt, prefer the project's design system patterns over literal Figma translation.
@@ -0,0 +1,14 @@
1
+ interface:
2
+ display_name: "Figma Implement Design"
3
+ short_description: "Turn Figma designs into production-ready code"
4
+ icon_small: "./assets/figma-small.svg"
5
+ icon_large: "./assets/figma.png"
6
+ default_prompt: "Implement this Figma design in this codebase, using mapped Code Connect components wherever available and matching layout, states, and responsive behavior."
7
+
8
+ dependencies:
9
+ tools:
10
+ - type: "mcp"
11
+ value: "figma"
12
+ description: "Figma MCP server"
13
+ transport: "streamable_http"
14
+ url: "https://mcp.figma.com/mcp"
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
2
+ <path fill="#000" fill-rule="evenodd" d="M4.994 5.986a2.014 2.014 0 1 0 0 4.028h2.069V5.986H4.994Zm5.063-.98h.055a2.014 2.014 0 1 0 0-4.026h-2.07v4.027h2.015Zm1.697.49A2.994 2.994 0 0 0 10.112 0H4.994a2.994 2.994 0 0 0-1.642 5.498A2.99 2.99 0 0 0 2 8a2.99 2.99 0 0 0 1.352 2.503A2.99 2.99 0 0 0 2 13.007C2 14.663 3.358 16 5.008 16c1.665 0 3.035-1.349 3.035-3.02v-2.765a2.984 2.984 0 0 0 2.014.778h.055a2.994 2.994 0 0 0 1.642-5.496Zm-1.642.49h-.055a2.014 2.014 0 1 0 0 4.028h.055a2.014 2.014 0 1 0 0-4.028Zm-7.132 7.02c0-1.111.902-2.013 2.014-2.013h2.069v1.987c0 1.123-.924 2.04-2.055 2.04a2.026 2.026 0 0 1-2.028-2.013Zm4.083-8H4.994a2.014 2.014 0 1 1 0-4.026h2.069v4.027Z" clip-rule="evenodd"/>
3
+ </svg>
@@ -0,0 +1,28 @@
1
+ <svg
2
+ width="400"
3
+ height="400"
4
+ viewBox="0 0 400 400"
5
+ fill="none"
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ >
8
+ <path
9
+ d="M97.5 302.5C97.5 274.195 120.445 251.25 148.75 251.25H200V302.5C200 330.805 177.055 353.75 148.75 353.75C120.445 353.75 97.5 330.805 97.5 302.5Z"
10
+ fill="#0ACF83"
11
+ />
12
+ <path
13
+ d="M200 200C200 171.696 222.945 148.75 251.25 148.75C279.554 148.75 302.5 171.695 302.5 200C302.5 228.305 279.554 251.25 251.25 251.25C222.945 251.25 200 228.304 200 200Z"
14
+ fill="#1ABCFE"
15
+ />
16
+ <path
17
+ d="M97.5 200C97.5 228.305 120.445 251.25 148.75 251.25H200V148.75H148.75C120.445 148.75 97.5 171.695 97.5 200Z"
18
+ fill="#A259FF"
19
+ />
20
+ <path
21
+ d="M200 46.25V148.75H251.25C279.555 148.75 302.5 125.805 302.5 97.5C302.5 69.1954 279.555 46.25 251.25 46.25H200Z"
22
+ fill="#FF7262"
23
+ />
24
+ <path
25
+ d="M97.5 97.5C97.5 125.805 120.445 148.75 148.75 148.75H200V46.25L148.75 46.25C120.445 46.25 97.5 69.1954 97.5 97.5Z"
26
+ fill="#F24E1E"
27
+ />
28
+ </svg>
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: newlogic-ui
3
+ description: This skill provides repo-specific rules for LLM agents working with the Newlogic UI framework. Use it for UI, components, layouts, styles, responsiveness, frontend logic, and design implementation in this repository.
4
+ ---
5
+
6
+ # Newlogic UI Skill
7
+
8
+ ALWAYS load `https://ui.newlogic.cz/llms-full.txt` before making changes in this framework.
9
+
10
+ ALWAYS read ALL local guides in `references/` before starting work. These guides are intentionally short and contain ONLY repo-specific rules that override, narrow, or clarify `llms-full.txt`.
11
+
12
+ ## Source Priority
13
+
14
+ Use this priority order when rules differ:
15
+
16
+ 1. Existing files in this repository
17
+ 2. Local guides in this skill
18
+ 3. `https://ui.newlogic.cz/llms-full.txt`
19
+
20
+ ## Working Rule
21
+
22
+ Use `llms-full.txt` for framework behavior, available components, and implementation examples.
23
+
24
+ Use the local guides for repository conventions that MUST be followed even if a generic example from `llms-full.txt` suggests another valid approach.
25
+
26
+ ## Required Guides
27
+
28
+ - [Project Guide](references/project-guide.md) - naming, structure, and placement rules
29
+ - [Assets Guide](references/assets-guide.md) - placeholder, image, and icon rules
30
+ - [Templating Guide](references/templating-guide.md) - Latte and JSON data rules for this repo
31
+ - [Styling Guide](references/styling-guide.md) - local CSS and component styling constraints
32
+ - [Theme Guide](references/theme-guide.md) - local theme token and theme file rules
33
+ - [Scripting Guide](references/scripting-guide.md) - local JS and Stimulus placement rules
@@ -0,0 +1,126 @@
1
+ # Assets Guide
2
+
3
+ ## Images
4
+
5
+ - Do NOT use assets from Figma unless the user explicitly asks for them.
6
+ - Instead, use the placeholder images below.
7
+ - For placeholder images use https://placehold.co/ (preferred by default) or https://picsum.photos/.
8
+ - NEVER reinvent or reconstruct the images from scratch. Either use a placeholder image as `img` or a Figma asset as `img`.
9
+ - Most content images SHOULD use the `x-image` wrapper.
10
+ - Put the aspect ratio utility on the `<img>` element, NOT on the wrapper.
11
+ - Transparent images SHOULD NOT use the `x-image` wrapper.
12
+
13
+ **Preferred markup:**
14
+
15
+ ```html
16
+ <div class="x-image before:skeleton">
17
+ <img class="aspect-4/3" src="https://placehold.co/800x600" loading="lazy" alt="">
18
+ </div>
19
+ ```
20
+
21
+ **Transparent image markup:**
22
+
23
+ ```html
24
+ <img class="aspect-3/2" src="https://placehold.co/300x200" loading="lazy" alt="">
25
+ ```
26
+
27
+ ## Icons
28
+
29
+ - ALWAYS use SVG for icons.
30
+ - Prefer `<use>` for reusable icons.
31
+ - If adding reusable outline icons, place them in `src/icons/outline/`.
32
+ - If adding reusable solid icons, place them in `src/icons/solid/`.
33
+ - Brand icons are available in `src/icons/simpleicons/`.
34
+ - Heroicons are already available through the build setup, so do NOT duplicate them in `src/icons/`.
35
+ - The `<use href="...">` symbol definitions are generated automatically by the build setup.
36
+ - Icon IDs SHOULD generally follow Figma naming when possible.
37
+ - Inline `<svg>` without `<use>` is allowed ONLY for one-off icons that will NOT be reused.
38
+
39
+ **Reusable icon examples:**
40
+
41
+ ```html
42
+ <svg class="size-6">
43
+ <use href="#icons-outline/hello"></use>
44
+ </svg>
45
+ ```
46
+
47
+ ```html
48
+ <svg class="size-6">
49
+ <use href="#simpleicons-solid/facebook"></use>
50
+ </svg>
51
+ ```
52
+
53
+ ```html
54
+ <svg class="size-6">
55
+ <use href="#heroicons-outline/academic-cap"></use>
56
+ </svg>
57
+ ```
58
+
59
+ ### Icon Strategy Summary
60
+
61
+ 1. Heroicons via `<use href="#heroicons-*/*">`
62
+ 2. Project reusable icons via `src/icons/outline`, `src/icons/solid`, or `src/icons/simpleicons`
63
+ 3. Inline `<svg>` without `<use>` for one-off icons ONLY
64
+
65
+ ## Example
66
+ You are about to translate the Figma output into this project.
67
+
68
+ ### Step 1 – Figma handoff
69
+ - Figma output provide provides assets like this `<img alt="" className="absolute block max-w-none size-full" src={imgVector}`
70
+ - with urls like this https://www.figma.com/api/mcp/asset/557d8c1d-efe3-42ad-bccb-e5db8ebd14e6
71
+ - You succefully identified a type of the asset as `image` or `icon` from the Figma output.
72
+
73
+ ### Step 2 – Image
74
+ - You check the width and height of the image and decide if it is transparent or not.
75
+
76
+ #### If the user didn't ask to use Figma assets
77
+ - In this case you will use the placeholder image.
78
+ - You will use the correct width and height and aspect ratio.
79
+
80
+ ```html
81
+ <div class="x-image before:skeleton">
82
+ <img class="aspect-4/3" src="https://placehold.co/800x600" loading="lazy" alt="">
83
+ </div>
84
+ ```
85
+
86
+ - If the image is transparent, you will use the following markup without the `x-image` wrapper:
87
+
88
+ ```html
89
+ <img class="aspect-3/2" src="https://placehold.co/300x200" loading="lazy" alt="">
90
+ ```
91
+
92
+ #### If the user explicitly asks to use Figma assets
93
+
94
+ - You downloaded the image from Figma and placed it in `src/assets/images`.
95
+ - You renamed the image to match the Figma asset name.
96
+ - You updated the markup to use the new image path.
97
+ - You will use the correct width and height and aspect ratio.
98
+
99
+ ```html
100
+ <div class="x-image before:skeleton">
101
+ <img class="aspect-4/3" src="/src/assets/my-new-image.jpg" loading="lazy" alt="">
102
+ </div>
103
+ ```
104
+
105
+ ### Step 2 – Icon
106
+ - You check the width and height of the icon and decide if it is a brand icon, heroicon or other icon.
107
+
108
+ - If you identify the icon as a brand icon, you will check if it is already available in `src/icons/simpleicons`.
109
+ - If it is not available, you will add it to `src/icons/simpleicons`.
110
+ - If it is available, you will use the existing icon.
111
+ - You will use the following markup in the HTML:
112
+
113
+ ```html
114
+ <svg class="size-6">
115
+ <use href="#simpleicons-solid/facebook"></use>
116
+ </svg>
117
+ ```
118
+
119
+ - If you identify the icon as a heroicon, you will match the figma name to the heroicon name.
120
+ - You will use the following markup in the HTML:
121
+ ```html
122
+ <svg class="size-6">
123
+ <use href="#heroicons-outline/academic-cap"></use>
124
+ </svg>
125
+ ```
126
+
@@ -0,0 +1,25 @@
1
+ # Project Guide
2
+
3
+ ## Naming
4
+
5
+ - Use PascalCase for component files such as `Button.latte`, `HeroSection.latte`, `Reveal.js`, `Header.css`.
6
+ - Use kebab-case with `x-` prefix for component classes such as `x-button`, `x-hero-section`.
7
+ - ALWAYS check if the component class name matches the file name, e.g. `HeroSection.latte` and `x-hero-section` matches
8
+ - ALWAYS keep one primary `x-*` component per file.
9
+ - Use kebab-case for generic utility files such as `format-date.js` or `scrollbar.css`.
10
+
11
+ ## Placement
12
+
13
+ - Latte components belong in `src/templates/components/`.
14
+ - UI component templates belong in `src/templates/components/(ui)/` when they are reusable UI building blocks.
15
+ - Section or layout groupings MAY use parentheses directories such as `(sections)` or `(layout)`.
16
+ - Component CSS belongs in `src/styles/components/`.
17
+ - Winduum-based UI component CSS belongs in `src/styles/components/(ui)/`.
18
+ - Component scripts belong in `src/scripts/components/`.
19
+ - Winduum-based UI controllers belong in `src/scripts/components/(ui)/`.
20
+
21
+ ## Structure
22
+
23
+ - Match template, style, and script names when the same component exists across layers.
24
+ - Keep the repo structure aligned with existing files before introducing a new folder or naming pattern.
25
+ - If a pattern already exists in nearby files, ALWAYS follow that pattern instead of inventing a parallel one.
@@ -0,0 +1,38 @@
1
+ # Scripting Guide
2
+
3
+ ## Placement
4
+
5
+ - Entry point is `src/scripts/main.js`.
6
+ - Shared setup belongs in `src/scripts/composables/`.
7
+ - Reusable helpers belong in `src/scripts/utils/`.
8
+ - Custom component controllers belong in `src/scripts/components/`.
9
+ - Winduum-based UI controllers belong in `src/scripts/components/(ui)/`.
10
+
11
+ ## Local Rules
12
+
13
+ - Use modern plain JS that matches the existing codebase.
14
+ - Register one primary controller per file.
15
+ - Keep controller names aligned with existing `x-*` naming in this repo.
16
+ - If dynamic HTML is inserted into the DOM, ALWAYS re-initialize it with `src/scripts/utils/initAfter.js`.
17
+ - Follow the existing import aggregation pattern with `+.js` files when adding new controllers to an existing folder.
18
+
19
+ **Local `initAfter` import pattern:**
20
+
21
+ ```javascript
22
+ import { initAfter } from '../utils/+.js'
23
+
24
+ initAfter(document.querySelector('.newlyAppendedContent'))
25
+ ```
26
+
27
+ **Aggregator pattern:**
28
+
29
+ ```javascript
30
+ // src/scripts/components/(ui)/+.js
31
+ import './Button.js'
32
+ import './Dialog.js'
33
+ ```
34
+
35
+ ## Before Adding JS
36
+
37
+ - Prefer existing Winduum, Stimulus, or utility behavior from `llms-full.txt` before creating new custom JS.
38
+ - Do NOT introduce a second interaction pattern if the repo already has an established controller for the same problem.
@@ -0,0 +1,75 @@
1
+ # Styling Guide
2
+
3
+ ## General
4
+
5
+ - ALWAYS prefer Tailwind utilities before writing custom CSS.
6
+ - Use custom CSS for defaults, complex states, or component-specific behavior that should NOT live in templates.
7
+ - Follow nearby files before introducing a new styling pattern.
8
+ - Prefer responsive utilities such as `sm:`, `md:`, and `lg:` in templates. Use `@custom-media` only when writing custom CSS.
9
+
10
+ **Custom breakpoint example:**
11
+
12
+ ```css
13
+ .my-component {
14
+ padding: 1rem;
15
+
16
+ @media (--media-lg) {
17
+ padding: 2rem;
18
+ }
19
+ }
20
+ ```
21
+
22
+ ## UI Components
23
+
24
+ - Winduum-based UI components live in `src/styles/components/(ui)/`.
25
+ - UI component defaults belong in their CSS files, NOT in template utility piles.
26
+ - Define base sizing, padding, radius, font defaults, and default colors in CSS for UI components.
27
+ - In templates, only small layout utilities are allowed on UI components, such as width, flex, gap, order, or spacing adjustments.
28
+ - Do NOT redefine a UI component's base look directly in templates.
29
+ - Do NOT restyle existing `x-*` UI components from a large level CSS file when the change is really a button, badge, control, field, pagination, or other UI-component concern.
30
+ - If a Figma page introduces a new shared UI look, extend the relevant file in `src/styles/components/(ui)/` instead of creating specific overrides from a parent component for that component.
31
+
32
+ ## Non-UI Components
33
+
34
+ - Regular non-UI components SHOULD be styled entirely with Tailwind utilities in the template by default.
35
+ - For non-UI components, prefer Tailwind even when the template gets longer. A longer utility-based template is still preferred over creating component CSS too early.
36
+ - Create component CSS for non-UI components ONLY when there is styling logic that genuinely should not live in the template, such as complex selectors, state relationships, pseudo-element composition, browser-specific behavior, or similarly non-trivial logic that cannot be expressed cleanly with Tailwind utilities alone.
37
+ - Do NOT create component CSS just to group utilities, shorten markup, or move ordinary layout/spacing/typography rules out of the template.
38
+ - Treat non-UI component CSS as a true last resort. It should be used only in genuinely exceptional cases, not as a convenience or organizational preference.
39
+ - If a non-UI component reaches that exceptional threshold and needs CSS, follow the `data-part` pattern for internal styling instead of inventing extra internal class names.
40
+ - Avoid large level CSS files that absorb layout, typography, and UI and other component styling at the same time. If a page file starts becoming the source of truth for `x-*` components, move that logic back into `(ui)` CSS and keep the page mostly utility-driven.
41
+
42
+ ## Tokens And Units
43
+
44
+ - ALWAYS use theme tokens such as `text-primary`, `bg-main`, or `text-body-foreground` before raw color values.
45
+ - If the design needs a new default token, update `src/styles/theme/main.css`.
46
+ - Do NOT use `px` units, except `1px` or `2px` borders when needed.
47
+
48
+ ## Component Parts
49
+
50
+ - This section applies primarily to non-UI components when CSS is truly unavoidable.
51
+ - Use `data-part` for stylable internal parts.
52
+ - Do NOT create extra part class names such as `x-card-header` or `x-hero-content` when `data-part` is sufficient.
53
+ - For non-UI components, `data-part` is the required internal styling pattern whenever an exceptional CSS case is justified.
54
+
55
+ **Preferred part pattern:**
56
+
57
+ ```html
58
+ <div class="x-my-component">
59
+ <div data-part="header">...</div>
60
+ <div data-part="content">...</div>
61
+ </div>
62
+ ```
63
+
64
+ ```css
65
+ .x-my-component {
66
+ [data-part="header"] {
67
+ /* complex styles */
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## Winduum Extensions
73
+
74
+ - Inspect the imported Winduum files in the component CSS to see which custom properties are available.
75
+ - Extend Winduum components through their existing imports and local CSS layers instead of re-implementing them from scratch.
@@ -0,0 +1,106 @@
1
+ # Templating Guide
2
+
3
+ ## Layout
4
+
5
+ - Use `src/templates/layouts/default.latte` unless the user explicitly asks for another layout.
6
+ - Do NOT create a custom layout when the default layout already supports the change.
7
+
8
+ ## Data Sources
9
+
10
+ - Global data lives in `src/data/main.json`.
11
+ - In this repo, global layout sections are typically defined through `head` and `foot` arrays in `src/data/main.json`.
12
+ - Page data lives in `src/pages/*.json` and inherits global data.
13
+ - Section rendering is handled through `src/templates/utils/sections.latte`.
14
+ - Components referenced from page JSON are passed as `$control`.
15
+ - In this repo, `src/pages/*.json` is the composition layer for whole pages. Prefer assembling a page there instead of creating a wrapper `*Page.latte` component that just nests the entire page structure.
16
+ - Preserve the existing `head` and `foot` layout structure unless the user explicitly asks to change the layout contract.
17
+ - If a Figma page includes a site header or site footer, implement those designs in the existing `components/header/Header.latte` and `components/footer/Footer.latte` flow rather than moving them into `body`.
18
+
19
+ **Global layout data example:**
20
+
21
+ ```json
22
+ {
23
+ "head": [
24
+ { "src": "components/header/Header.latte" }
25
+ ],
26
+ "foot": [
27
+ { "src": "components/footer/Footer.latte" }
28
+ ]
29
+ }
30
+ ```
31
+
32
+ **Layout asset access example:**
33
+
34
+ ```latte
35
+ <link n:foreach="$assets->css->all as $url" href="{$url|asset}" rel="stylesheet">
36
+ <script src="{$assets->js->main|asset}" type="module"></script>
37
+ ```
38
+
39
+ ## JSON Rules
40
+
41
+ - Do NOT store CSS class strings in JSON.
42
+ - JSON should contain semantic values and content, NOT presentation classes.
43
+ - If a template depends on an optional flag such as `active`, `dropdown`, or variant switches, define that flag explicitly in JSON.
44
+ - Keep repeated global UI data in `src/data/main.json` rather than duplicating it across page JSON files.
45
+
46
+ ## Latte Rules
47
+
48
+ - Prefer direct access to existing variables such as `$control` and global layout data.
49
+ - Keep ad hoc `{var ...}` usage to a minimum.
50
+ - Use `{default}` for optional fallback values when needed.
51
+ - Do NOT combine `class` and `n:class` on the same element. Use one `n:class` expression that includes the base classes.
52
+
53
+ **`n:class` pattern:**
54
+
55
+ ```latte
56
+ <a n:class="'base classes ' . ($isActive ? 'active' : 'idle')">Link</a>
57
+ ```
58
+
59
+ **`{default}` pattern:**
60
+
61
+ ```latte
62
+ {default $disabled = false}
63
+ ```
64
+
65
+ ## Components
66
+
67
+ - Put reusable page sections in `src/templates/components/`.
68
+ - Keep component file names in PascalCase.
69
+ - If a component is rendered from page JSON, assume `$control` is the primary input object unless the existing local pattern clearly does something else.
70
+ - Match the current folder conventions such as `(sections)`, `(ui)`, `header/`, `footer/`, `dialog/`, or `cookieconsent/` before introducing a new grouping.
71
+ - Do NOT create a monolithic page wrapper component when the page can be expressed as multiple body sections in JSON.
72
+ - Prefer one component per visible section or repeated block, then compose those sections from `src/pages/*.json`.
73
+ - If an existing component already matches the Figma element, reuse that component instead of creating a specific duplicate.
74
+ - If a Figma element maps to an existing `(ui)` component such as `Pagination.latte`, `Button`, `Dialog`, `Toast`, or similar, extend that existing component if needed; do NOT create parallel specific versions like `ArticlesPagination.latte` unless the user explicitly asks for a separate component.
75
+
76
+ **Page JSON to component flow:**
77
+
78
+ ```json
79
+ {
80
+ "body": [
81
+ {
82
+ "src": "components/HeroSection.latte",
83
+ "heading": "Welcome",
84
+ "buttonText": "Get Started"
85
+ }
86
+ ]
87
+ }
88
+ ```
89
+
90
+ ```latte
91
+ {foreach $sections as $section}
92
+ {include ('../' . $section->src), control => $section}
93
+ {/foreach}
94
+ ```
95
+
96
+ ```latte
97
+ <section class="x-hero-section">
98
+ <h1 n:if="isset($control->heading)">{$control->heading}</h1>
99
+ </section>
100
+ ```
101
+
102
+ **Direct include pattern:**
103
+
104
+ ```latte
105
+ {include 'components/Button.latte', text: 'Click me'}
106
+ ```
@@ -0,0 +1,23 @@
1
+ # Theme Guide
2
+
3
+ ## Theme Files
4
+
5
+ - Main website theme tokens live in `src/styles/theme/main.css`.
6
+ - Keep website theme defaults in `@theme`.
7
+ - Extend the existing token system before inventing component-local hardcoded values.
8
+
9
+ ## Local Rules
10
+
11
+ - ALWAYS prefer semantic tokens over raw values in templates and components.
12
+ - If the design introduces a new shared color, spacing, or layout default, add or adjust the token in `src/styles/theme/main.css`.
13
+ - Reuse existing tokens such as `primary`, `main`, `body`, and status colors before creating new ones.
14
+ - Keep theme changes centralized instead of scattering hardcoded values across multiple component files.
15
+
16
+ **Common token usage:**
17
+
18
+ ```html
19
+ <div class="bg-primary text-primary-foreground">Primary Button</div>
20
+ <div class="bg-main text-main-foreground">Dark Section</div>
21
+ <div class="max-w-(--container-width)">Constrained content</div>
22
+ <div class="x-button accent-main">Primary text</div>
23
+ ```
@@ -0,0 +1,107 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import { styleText } from 'node:util'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { getPackageInfo } from 'vituum/utils/common.js'
6
+
7
+ const IS_WIN32 = process.platform === 'win32'
8
+ const { name } = getPackageInfo(new URL('../package.json', import.meta.url).href)
9
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url))
10
+ const packageRoot = path.resolve(scriptDir, '..')
11
+ const sourceSkillsDir = path.join(packageRoot, 'skills')
12
+ const projectRoot = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : null
13
+
14
+ function isSameSymlinkTarget(targetPath, expectedSourcePath) {
15
+ const currentTarget = fs.readlinkSync(targetPath)
16
+ const resolvedTarget = path.resolve(path.dirname(targetPath), currentTarget)
17
+
18
+ return resolvedTarget === expectedSourcePath
19
+ }
20
+
21
+ function getExistingTargetStat(targetPath) {
22
+ try {
23
+ return fs.lstatSync(targetPath)
24
+ }
25
+ catch (error) {
26
+ if (error?.code === 'ENOENT') {
27
+ return null
28
+ }
29
+
30
+ throw error
31
+ }
32
+ }
33
+
34
+ function createDirectorySymlink(sourcePath, targetPath) {
35
+ const symlinkTarget = IS_WIN32
36
+ ? sourcePath
37
+ : path.relative(path.dirname(targetPath), sourcePath)
38
+ const symlinkType = IS_WIN32 ? 'junction' : 'dir'
39
+
40
+ fs.symlinkSync(symlinkTarget, targetPath, symlinkType)
41
+ }
42
+
43
+ if (!projectRoot || projectRoot === packageRoot || !fs.existsSync(sourceSkillsDir)) {
44
+ process.exit(0)
45
+ }
46
+
47
+ const targetAgentsDir = path.join(projectRoot, '.agents')
48
+ const targetSkillsDir = path.join(targetAgentsDir, 'skills')
49
+ const targetClaudePath = path.join(projectRoot, '.claude')
50
+ const skillEntries = fs.readdirSync(sourceSkillsDir, { withFileTypes: true })
51
+ .filter(entry => entry.isDirectory())
52
+
53
+ if (skillEntries.length === 0) {
54
+ process.exit(0)
55
+ }
56
+
57
+ fs.mkdirSync(targetSkillsDir, { recursive: true })
58
+
59
+ let linkedCount = 0
60
+ let linkedClaudeDir = false
61
+
62
+ for (const entry of skillEntries) {
63
+ const sourcePath = path.join(sourceSkillsDir, entry.name)
64
+ const targetPath = path.join(targetSkillsDir, entry.name)
65
+ const targetStat = getExistingTargetStat(targetPath)
66
+
67
+ if (targetStat) {
68
+ if (!targetStat.isSymbolicLink()) {
69
+ console.warn(`${styleText(['cyan', 'bold'], name)} ${styleText('yellow', `Skipping skill "${entry.name}" because "${targetPath}" already exists and is not a symlink.`)}`)
70
+ continue
71
+ }
72
+
73
+ if (isSameSymlinkTarget(targetPath, sourcePath)) {
74
+ continue
75
+ }
76
+
77
+ fs.unlinkSync(targetPath)
78
+ }
79
+
80
+ createDirectorySymlink(sourcePath, targetPath)
81
+ linkedCount += 1
82
+ }
83
+
84
+ const claudeStat = getExistingTargetStat(targetClaudePath)
85
+
86
+ if (claudeStat) {
87
+ if (!claudeStat.isSymbolicLink()) {
88
+ console.warn(`${styleText(['cyan', 'bold'], name)} ${styleText('yellow', `Skipping ".claude" because "${targetClaudePath}" already exists and is not a symlink.`)}`)
89
+ }
90
+ else if (!isSameSymlinkTarget(targetClaudePath, targetAgentsDir)) {
91
+ fs.unlinkSync(targetClaudePath)
92
+ createDirectorySymlink(targetAgentsDir, targetClaudePath)
93
+ linkedClaudeDir = true
94
+ }
95
+ }
96
+ else {
97
+ createDirectorySymlink(targetAgentsDir, targetClaudePath)
98
+ linkedClaudeDir = true
99
+ }
100
+
101
+ if (linkedCount > 0) {
102
+ console.info(`${styleText(['cyan', 'bold'], name)} ${styleText('green', `Linked ${linkedCount} skill${linkedCount === 1 ? '' : 's'} into "${targetSkillsDir}".`)}`)
103
+ }
104
+
105
+ if (linkedClaudeDir) {
106
+ console.info(`${styleText(['cyan', 'bold'], name)} ${styleText('green', `Linked "${targetClaudePath}" to "${targetAgentsDir}".`)}`)
107
+ }