Skip to content

Repository files navigation

تعلَّم التجويد · Learn Tajweed

الموقع → dartajweed.com

دليلٌ مجّانيٌّ مفتوح المصدر لتعلُّم أحكام تجويد القرآن الكريم، بالعربيّة الفصحى، على رواية حفص عن عاصم من طريق الشاطبيّة.

مكتوبٌ لمن يقرأ العربيّة ويعرف التشكيل لكنّه لا يعرف أسماء الأحكام ولا متى تُطبَّق: أربعةٌ وثلاثون درسًا في إحدى عشرة وحدة، من الأسهل إلى الأصعب، مع أمثلةٍ مسموعةٍ من القرآن الكريم وتمارينَ بعد كلّ درس.

A free, open-source Arabic guide to Qur'anic tajweed. Thirty-four lessons in eleven units, ordered from easiest to hardest, with audio examples and quizzes.


Why this repo is unusual: the text is machine-verified

Nobody types a Qur'anic verse into this repository. Lessons reference verses by number (ref: 2:19) and the build fills in the text from a checked-in Uthmani corpus that is pinned by SHA-256.

npm run build refuses to produce a site if any of these fail:

  1. The corpus in data/quran-uthmani.txt no longer matches its pinned checksum.
  2. A lesson references a verse that does not exist.
  3. A phrase a lesson wants to highlight is not in that verse, or occurs more than once.
  4. Any file contains Uthmani orthography that does not match the mushaf character for character.
  5. Any lesson has broken frontmatter, a duplicate order, or an unknown unit.

Full details: docs/quran-pipeline.md.

Tech stack

  • React 19 + TypeScript (strict) on Vite
  • Tailwind CSS v4, CSS-first theming, light and dark
  • React Router for pages
  • Lessons are plain Markdown rendered with react-markdown, plus a handful of custom blocks
  • Self-hosted fonts: Cairo for the interface, Amiri Quran for Qur'anic text
  • No backend, no accounts, no tracking. Progress lives in localStorage.

Run it locally

npm install
npm run dev

Other scripts:

npm run build        # verify the text, type-check, build, and pre-render routes
npm run preview      # serve the production build
npm run lint         # oxlint
npm run check        # verify + lint + type-check, without building

npm run content:build # regenerate the verse data and the lesson index (runs automatically)
npm run quran:fetch  # re-download the corpus from Tanzil and verify its checksum
npm run quran:find -- "من الصواعق"   # find which verse contains a phrase
npm run og           # regenerate the share card and PNG icons (needs Chrome)

Add or edit a lesson

  1. Create a file in src/content/lessons/, for example madd-badal.md.
  2. Copy the frontmatter from a neighbouring lesson and fill it in.
  3. Write the body using the blocks documented in docs/writing-lessons.md.
  4. Run npm run check. It will tell you, in Arabic, exactly what is wrong.

No code change is needed. The file name becomes the URL (madd-badal.md/lessons/madd-badal), and the site picks it up automatically.

Project structure

data/                     the Uthmani mushaf text + surah names (checked in, pinned)
scripts/
  fetch-quran.mjs         downloads the corpus and verifies its checksum
  build-quran.mjs         verifies every reference and generates the runtime data
  find-ayah.mjs           search helper for lesson authors
