← back_to_portfolio
The Problem

Journaling apps are graveyards of text. Day One, Notion, even physical journals — they store your thoughts with perfect fidelity and then do absolutely nothing with them. You can journal every day for five years and have no clearer picture of your emotional patterns, cognitive loops, or recurring themes than when you started. You're generating data with no analysis layer.

Therapists do the analysis — but they're expensive, available one hour a week, and work from the tiny fraction of what you say out loud. The rest of the signal is lost.

What if every journal entry was automatically read by something with the pattern-recognition of a therapist, the memory of a database, and the availability of software? What would that surface about how you actually think?

Pratyaksha (Sanskrit: "direct perception" or "clear seeing") is my attempt to answer that. Not a chatbot. Not a mood tracker. A multi-agent AI system that reads your entries the same way a skilled analyst would — looking for intent, emotion, themes, and contradictions — and then makes them visible.

My Approach

The central design decision was multi-agent over monolithic. A single LLM prompt like "analyse this journal entry" produces shallow, generic output — it tries to do everything and does nothing well. Instead, I decomposed the problem into four specialised concerns and gave each its own agent.

Critically, agents don't share state. Each agent receives the raw journal entry plus the structured output of the previous agent — nothing else. This keeps the reasoning chain clean, traceable, and debuggable. If the Emotion Agent produces a wrong classification, you can see exactly what it received and why it concluded what it did.

Design principle: agents should specialise, not generalise. The Intent Agent knows nothing about emotions. The Insight Agent knows nothing about raw text. Each is maximally good at one thing.

The marketing site was built to be a portfolio piece in itself — an interactive 3D brain that responds to emotional keywords typed in real-time (React Three Fiber), Apple-style scroll storytelling that walks through each agent's function (GSAP ScrollTrigger), and a Bento Grid displaying all 21 chart types with live sample data.

Architecture

The 4-agent pipeline — each agent receives raw entry + previous agent's structured output:

┌──────────────────────────────────────────────────────────────────┐
│                    PRATYAKSHA AGENT PIPELINE                     │
└──────────────────────────────────────────────────────────────────┘

  INPUT: Raw journal entry text (free-form, any length)
  │
  ▼
┌─────────────────────────────────────────────────────────────┐
│  AGENT 01: INTENT AGENT                                     │
│  Input:  raw entry                                          │
│  Output: { type: "Emotional|Cognitive|Work|Health",         │
│            confidence: 0.94,                                │
│            primary_concern: "...",                          │
│            context_tags: ["..."] }                          │
└──────────────────────────┬──────────────────────────────────┘
                           │ (raw entry + intent output)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  AGENT 02: EMOTION AGENT                                    │
│  Input:  raw entry + intent classification                  │
│  Output: { mood: "Anxious|Calm|Hopeful|...",                │
│            energy_level: 0-100,                             │
│            patterns: ["avoidance", "catastrophising"],      │
│            mode: "Anxious|Calm|Hopeful" }                   │
└──────────────────────────┬──────────────────────────────────┘
                           │ (raw entry + intent + emotion)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  AGENT 03: THEME AGENT                                      │
│  Input:  raw entry + intent + emotion + history             │
│  Output: { recurring_themes: ["..."],                       │
│            contradictions: ["..."],                         │
│            cognitive_loops: ["..."],                        │
│            narrative_shift: bool }                          │
└──────────────────────────┬──────────────────────────────────┘
                           │ (all above outputs)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  AGENT 04: INSIGHT AGENT                                    │
│  Input:  all previous outputs                               │
│  Output: { summary: "...",                                  │
│            recommendations: ["..."],                        │
│            next_action: "...",                              │
│            cbt_reframe: "..." }                             │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
  ┌─────────────────────────────────────────────────────┐
  │  21 VISUALISATIONS (Next.js Dashboard)              │
  │  React Query + aggressive caching + live data       │
  │  Emotional Timeline · Energy Radar · Heatmap        │
  │  Sankey Flow · Contradiction Tracker · + 15 more   │
  └─────────────────────────────────────────────────────┘

  Marketing: R3F 3D Brain + GSAP Scroll + Bento Grid
Hard Challenges
Challenge 01
3D Brain in React Three Fiber responding to real-time typed keywords

The marketing site hero has a 3D brain that reacts as a user types — activating different lobes, changing glow intensity, and pulsing based on the emotional valence of detected keywords. The challenge: keystrokes fire at human typing speed (6–12 chars/sec), WebGL is expensive, and a naive approach causes visible jank on every keystroke.

Solution: 300ms debounce on keyword detection so analysis only runs when the user pauses. Emotion-to-geometry mapping stored as a lookup table (not computed on every frame). Glow effects driven by shader uniforms updated via useFrame — not React state — so no re-renders occur during animation. Result: smooth 60fps even on mid-range mobile hardware.
Challenge 02
21 visualisations with live data — performance at dashboard scale

21 charts on a single dashboard, each making independent data requests, with some requiring the full history of journal entries — the naive implementation made 21 separate API calls on mount and the dashboard was unusable for users with more than a few months of data.

Solution: React Query with a carefully designed cache key strategy. All charts that share a data dependency use the same cache key — the first chart to mount fetches, every subsequent chart reads from cache. Charts that don't need live data are rendered server-side in Next.js App Router and hydrated statically.

Challenge 03
GSAP ScrollTrigger scroll storytelling without jank on mobile

The marketing site's Apple-style scroll section pins a section and animates through the 4-agent pipeline as you scroll. Desktop was smooth. Mobile was a disaster: pinned sections have known interaction with iOS Safari's elastic bounce scroll, and touch event timing caused frames to drop during fast swipes.

Solution: replaced the pin approach on mobile with a standard scroll-triggered opacity/translateY animation (no pinning). Used GSAP's ScrollTrigger.normalizeScroll(true) to handle iOS momentum scroll. Separate animation timelines for mobile vs desktop, detected via a media query matcher at ScrollTrigger.create time.

Results

Core product metrics at the end of the build:

4 Specialised AI Agents
21 Live Charts
60fps 3D Brain Performance
SSR Next.js App Router
The marketing site's scroll storytelling section became the most-shared element. The 3D brain on the hero converts better as a demo than any static screenshot or video walkthrough of the product.
Lessons Learned
  • Multi-agent pipelines are more maintainable than monolithic LLM prompts.

    When the Emotion Agent produces a wrong output, I can test it in isolation with known inputs. With a monolithic prompt, a regression anywhere in the reasoning chain is nearly impossible to localise.

  • 3D on the web is more accessible than expected with React Three Fiber.

    R3F's declarative model means you write 3D scenes the way you write React components. The learning curve is the 3D geometry concepts — not the WebGL API. The brain model went from concept to interactive in under a week.

  • GSAP ScrollTrigger on mobile needs careful pinning configuration.

    Pin-based scroll storytelling is a desktop-first pattern. Building mobile-first and treating the pinned version as a progressive enhancement would have saved significant debugging time.

  • React Query cache key design is architecture, not an implementation detail.

    Getting cache key strategy right from the beginning is the difference between a dashboard that loads in 300ms and one that makes 21 API calls every time a user switches tabs.

  • The marketing site is part of the product.

    The interactive 3D brain demo communicates what Pratyaksha does more effectively than any paragraph of copy. Time invested in the marketing site experience directly converts to user trust.