smithery/verekia

verekia-setup

Verekia's preferred project setup with Next.js Pages Router, Tailwind 4, oxfmt, oxlint, and TypeScript.

Installation

$ npx skills add smithery/verekia --skill verekia-setup

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/verekia · top by installs.

npx skills add smithery/verekia

Browse all from smithery/verekia

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 9,962 B
  • docs SUMMARY.md 119 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Verekia's Project Setup

Installation instructions and boilerplate for setting up a new R3F game project.

package.json

{
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "serve out"
  },
  "dependencies": {
    "@react-three/drei": "11.0.0-alpha.4",
    "@react-three/fiber": "10.0.0-alpha.1",
    "miniplex": "2.0.0",
    "miniplex-react": "2.0.1",
    "next": "16.1.2",
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "three": "0.182.0",
    "zustand": "5.0.10"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "4.1.18",
    "@types/node": "25.0.9",
    "@types/react": "19.2.8",
    "@types/react-dom": "19.2.3",
    "@types/three": "0.182.0",
    "@verekia/warden": "0.0.3",
    "babel-plugin-react-compiler": "1.0.0",
    "oxfmt": "0.48.0",
    "oxlint": "1.63.0",
    "portless": "0.13.0",
    "postcss": "8.5.6",
    "serve": "14.2.5",
    "tailwindcss": "4.1.18",
    "typescript": "5.9.3"
  },
  "overrides": {
    "three": "0.182.0"
  },
  "patchedDependencies": {
    "[email protected]": "patches/[email protected]",
    "[email protected]": "patches/[email protected]"
  }
}

Use Bun as package manager and runtime.

patches/[email protected]

Fixes GPUShaderStage SSR error:

diff --git a/build/three.webgpu.js b/build/three.webgpu.js
index 31ff163d67f4cc5dec060a11bc7151c64f949fd9..823c1c35bca5411a27cbf52c5c3a188001fe0445 100644
--- a/build/three.webgpu.js
+++ b/build/three.webgpu.js
@@ -70604,7 +70604,7 @@ const GPUPrimitiveTopology = {
 	TriangleStrip: 'triangle-strip',
 };

