cortex-agents 1.0.1 → 2.1.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.
Files changed (34) hide show
  1. package/.opencode/agents/build.md +34 -3
  2. package/.opencode/agents/debug.md +24 -2
  3. package/.opencode/agents/devops.md +1 -2
  4. package/.opencode/agents/fullstack.md +1 -2
  5. package/.opencode/agents/plan.md +5 -3
  6. package/.opencode/agents/security.md +1 -2
  7. package/.opencode/agents/testing.md +1 -2
  8. package/.opencode/skills/api-design/SKILL.md +348 -0
  9. package/.opencode/skills/architecture-patterns/SKILL.md +323 -0
  10. package/.opencode/skills/backend-development/SKILL.md +329 -0
  11. package/.opencode/skills/code-quality/SKILL.md +12 -0
  12. package/.opencode/skills/database-design/SKILL.md +347 -0
  13. package/.opencode/skills/deployment-automation/SKILL.md +7 -0
  14. package/.opencode/skills/design-patterns/SKILL.md +295 -0
  15. package/.opencode/skills/desktop-development/SKILL.md +295 -0
  16. package/.opencode/skills/frontend-development/SKILL.md +210 -0
  17. package/.opencode/skills/mobile-development/SKILL.md +407 -0
  18. package/.opencode/skills/performance-optimization/SKILL.md +330 -0
  19. package/.opencode/skills/testing-strategies/SKILL.md +33 -0
  20. package/README.md +390 -76
  21. package/dist/cli.js +355 -68
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +38 -0
  24. package/dist/plugin.js +3 -2
  25. package/dist/registry.d.ts +45 -0
  26. package/dist/registry.d.ts.map +1 -0
  27. package/dist/registry.js +140 -0
  28. package/dist/tools/cortex.d.ts.map +1 -1
  29. package/dist/tools/cortex.js +2 -3
  30. package/dist/tools/docs.d.ts +52 -0
  31. package/dist/tools/docs.d.ts.map +1 -0
  32. package/dist/tools/docs.js +328 -0
  33. package/package.json +11 -4
  34. package/.opencode/skills/web-development/SKILL.md +0 -122
