PlayerCross is a deduction crossword-style vocabulary activity for Moodle. Each round draws a mystery phrase and a set of terms built from related course concepts; resolving a term reveals the letters it shares with every other pending term and with the mystery phrase itself.
👈 Use the sidebar to jump to any section on this page.
✨ Features
- 🧩 Deduction Crossword Gameplay: Each round picks a mystery phrase (a course concept’s own clue) and a set of terms (other concepts whose words share letters with the mystery phrase). Solving a term reveals its shared letters everywhere they occur — in every pending term and in the mystery phrase itself — by letter identity, not by spatial position.
- 🎯 Direct Mystery-Phrase Guess: Students can risk a direct guess of the mystery phrase at any point in the round, without waiting to resolve every term first. Guessing correctly before resolving any term earns an early-guess bonus — see Grading & Ranking.
- ⚖️ Configurable Win Condition: Choose whether a round is won only by resolving every term and guessing the mystery phrase, or by the mystery-phrase guess alone (terms still help by revealing letters, but are optional to finish the round). See Grading & Ranking.
- 🛡️ Automatic Loss on Term Exhaustion: Under the “both required” win condition, a term that runs out of attempts makes winning mathematically impossible — the round ends immediately as a loss instead of leaving the student stuck.
- 🚫 Automatic Loss on Mystery-Phrase Exhaustion: The mystery phrase has its own configurable attempt limit. Running out always ends the round as a loss, regardless of win condition — the phrase is required to win either way.
- 🔡 Uncovered-Slot Handling (Configurable): A mystery-phrase letter that no selected term happens to share is, by default, revealed automatically from the start of the round (no term could ever reveal it “for free” otherwise); teachers can disable this so it stays hidden until a paid hint or the round’s end.
- 📖 Glossary Integration: Import concepts from one or all course glossaries as the word pool, with definitions used as each word’s clue.
- ✂️ Split Multi-Word Concepts (optional, off by default): A multi-word glossary concept (e.g. “Operating System”) can be split into separate single-word candidates. Off by default to favour clue quality — when disabled, that concept is simply left out of the pool instead of producing isolated terms that do not always make sense on their own.
- 🚧 Configurable Stopwords: A per-activity, comma-separated list of words (e.g. “the, of, and”) to ignore when splitting a multi-word glossary concept into candidates — only relevant while splitting concepts above is enabled.
- 🤖 AI Word Generation (Optional): Generate candidate words and clues for a given topic via AI Hub (
local_aihub) or Moodle’score_aifallback. Generated words are treated as untrusted input — only single-token, purely alphabetic terms within the configured length bounds are saved, and they enter the pool pending teacher approval. - ✍️ Manual Word Pool: Teachers can add, edit, approve, and delete words directly from the management page.
- 🚫 Duplicate Prevention: The same word text can only exist once per activity pool, regardless of which source added it — a manual entry blocks a colliding glossary import (and vice versa), so random selection is never skewed toward one accidentally-duplicated word.
- 🔤 Manual-Word Validation: A manually added word must be letters only, within the configured length range, and not already in the pool; the form rejects an invalid one with a specific reason instead of silently accepting a word the game could never actually draw.
- 🧩 Fragmented-Concept Warning: A multi-word glossary concept split into several single-word entries is flagged in the word management table, since each sibling word still carries the full original concept’s definition as its clue.
- 🔍 Live Eligible-Words Count: The settings form shows, live via AJAX, how many words currently fall within the configured length range — checked separately for the mystery phrase’s own range and the terms’ range — against the real pool while editing an existing activity, or a preview of the selected glossary’s content while creating a brand-new one.
- 🔍 Inactive Word Detection: Pool words that can no longer be drawn (wrong length for their role, invalid characters, still pending approval) are flagged by name, with the reason, in the word management table; an active/inactive word count is shown above the game area for whoever can manage the activity.
- 🎯 Draw-Count Tracking: The word management table shows how many times each word has actually been drawn as the mystery phrase, counted live from attempt history — no recompute step needed.
- 🔀 Word Modes: Random mystery phrase per round (default) or shared sequence mode, where every student receives the same puzzle in the same order — terms are never drawn separately, so the same phrase always brings the same terms.
- 📏 Independent Length Ranges: The mystery phrase’s minimum (and optional maximum) letter-count is configured separately from the term words’ own length range, so a long, descriptive clue can still produce a manageable puzzle.
- 🔢 Configurable Term Count: 3 to 10 terms per round (default 5), balancing puzzle difficulty against pool size.
- ⏳ Configurable Attempts, Per Term and For the Mystery Phrase: Cap the number of guesses allowed per individual term, and separately for the mystery phrase itself (0 = unlimited for either; both default to 3). Choosing Linear scoring for the grade or the ranking requires both to be a real number.
- 💡 Hint System (Toggleable): A single round-wide “Hint” button reveals one letter at a time — that letter shows up in every pending term and the mystery phrase that share it, just like solving a term would — optionally at an item cost via PlayerHUD. Teachers can turn the reveal-hint mechanic off entirely for the activity; when left on (the default), it can be capped to a fixed number of reveals per round (default 3) or left unlimited. Revealing enough hints to uncover every letter finishes and wins the round on its own, without needing every term resolved.
- 🏳️ Give Up: Students can forfeit the current round at any time — the correct mystery phrase and every term word are revealed immediately.
- ⏱️ Configurable Cooldown: Minimum wait between rounds (minutes, hours, or days), always recomputed from the activity’s current setting.
- 🔢 Round Limit: Teachers can cap the total number of rounds per student (1–10 or unlimited).
- 🛡️ Round-Limit Integrity: A round abandoned mid-play (closed tab, lost session) still counts against the round limit — reserved the moment it starts, not only once it finishes, so it can never grant a free re-roll.
- 🔡 Accent-Insensitive Matching: Diacritics are always stripped before comparing a guess and its target.
- ⌨️ Accent Picker on the Virtual Keyboard: Long-pressing a key with accented variants (most vowels, plus C, N and S) on the on-screen keyboard opens a popup with those variants, mirroring a mobile keyboard’s own long-press behaviour — sliding the finger picks a variant, releasing confirms it. Covers Portuguese, Spanish, French, Italian and German diacritics (including Ç, Ñ and ß); alphabets outside that set (Nordic, Slavic, Turkish, Icelandic…) are a possible future addition, not covered today. Purely cosmetic: guess matching stays accent-insensitive throughout.
- ⌨️ Keyboard Marks Already-Revealed Letters: A letter already revealed in any pending term or in the mystery phrase is highlighted on the virtual keyboard, so the student doesn’t waste time retrying something already known.
- 🟢 Submit-Ready Cue: A term’s row (or the mystery phrase’s own row) reveals its own submit button the instant every one of its boxes is filled, right next to the tiles — no need to fill in every other term first, and no separate button to look for elsewhere on screen. A physical Enter key works too; the on-screen keyboard itself carries only letters and Backspace, matching the original game this plugin is based on.
- ✅ True-Spelling Reveal: When a term is resolved, the mystery phrase is guessed correctly, or the round ends, the term word and the mystery phrase are shown with their real, accented spelling from the word bank, even if the winning guess was typed without accents. A term left entirely spelled out by already-shared letters auto-resolves the moment the mystery phrase is guessed correctly, instead of staying marked unresolved.
- 🧮 Binary/Linear Scoring: Grade and ranking each choose their own scoring mode independently — Binary (full credit on a win) or Linear (credit decreases with every wrong guess, across every term and the mystery phrase together) — plus an early-guess bonus for guessing the mystery phrase directly before any term is resolved — see Grading & Ranking.
- 📊 Grading Methods: Highest grade, average grade, first attempt, last attempt, or average over all required rounds.
- 🧮 Grading Transparency: Students see the active grading method before playing, the same way mod_quiz communicates its own grading method.
- 📋 Gradebook Integration: Grades are written automatically on every round completion.
- ✅ Custom Completion Rule: Minimum number of completed rounds, evaluated and applied immediately after each round.
- 🔄 Course Reset Support: “Reset course” clears student attempts and resets grades for the activity, scoped to the target course only.
- 🏆 Top 5 Ranking: Leaderboard scoped to the activity, capped to the top 5, with an outsider row so a lower-ranked student still sees their own real position. Respects
SEPARATEGROUPS. - 📋 Attempt History: Students review every finished round of their own — mystery phrase, terms resolved, attempts used, time, and score — via the toolbar. Whoever can manage the activity sees that same page too (including their own attempts, if any), plus a separate all-students report — see Grading & Ranking.
- 🗑️ Attempt Deletion: From the all-students report, whoever can manage the activity can delete attempts individually or in bulk (with a select-the-current-page option). The affected student’s grade is recalculated automatically, including unlocking activity settings that lock once a real grade exists, if every one of their attempts is removed. Already-granted PlayerHUD items are not reverted automatically — an on-page notice covers this whenever the activity grants items for winning.
- ❓ In-Game Help: A dedicated help page explains the puzzle mechanic, how to submit a guess, attempts, hints, timer, the activity’s win condition, grading method and (when Linear scoring is active) the scoring formula — plus, when the relevant attempt limits are set, the risk of losing the round if a term’s or the mystery phrase’s attempts run out.
- 👋 First-Visit Onboarding: The how-to-play modal opens automatically the very first time a user visits any PlayerCross activity on the site — once, ever, site-wide — and never repeats after that; the toolbar help icon always reopens it on demand.
- ♿ Accessibility: WCAG AA contrast on every puzzle tile; non-colour state indicators;
aria-labelon every input; per-letter-box focus behaviour mirrors a verification-code input for predictable keyboard and click navigation. - ⚡ AJAX-Powered: Every round transition (term guess, final guess, hint, forfeit, timeout, start, new round) happens without a page reload.
- 🔔 Toast Feedback: Round-flow outcomes (a term resolved, a wrong guess, a hint revealed) surface as brief, auto-dismissing toast notifications instead of blocking dialogs, keeping the student in the puzzle.
- 🎮 PlayerHUD Integration (Optional): Require inventory items to start a round or to reveal a hint, with atomic FIFO consumption. The student’s current balance against the required quantity is always shown up front, and a cost pointing at a deleted or another course’s item is waived rather than blocking the student. Can also grant an item for each round won; matching PlayerHUD’s own anti-farming rule, no XP is awarded from that item while the activity allows unlimited rounds, and the potential win-grant XP is reflected in PlayerHUD’s own “Total XP in the game” ceiling estimate.
- 🛡️ Safe Cross-Course Integration: Every PlayerHUD item reference is validated against the course’s own block instance, never a stale or another course’s item — even after backup/restore or course duplication.
- 🔔 PlayerHUD Dependency Awareness: When PlayerHUD is installed on the site but hasn’t been added to the current course yet, the settings form explains that the integration will appear once the block is added. When the block_playerhud plugin isn’t installed anywhere on the site, the site administrator sees an equivalent notice on the plugin’s own settings page.
- 📦 Backup & Restore: Full Moodle 2 backup/restore support, including the “Duplicate activity” action, word pool, attempts, user/glossary id remapping, and safe PlayerHUD item remapping.
- 🔐 Privacy API: GDPR/LGPD compliant — complete data export and deletion for all stored personal data.
🎓 Educational Purpose
PlayerCross is designed to:
- Reinforce learning of concepts covered in the course or subject
- Exercise several related concepts in the same round, rewarding students for noticing the connective idea — a unit theme or category — that ties a set of already-studied terms together
- Foster playful, game-based learning experiences
- Simplify and make learning and assessment dynamics more intuitive
- Contribute to achieving educational goals across different courses and disciplines
- Promote active learning methodologies, including game-based learning and gamification
- Support retrieval practice — students must recall each concept from memory before seeing any answer, one of the most effective techniques for long-term retention
- Encourage spaced practice — the configurable cooldown between rounds brings students back to the content across multiple sessions, aligning with the principles of spaced repetition
- Add a layer of associative/elaborative learning: solving the mystery phrase requires holding multiple concepts in mind at once and noticing how they relate through shared letters — a synthesis exercise that a single isolated word does not provoke
Suitable for:
- Any course that uses concept-based terminology, especially units with several related terms
- Gamified academic courses using the PlayerGames ecosystem
- Formative assessment and self-study reinforcement
- Engagement reinforcement strategies
🕹️ PlayerGames Ecosystem
PlayerCross is part of the PlayerGames gamification ecosystem for Moodle. Its main direct integration is with the PlayerHUD block:
-
PlayerHUD Block (Optional, v1.7.1+): Configure item costs for starting a round or revealing a term’s hint, and an item grant for each round won.
-
PlayerGroup (Compatible): Standard Moodle groups — created manually or via the PlayerGroup activity — are honoured by the ranking’s
SEPARATEGROUPSfiltering. -
PlayerWords (Sibling Activity): Also part of the ecosystem, PlayerWords tests recall of one concept per round in a Wordle-style format. PlayerCross builds on the same word-pool/PlayerHUD/gradebook architecture to add a puzzle that connects several concepts in a single round.
See the PlayerGames hub for the full plugin family.
🧩 Optional Integration: AI Hub
PlayerCross’s optional AI Word Generation feature can draw on AI Hub (local_aihub, by the same author, part of the shared PlayerGames ecosystem services). When AI Hub is installed, any personal or site key a teacher or admin has already configured there is automatically available to PlayerCross — no key needs to be re-entered. PlayerCross never contacts an AI provider directly; without AI Hub installed, it falls back to Moodle’s own core_ai subsystem, routing to whatever provider the site administrator has configured there instead.
👉 https://github.com/jeanlucio/moodle-local_aihub
📦 Requirements
| Component | Version |
|---|---|
| Moodle | 4.5 – 5.2 |
| PHP | 8.1+ |
| PlayerHUD (optional) | v1.7.1+ |
🛠️ Installation & Configuration
- Download the
.zipfile or clone this repository. - Extract the folder into your Moodle
mod/directory. - Rename the folder to
playercross(if necessary). Final path:your-moodle/mod/playercross/ - Visit Site administration > Notifications to complete installation.
- Add a PlayerCross activity to any course.
This plugin has no site-level settings for an admin to configure — every setting is
configured by the teacher when adding the activity to a course, as covered in
Usage below. If block_playerhud isn’t installed on the site, the plugin’s own
settings page under Site administration → Plugins → Activity modules → PlayerCross shows
an informational notice about it — there’s nothing to configure there either way.
📖 Usage
- Add a PlayerCross activity to your course.
- Configure:
- Mystery-phrase length range (independent from the term words’ own length range) and number of terms per round
- Win condition (both terms and mystery phrase required, or the mystery-phrase guess alone) and whether uncovered mystery-phrase letters are auto-revealed
- Maximum attempts per term and for the mystery phrase, cooldown between rounds, and round limit
- Whether hints are allowed at all, and if so, the maximum reveals per round (default 3, or unlimited)
- Word mode (random or shared sequence)
- Grading method, grade and ranking scoring mode (Binary or Linear), and gradebook settings
- Word sources (manual, Glossary, AI), Glossary source, and a stopword list to skip when splitting multi-word glossary concepts (all optional)
- PlayerHUD item costs and win grant (optional, when PlayerHUD block is present)
- Open the Manage words page to add, generate with AI, approve, edit, or delete words.
- Students play directly from the activity page — resolving terms, guessing the mystery phrase, revealing hints, and forfeiting rounds, with no page reload. The page’s own toolbar gives access to the rules (help), attempt history, and the ranking.
- Grades and ranking update automatically after each round.
🧮 Grading & Ranking
PlayerCross computes a grade and a ranking total from the same finished rounds, but the two are configured completely independently — a teacher can keep the grade simple while still rewarding efficient play in the ranking, or the other way around.
Both are entirely optional, and each is switched on or off on its own:
- Grade: leave the standard
Gradefield set to None to run the activity fully ungraded — no grade is ever computed or written to the gradebook, and theGrading method/Grade scoring modesettings disappear from the form. - Ranking: leave
Show rankingset to No to hide the ranking everywhere — in-game, on the dedicated ranking page, and the extra column in the attempt history — and theRanking scoring modesetting disappears from the form too.
Turning one off never affects the other: an activity can be graded with no ranking, ranked with no grade, both, or neither.
Per-round scoring decides how much a single round is worth, chosen separately for the grade
and for the ranking (Grade scoring mode / Ranking scoring mode settings, both default to
Binary). The grade is scored against the activity’s own configured maximum grade; the
ranking always uses its own fixed 100-point base, completely independent of the grade — even
when the activity has no grade at all (Grade = None, the form’s default), the ranking still
works normally:
| Mode | A won round is worth… | A lost round |
|---|---|---|
| Binary (default) | The full base (the activity’s grade, or a fixed 100 points for ranking) | Zero |
| Linear | A share that decreases with every wrong guess made — across every term and the mystery phrase, counted together as a single pool | Zero |
Terms carry no per-term point value of their own: every wrong guess, whether on a term or on the mystery phrase itself, draws from the same shared error pool, and that pool’s size determines the whole round’s Linear score:
max_errors = num_terms × (max_attempts_per_term − 1) + (max_attempts_final_guess − 1)
points (grade) = grade × (max_errors − errors_used + 1) / (max_errors + 1)
points (ranking) = 100 × (max_errors − errors_used + 1) / (max_errors + 1)
Linear has no grace period: the very first wrong guess already reduces the score. A flawless run
(zero wrong guesses anywhere) is still always exactly full credit, and the score never reaches
zero for a genuinely completed win — it floors at base / (max_errors + 1) even at the maximum
error budget. Because max_errors depends on both attempts settings, choosing Linear for
either the grade or the ranking requires Maximum attempts per term and Maximum attempts for
the mystery phrase to both be a real number, not unlimited — the settings form blocks saving
otherwise.
Worked example with 5 terms, 3 attempts per term, 3 attempts for the mystery phrase
(max_errors = 5 × 2 + 2 = 12) — the grade column assumes a 100-point maximum grade, but the
ranking column is exactly this in any activity, even one with no grade configured at all:
| Errors | Grade (100-point base) | Ranking (100-point base, always) | Errors | Grade | Ranking |
|---|---|---|---|---|---|
| 0 | 100.00 | 100.00 | 7 | 46.15 | 46.15 |
| 1 | 92.31 | 92.31 | 8 | 38.46 | 38.46 |
| 2 | 84.62 | 84.62 | 9 | 30.77 | 30.77 |
| 3 | 76.92 | 76.92 | 10 | 23.08 | 23.08 |
| 4 | 69.23 | 69.23 | 11 | 15.38 | 15.38 |
| 5 | 61.54 | 61.54 | 12 | 7.69 | 7.69 |
| 6 | 53.85 | 53.85 | Not completed | 0.00 | 0.00 |
Early-guess bonus: guessing the mystery phrase correctly before resolving any term adds a flat 10% on top of the base score above — 10% of the activity’s grade, for the grade; 10% of the fixed 100-point base (i.e. always +10 points), for the ranking. For the grade, this is capped at the activity’s nominal maximum — a flawless run already at 100% stays at 100%. For the ranking, it is uncapped — the same flawless run’s ranking total becomes 110, legitimately exceeding the nominal 100-point base, since the ranking rewards efficient early deduction beyond what a gradebook value can represent.
Combining several rounds into one final grade is a separate setting, Grading method
(highest grade, average grade, first attempt, last attempt, or average over all required rounds).
It works the same regardless of whether the per-round scoring above is Binary or Linear: it only
ever aggregates whatever value each round already recorded.
The ranking is the sum of every finished round’s ranking points for a student (SUM),
ordered highest first; ties are broken by fewer attempts used on average, then less time spent on
average. It only appears when the teacher enables “Show ranking”, and never reveals a round still
in progress.
Only the top 5 are shown — deliberately, not a bug: both the in-game ranking widget and the dedicated ranking page cap the list at 5 rows, to avoid publicly ranking every student in the class. A student ranked lower still sees exactly where they stand: an extra row, separated by “…”, shows their own real position and score, without exposing anyone else’s rank below 5th. Anyone who can manage the activity (editingteacher, manager) never appears in the ranking at all, even if they play the activity themselves — the same way their own attempts are excluded from the attempt report below.
“Show ranking” only controls visibility, not data collection: ranking points are computed and stored for every finished round regardless of whether the setting is on or off at the time. Turning it on after students have already played reveals the full total accumulated since the activity started, not just the points earned from that moment forward — nothing is lost, and nothing needs to be “recovered” by switching it off and back on.
Locked once graded: the moment the activity records a real grade for any student, Terms per
round, Grading method, Maximum attempts per term, Maximum attempts for the mystery phrase
and Grade scoring mode all lock — the same way Moodle already locks a graded activity’s own
“Maximum grade” field once real grades exist. Since the Linear formula’s error budget is a direct
function of the terms count and both attempts settings, changing any of them after real scores
exist would make earlier and later rounds worth different things; locking them guarantees every
round ever recorded stays internally consistent for the activity’s whole lifetime.
Ranking scoring mode locks separately, the moment any finished attempt exists — it doesn’t
wait for a real grade, because ranking points are already computed and stored for every finished
round regardless of whether Grade or Show ranking are even on (see above). An entirely
ungraded, ranking-only activity already accumulates real history from its very first round; locking
the scoring mode once that history exists prevents the same scale inconsistency the lock above
prevents for the grade.
Attempt history: each student can review their own past rounds — mystery phrase, terms resolved, attempts used, time, grade score and (when ranking is enabled) ranking points — on a dedicated toolbar page. Whoever can manage the activity sees that same page too, including their own attempts if they have played the activity. The all-students report lives on a separate page, visible only to whoever can manage the activity: one table with every student’s attempts, sortable by clicking any column header, and filterable to a single student. Like the ranking, that report never includes a manager’s own attempts.
Deleting attempts reverses these locks when they no longer apply. From the all-students
report, whoever can manage the activity can delete a student’s attempts individually or in bulk.
Deleting genuinely clears that student’s grade rather than leaving a stale value behind, so if
every attempt for every student is removed, Terms per round, Grading method, both attempt
limits and Grade scoring mode unlock again exactly as grade_item::has_grades() expects — the
same way they would on an activity that was never played at all. Ranking scoring mode follows
the same logic against the attempts table directly, independent of whether grading is even on.
🧪 Automated Tests
PlayerCross ships with a PHPUnit test suite covering business logic, repository queries, web services, and Privacy API compliance, plus a Behat suite covering gameplay, PlayerHUD integration, and reports end-to-end in a real browser. Every CI push runs against the full matrix (Moodle 4.5 → 5.x, PostgreSQL & MariaDB).
PHPUnit — Core Tests
| Test file | Cases |
|---|---|
backup_restore_test.php |
8 |
cross_instance_security_test.php |
4 |
lib_grant_potential_test.php |
6 |
lib_reset_userdata_test.php |
4 |
lib_supports_test.php |
2 |
completion/custom_completion_test.php |
6 |
privacy/provider_test.php |
21 |
lib_update_grades_test.php |
2 |
mod_form_test.php |
4 |
| Subtotal | 57 |
Local Business-Logic Tests (tests/local/)
| Test file | Cases |
|---|---|
ai_word_generator_test.php |
19 |
attempts_history_service_test.php |
21 |
gameplay_service_test.php |
16 |
hud_service_test.php |
27 |
intro_service_test.php |
5 |
puzzle_builder_test.php |
9 |
ranking_service_test.php |
9 |
round_presenter_test.php |
60 |
round_service_test.php |
67 |
view_page_service_test.php |
40 |
word_normalizer_test.php |
38 |
words_repository_test.php |
67 |
| Subtotal | 378 |
Web Services Tests (tests/external/)
| Test file | Cases |
|---|---|
count_eligible_theme_words_test.php |
5 |
count_eligible_words_test.php |
5 |
count_glossary_candidates_test.php |
5 |
end_round_test.php |
6 |
new_round_test.php |
5 |
reveal_hint_test.php |
8 |
start_round_test.php |
7 |
submit_term_guess_test.php |
8 |
submit_final_guess_test.php |
7 |
| Subtotal | 56 |
| Grand Total | 491 |
vendor/bin/phpunit --testsuite mod_playercross
Overall line coverage (moodle-coverage, PHPUnit + Xdebug): 90%.
Behat — End-to-End Tests
| Feature file | Scenarios |
|---|---|
mod_playercross_smoke.feature |
1 |
mod_playercross_gameplay.feature |
15 |
mod_playercross_playerhud.feature |
4 |
mod_playercross_reports.feature |
5 |
mod_playercross_settings.feature |
5 |
mod_playercross_toolbar.feature |
9 |
| Subtotal | 39 |
Full test-by-test breakdown and coverage table →
🔐 Security & Compliance
- Capability-based access control (
mod/playercross:view,mod/playercross:addinstance,mod/playercross:managewords,mod/playercross:viewreports) require_sesskey()protection on all POST actions; AJAX calls are validated by Moodle’score/ajaxdispatcher- Server-side enforcement of round limits and cooldown, always recomputed from current settings
- Round timeout is re-validated against the server’s own deadline instead of trusting the client’s countdown alone
- Guess charset validation — only Unicode letters accepted
- AI-generated words are treated as untrusted input: only single-token, alphabetic terms within the configured length bounds are saved, and they enter pending teacher approval
- Session round state is isolated per activity instance and per user — a word id or session key from one activity is never accepted by another
- A wrong term guess or a wrong mystery-phrase guess never leaks the correct word; the theme word is only ever revealed once the round has actually finished
- Moodle External API compliant
- Privacy API fully implemented (GDPR/LGPD)
🔒 Third-party Service Disclosure
AI word generation is optional and disabled by default. When a teacher uses it, the
activity topic (never student data or attempt records) is sent through AI Hub
(local_aihub) — using that user’s or the site’s own BYOK key, if the plugin is installed — or,
as a fallback, through Moodle’s own core AI subsystem (core_ai), which routes to whatever
provider the site administrator has configured. PlayerCross never contacts an AI provider
directly; the request and its disclosure/consent are entirely owned by local_aihub or by
core_ai. If neither is installed or configured, the AI word source is unavailable and every
other feature keeps working normally.
- Cost: None required by PlayerCross itself. If used, any cost is whatever the underlying
provider charges through a
local_aihubBYOK key, or nothing at all via a free/institutionalcore_aiprovider the site admin may have already configured. - API keys / credentials: Not configured in PlayerCross. Obtain and configure a personal or
site key inside AI Hub (
local_aihub), or ask the site administrator to configure acore_aiprovider instead. - Demo credentials: Not applicable — no credentials are required to install or use PlayerCross; AI generation is entirely opt-in.
📄 License
This project is licensed under the GNU General Public License v3 (GPLv3).
Copyright: 2026 Jean Lúcio