From darkroom
Creates typed reusable React hooks (useX pattern) for Next.js or React Router projects, auto-detecting stack from package.json and generating templates in lib/hooks or hooks directories.
npx claudepluginhub darkroomengineering/cc-settingsThis skill uses the workspace's default tool permissions.
Create a custom React hook following Darkroom conventions. The hook itself is stack-agnostic — what differs between satus and novus is the path alias.
Generates React hooks with step-by-step guidance, best practices, and production-ready code. Activates for frontend development tasks on 'react hook creator' mentions, covering React, Vue, CSS, accessibility, and performance.
Guides React Hooks usage including useState, useEffect, useContext, useReducer, useMemo, useCallback, custom hooks, and patterns for state, effects, and performance in functional components.
Guides writing React hooks with conventions for object returns, SSR safety, state design, effect patterns, cleanup, TypeScript, and performance.
Share bugs, ideas, or general feedback.
Create a custom React hook following Darkroom conventions. The hook itself is stack-agnostic — what differs between satus and novus is the path alias.
Read package.json:
dependencies.next → satus / Next.js (path alias @/, no lib/hooks/ requires 'use client' boundary)dependencies["react-router"] → novus / React Router (path alias ~/, components isomorphic)| Stack | Hook path |
|---|---|
| satus | lib/hooks/<name>.ts |
| novus | hooks/<name>.ts (novus puts hooks/ at the project root) |
Confirm by checking the existing lib/hooks/ or hooks/ directory structure if either pattern is unclear from package.json alone.
// lib/hooks/<name>.ts
'use client'
import { useState, useEffect } from 'react'
interface Use<Name>Options {
// Hook configuration options
}
interface Use<Name>Return {
// Return type definition
}
export function use<Name>(options?: Use<Name>Options): Use<Name>Return {
// Implementation
return {
// Return values
}
}
// hooks/<name>.ts
// No 'use client' — RR components are isomorphic; the hook runs wherever
// it's called from. If the hook touches browser APIs, guard with
// `typeof window !== 'undefined'` or call from inside `useEffect`.
import { useState, useEffect } from 'react'
interface Use<Name>Options {
// Hook configuration options
}
interface Use<Name>Return {
// Return type definition
}
export function use<Name>(options?: Use<Name>Options): Use<Name>Return {
// Implementation
return {
// Return values
}
}
export function useX, not default.use — React hook naming convention.| satus | novus | |
|---|---|---|
| Directive | 'use client' (hooks live in client boundary) | None (isomorphic) |
| Browser API guard | Only runs after hydration anyway | Guard with typeof window or use useEffect |
| Path alias | @/ | ~/ |
If this hook uses an external library, fetch docs first:
/docs <library> to get current API via context7.bun info <package> to check the latest version.For common use cases, prefer hamo hooks (run /docs hamo first):
import { useWindowSize, useRect, useIntersectionObserver } from 'hamo'
Only create custom hooks when hamo doesn't cover the use case.
User: "create a useLocalStorage hook" (in satus repo)
→ Creates lib/hooks/use-local-storage.ts with 'use client' directive
User: "create a useLocalStorage hook" (in novus repo)
→ Creates hooks/use-local-storage.ts, no directive, browser-API-guarded
$ARGUMENTS — Hook name (e.g., "useAuth", "useLocalStorage")