-const GPUShaderStage = ( typeof self !== 'undefined' ) ? self.GPUShaderStage : { VERTEX: 1, FRAGMENT: 2, COMPUTE: 4 };
+const GPUShaderStage = ( typeof self !== 'undefined' && self.GPUShaderStage ) ? self.GPUShaderStage : { VERTEX: 1, FRAGMENT: 2, COMPUTE: 4 };

 const GPUCompareFunction = {
 	Never: 'never',

patches/[email protected]

Adds missing exports field:

diff --git a/package.json b/package.json
index 22ffa92b457c0d83c052eab3f1961110d134d1b3..4f5f9ef7a8a80d6f85e3e5b241a87091d95bbe39 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,12 @@
   "main": "dist/detect-gpu.umd.js",
   "module": "dist/detect-gpu.esm.js",
   "types": "dist/src/index.d.ts",
+  "exports": {
+    ".": {
+      "import": "./dist/detect-gpu.esm.js",
+      "require": "./dist/detect-gpu.umd.js"
+    }
+  },
   "homepage": "https://github.com/pmndrs/detect-gpu#readme",
   "bugs": {
     "url": "https://github.com/pmndrs/detect-gpu/issues"

Run bun install to apply patches.

next.config.mjs

Use the Pages Router with static export:

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  reactCompiler: true,
  output: 'export',
}

export default nextConfig

Pages go in pages/ directory. Each file becomes a route. 'use client' directives should not be used since we are in the Pages router.

global.css

Tailwind 4 uses CSS-based configuration with @import. No tailwind.config.js needed.

@import 'tailwindcss';

body {
  background-color: #111;
  color: #eee;
}

html,
body,
#__next,
canvas {
  height: 100%;
  width: 100%;
}

.oxfmtrc.json

{
  "$schema": "./node_modules/oxfmt/configuration_schema.json",
  "printWidth": 120,
  "tabWidth": 2,
  "useTabs": false,
  "semi": false,
  "singleQuote": true,
  "trailingComma": "all",
  "arrowParens": "avoid",
  "bracketSpacing": true,
  "sortTailwindcss": true,
  "ignorePatterns": ["node_modules", "dist", "out", ".next"]
}

tsconfig.json

No src/ folder - files live at the root. Use @/ for absolute imports.

No need to create tsconfig.json manually. Run bun run build and Next.js will create it. Add the @/ paths to the generated file:

{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "noEmit": true,
    "incremental": true,
    "module": "esnext",
    "esModuleInterop": true,
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "paths": { "@/*": ["./*"] }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

.gitignore

node_modules/
.next/
out/
.DS_Store
.env*.local
*.tsbuildinfo
analyze/
*.blend1
next-env.d.ts
playwright-report/
.last-run.json

Folder Structure

Create these folders and files:

entities/
  entities.tsx (empty)
models/
systems/
stores/
  core-store.ts
  ui-store.ts
  local-store.ts
lib/
  ecs.ts
  hooks.ts
  math.ts
components/
  ModelContainer.tsx
r3f.d.ts

Boilerplate: r3f.d.ts

R3F type declarations for WebGPU. Make sure it's included in your tsconfig.json.

import type { ThreeToJSXElements } from '@react-three/fiber'
import type * as THREE from 'three/webgpu'

declare module '@react-three/fiber' {
  interface ThreeElements extends ThreeToJSXElements<typeof THREE> {}
}

Boilerplate: lib/ecs.ts

import { World } from 'miniplex'
import createReactAPI from 'miniplex-react'
import { Object3D } from 'three'

type Entity = {
  position?: { x: number; y: number; z: number }
  velocity?: { x: number; y: number; z: number }
  three?: Object3D
}

export const world = new World<Entity>()

export const { Entities } = createReactAPI(world)

Boilerplate: components/ModelContainer.tsx

import { ReactNode } from 'react'
import { Object3D } from 'three'
import { world } from '@/lib/ecs'

type Entity = {
  three?: Object3D
}

export const ModelContainer = ({ children, entity }: { children: ReactNode; entity: Entity }) => (
  <group
    ref={ref => {
      if (!ref) return
      world.addComponent(entity, 'three', ref)
      return () => {
        world.removeComponent(entity, 'three')
      }
    }}
  >
    {children}
  </group>
)

Boilerplate: stores/core-store.ts

import { create } from 'zustand'

const defaultState = {
  isDebugMode: false,
}

type State = typeof defaultState
type Key = keyof State

const useCoreStore = create<State>(() => structuredClone(defaultState))
export const useCore = <K extends Key>(key: K) => useCoreStore(state => state[key])
export const getCore = useCoreStore.getState
export const setCore = <K extends Key>(...args: [key: K, value: State[K]] | [state: Partial<State>]) =>
  useCoreStore.setState(args.length === 2 ? { [args[0]]: args[1] } : args[0])
export const resetCore = () => useCoreStore.setState(structuredClone(defaultState))

// @ts-expect-error Normal
if (typeof window !== 'undefined') window.getCore = getCore

Boilerplate: stores/ui-store.ts

import { create } from 'zustand'

const defaultState = {
  areSettingsOpen: false,
}

type State = typeof defaultState
type Key = keyof State

export type UIState = State
export type UIKey = Key

const useUIStore = create<State>(() => structuredClone(defaultState))
export const useUI = <K extends Key>(key: K) => useUIStore(state => state[key])
export const getUI = useUIStore.getState
export const setUI = <K extends Key>(...args: [key: K, value: State[K]] | [state: Partial<State>]) =>
  useUIStore.setState(args.length === 2 ? { [args[0]]: args[1] } : args[0])
export const resetUI = () => setUI(structuredClone(defaultState))

export const isAnyModalOpen = () => {
  const ui = getUI()
  return ui.areSettingsOpen
}

export const closeAnyModal = () => {
  if (getUI().areSettingsOpen) {
    setUI('areSettingsOpen', false)
    return true
  }
  return false
}

export const useIsAnyModalOpen = () => {
  const areSettingsOpen = useUI('areSettingsOpen')
  return areSettingsOpen
}

// @ts-expect-error Normal
if (typeof window !== 'undefined') window.getUI = getUI

Boilerplate: stores/local-store.ts

import { create } from 'zustand'
import { persist } from 'zustand/middleware'

const defaultState = {
  hello: 'world',
}

type State = typeof defaultState
type Key = keyof State

const useLocalStore = create<State>()(persist(() => structuredClone(defaultState), { name: 'my-game-local' }))
export const useLocal = <K extends Key>(key: K) => useLocalStore(state => state[key])
export const getLocal = useLocalStore.getState
export const setLocal = <K extends Key>(...args: [key: K, value: State[K]] | [state: Partial<State>]) =>
  useLocalStore.setState(args.length === 2 ? { [args[0]]: args[1] } : args[0])
export const resetLocal = () => setLocal(structuredClone(defaultState))

// @ts-expect-error Normal
if (typeof window !== 'undefined') window.getLocal = getLocal

Boilerplate: lib/hooks.ts

import { useFrame } from '@react-three/fiber/webgpu'
import { useRef, useState } from 'react'

export const useReactive = <T>(selector: () => T, fps = 30): T => {
  const [reactiveValue, setReactiveValue] = useState<T>(selector())
  const previousValueRef = useRef(reactiveValue)

  useFrame(
    () => {
      const newValue = selector()
      if (previousValueRef.current !== newValue) {
        previousValueRef.current = newValue
        setReactiveValue(newValue)
      }
    },
    { fps },
  )

  return reactiveValue
}

export const useReactiveSlow = <T>(selector: () => T): T => useReactive(selector, 10)
export const useReactiveFast = <T>(selector: () => T): T => useReactive(selector, 30)

Boilerplate: lib/math.ts

// https://lisyarus.github.io/blog/posts/exponential-smoothing.html
// Usage: `mesh.position.x += addSmoothExp(mesh.position.x, targetX, 10, dt)`
export const addSmoothExp = (current: number, target: number, speed: number, dt: number) =>
  (target - current) * (1 - Math.exp(-speed * dt))

This skill is part of verekia's r3f-gamedev.