PPT.ai is a full-stack web app that turns plain text or notes into slide decks. You describe what you want, pick style and tone, and the app uses AI to draft slides with titles, content, speaker notes, and image prompts. You can preview the deck in the browser, present in a fullscreen slideshow, and download a .pptx file.
The product name and positioning match the app shell: “PPT.ai — Generate presentations from text” (see src/routes/__root.tsx).
| Area | Choice |
|---|---|
| Framework | TanStack Start + TanStack Router (file-based routes, SSR) |
| UI | React 19, Tailwind CSS v4, Radix UI / shadcn-style components |
| Data & cache | TanStack Query, Prisma 7 + PostgreSQL |
| Auth | Better Auth with Google and GitHub OAuth, Prisma adapter |
| AI | Vercel AI SDK (ai, @ai-sdk/google) — Gemini for structured slide generation |
| Background jobs | Inngest — async presentation/generate workflow |
| Images | ImageKit URLs for slide imagery (see src/integrations/inngest/functions.ts) |
| Export | PptxGenJS |
| Env validation | @t3-oss/env-core (src/env.ts) |
| Tooling | Vite 8, TypeScript, Vitest, ESLint (TanStack config), Prettier |
- Sign in with Google or GitHub (Better Auth +
/api/auth/*). - Home (
/) — Authenticated dashboard: list presentations, compose a prompt, choose slide count, style, tone, and layout, then create a deck. Creating a presentation enqueues generation and navigates to the detail page. - Presentation detail (
/presentations/:presentationId) — Live status while Inngest generates slides; view slides in a carousel-style preview; edit metadata and content; regenerate the deck; delete; fullscreen preview; slideshow modal; export to PowerPoint (.pptx). - Public-ish routes —
/loginand auth/Inngest API paths are public (seesrc/lib/auth-paths.ts)./aboutexists as a simple marketing-style page (other routes may enforce auth inbeforeLoad). - Server functions — Create/update/regenerate/delete presentations and load data via TanStack Start
createServerFn(undersrc/features/presentations/).
- Node.js (current LTS recommended)
- pnpm (preferred in this repo;
npmalso works — both lockfiles may be present) - PostgreSQL database
- Google AI (Gemini) API key for generation
- Inngest for background runs (local dev uses the Inngest dev server; production uses your deployed
/api/inngestendpoint) - ImageKit account and keys for slide image URLs
- OAuth apps (optional but expected for login): Google and/or GitHub developer console apps with correct redirect URLs
Create a .env or .env.local in the project root (Prisma also loads these via prisma.config.ts).
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string for Prisma |
BETTER_AUTH_SECRET |
Yes* | Secret for Better Auth sessions (*required for real auth; generate e.g. with npx @better-auth/cli secret) |
GOOGLE_GENERATIVE_AI_API_KEY |
Yes | Gemini API key for @ai-sdk/google / generateText in Inngest |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
For Google sign-in | OAuth credentials |
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET |
For GitHub sign-in | OAuth credentials |
IMAGEKIT_PUBLIC_KEY |
Yes (for generation path) | ImageKit public key |
IMAGEKIT_PRIVATE_KEY |
Yes | ImageKit private key |
IMAGEKIT_BASE_URL |
Yes | ImageKit URL endpoint (used when building slide image URLs) |
VITE_APP_TITLE |
No | Optional client-visible app title (src/env.ts) |
SERVER_URL |
No | Optional server URL (src/env.ts) |
Better Auth / OAuth: Configure your provider dashboards so redirect URLs match your environment (e.g. http://localhost:3000/api/auth/callback/google for local dev). See Better Auth docs.
Google AI: Key creation and quotas are documented in Google AI Studio.
-
Install dependencies
pnpm install
-
Configure environment
Add the variables from the table above to.envor.env.local. -
Database
pnpm db:generate pnpm db:push
Or use migrations if you prefer:
pnpm db:migrate
Optional seed (currently seeds example Todo rows from
prisma/seed.ts, not presentations):pnpm db:seed
-
Inngest (local development)
Run the Inngest dev server so/api/inngestcan receive and execute functions (e.g.generatePresentation). Typical workflow:npx inngest-cli@latest dev
Point it at your app URL (e.g.
http://localhost:3000) per Inngest CLI instructions so events and thepresentation/generatefunction run locally. -
Start the app
pnpm dev
The dev server defaults to port 3000 (
package.jsonscript).
| Script | Description |
|---|---|
pnpm dev |
Vite dev server (TanStack Start) on port 3000 |
pnpm build |
Production build |
pnpm preview |
Preview production build |
pnpm test |
Vitest |
pnpm lint |
ESLint |
pnpm format |
Prettier check |
pnpm check |
Format write + ESLint fix |
pnpm db:generate |
prisma generate |
pnpm db:push |
Push schema to DB |
pnpm db:migrate |
Create/apply migrations |
pnpm db:studio |
Prisma Studio |
pnpm db:seed |
Run seed script |
src/
routes/ # File-based routes (__root, index, login, presentations, api/inngest, api/auth)
features/presentations/ # UI, hooks, server actions, queries, export-pptx, templates/options
integrations/ # TanStack Query root provider, Inngest client + functions
lib/ # auth, auth paths, imagekit helpers
middleware/ # Auth middleware helpers (e.g. for server functions)
components/ # Shared UI (including shadcn-style components)
db.ts # Prisma client + PostgreSQL adapter
prisma/
schema.prisma # User, Presentation, Slide, Better Auth models
Generated Prisma client output: src/generated/prisma (see schema.prisma generator block).
- User submits a prompt and options on
/→createPresentationserver function creates aPresentationrow with statusGENERATINGand sends an Inngest eventpresentation/generate. - Inngest (
src/integrations/inngest/functions.ts) loads the presentation, calls Gemini with a structured schema for slides, replacesSliderows, builds ImageKit-backed image URLs, then marks the presentationCOMPLETED(or you can extend error handling forFAILED). - The detail page polls/refetches so the UI updates when generation finishes.
Add components with the latest CLI:
pnpm dlx shadcn@latest add buttonpnpm test
pnpm lint
pnpm format
pnpm check