Inspiration

Tiruno was inspired by the gap between how students consume information and how they actually learn. Course materials, research papers, articles, and technical notes are often dense, static, and hard to stay engaged with. We wanted to build something that felt less like scrolling through a document and more like learning with a patient tutor.

The idea was to create an AI-powered study companion that could narrate content, answer questions conversationally, guide students through checkpoints, and make learning feel more interactive, visual, and emotionally engaging.

What it does

Tiruno helps learners study technical topics through an interactive learning experience. It includes:

Voice-based article learning Articles can be narrated using text-to-speech, allowing students to listen instead of only reading. Ask-Tiru voice loop Students can ask questions using their microphone. Tiruno transcribes the question, generates a grounded answer, and speaks it back. Interactive lessons and quizzes Learners can go through multiple-choice lessons and review their understanding. Personalized learning flow The app includes onboarding, a learning feed, lessons, article pages, review, and profile sections. Mascot-guided experience Tiru, the mascot, reacts with poses, animations, sound effects, and celebration effects to make the learning experience more engaging. Course-inspired mock content The prototype includes learning material around topics such as Android development, distributed systems, Redis vectors, RAG, LLMs, and system design.

How we built it

We built Tiruno as a modern web app using Next.js App Router, React, and Tailwind CSS, structured around interactive routes for onboarding, learning feed, lessons, articles, review, and profile.

The onboarding flow branches by persona. A Student is taken through a Connect Canvas → Sync → course-selection path; a Professional picks interests instead. We modeled this in a persisted Zustand store (persona, selectedCourses, selectedInterests) with a hydration gate to keep server- and client-rendered UI consistent.

For Canvas data ingestion, we built a thin BFF endpoint that receives a Canvas snapshot (the user's course list) relayed by a Chrome extension and caches it in Redis (canvas:snapshot). This keeps the design "mock-first": the same interface serves mock courses for the demo today and a real school Canvas session later, with no downstream changes.

For voice interaction, we integrated Deepgram: TTS for narration and STT for transcribing questions, behind a voice utility layer handling speaking, stopping, push-to-talk, and transcription.

For the mascot, we created a manifest-driven system mapping learning states to poses, clips, sound effects, and visual effects, with graceful fallbacks (WebM clip → animated WebP → static pose).

We also designed Redis as the backbone for memory, progress, and vector search (course-material embeddings for grounded retrieval). The Canvas snapshot cache is live; the broader vector/agent workstream was partially explored but blocked by Redis Cloud connectivity issues during the build.

Challenges we ran into

Reliable voice. TTS/STT flows need careful state management so narration, recording, transcription, and playback don't collide. Mascot fallbacks. A flexible fallback chain was needed so the experience holds up when a clip, animated image, or sound is unavailable. Hydration and persistence. Persisted Zustand state needed a hydration gate to avoid SSR/client mismatches. Redis infrastructure. The app is ready for Redis-backed memory and vector search, but a Redis Cloud auth/connectivity issue blocked those workstreams.

Accomplishments that we're proud of

Real Canvas ingestion path. A working, credential-safe way to bring real course data into the learning path. A working voice learning loop. Narrated content plus spoken Q&A. A polished, gamified interface with XP, streaks, hearts, and a consistent design system. Mascot-driven engagement with robust graceful degradation. A scalable architecture ready to grow into retrieval, memory, and agentic study workflows.

What we learned

Building an AI learning product is less about calling a model and more about designing the learning experience around it — and around the data source. Supporting both a syllabus-driven persona (Canvas) and an interest-driven persona (professionals) forced us to think hard about what a "learning path" really is.

We deepened our skills in:

Next.js App Router and persona-branched onboarding Persisted client state with Zustand (hydration gating) Ingesting external data (Canvas) safely via a relay + Redis cache Integrating Deepgram TTS and STT Mascot/animation state systems and audio/push-to-talk flows Planning Redis vector search and memory for grounded retrieval

What's next for Tiruno

Full Canvas integration — beyond the course list to files, modules, and deadlines, turning real materials into grounded, cited lessons. Richer professional mode — proactive article discovery ranked by real engagement across the web for chosen interests. Redis-backed memory and vector search — learning history, embeddings, and retrieval context. Personalized recommendations — what to review next based on performance. Deeper ingestion — upload notes, slides, PDFs, or links and convert them into lessons. Adaptive review — spaced repetition and targeted practice. Expanded mascot behavior and teacher/classroom support.

Built With

  • css-frameworks-&-libraries:-next.js
  • cwebp
  • deepgram
  • deepgram-speech-to-text-data-sources-&-ingestion:-canvas-lms-(course-data-via-chrome-extension-relay)
  • ffmpeg
  • howler.js
  • html
  • javascript
  • lucide-react-ai-&-voice-apis:-deepgram-text-to-speech
  • macos-image-tooling-developer-tools:-node.js
  • mp3/ogg-audio
  • next.js
  • next.js-build-tooling
  • npm
  • professional-interest-selection-database-&-infrastructure:-redis-/-redis-cloud-(canvas-snapshot-cache-live;-vector-search-planned)
  • react
  • redis
  • redis-vector-search-(planned-for-retrieval/personalization)-media-&-asset-tools:-webp
  • tailwind-css
  • webm-clips
  • webp
  • ypescript
  • zustand
Share this project:

Updates