Gospel Story

One story.
Every language.
Shaped by what you carry.

An AI-powered experience that retells true stories from the life of Jesus in your language, your cultural context, shaped by whatever you're going through. No translation tables. No templates. One skeleton, infinite tellings.

What are you carrying right now?

My grandmother passed last week and I don't know how to grieve in a way that honors her

English detected · routing to grief arc

Enter the story

She came alone at noon.
The others came in the cool of morning.

It starts with you

You type what you're going through. The AI listens.

No menu. No categories. Just one question: “What are you carrying right now?” Write in any language, any length. The AI detects your language, reads your emotional state, and selects a story arc that meets you where you are.

Then a bridge sentence appears — one line, streamed word by word, that echoes your own words and invites you into a story about someone who carried something similar, two thousand years ago.

Step 1 — User input

What are you carrying right now?

친구를 잃었어요. 아직도 믿기지 않아요.

Detected: Korean · Emotion: grief · Arc: When He Wept

Step 2 — Bridge sentence (streamed)

“친구를 잃었어요. 아직도 믿기지 않아요.”

아직도 믿기지 않는 그 마음, 이천 년 전에도 똑같이 느꼈던 사람들이 있었습니다. 그들의 이야기를 들려드릴게요.

이야기 속으로 →

Language

The same scene. Four languages. No translation.

Each phone shows the same moment from John 11 — generated directly in English, Korean, Japanese, and Spanish. The AI doesn't translate. It retells, using the natural rhythms, sentence structure, and emotional register of each language.

She came alone at noon.
The others came in the cool of morning.

English

Original telling

그녀는 혼자 한낮에 왔다.
다른 사람들은 아침 시원할 때 왔다.

한국어

Same scene, generated in Korean

彼女は 真昼に一人で来た。
他の人々は 朝の涼しい時間に来た。

日本語

Same scene, generated in Japanese

Ella vino sola al mediodía.
Los demás venían en el fresco de la mañana.

Español

Same scene, generated in Spanish

Culture

Same grief. Different worlds.

Language is only the surface. The AI also contextualizes for culture — how grief is expressed, the social expectations around loss, the emotional textures that make a story feel native rather than imported.

The house was full of people.
Martha heard them say the right things.

American reader

"I just lost my best friend and I feel numb"

Western individualist grief — isolation, numbness

조문객들이 줄을 이었다.
마르다는 웃는 얼굴로 받았다.

한국인 독자

"할머니가 돌아가셨는데 아무렇지 않은 척 해야 해요"

Korean communal grief — performing composure for others

弔問客は 静かに頭を下げた。
マルタは 一人で立ち尽くした。

日本人の読者

"父が亡くなって、まだ泣けていません"

Japanese grief — restraint, the weight of not crying

Five emotional paths

What you're carrying determines which story you enter.

Each emotion routes into a different passage from the Gospels. Each arc has its own color world, its own guardrails, its own opening line.

Grief

When He Wept

John 11:1-44

A story for the ache that stays after the room goes quiet.

Doubt

The Night He Answered

John 20:24-29

A story for the person who needs more than slogans.

Searching

The King Who Came

Luke 2 / Matthew 2

A story about a rescue no one expected.

Curiosity

Come and See

John 1:35-51

A story for the person who is open, observant, and not yet convinced.

Anger

The Storm He Stilled

Mark 4:35-41

A story for the noise inside you when everything feels too much.

How it works

One skeleton. Infinite tellings.

The system works in six steps. Each story has exactly five beats, generated live from the same skeleton data. The events are fixed by scripture. The telling is shaped by you.

Share

User writes what they’re carrying in any language

Classify

Gemini detects language, emotion, selects arc

Bridge

A sentence streams in their language, echoing their words

Generate

Five beats stream live from skeleton + guardrails + user context

Check-in

Between beats, a reflective question deepens the next scene

Guard

Guardrails ensure no invented dialogue, no church vocab, scripture-faithful

Behind the scenes — Assembled system prompt (color-coded)

