Hackerlab is an Electron desktop app - a JavaScript/TypeScript REPL similar to RunJS with enhanced features:
- TypeScript, JSX/TSX support with full type checking
- Import any npm package (server or client side)
- Output panel displays results or rendered React components
- Notion-style "blocks" for organizing different content types
- VS Code theme compatibility (installable from marketplace)
- Work in progress - not yet production ready
- Runtime: Electron
- UI: React + TailwindCSS
- Editor: Monaco Editor
- Languages: TypeScript, TSX, JSX
- Always use TypeScript instead of JavaScript unless specifically directed otherwise
- Always use
typeinstead ofinterfacefor type definitions - Use explicit
typekeyword for type imports:- All type imports:
import type { Type1, Type2 } from './file' - Mixed imports:
import { type Type1, type Type2, someFunction } from './file'
- All type imports:
- Keep types close to the functions/modules they're used with (don't create separate
types.tsfiles just to store types) - Path aliases: Use
@/*→src/*(this project has a build step) - Prefer options objects over multiple function parameters for better readability and flexibility:
-
Multiple positional parameters obscure argument meaning and require remembering order
-
Options objects are self-documenting, can be passed in any order, and are easier to extend
-
Exception: If a function has a clear "primary" argument (the main subject of the operation), use it as the first positional parameter followed by an options object:
// Good: primary argument + options function findUser( id: string, options: { includeDeleted?: boolean; fields?: string[] }, ) // Good: all options (no clear primary) function createReport(options: { startDate: Date endDate: Date format: string }) // Avoid: multiple positional parameters function findUser(id: string, includeDeleted: boolean, fields: string[])
-
- Functional components with TypeScript
- Use
typefor props definitions (not interface) - In useEffect, define async function inside then call it:
useEffect(() => { async function fetchData() { try { const result = await doSomething() setData(result) } catch (error: unknown) { console.error(error) } } fetchData() }, [])
- Clear main/renderer process separation
- Use IPC for process communication
- Preload scripts for secure context bridging
- Configure for TypeScript/TSX language support
- Integrate VS Code themes
- Use Tailwind utility classes for styling
- Keep custom CSS minimal
- Notion-style blocks for content organization
- Block types: code, output, markdown, React component preview
- Use
pnpm/pnpx(not npm/yarn/npx)
- Use ESM (
"type": "module"in package.json) - Use
import/exportsyntax (not CommonJSrequire/module.exports)
- Use defaults from github/gitignore for project type
- ALWAYS include
.envin every.gitignore
- Use Conventional Commits format (
feat:,fix:,chore:, etc.) - Use multiple
-mflags to separate title from body (keeps GitHub titles clean):git commit -m "feat: Add database initialization" -m "Detect if database is installed, run seeds if detected"
- Do NOT include "Co-authored-by: Claude" or similar attribution
{ "printWidth": 80, "semi": false, "singleQuote": true, "trailingComma": "all" }- Create
.prettierignoreexcluding markdown files - Add script:
"format": "prettier --write ."
- Use reasonable defaults for React/TypeScript project
- Add script:
"lint": "eslint ."
- Use
try/catchwith thrown errors - Always use
error(noterr) in catch blocks - Always use
awaitinstead of.then()chains - Error messages should include actionable fix suggestions
- Use
functionkeyword for named functions:function myFunction() {} - Use arrow functions only for: anonymous functions, inline callbacks, IIFEs
- IIFE style:
(() => {})()not(function() {})()
- Files: kebab-case (e.g.,
user-service.ts,api-helpers.ts) - Functions/Variables: camelCase (e.g.,
getUserById,isActive) - Types: PascalCase (e.g.,
UserConfig,ApiResponse) - Constants: SCREAMING_SNAKE_CASE (e.g.,
DEFAULT_TIMEOUT,MAX_RETRIES) - React Components: PascalCase files (e.g.,
CodeBlock.tsx,OutputPanel.tsx)
- Always ask before setting up testing
- Use Vitest for this project (React + Vite-based tooling)
- Ask before updating README.md after significant features
- Do not create markdown files without asking