@@ -0,0 +1,295 @@
1
+ ---
2
+ name: desktop-development
3
+ description: Cross-platform (Electron, Tauri) and native (SwiftUI, WPF/WinUI, GTK) desktop application development patterns
4
+ license: Apache-2.0
5
+ compatibility: opencode
6
+ ---
7
+
8
+ # Desktop Development Skill
9
+
10
+ This skill provides patterns and best practices for building desktop applications, covering both cross-platform and native approaches.
11
+
12
+ ## When to Use
13
+
14
+ Use this skill when:
15
+ - Building new desktop applications
16
+ - Choosing between cross-platform and native development
17
+ - Implementing desktop-specific features (system tray, file access, menus)
18
+ - Packaging and distributing desktop applications
19
+ - Optimizing desktop app performance
20
+
21
+ ## Framework Decision Matrix
22
+
23
+ | Framework | Language | Bundle Size | Performance | Native Feel | Best For |
24
+ |-----------|----------|-------------|-------------|-------------|----------|
25
+ | Tauri | Rust + Web | ~3-10 MB | Excellent | Good | Modern cross-platform, small bundles |
26
+ | Electron | JS/TS | ~80-150 MB | Good | Fair | Web team building desktop app |
27
+ | .NET MAUI | C# | ~30-50 MB | Good | Good | Microsoft ecosystem, mobile + desktop |
28
+ | Qt/QML | C++ | ~20-40 MB | Excellent | Excellent | Performance-critical, embedded |
29
+ | SwiftUI | Swift | Native | Excellent | Excellent | macOS-only, Apple ecosystem |
30
+ | WPF/WinUI | C# | Native | Good | Excellent | Windows-only, enterprise |
31
+ | GTK 4 | C/Rust/Python | Native | Good | Good (Linux) | Linux-native, GNOME |
32
+
33
+ ### When to Choose Cross-Platform
34
+ - Target multiple OS (Windows, macOS, Linux)
35
+ - Web development team (Electron, Tauri)
36
+ - Rapid prototyping and iteration
37
+ - Content-focused apps (editors, dashboards)
38
+
39
+ ### When to Choose Native
40
+ - Deep OS integration required
41
+ - Maximum performance needed
42
+ - Single-platform target
43
+ - Platform-specific design language
44
+
45
+ ## Cross-Platform: Tauri
46
+
47
+ ### Architecture
48
+ ```
49
+ ┌────────────────────────────────┐
50
+ │ Tauri Application │
51
+ ├────────────────────────────────┤
52
+ │ Frontend (Web) │ Backend │
53
+ │ ───────────── │ (Rust) │
54
+ │ HTML/CSS/JS │ │
55
+ │ React/Vue/Svelte │ Commands │
56
+ │ Any web framework │ Plugins │
57
+ │ │ System │
58
+ │ │ Access │
59
+ ├────────────────────────────────┤
60
+ │ System WebView (OS-native) │
61
+ │ macOS: WKWebView │
62
+ │ Windows: WebView2 (Edge) │
63
+ │ Linux: WebKitGTK │
64
+ └────────────────────────────────┘
65
+ ```
66
+
67
+ ### Key Concepts
68
+ - **Commands** — Rust functions callable from frontend via IPC
69
+ - **Events** — Bidirectional event system between frontend and backend
70
+ - **Plugins** — Modular system capabilities (file system, dialog, shell, etc.)
71
+ - **Permissions** — Fine-grained security model (allowlist for system access)
72
+
73
+ ### Tauri Command Example
74
+ ```rust
75
+ #[tauri::command]
76
+ async fn read_file(path: String) -> Result<String, String> {
77
+ std::fs::read_to_string(&path)
78
+ .map_err(|e| format!("Failed to read file: {}", e))
79
+ }
80
+
81
+ // Frontend call
82
+ import { invoke } from '@tauri-apps/api/core';
83
+ const content = await invoke('read_file', { path: '/tmp/data.txt' });
84
+ ```
85
+
86
+ ### Tauri Best Practices
87
+ - Use permission system — never allow unrestricted file/shell access
88
+ - Keep Rust backend thin — handle system calls, delegate logic to frontend
89
+ - Use Tauri plugins for common needs (fs, dialog, clipboard, notification)
90
+ - Embed frontend assets for offline capability
91
+ - Target specific WebView versions for consistent behavior
92
+
93
+ ## Cross-Platform: Electron
94
+
95
+ ### Architecture
96
+ ```
97
+ ┌──────────────────────────────┐
98
+ │ Electron Application │
99
+ ├───────────────┬──────────────┤
100
+ │ Main Process │ Renderer │
101
+ │ (Node.js) │ (Chromium) │
102
+ │ │ │
103
+ │ App lifecycle│ UI (HTML/ │
104
+ │ Native APIs │ CSS/JS) │
105
+ │ System access│ Web APIs │
106
+ │ IPC handling │ IPC calls │
107
+ ├───────────────┴──────────────┤
108
+ │ Chromium + Node.js Runtime │
109
+ └──────────────────────────────┘
110
+ ```
111
+
112
+ ### IPC Communication
113
+ ```typescript
114
+ // Main process — handle IPC
115
+ import { ipcMain, dialog } from 'electron';
116
+
117
+ ipcMain.handle('open-file', async () => {
118
+ const result = await dialog.showOpenDialog({
119
+ properties: ['openFile'],
120
+ filters: [{ name: 'Text', extensions: ['txt', 'md'] }],
121
+ });
122
+ if (result.canceled) return null;
123
+ return fs.readFileSync(result.filePaths[0], 'utf-8');
124
+ });
125
+
126
+ // Renderer process — invoke IPC
127
+ const content = await window.electronAPI.openFile();
128
+ ```
129
+
130
+ ### Security Best Practices
131
+ - Enable `contextIsolation: true` (default in modern Electron)
132
+ - Disable `nodeIntegration` in renderer (use preload scripts)
133
+ - Use `contextBridge` to expose safe APIs to renderer
134
+ - Validate all IPC inputs — treat renderer as untrusted
135
+ - Enable `sandbox: true` for renderer processes
136
+ - Keep Electron updated — security patches for Chromium
137
+
138
+ ### Electron Performance
139
+ - Use `BrowserView` for multi-panel UIs instead of multiple windows
140
+ - Lazy-load heavy modules in main process
141
+ - Offload CPU work to worker threads or child processes
142
+ - Monitor memory — Chromium per-process can be expensive
143
+ - Use Electron Forge or electron-builder for optimized builds
144
+
145
+ ## Native: macOS (SwiftUI / AppKit)
146
+
147
+ ### SwiftUI Desktop Patterns
148
+ ```swift
149
+ @main
150
+ struct MyApp: App {
151
+ var body: some Scene {
152
+ WindowGroup {
153
+ ContentView()
154
+ }
155
+ .commands {
156
+ CommandMenu("File") {
157
+ Button("Open...") { openFile() }
158
+ .keyboardShortcut("o")
159
+ }
160
+ }
161
+
162
+ MenuBarExtra("Status", systemImage: "circle.fill") {
163
+ StatusView()
164
+ }
165
+ .menuBarExtraStyle(.window)
166
+
167
+ Settings {
168
+ SettingsView()
169
+ }
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### macOS-Specific Features
175
+ - **Menu bar apps** — `MenuBarExtra` for status bar items
176
+ - **Settings window** — `Settings` scene for preferences
177
+ - **Toolbar** — `.toolbar { }` modifier for window toolbars
178
+ - **Sidebar** — `NavigationSplitView` for master-detail layouts
179
+ - **Drag & drop** — `.onDrop()` and `.draggable()` modifiers
180
+ - **Sandboxing** — App Sandbox for Mac App Store distribution
181
+
182
+ ## Native: Windows (WPF / WinUI 3)
183
+
184
+ ### WinUI 3 Architecture
185
+ - **XAML** for declarative UI layout
186
+ - **MVVM** pattern (Model-View-ViewModel)
187
+ - **Windows App SDK** for modern APIs
188
+ - **WinGet / MSIX** for distribution
189
+
190
+ ### Key Features
191
+ - Fluent Design System integration
192
+ - Acrylic/Mica material backgrounds
193
+ - Toast notifications via Windows API
194
+ - File system and registry access
195
+ - MSI/MSIX packaging for enterprise deployment
196
+
197
+ ## Native: Linux (GTK 4)
198
+
199
+ ### GTK 4 Key Concepts
200
+ - **Widgets** — composable UI elements
201
+ - **Signals** — event-driven communication between widgets
202
+ - **CSS styling** — GTK supports CSS for theming
203
+ - **Flatpak** — recommended packaging format for distribution
204
+
205
+ ### GNOME Integration
206
+ - Follow GNOME Human Interface Guidelines (HIG)
207
+ - Use libadwaita for adaptive, modern GNOME UI
208
+ - Support dark/light theme switching via system preference
209
+ - Use GSettings for persistent configuration
210
+
211
+ ## Desktop-Specific Patterns
212
+
213
+ ### System Tray / Menu Bar
214
+ - Minimize to tray for background apps
215
+ - Show status indicators and quick actions
216
+ - Right-click context menu for common operations
217
+ - Notifications from tray icon
218
+
219
+ ### File System Access
220
+ - Use native file dialogs for open/save (never custom file pickers)
221
+ - Watch file system for changes (fs.watch, FSEvents, inotify)
222
+ - Handle file associations — register as handler for file types
223
+ - Recent files list — track and display recently opened files
224
+
225
+ ### Native Menus & Keyboard Shortcuts
226
+ - Follow platform conventions (Cmd on macOS, Ctrl on Windows/Linux)
227
+ - Standard menu structure: File, Edit, View, Window, Help
228
+ - Global shortcuts for power users
229
+ - Context menus for right-click actions
230
+
231
+ ### Window Management
232
+ - Remember window size and position between launches
233
+ - Support multiple windows when appropriate
234
+ - Handle fullscreen/maximize/minimize states
235
+ - Multi-monitor awareness
236
+
237
+ ### Drag & Drop
238
+ - Support drag from file explorer into app
239
+ - Internal drag for reordering, organizing
240
+ - Drag out to export (files, text, images)
241
+ - Visual feedback during drag operations
242
+
243
+ ## Auto-Update
244
+
245
+ | Framework | Update Mechanism |
246
+ |-----------|-----------------|
247
+ | Tauri | Built-in updater plugin (checks remote endpoint) |
248
+ | Electron | electron-updater (GitHub Releases, S3, generic server) |
249
+ | macOS Native | Sparkle framework (RSS-based updates) |
250
+ | Windows Native | WinGet, MSIX auto-update, ClickOnce |
251
+ | Linux | Flatpak auto-update, AppImage with AppImageUpdate |
252
+
253
+ ### Update Best Practices
254
+ - Check for updates on launch (non-blocking)
255
+ - Allow user to defer updates
256
+ - Show changelog/release notes
257
+ - Delta updates when possible (reduce download size)
258
+ - Rollback mechanism for failed updates
259
+ - Code sign updates to prevent tampering
260
+
261
+ ## Packaging & Distribution
262
+
263
+ ### macOS
264
+ - **DMG** — Disk image with drag-to-Applications install
265
+ - **pkg** — Installer package for complex setups
266
+ - **Mac App Store** — Sandboxed, Apple review required
267
+ - **Code signing** — Required for Gatekeeper (Developer ID)
268
+ - **Notarization** — Required for distribution outside App Store
269
+
270
+ ### Windows
271
+ - **MSI** — Traditional Windows installer
272
+ - **MSIX** — Modern packaging, auto-update, sandboxed
273
+ - **Portable** — Single .exe, no installation
274
+ - **Code signing** — EV certificate to avoid SmartScreen warnings
275
+ - **Microsoft Store** — Optional, sandboxed distribution
276
+
277
+ ### Linux
278
+ - **AppImage** — Single-file, no installation, runs on most distros
279
+ - **Flatpak** — Sandboxed, auto-update, Flathub distribution
280
+ - **Snap** — Canonical's universal package (Ubuntu-focused)
281
+ - **deb/rpm** — Traditional packages for specific distros
282
+
283
+ ## Technology Recommendations
284
+
285
+ ### By Use Case
286
+ | Use Case | Recommended Stack |
287
+ |----------|-------------------|
288
+ | Web team → Desktop | Tauri + React/Vue/Svelte |
289
+ | Legacy web app → Desktop | Electron + existing frontend |
290
+ | macOS-only tool | SwiftUI + AppKit |
291
+ | Windows enterprise app | WinUI 3 + .NET |
292
+ | Linux GNOME app | GTK 4 + Rust (gtk-rs) or Python |
293
+ | Cross-platform + mobile | .NET MAUI (C#) |
294
+ | Performance-critical (CAD, games) | Qt/QML + C++ |
295
+ | Small utility / CLI with UI | Tauri + minimal frontend |
@@ -0,0 +1,210 @@
1
+ ---
2
+ name: frontend-development
3
+ description: Component architecture, state management, rendering strategies, styling, and accessibility for modern frontend applications
4
+ license: Apache-2.0
5
+ compatibility: opencode
6
+ ---
7
+
8
+ # Frontend Development Skill
9
+
10
+ This skill provides patterns and best practices for building modern frontend applications across frameworks.
11
+
12
+ ## When to Use
13
+
14
+ Use this skill when:
15
+ - Starting a new frontend project or choosing a framework
16
+ - Designing component architecture and state management
17
+ - Implementing routing, SSR/SSG, or rendering strategies
18
+ - Making styling and accessibility decisions
19
+ - Optimizing frontend performance and build tooling
20
+
21
+ ## Component Architecture
22
+
23
+ ### Design Principles
24
+ - Single Responsibility — one component, one purpose
25
+ - Composition over inheritance — combine small components into complex UIs
26
+ - Controlled vs uncontrolled — explicit state vs DOM-managed state
27
+ - Container/Presentational — separate data logic from rendering
28
+ - Compound components — related components that share implicit state
29
+
30
+ ### Component Patterns
31
+
32
+ ```typescript
33
+ // Composition pattern — flexible, reusable
34
+ interface CardProps {
35
+ children: React.ReactNode;
36
+ }
37
+
38
+ function Card({ children }: CardProps) {
39
+ return <div className="card">{children}</div>;
40
+ }
41
+
42
+ Card.Header = ({ children }: CardProps) => (
43
+ <div className="card-header">{children}</div>
44
+ );
45
+ Card.Body = ({ children }: CardProps) => (
46
+ <div className="card-body">{children}</div>
47
+ );
48
+ ```
49
+
50
+ ### Custom Hooks / Composables
51
+ - Extract reusable logic into hooks (React) or composables (Vue)
52
+ - Keep hooks focused — one concern per hook
53
+ - Prefix with `use` (React/Vue) for convention
54
+ - Return minimal API surface — only what consumers need
55
+
56
+ ## Framework Patterns
57
+
58
+ ### React
59
+ - Hooks for all state and effects (useState, useEffect, useReducer)
60
+ - Context for cross-cutting concerns (theme, auth, locale)
61
+ - Suspense + lazy() for code splitting
62
+ - Server Components (RSC) for reduced client bundle
63
+ - Error Boundaries for graceful failure handling
64
+
65
+ ### Vue 3
66
+ - Composition API with `<script setup>` for concise components
67
+ - Composables for reusable logic (equivalent to React hooks)
68
+ - Provide/Inject for dependency injection
69
+ - Teleport for portal rendering
70
+ - Keep Options API for simple components if team prefers
71
+
72
+ ### Angular
73
+ - Standalone components (preferred over NgModules)
74
+ - Signals for reactive state management
75
+ - Services with dependency injection for shared logic
76
+ - RxJS for complex async flows
77
+ - Structural directives for template logic
78
+
79
+ ### Svelte
80
+ - Runes ($state, $derived, $effect) for reactivity (Svelte 5)
81
+ - Stores for shared state across components
82
+ - Actions for reusable DOM behavior
83
+ - Transitions and animations built-in
84
+ - Minimal boilerplate — write less, do more
85
+
86
+ ### Laravel Frontend (Blade, Livewire, Inertia.js)
87
+ - **Blade** — Server-rendered templates with `@directives`, layouts, and components
88
+ - **Livewire** — Reactive components without writing JavaScript (server-driven SPA feel)
89
+ - **Inertia.js** — SPA experience using React/Vue/Svelte with Laravel backend (no API needed)
90
+ - **Vite integration** — Built-in Vite support for asset bundling (`@vite` directive)
91
+ - Use Livewire for CRUD-heavy admin panels and dashboards
92
+ - Use Inertia.js for full SPA behavior with Laravel routing and auth
93
+
94
+ ## State Management
95
+
96
+ ### State Categories
97
+ | Type | Scope | Tools |
98
+ |------|-------|-------|
99
+ | Local state | Single component | useState, ref(), signal |
100
+ | Shared state | Component subtree | Context, provide/inject, props |
101
+ | Global state | Entire app | Redux/Zustand, Pinia, NgRx, Svelte stores |
102
+ | Server state | Remote data cache | TanStack Query, SWR, Apollo Client |
103
+ | URL state | Browser URL | React Router, Vue Router, route params |
104
+ | Form state | Form inputs | React Hook Form, Formik, VeeValidate |
105
+
106
+ ### Best Practices
107
+ - Keep state as local as possible — lift only when needed
108
+ - Normalize nested data in global stores
109
+ - Use server state libraries for API data — avoid duplicating cache
110
+ - Derive state instead of storing computed values
111
+ - Use optimistic updates for responsive UIs
112
+
113
+ ## Routing & Navigation
114
+
115
+ - File-based routing (Next.js, SvelteKit, Nuxt) — convention over configuration
116
+ - Nested routes for layout composition
117
+ - Route guards / middleware for auth protection
118
+ - Code splitting by route for optimal loading
119
+ - Parallel routes for simultaneous views (Next.js App Router)
120
+ - Preserve scroll position on navigation
121
+
122
+ ## Rendering Strategies
123
+
124
+ | Strategy | When to Use | Examples |
125
+ |----------|-------------|---------|
126
+ | CSR (Client-Side) | Interactive apps, auth-gated content | SPAs, dashboards |
127
+ | SSR (Server-Side) | SEO-critical, dynamic content | E-commerce, news sites |
128
+ | SSG (Static Generation) | Content that rarely changes | Blogs, docs, marketing |
129
+ | ISR (Incremental Static) | Static + periodic updates | Product catalogs |
130
+ | Streaming SSR | Large pages, progressive loading | Next.js App Router, SvelteKit |
131
+
132
+ ### Meta-Framework Recommendations
133
+ - **Next.js** — React, hybrid rendering, App Router for RSC
134
+ - **Nuxt 3** — Vue 3, auto-imports, hybrid rendering
135
+ - **SvelteKit** — Svelte, file-based routing, adapters for any platform
136
+ - **Astro** — Content-focused, island architecture, multi-framework
137
+
138
+ ## Styling Approaches
139
+
140
+ | Approach | Pros | Cons | Best For |
141
+ |----------|------|------|----------|
142
+ | Tailwind CSS | Fast, consistent, small bundle | Verbose markup | Most projects |
143
+ | CSS Modules | Scoped, standard CSS | No dynamic styles | Component libraries |
144
+ | CSS-in-JS | Dynamic, co-located | Runtime overhead | Theme-heavy apps |
145
+ | SCSS/Sass | Powerful, familiar | Global scope risk | Large legacy projects |
146
+
147
+ ### Design Tokens
148
+ - Use CSS custom properties for theming
149
+ - Define tokens for colors, spacing, typography, shadows
150
+ - Support dark mode with `prefers-color-scheme` and class toggle
151
+ - Use design system tools (Style Dictionary, Tailwind config)
152
+
153
+ ## Accessibility
154
+
155
+ ### Core Requirements
156
+ - Semantic HTML first — use `<button>`, `<nav>`, `<main>`, `<article>`
157
+ - Keyboard navigation — all interactive elements focusable and operable
158
+ - ARIA attributes — use only when semantic HTML is insufficient
159
+ - Color contrast — minimum 4.5:1 for normal text (WCAG AA)
160
+ - Screen reader testing — test with VoiceOver, NVDA, or JAWS
161
+
162
+ ### Common Patterns
163
+ - Skip navigation links for keyboard users
164
+ - Focus management on route changes (SPAs)
165
+ - Live regions (`aria-live`) for dynamic content updates
166
+ - Form labels — every input needs an associated label
167
+ - Alt text — descriptive for content images, empty for decorative
168
+
169
+ ## Performance
170
+
171
+ ### Core Web Vitals
172
+ - **LCP** (Largest Contentful Paint) < 2.5s — optimize hero images, fonts
173
+ - **INP** (Interaction to Next Paint) < 200ms — reduce JS execution
174
+ - **CLS** (Cumulative Layout Shift) < 0.1 — reserve space for dynamic content
175
+
176
+ ### Optimization Techniques
177
+ - Memoization (useMemo, useCallback, React.memo, computed)
178
+ - Lazy loading for below-fold content and heavy components
179
+ - Virtualization for long lists (TanStack Virtual, react-window)
180
+ - Image optimization (next/image, responsive srcset, WebP/AVIF)
181
+ - Bundle analysis and tree shaking
182
+
183
+ ## Build Tooling
184
+
185
+ ### Recommended Tools
186
+ - **Vite** — Fast dev server, optimized production builds (recommended for most projects)
187
+ - **Turbopack** — Next.js incremental bundler
188
+ - **Webpack** — Mature, extensive plugin ecosystem
189
+ - **esbuild** — Ultra-fast bundling for libraries
190
+
191
+ ### Best Practices
192
+ - Enable tree shaking — use ES modules, avoid side effects
193
+ - Configure code splitting — route-based and component-based
194
+ - Analyze bundle size regularly (rollup-plugin-visualizer, webpack-bundle-analyzer)
195
+ - Use import aliases for clean paths
196
+ - Configure path aliases in tsconfig and bundler
197
+
198
+ ## Technology Recommendations
199
+
200
+ ### By Project Type
201
+ | Project | Recommended Stack |
202
+ |---------|-------------------|
203
+ | SPA / Dashboard | React + Vite + Zustand + Tailwind |
204
+ | SEO + Dynamic | Next.js (App Router) + TanStack Query |
205
+ | Content Site | Astro + any UI framework + MDX |
206
+ | Enterprise App | Angular + NgRx + Material |
207
+ | Rapid Prototyping | SvelteKit + Tailwind |
208
+ | Vue Ecosystem | Nuxt 3 + Pinia + VueUse + Tailwind |
209
+ | Laravel Full-Stack | Laravel + Inertia.js + Vue/React + Tailwind |
210
+ | Laravel Server-Driven | Laravel + Livewire + Alpine.js + Tailwind (TALL stack) |