The reader said: "I lost my best friend last month and I don't know how to keep going" Language: en

Check-in answer: "He just let me cry on the phone. Didn't say anything."

MUST NOT: Explain why God allows suffering. No theodicy.\nMUST NOT: Use church vocabulary (saved, sin, repent, salvation, born again).\nMUST NOT: Rush past the grief to get to the miracle.

John 11:33-35. "Jesus wept." Non-negotiable: the text says he wept — do not soften to "his eyes glistened" or similar. Two words.

Literary, not devotional. Sit in the ache. Let beats about the delay and the weeping breathe. Do not rush to resolution.

Beat 3: "Jesus weeps." When Jesus sees Mary weeping, and the people with her weeping, he is deeply moved. He asks where they have laid Lazarus. And then: Jesus wept.

Capabilities

What the system does

✍️

Live story generation

Each beat streams in real time from Gemini 2.5 Flash. The prose is generated directly in the reader’s language — not translated after the fact. Five beats per story, each shaped by the reader’s input and check-in answers.

🔒

Scripture guardrails

Three layers of fidelity enforcement. No invented dialogue. No attributed emotions beyond the text. Per-beat verse bounds.

🌐

Any language on earth

Korean, Japanese, Spanish, Tagalog, Arabic — the AI generates natively. One English skeleton serves every language.

💡

Emotional classification

Structured output from Gemini classifies input into one of five emotional keys. Ambiguous input defaults to “searching.”

💬

Mid-story check-ins

After each non-end beat, a reflective question pauses the flow. The reader’s answer is accumulated and shapes every subsequent beat — the narrator’s voice shifts to meet what you shared.

🎨

Cultural contextualization

Not just language — the telling adapts to cultural expressions of grief, doubt, and searching.

⚖️

No church vocabulary

Saved, sin, repent, born again — banned across all five arcs. The story speaks in human language.

👁️

Behind the scenes

After the story ends, readers can see every system prompt that was sent — color-coded by section.

“You can contextualize the telling, but you cannot change the events.”

The reader's words shape the narrator's voice and the scene's atmosphere — but never appear in the mouths of biblical characters. The narrator bridges the reader's world and the ancient story. Jesus and the other characters speak only what scripture records.

API Routes

Two endpoints, streaming responses

POST/api/entryClassify input (language + emotion), stream bridge sentence. Headers: X-Detected-Lang, X-Emotional-Key, X-Arc-Slug
POST/api/storyGenerate a story beat. Accepts storySlug, beatId, userInput, lang, previousBeats, checkinAnswers. Streams prose via headers.

Response headers from /api/story

# Beat metadata sent as HTTP headers X-Beat-Id: beat-grief-3 X-Is-End: false X-Beat-Order: 3 X-Choices: [{"id":"choice-grief-3","nextBeatId":"beat-grief-4","hint":"Follow him to the tomb"}] X-Checkin-Prompt: When was the last time someone sat in your pain with you... X-Illustration-Url: /beat-illustrations/when-he-wept/beat-5.svg

Get started

Clone, install, run

Requires Node.js 20+ and a Google AI API key (Gemini 2.5 Flash). Supabase is optional — the app runs with mock skeleton data by default.

# Clone git clone https://github.com/jeeminhan/jesus-story.git cd jesus-story # Install dependencies npm install # Set up environment cp .env.example .env.local # Add your GOOGLE_GENERATIVE_AI_API_KEY to .env.local # Run dev server npm run dev # Run tests npx vitest run # 118 unit/integration tests npx playwright test # E2E tests

Available scripts

RUNnpm run devStart the Next.js dev server
RUNnpm run buildProduction build
RUNnpm run testRun Vitest suite (118 tests)
RUNnpm run test:e2eRun Playwright E2E tests
RUNnpm run seedSeed Supabase with skeleton data

See it for yourself.

The demo walks through the grief arc with a sample input. Or try it with your own words, in your own language.

Next.js 15TypeScriptTailwind CSSAI SDK v6Gemini 2.5 FlashSupabaseVitestPlaywrightVercel