← Back to Home

An idea, brought to life

Mr. Fluff.

You have a point.
So does he.

A witty voice companion with another perspective on your ideas. And usually a remark to go with it.

Explore the build
A friendly pain
in your assumptions.
Curiosity, with a raised eyebrow.
An independent product, from concept to working application.Product · Interaction · Engineering

The starting point

Why another
perspective?

Algorithms are good at giving us more of what we already like. That bothers me when it means hearing the same opinions again and again. I wanted a companion that would push back, with enough wit to make me want to hear him out.

I had the idea about a year before I built it. When the tools made it practical, I picked it up again. Mr. Fluff is what came out of that curiosity.

Make room for another perspective.

01 / The experience

A conversation with
a raised eyebrow.

Hold the face, say what you think, then release to hear his reply. Push back if you disagree. The conversation works in English and Spanish.

Ready

Your turn.

Waiting for you. Opening the app does not start recording.

Listening

You have his attention.

Hold to speak; release to stop recording. The expression follows the microphone’s actual state.

Thinking

Considering the other side.

Recording has stopped. He is preparing a reply, and the face makes that pause visible.

Speaking

A point. With a punchline.

The mouth follows the audio you hear. Stop interrupts the reply; End closes the session. This illustration is silent.

Interaction illustration · no recording, audio or model connection.

Illustrative exchange

“Automation always saves time.”

It can—once the task repeats enough. Otherwise you’ve built a tiny factory to fold one napkin.

He needs a reason to disagree. If your argument holds up, another angle or a useful caveat is enough. Contradiction for its own sake gets boring quickly.

02 / Product judgement

The decisions
that shaped it.

  1. 01

    Make speaking a deliberate act.

    Holding the face gives recording a clear start and finish, without another button competing for attention. It also makes touch handling critical: the face must stay under your finger, and cancellation must stop capture.

    Hold → speak → release
  2. 02

    Give the humour a job.

    I wanted a reason with a comic payoff, not a stream of jokes. That means judging humour separately from accuracy and relevance. A funny answer that misses your point still fails.

    Reason + comic payoff
  3. 03

    Keep the system small and controllable.

    One backend handles access, conversations and spending. That keeps deployment manageable, but puts audio traffic through the server. Adding replicas would need more coordination; it is not just a hosting switch.

    Access · capacity · budget

03 / Technical architecture

What sits behind
the face.

React in the browser, one FastAPI backend, PostgreSQL for persistent records. Audio travels through the backend so access and spending checks happen before a paid model call.

The system at a glanceOne application. Clear responsibilities.
  1. 01

    Visitor browser

    React · TypeScript · Web Audio

    Capture, playback and expression→
  2. 02

    Cloudflare

    HTTPS · Tunnel

    Public entry to the application→
  3. 03

    FastAPI application

    HTTP + WebSocket · internal modules

    Identity / conversation / spending↔
  4. 04

    PostgreSQL

    SQLAlchemy · transactions

    Sessions, reservations and usage
Application ↔ provider

OpenAI

Voice generation and transcription

Application ↔ identity service

Google identity

Owner sign-in

Identity, conversation and spending are modules inside the FastAPI application. External services connect through that backend.

Control paid work at the server.

Provider credentials and spending limits stay on the backend. The browser sends application commands, not arbitrary provider requests.

Keep spending durable.

Reserve allowance in a database transaction before dispatch. Settle against provider receipts; keep missing usage evidence unresolved.

Let presentation evolve independently.

The SVG renderer receives state and audio level. Changing an expression cannot open the microphone or authorise a charge.

One voice turn

  1. 01

    Capture

    AudioWorklet → PCM chunks.

  2. 02

    Admission

    Release → validate and reserve.

  3. 03

    Response

    OpenAI → backend → browser.

  4. 04

    Playback

    Web Audio → sound and mouth.

  5. 05

    Settlement

    Usage receipts → PostgreSQL.

Audio streams while the reply is generated. Playback and usage settlement finish independently.

The stack and deployment choices
Audio and rendering
An AudioWorklet converts microphone input to 24 kHz mono PCM in 100 ms chunks. Web Audio schedules playback; the SVG mouth follows playback energy without a React render on every frame.
Transport and contracts
The React/TypeScript frontend, HTTP API and application WebSocket share one origin under /MrFluff. FastAPI and Pydantic validate commands. The backend owns the separate model connection; generated TypeScript types keep HTTP contracts aligned.
Persistence and deployment
SQLAlchemy and PostgreSQL hold sessions, reservations and usage; Alembic manages schema changes. Docker packages the compiled frontend and Python backend together. The demo runs on a laptop through Cloudflare Tunnel, so availability still depends on that machine and its connection.

04 / Working through the details

Where the build
became interesting.

Challenge 01

A reply finished before its sound did.

What happened
Generation could finish while audio was still buffered in the browser.
What changed
I separated generation, playback and accounting, and tied the face to playback.
Why it mattered
He should stop moving his mouth when you stop hearing him.
Generation
Playback
Settlement
Three clocks. Three meanings of finished.Conceptual illustration
Challenge 02

A touch target moved beneath the finger.

What happened
Press scaling and nearby controls shifted the held face. Small screens also hid the entry action.
What changed
I fixed the hold geometry and shortened the welcome layout across languages and orientations.
Why it mattered
A passing click test means little if you cannot find or hold the control.
PressHoldRelease
A stable target, from press to release.Conceptual illustration
Challenge 03

The reasoning worked. The wit needed work.

What happened
Replies could be insightful yet miss the character’s comic payoff.
What changed
I revised the character guidance and assessed humour separately from truth, relevance and continuity.
Why it mattered
Correct answers were only half the brief. The revised character still needs human assessment.
Relevant reasonA comic turnTruth · continuity · judgement
Insight, relevance and wit need separate attention.Conceptual illustration
Challenge 04

More conversations changed the problem.

What happened
Eight-user stress scenarios exposed storage contention and timing failures.
What changed
I refined transaction admission and reran isolated scenarios with the packaged app.
Why it mattered
Limits need evidence. Those scenarios informed the fix; final capacity verification is still outstanding.
Check & reserveBounded paid work
Admission before dispatch. Evidence before expansion.Conceptual illustration

05 / Where it stands

A working product.
A clear next step.

Built

Bilingual voice conversations, an expressive face, owner controls and persistent spending records.

Evaluated

Logic, browser journeys and real database transactions have separate checks. Provider samples confirm compatibility, not conversational quality.

Next

Character assessment, real-device responsiveness, final capacity verification and independent recovery.

I came for the character. The audio timing, awkward touch behaviour and spending controls gave me plenty of reasons to stay curious. There is more to do, and I want to hear what he makes of your ideas.

Meet Mr. Fluff (opens in a new tab)

Conversation access depends on demo availability.

CONTACT

Let’s talk.

About a challenge, an idea, or something we could do together.

Connect on LinkedIn