PVR Tech Studio
Getting started

Getting Started

Install Luminaux, run it locally, understand the project layout, and add your first page.

2 min read
Updated July 15, 2026

What you receive

Luminaux is a production-style React admin template. It ships as a real single-page application wired to a REST API client, with a fully configurable shell, 13 visual skins, dark mode, internationalization, and a large component + application library. This guide gets you from a fresh clone to a running dev server.

Tech stack

ConcernChoice
Build toolVite 6 (@vitejs/plugin-react)
FrameworkReact 19.2 + TypeScript 5.7 (strict)
StylingTailwind CSS v4 (CSS-first) + a small SCSS structural layer
RoutingReact Router 7
Iconslucide-react
AnimationMotion (motion/react) — free tier only
Data gridAG Grid Community v36
ChartsRecharts, ApexCharts, ECharts, Chart.js
CalendarFullCalendar v6 (MIT plugins + rrule)
Drag & drop@dnd-kit
i18ni18next + react-i18next
Rich textTiptap

Prerequisites

  • Node.js 20+ (Vite 6 requires Node 18+; 20 LTS recommended).
  • npm — the repo ships a package-lock.json. Yarn/pnpm work too, but examples use npm.

Install & run

Install dependencies

npm install

Start the dev server

Runs with hot-reload at http://localhost:5173 (Vite falls back to 5174 if the port is taken).

npm run dev

Build for production

Type-checks the project references, then bundles to dist/.

npm run build

Preview the production build

npm run preview

Environment variables

Create a .env file at the repo root as needed. Only variables prefixed with VITE_ are exposed to the client bundle.

# REST API base URL used by the HTTP client (src/lib/api.ts). Defaults to "/api" when unset.
VITE_API_BASE_URL=https://api.example.com
 
# Required only for the translation tool (npm run i18n:translate).
DEEPL_API_KEY=your-deepl-key

The API client reads VITE_API_BASE_URL through @/platform/env and auto-attaches a bearer token from localStorage('auth_token').

Adding a new page

A real page is three coordinated edits:

Register the route

Add a lazy(() => import('@/pages/…')) const and one appRoutes entry in src/routes.tsx. Every page is code-split and wrapped in one shared <Suspense>.

Add the nav item

Add a leaf to src/data/menu.ts — a menu leaf with no matching route auto-renders a titled placeholder, so nav and router can't drift.

Add the label

Add a nav:<key> string to src/locales/en/nav.json and render it via t('nav:<key>').

Was this page helpful?