src/
  content/lessons/*.md    THE CONTENT. One file = one lesson.
  content/pages/*.md      the summary sheet and the about page
  lib/units.ts            the eleven units, in curriculum order
  lib/rules.ts            every tajweed rule: name, colour, definition, lesson
  lib/glossary.ts         terms that are not rule names
  components/content/     the custom Markdown blocks
  components/layout/      header, footer, theme toggle, back-to-top
  components/CompletionCard.tsx   what the reader sees on finishing the guide
  components/ProgressBar.tsx      how far through the curriculum they are
  pages/                  Home, LessonPage, Practice, Cheatsheet, Glossary, About
docs/                     how the pipeline works, how to write a lesson

Sources

Contributing

Found a mistake? It is a mistake about the Book of Allah, so please report it:

  • Open an issue on this repository, or
  • Send a pull request.

If the correction is a point of tajweed, cite a source from the recognised books of the field so it can be checked.

Deployment

Forking this

To get it deployed: nothing. Fork it, turn on GitHub Pages (Settings → Pages → Source: GitHub Actions), and push. The workflow works out your address from your repository name, so your copy builds and deploys to https://<your-username>.github.io/<your-repo>/ without you editing a single file. site.config.mjs needs no changes, and no URL in the build points at the original site.

Three things still carry our details, and they are not automatic:

What Where Why it matters
The share card image public/og.png The address is printed into the picture. Until you regenerate it, every WhatsApp or Telegram preview of your site shows ours.
The "found a mistake?" link src/content/pages/about.md Sends your readers' bug reports to our issue tracker.
The copyright line LICENSE 0BSD lets you keep it, but you probably want your own name.

Regenerating the card needs Chrome and your own address:

SITE_URL=https://your-site.example/ npm run og
# not on macOS? point CHROME_PATH at your browser first:
CHROME_PATH=/usr/bin/google-chrome SITE_URL=https://your-site.example/ npm run og

The footer's GitHub link needs no attention — it is derived from your repository at build time, so it already points at your fork.

You may also want to change name in package.json, and the localStorage keys in src/hooks/ if you will host more than one copy under the same github.io account, since browser storage is shared per origin rather than per path.

How it works

Every push to main runs .github/workflows/deploy.yml. It verifies the Qur'anic text, builds the site, and publishes it to GitHub Pages. Two environment variables control the addresses, and both have sensible defaults:

Variable What it means Default
SITE_URL Where this build is served from. Assets, links and fonts resolve against it. https://<owner>.github.io/<repo>/
SITE_CANONICAL The address this build says it is, in canonical tags and the sitemap. the same as SITE_URL

They are only different when one site is published at two addresses. To build a copy locally for a specific address:

SITE_URL=https://example.com/ npm run build

Publishing at a second address (optional)

This repository publishes twice, at dartajweed.com and at edriso.github.io/learn-tajweed. The reason is worth knowing before you copy it: GitHub Pages redirects a repository's own Pages URL to its custom domain, and there is no setting to stop it. So attaching a domain does not leave the github.io address as a spare — it turns it into a sign pointing at the domain, and if the domain ever expires both addresses break at once. Publishing the same files to a second repository is the only way to keep an address that does not depend on the domain being paid for.

To set that up, add these in Settings → Secrets and variables → Actions:

Name Kind Example
MIRROR_REPO Variable edriso/dartajweed
SITE_URL Variable https://dartajweed.com/
MIRROR_DEPLOY_KEY Secret private half of an SSH deploy key with write access to MIRROR_REPO

Leave MIRROR_REPO unset and the whole second half is skipped — the mirror job never runs, so a fork never sees a failed deploy. The mirror repository holds no source, only the built site, replaced on every deploy. Its build writes a CNAME file, because branch-based Pages reads that file where actions/deploy-pages ignores it, and every mirror push replaces everything.

Both copies claim the same canonical address, so two sites with identical text never compete in search, and each serves its own og:image so link previews keep working even if the other address is down.

Licence

What Licence
Everything written for this repository — the app, the build scripts, the styling, and the lessons 0BSD
The Qur'anic text in data/ © Tanzil Project, CC BY 3.0 — see NOTICE
Surah names, recitation audio, fonts third-party — see NOTICE

0BSD is a public-domain-equivalent licence: fork the site, print the lessons for a halaqah, translate them, put them in a book, re-host them, sell them. You owe no credit and no notice. It is sadaqah, and being asked for a footer would defeat the point.

What you cannot relicense is the material this repository only redistributes. The Tanzil terms on the Qur'anic text require Tanzil to be named and forbid modifying the text; they travel with it into your fork, so keep the attribution that is already on the «عن هذا الدليل» page. NOTICE lists all of it.

One request, and it is a request rather than a condition of the licence: if you republish the lessons, keep the places where the text names a scholarly disagreement or the riwayah a rule belongs to. Flattening those is how a guide to reciting the Qur'an starts doing harm.

About

تعلَّم أحكام التجويد خطوةً بخطوة · A free Arabic guide to Qur'anic tajweed (Hafs from Asim, Shatibiyyah). Every verse is machine-verified against a checksum-pinned Uthmani mushaf.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages