jarvis-interview-platform: Jarvis Interview Platform: How a Browser Pretends to Be a High-Stakes Interview Room

A voice-first mock interview app uses Gemini, Web Speech, and Firebase to turn a simple frontend into a tense, cinematic coaching loop that survives failed mic input, slow models, and empty transcripts.

8 min read • View on GitHub • More from Namita-sha

A lone candidate sits at a desk facing a glowing interview terminal in a stark room. The scene makes the browser feel like a formal interview chamber, which explains the app’s central trick: it uses branding, voice, and pacing to create pressure before the first question even lands.
The product is selling a feeling first. The stack exists to sustain it.
Key Takeaways

Most AI interview tools optimize for convenience. This one optimizes for tension. The Jarvis branding, the voice-first loop, and the HUD styling all push the same idea: the user should feel like they are in a real interview room, not a chat window.

That distinction matters because the product’s hardest problem is not intelligence. It is continuity. If the mic drops, if the model stalls, or if the transcript gets lost during a re-render, the illusion breaks. The repo is interesting because it treats that risk as a core product problem, not an edge case.

Why This Feels Like an Interview, Not a Chatbot

The first win is psychological. The interface does not greet you like a helper. It stages you like a candidate. That changes the user’s posture before the first prompt arrives, which is exactly what a mock interview tool should do.

The code supports that effect with more than branding. `JarvisIntro`, the Arc Reactor-style visual language, and the voice interaction sequence all work together to create a deliberate boot sequence. The point is not novelty. The point is to make the session feel ceremonial enough that the feedback lands with more weight.

The Interview Loop Is a State Machine in Disguise

Under the theatrics, the interview flow behaves like a state machine: `intro -> speaking -> listening -> complete`. That is the right shape for a browser speech app because speech synthesis, recognition, interim results, and transcript assembly all need explicit boundaries.

The app’s core loop is not a single request. It is a chain of guarded states that keeps speech, transcripts, and fallbacks from stepping on each other.

useEffect(() => {
  if (phase === 'speaking') {
    speakQuestion(currentQuestion);
  }

  if (phase === 'listening') {
    recognition.continuous = true;
    recognition.interimResults = true;
    recognition.onresult = (event) => {
      for (let i = event.resultIndex; i < event.results.length; i++) {
        const chunk = event.results[i][0].transcript;
        if (event.results[i].isFinal) {
          finalRef.current += chunk + ' ';
        }
      }
    };
  }
}, [phase]);

The important detail is the ref. `finalRef` accumulates speech outside React state, which keeps the transcript stable while the UI re-renders. That is a small implementation choice with a big consequence: the app can listen continuously without losing the user’s answer halfway through.

A close-up pipeline shows sound waves entering one side, passing through gated stages, and emerging as separate candidate and interviewer transcripts plus an evaluation card. One branch falls into a fallback path, showing how the app protects the experience when speech input or the model fails.
The app does not just listen. It separates roles, preserves speech, and prevents failure from collapsing the feedback loop.

Gemini Does Two Jobs Here, and the App Guards Both

The repo uses Gemini in two distinct places. First, it generates interview questions. Then it evaluates the finished transcript. Those are different tasks, so the code treats them differently: structured output on the front end of the session, then role-aware scoring on the back end of the loop.

That separation matters because interview feedback is easy to distort. If the transcript is empty, or if the browser never granted mic access, the app should not hallucinate a meaningful evaluation. The fallback logic makes that constraint explicit, which is a sign the developer has thought about failure modes instead of hoping they never happen.

ModeWhat it takes inWhere it breaksWhat the app does about it
Question generationA structured prompt and JSON outputAPI failure or rate limitsFalls back to a hardcoded question set
Interview evaluationCandidate and interviewer transcript rolesEmpty transcript or no mic inputUses guardrails to avoid scoring silence
Voice interactionSpeech synthesis and recognitionBrowser incompatibility or timeoutKeeps the loop alive with defensive state handling

That architecture is not flashy, but it is disciplined. The product does not depend on Gemini being perfect. It depends on Gemini being useful, then wraps it in enough fallback behavior that the session can keep moving when it is not.

The Product Depends on Frictionless Setup

`Setup.jsx`, Firestore, and protected routes are not the headline, but they are what make the experience feel like a product instead of a demo. The user needs a saved session, a generated question set, and a clean return path so the interview atmosphere does not reset every time the page changes.

LayerWhat it protectsWhy it matters here
Protected routesAuthenticated sessionsThe interview should feel private and continuous
FirestoreGenerated setup data and questionsThe app needs state ready when the interview page loads
Session storageOne-time intro playbackThe cinematic opening should not become repetitive noise

This is the difference between a feature and a flow. Authentication and persistence are usually framed as infrastructure. In this repo, they are mood management.

What the Stack Optimizes For

The stack choices line up with a single product goal: time-to-feel. Firebase reduces backend weight. Gemini reduces content authoring overhead. Web Speech reduces latency by keeping the interaction in the browser where the conversation happens.

That makes the app a useful blueprint for a certain kind of AI product. If the goal is not to build the smartest assistant, but to build the most convincing one, then speed, continuity, and graceful failure matter more than raw model novelty.

LayerTypical defaultJarvis choiceStrategic effect
BackendCustom server logicFirebaseLess plumbing, faster product iteration
Conversation brainSingle chat promptQuestion generation plus evaluationSeparates creation from judgment
Voice I/OServer round tripsBrowser speech APIsKeeps the experience immediate
Failure handlingManual retry buttonsBuilt-in fallbacksPreserves the interview mood

How This Differs From Text-Based Interview Prep

Plain text interview prep tools are easier to build and easier to reason about. They also feel easier to ignore. This repo makes a different trade: it accepts more browser complexity in exchange for a more believable simulation of pressure.

DimensionPlain text chatbotGeneric voice assistantJarvis Interview Platform
Input modeTypingSpeakingSpeaking with transcript retention
Latency sensitivityLowMediumHigh
Emotional realismModestModerateHigh
Failure handlingSimple retryPartial recoveryFallback questions and no-mic guards
Feedback qualityBroadly genericOften shallowTranscript-aware and role-aware

That is the core editorial point. Jarvis is not trying to be the smartest interviewer. It is trying to feel the most like a real one. The repo’s best work is not in the model call itself. It is in the small pieces of engineering that keep the illusion intact long enough for the feedback to matter.