tango is a Chrome extension for learning Japanese in small, repeated sessions while browsing the web. It presents short lessons as unobtrusive cards in the active tab instead of requiring the learner to open a separate course application. Cards can be answered, dismissed, or followed across tabs until they are completed.
The current release is an MVP focused on hiragana, greetings, and basic vocabulary. Lesson content is bundled with the extension, so the core learning flow works locally without a remote content service.
The extension is a Manifest V3 application with three cooperating surfaces:
http:// and https:// pages.Progress, settings, and the pending card are stored locally with chrome.storage.local. Scheduled prompts use chrome.alarms; the pending card is kept in storage when Chrome cannot inject into a restricted page and is shown again when an injectable tab becomes active.
Google OAuth and the Go backend are present as an integration path for authentication. The local extension defaults to an API at localhost:8080; authentication and production API use require the corresponding backend and OAuth configuration to be deployed and configured.
@crxjs/vite-plugin, and the Vite React pluginwebextension-polyfill with Chrome type definitionsgulp-zipapps/backend, using Echo and PostgreSQL/Redis infrastructure for the wider application>= 14.18.0 (a current LTS release is recommended)From this directory (apps/client):
npm install
npm run dev
npm run dev starts Vite in watch mode and writes the unpacked extension to build/. In Chrome:
chrome://extensions.apps/client/build directory.http:// or https:// page and click the tango toolbar icon.After source changes, use Reload on the extension card in chrome://extensions when the change affects the service worker or extension pages. Content-script changes may also require refreshing the web page.
The client currently expects its local API at localhost:8080. To run the companion service, follow the backend setup guide, including its environment file, database services, and task dev command. The extension’s local auth flow also uses Google identity APIs, so a matching OAuth client configuration is required for sign-in testing.
| Command | Purpose |
|---|---|
npm run dev |
Start the Vite development/watch build. |
npm run build |
Run TypeScript checking and create a production build in build/. |
npm run preview |
Serve the built output for local inspection. |
npm run fmt |
Format TypeScript, JSON, CSS, SCSS, and Markdown files with Prettier. |
npm run zip |
Build the extension and create a versioned archive in package/. |
The project has a manual browser checklist in TESTING.md. It covers:
For a quick smoke test, build the extension, load build/ unpacked, open an ordinary HTTPS page, open the side panel, and use Show card now. Chrome internal pages such as chrome://extensions cannot receive content-script cards.
The manifest requests the following capabilities:
storage for local progress, settings, and pending-card state;alarms for spaced prompts;tabs, activeTab, and scripting to identify an active injectable tab and show cards;sidePanel for the progress/control surface;identity and identity.email for the Google sign-in integration; andThe extension should request only the permissions needed by the shipped features. Before publishing, review every permission and the OAuth scope list in src/manifest.ts, add a public privacy policy that describes local storage and any account/API data flow, and ensure the Chrome Web Store privacy disclosures match the implementation.
Create a release artifact with:
npm run build
npm run zip
The archive is written to package/ with the extension name and manifest version. Before uploading it:
version and user-facing metadata in package.json.build/manifest.json, icons, OAuth settings, API endpoint, host permissions, and content-script behavior against the production environment.build/ unpacked in a clean Chrome profile.build/, complete the privacy and distribution declarations, and submit it for review.The repository does not contain an automated Chrome Web Store publishing workflow. Store uploads and review submissions are therefore manual unless a future release pipeline is added. Never commit OAuth client secrets, backend secrets, signing credentials, or private store credentials.
apps/client/
├── public/ Static icons and images
├── src/
│ ├── background/ Service worker, scheduler, messaging, API client
│ ├── common/ Shared storage, helpers, and message types
│ ├── content/ Bundled lesson content
│ ├── contentScript/ Card injection into web pages
│ ├── options/ Settings page
│ ├── popup/ Toolbar popup
│ ├── sidepanel/ Progress and controls
│ ├── manifest.ts Manifest V3 definition
│ └── zip.js Release archive task
├── build/ Generated unpacked extension output
├── package/ Generated release archives
├── TESTING.md Manual QA checklist
├── package.json Scripts, dependencies, and version
└── vite.config.ts Vite and CRXJS configuration
Generated directories such as build/ and package/ should be recreated by the build scripts rather than edited by hand.
Keep changes focused, run npm run build before opening a pull request, and update TESTING.md when a user-facing flow changes. For content changes, preserve the lesson order and the mastery rules used by the existing domain types.
tango is distributed under the MIT License. See LICENSE.