gitextract_re_01zim/ ├── .codex/ │ └── environments/ │ └── environment.toml ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ ├── build.yml │ ├── build_pr.yml │ └── ci.yaml ├── .gitignore ├── AGENTS.md ├── CLAUDE.md ├── CONTEXT.md ├── README.md ├── biome.json ├── components.json ├── convex/ │ ├── _generated/ │ │ ├── ai/ │ │ │ ├── ai-files.state.json │ │ │ └── guidelines.md │ │ ├── api.d.ts │ │ ├── api.js │ │ ├── dataModel.d.ts │ │ ├── server.d.ts │ │ └── server.js │ ├── account.ts │ ├── adminData.ts │ ├── adminStoryWrite.ts │ ├── adminWrite.ts │ ├── audioRead.ts │ ├── auth.config.ts │ ├── auth.ts │ ├── authFunctions.ts │ ├── authMigration.ts │ ├── betterAuth/ │ │ ├── _generated/ │ │ │ ├── api.ts │ │ │ ├── component.ts │ │ │ ├── dataModel.ts │ │ │ └── server.ts │ │ ├── adapter.ts │ │ ├── auth.ts │ │ ├── convex.config.ts │ │ └── schema.ts │ ├── convex-env.d.ts │ ├── convex.config.ts │ ├── convex_rules.md │ ├── courseContributorBackfill.ts │ ├── courseWrite.ts │ ├── discordAvatarSync.ts │ ├── discordBot.ts │ ├── discordData.ts │ ├── discordRoleSync.ts │ ├── editorRead.ts │ ├── editorSideEffects.ts │ ├── http.ts │ ├── landing.ts │ ├── languageWrite.ts │ ├── lib/ │ │ ├── authorization.ts │ │ ├── courseContributors.ts │ │ ├── courseCounts.ts │ │ ├── discordAvatarSync.ts │ │ ├── phpbb.ts │ │ └── publicStoryContent.ts │ ├── localization.ts │ ├── localizationWrite.ts │ ├── lookupTables.ts │ ├── roles.ts │ ├── schema.ts │ ├── storyApproval.ts │ ├── storyDone.ts │ ├── storyPublicContent.ts │ ├── storyRead.ts │ ├── storyTables.ts │ ├── storyWrite.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── userPreferences.ts ├── database/ │ └── stories/ │ ├── es-en-o/ │ │ ├── 1_1_es-en-buenos-dias.txt │ │ ├── 1_2_es-en-una-cita.txt │ │ └── 1_3_es-en-una-cosa.txt │ ├── nl-en/ │ │ ├── 0_1_es-en-el-pastel-de-dragones.txt │ │ ├── 0_2_es-en-es-amor.txt │ │ ├── 0_3_es-en-la-pelea-de-boxeo.txt │ │ ├── 0_4_es-en-el-neumatico-pinchado.txt │ │ ├── 1_1_es-buenos-dias.txt │ │ ├── 1_2_es-una-cita.txt │ │ ├── 1_3_es-una-cosa.txt │ │ ├── 1_4_es-en-la-luna-de-miel.txt │ │ ├── 2_1_es-en-la-chaqueta-roja.txt │ │ ├── 2_2_es-en-el-pasaporte.txt │ │ ├── 2_3_es-en-una-familia-muy-grande.txt │ │ └── 2_4_es-en-el-doctor-eddy.txt │ └── test-en/ │ ├── 1_1_es-en-buenos-dias.txt │ └── 1_2_es-en-una-cita.txt ├── discord_roles/ │ ├── CONTEXT.md │ ├── audio_cleanup.py │ ├── blame.py │ ├── combine.py │ ├── discord_bot.py │ ├── discord_reacting_bot.py │ ├── env_utils.py │ └── requirements.txt ├── docs/ │ └── bulk-audio-editor-spec.md ├── import_tools/ │ ├── README.md │ ├── app.py │ └── greasmonkey.js ├── instrumentation-client.ts ├── jsconfig.json ├── knip.json ├── next.config.js ├── package.json ├── postcss.config.mjs ├── process.d.ts ├── public/ │ ├── .well-known/ │ │ └── assetlinks.json │ ├── darklight.js │ ├── docs/ │ │ ├── audio-generation/ │ │ │ ├── character-editor.mdx │ │ │ ├── edit.mdx │ │ │ ├── engines.mdx │ │ │ ├── fix-problems.mdx │ │ │ ├── generate.mdx │ │ │ └── overview.mdx │ │ ├── become-contributor/ │ │ │ ├── application.mdx │ │ │ └── colang.mdx │ │ ├── docs.json │ │ ├── introduction.mdx │ │ ├── search.js │ │ ├── story-creation/ │ │ │ ├── import.mdx │ │ │ └── translate.mdx │ │ ├── story-editing/ │ │ │ ├── exercises.mdx │ │ │ ├── overview.mdx │ │ │ └── translation-hints.mdx │ │ └── story-publishing/ │ │ ├── publishing.mdx │ │ └── without_tts.mdx │ ├── linja-pona-4.9.otf │ ├── linjalipamanka-normal.otf │ ├── robots.txt │ └── sw.js ├── scripts/ │ ├── backfill-course-contributors.ts │ ├── backfill-discord-avatars.ts │ └── find-missing-story-images.ts ├── skills-lock.json ├── src/ │ ├── app/ │ │ ├── (stories)/ │ │ │ ├── (main)/ │ │ │ │ ├── EditorCommandPaletteClient.tsx │ │ │ │ ├── [course_id]/ │ │ │ │ │ ├── course_page_client.tsx │ │ │ │ │ ├── not-found.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── story_button.tsx │ │ │ │ ├── course-dropdown.tsx │ │ │ │ ├── course_list.tsx │ │ │ │ ├── faq/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── footer_links.tsx │ │ │ │ ├── get_course_data.ts │ │ │ │ ├── header.tsx │ │ │ │ ├── icons.tsx │ │ │ │ ├── landing_stats_client.tsx │ │ │ │ ├── language_button.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── not-found.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── privacy_policy/ │ │ │ │ │ └── page.tsx │ │ │ │ └── profile/ │ │ │ │ ├── actions.ts │ │ │ │ ├── data.ts │ │ │ │ ├── page.tsx │ │ │ │ └── profile.tsx │ │ │ ├── learn/ │ │ │ │ ├── page.tsx │ │ │ │ └── welcome.tsx │ │ │ └── story/ │ │ │ ├── [story_id]/ │ │ │ │ ├── auto_play/ │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── story_wrapper.tsx │ │ │ │ ├── getStory.ts │ │ │ │ ├── loading.tsx │ │ │ │ ├── not-found.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── script/ │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── story_wrapper.tsx │ │ │ │ ├── story_wrapper.tsx │ │ │ │ └── test/ │ │ │ │ ├── page.tsx │ │ │ │ └── story_wrapper.tsx │ │ │ └── layout.tsx │ │ ├── admin/ │ │ │ ├── AdminDialogTrigger.tsx │ │ │ ├── AdminHeader.tsx │ │ │ ├── FlagName.tsx │ │ │ ├── adminDetailStyles.ts │ │ │ ├── adminTableStyles.ts │ │ │ ├── courses/ │ │ │ │ ├── courses.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── page_client.tsx │ │ │ ├── edit_dialog.tsx │ │ │ ├── languages/ │ │ │ │ ├── language_list.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── page_client.tsx │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ ├── story/ │ │ │ │ ├── [story_id]/ │ │ │ │ │ ├── actions.ts │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── story_display.tsx │ │ │ │ └── page.tsx │ │ │ └── users/ │ │ │ ├── [user_id]/ │ │ │ │ ├── actions.ts │ │ │ │ ├── page.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── user_display.tsx │ │ │ ├── page.tsx │ │ │ └── user_list.tsx │ │ ├── api/ │ │ │ ├── auth/ │ │ │ │ └── [...all]/ │ │ │ │ └── route.ts │ │ │ ├── og/ │ │ │ │ └── route.tsx │ │ │ ├── og-course/ │ │ │ │ └── route.tsx │ │ │ └── og-story/ │ │ │ └── route.tsx │ │ ├── audio/ │ │ │ ├── _lib/ │ │ │ │ └── audio/ │ │ │ │ ├── azure_tts.ts │ │ │ │ ├── elevenlabs.ts │ │ │ │ ├── google.ts │ │ │ │ ├── index.ts │ │ │ │ ├── polly.ts │ │ │ │ └── types.ts │ │ │ ├── create/ │ │ │ │ └── route.ts │ │ │ ├── elevenlabs_quota/ │ │ │ │ └── page.tsx │ │ │ ├── upload/ │ │ │ │ └── route.ts │ │ │ └── voices/ │ │ │ └── route.ts │ │ ├── auth/ │ │ │ ├── admin/ │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── editor/ │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── register/ │ │ │ │ ├── page.tsx │ │ │ │ └── register.tsx │ │ │ ├── reset_pw/ │ │ │ │ ├── page.tsx │ │ │ │ └── reset_pw.tsx │ │ │ └── signin/ │ │ │ ├── login_options.tsx │ │ │ └── page.tsx │ │ ├── dev/ │ │ │ └── story-footer-button-test/ │ │ │ ├── page.module.css │ │ │ └── page.tsx │ │ ├── docs/ │ │ │ ├── [[...slug]]/ │ │ │ │ ├── doc_data.ts │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ └── loading.tsx │ │ ├── editor/ │ │ │ ├── (course)/ │ │ │ │ ├── course/ │ │ │ │ │ └── [course_id]/ │ │ │ │ │ ├── import/ │ │ │ │ │ │ └── [from_id]/ │ │ │ │ │ │ ├── import_list.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── page_client.tsx │ │ │ │ │ ├── localization/ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── page_client.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── page_client.tsx │ │ │ │ │ ├── story/ │ │ │ │ │ │ └── [story]/ │ │ │ │ │ │ ├── audio-cutter/ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ └── page_client.tsx │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── voices/ │ │ │ │ │ ├── edit/ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── page_client.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── page_client.tsx │ │ │ │ ├── course_list.tsx │ │ │ │ ├── course_view_memory.ts │ │ │ │ ├── edit_list.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── layout_client.tsx │ │ │ │ ├── layout_flag.tsx │ │ │ │ ├── loading.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── swipe.tsx │ │ │ │ └── types.ts │ │ │ ├── _components/ │ │ │ │ ├── breadcrumbs.tsx │ │ │ │ ├── editor_command_palette.tsx │ │ │ │ ├── header_context.tsx │ │ │ │ ├── header_shell.tsx │ │ │ │ ├── page_layout.tsx │ │ │ │ └── story_editor_preferences.tsx │ │ │ ├── editor_button.tsx │ │ │ ├── language/ │ │ │ │ └── [language]/ │ │ │ │ ├── language_editor.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── page_client.tsx │ │ │ │ ├── tts_edit/ │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── page_client.tsx │ │ │ │ │ └── tts_edit.tsx │ │ │ │ └── types.ts │ │ │ ├── layout.tsx │ │ │ ├── localization/ │ │ │ │ └── [language]/ │ │ │ │ ├── layout.tsx │ │ │ │ ├── localization_editor.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── page_client.tsx │ │ │ │ └── text_edit.tsx │ │ │ └── story/ │ │ │ └── [story]/ │ │ │ ├── audio-cutter-dialog.tsx │ │ │ ├── audio-cutter-storage.ts │ │ │ ├── bulk-audio-editor.tsx │ │ │ ├── editor_state.ts │ │ │ ├── header.tsx │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ ├── page_client.tsx │ │ │ ├── sound-recorder.tsx │ │ │ ├── types.ts │ │ │ └── v2/ │ │ │ ├── editor_v2.tsx │ │ │ └── use_story_editor_model.ts │ │ ├── layout.tsx │ │ ├── manifest.json │ │ └── not-found.tsx │ ├── components/ │ │ ├── Button/ │ │ │ ├── Button.tsx │ │ │ └── index.ts │ │ ├── CheckButton/ │ │ │ ├── CheckButton.tsx │ │ │ └── index.ts │ │ ├── ContributorList.tsx │ │ ├── Docs/ │ │ │ ├── CustomMDXServer/ │ │ │ │ ├── CustomMDXServer.tsx │ │ │ │ ├── index.ts │ │ │ │ └── process_mdx.ts │ │ │ ├── MdxTree/ │ │ │ │ ├── MdxTree.tsx │ │ │ │ └── index.ts │ │ │ └── docsClasses.ts │ │ ├── DocsBreadCrumbNav/ │ │ │ ├── DocsBreadCrumbNav.tsx │ │ │ └── index.ts │ │ ├── DocsHeader/ │ │ │ ├── DocsHeader.tsx │ │ │ └── index.ts │ │ ├── DocsNavigation/ │ │ │ ├── DocsNavigation.tsx │ │ │ └── index.ts │ │ ├── DocsNavigationBackdrop/ │ │ │ ├── DocsNavigationBackdrop.tsx │ │ │ └── index.ts │ │ ├── DocsSearchModal/ │ │ │ ├── DocsSearchModal.tsx │ │ │ └── index.ts │ │ ├── EditorSSMLDisplay/ │ │ │ ├── EditorSSMLDisplay.tsx │ │ │ └── index.ts │ │ ├── FadeGlideIn/ │ │ │ ├── FadeGlideIn.tsx │ │ │ └── index.ts │ │ ├── LocalisationProvider/ │ │ │ ├── LocalisationProvider.tsx │ │ │ ├── LocalisationProviderContext.tsx │ │ │ └── index.ts │ │ ├── NavigationModeProvider/ │ │ │ ├── NavigationModeProvider.tsx │ │ │ └── index.ts │ │ ├── PlayAudio/ │ │ │ ├── PlayAudio.tsx │ │ │ └── index.ts │ │ ├── ProgressBar/ │ │ │ ├── ProgressBar.tsx │ │ │ └── index.ts │ │ ├── StoryAutoPlay/ │ │ │ ├── StoryAutoPlay.tsx │ │ │ └── index.ts │ │ ├── StoryChallengeArrange/ │ │ │ ├── StoryChallengeArrange.tsx │ │ │ └── index.ts │ │ ├── StoryChallengeContinuation/ │ │ │ ├── StoryChallengeContinuation.tsx │ │ │ └── index.ts │ │ ├── StoryChallengeMatch/ │ │ │ ├── StoryChallengeMatch.tsx │ │ │ └── index.ts │ │ ├── StoryChallengeMultipleChoice/ │ │ │ ├── StoryChallengeMultipleChoice.tsx │ │ │ └── index.ts │ │ ├── StoryChallengePointToPhrase/ │ │ │ ├── StoryChallengePointToPhrase.tsx │ │ │ └── index.ts │ │ ├── StoryChallengeSelectPhrases/ │ │ │ ├── StoryChallengeSelectPhrases.tsx │ │ │ └── index.ts │ │ ├── StoryEditorPreview/ │ │ │ ├── StoryEditorPreview.tsx │ │ │ └── index.ts │ │ ├── StoryFinishedScreen/ │ │ │ ├── StoryFinishedScreen.tsx │ │ │ └── index.ts │ │ ├── StoryFooter/ │ │ │ ├── StoryFooter.tsx │ │ │ └── index.ts │ │ ├── StoryHeader/ │ │ │ ├── StoryHeader.tsx │ │ │ └── index.ts │ │ ├── StoryHeaderProgress/ │ │ │ ├── StoryHeaderProgress.tsx │ │ │ └── index.ts │ │ ├── StoryLineHints/ │ │ │ ├── StoryLineHints.tsx │ │ │ └── index.ts │ │ ├── StoryProgress/ │ │ │ ├── StoryProgress.tsx │ │ │ └── index.ts │ │ ├── StoryQuestionArrange/ │ │ │ ├── StoryQuestionArrange.tsx │ │ │ └── index.ts │ │ ├── StoryQuestionMatch/ │ │ │ ├── StoryQuestionMatch.tsx │ │ │ └── index.ts │ │ ├── StoryQuestionMultipleChoice/ │ │ │ ├── StoryQuestionMultipleChoice.tsx │ │ │ └── index.ts │ │ ├── StoryQuestionPointToPhrase/ │ │ │ ├── StoryQuestionPointToPhrase.tsx │ │ │ └── index.ts │ │ ├── StoryQuestionPrompt/ │ │ │ ├── StoryQuestionPrompt.tsx │ │ │ └── index.ts │ │ ├── StoryQuestionSelectPhrase/ │ │ │ ├── StoryQuestionSelectPhrase.tsx │ │ │ └── index.ts │ │ ├── StoryTextLine/ │ │ │ ├── StoryTextLine.tsx │ │ │ ├── index.ts │ │ │ └── use-audio.hook.ts │ │ ├── StoryTextLineSimple/ │ │ │ ├── StoryTextLineSimple.tsx │ │ │ └── index.ts │ │ ├── StoryTitlePage/ │ │ │ ├── StoryTitlePage.tsx │ │ │ └── index.ts │ │ ├── VisuallyHidden/ │ │ │ ├── VisuallyHidden.tsx │ │ │ └── index.ts │ │ ├── WordButton/ │ │ │ ├── WordButton.tsx │ │ │ └── index.ts │ │ ├── auth/ │ │ │ └── styles.ts │ │ ├── editor/ │ │ │ └── story/ │ │ │ ├── cast.tsx │ │ │ ├── editor-resize.ts │ │ │ ├── inline_tts.ts │ │ │ ├── parser.test.ts │ │ │ ├── parser.ts │ │ │ ├── scroll_linking.ts │ │ │ ├── syntax_parser_new.ts │ │ │ └── syntax_parser_types.ts │ │ ├── icons.tsx │ │ ├── layout/ │ │ │ └── legal.tsx │ │ ├── login/ │ │ │ ├── LoggedInButtonWrappedClient.tsx │ │ │ └── loggedinbutton.tsx │ │ ├── providers/ │ │ │ ├── ConvexClientProvider.tsx │ │ │ └── PostHogUserIdentifier.tsx │ │ └── ui/ │ │ ├── badge.tsx │ │ ├── button.tsx │ │ ├── dialog.tsx │ │ ├── flag.tsx │ │ ├── input.tsx │ │ ├── kbd.tsx │ │ ├── language-flag.tsx │ │ ├── shadcn/ │ │ │ ├── dropdown-menu.tsx │ │ │ └── index.ts │ │ ├── sheet.tsx │ │ ├── spinner.tsx │ │ └── switch.tsx │ ├── hooks/ │ │ ├── use-choice-buttons.hook.ts │ │ ├── use-keypress.hook.ts │ │ └── use-scroll-into-view.hook.ts │ ├── instrumentation-client.ts │ ├── lib/ │ │ ├── audio/ │ │ │ └── client-audio-processing.ts │ │ ├── auth-client.ts │ │ ├── auth-server.ts │ │ ├── editor/ │ │ │ ├── audio/ │ │ │ │ ├── audio_edit_tools.test.ts │ │ │ │ ├── audio_edit_tools.ts │ │ │ │ └── text_with_mapping.ts │ │ │ ├── editorHandlers.ts │ │ │ └── tts_transcripte.ts │ │ ├── fetch_post.ts │ │ ├── getUserId.ts │ │ ├── get_localisation.ts │ │ ├── get_localisation_func.tsx │ │ ├── hooks.ts │ │ ├── is-typing-target.ts │ │ ├── lamejs-compat.ts │ │ ├── posthog-server.ts │ │ ├── posthog-user.ts │ │ ├── shuffle.ts │ │ ├── sound-effects.ts │ │ ├── story-preferences.ts │ │ ├── story-search.ts │ │ ├── userInterface.ts │ │ └── utils.ts │ ├── styles/ │ │ └── global.css │ └── types/ │ ├── lamejs.d.ts │ └── react-dom.d.ts └── tsconfig.json