User Script Guide
Section titled “User Script Guide”StarX ships a built-in user script system since 1.5.4: extend the module with JavaScript without waiting for a module release.
1. What you can do
Section titled “1. What you can do”- Run scripts in global, exam, homework, in-class quiz, chapter quiz, video and sign-in contexts, or several of them at once
- Call the capabilities the module already has: AI answers, question bank lookup, answer query (including images)
- Answer a question yourself the moment it is dispatched, taking priority over AI and the question bank - the exam pipeline included
- Send your own requests with
StarX.httpand persist data withStarX.storage - Install your own native hooks (requires Xposed framework API 102 or newer)
- Talk to other scripts over the event bus
Scripts run on Rhino (ES6 language level, interpreted only) and cannot see any Java class. Only the APIs documented here are available.
2. Script folder
Section titled “2. Script folder”/storage/emulated/0/Download/StarX/└── scripts/ ├── scripts.json enable/disable index (maintained by the module) ├── my_script.js script source ├── data/ │ └── my_script.json StarX.storage backing file └── logs/ └── my_script.log runtime log (rotates after 256 KB)Notes:
- The base folder is
/storage/emulated/0/Download/StarX, falling back to/sdcard/Download/StarXwhen not writable. - The file name without
.jsis the script ID. Onlya-z A-Z 0-9 . _ -are kept; other characters become_. Prefer ASCII file names. - Editing a file hot-reloads it within 2 seconds. MT Manager, VS Code or MTP from a PC all work; no restart of the host app is needed.
- A missing or broken index means “disabled” - scripts never run by accident.
3. Three ways to create a script
Section titled “3. Three ways to create a script”3.1 From the module UI (recommended)
Section titled “3.1 From the module UI (recommended)”- Open StarX and switch to the User Scripts tab
- Tap New script
- Name it and write the code in the editor (the template already contains a metadata header and an example)
- Tap Save; the module writes it into
scripts/and reports “hot reload within 2 seconds”
Each script card offers enable/disable, Edit, Log and Delete. The Usage button shows the scope and event cheat sheet.
3.2 Write the file directly
Section titled “3.2 Write the file directly”Create xxx.js inside scripts/ with a metadata header. The module loads it within 2 seconds; new scripts are enabled by default.
3.3 Install someone else’s script
Section titled “3.3 Install someone else’s script”Drop the .js file into scripts/. Scripts can only use the APIs documented here and cannot see Java classes, but they can still make arbitrary network requests, read and write the clipboard, and read and write their own storage file. Only run scripts you trust.
4. Metadata header
Section titled “4. Metadata header”The header follows the Tampermonkey ==UserScript== comment style. ==StarXScript== is an equivalent alias.
// ==UserScript==// @name Exam keyword answer// @namespace local.example// @version 1.0.0// @description Answers locally on keyword hits// @author you// @scope exam// @grant ai,tiku// ==/UserScript==| Field | Meaning |
|---|---|
@name | Display name; file name when omitted |
@namespace | Namespace, identifier only |
@version | Version shown on the script card |
@description | One-line description |
@author | Author |
@scope | Scopes, separated by commas, spaces or ` |
@match / @include | Page match rules (Tampermonkey semantics); a hit makes the script receive page events |
@exclude | Excludes URLs from @match hits |
@grant | Declares usable API groups; omitting it allows everything, declaring it allows only the listed groups |
@require | Remote JS loaded and executed synchronously before the script (512 KB per file, cached per process) |
@run-at | Reserved, metadata only |
@noframes | Reserved |
Match rules: * matches any length, ? a single character, and /regex/ is used as a regular expression (an invalid regex degrades to a literal match).
5. Scopes
Section titled “5. Scopes”@scope decides where the script runs. Without @scope it defaults to global.
| Value | Position | What it receives today |
|---|---|---|
global | Global | tick (5 s heartbeat), questions published via question.publish, events you emit |
exam | Exam | question (single-question pages, full-paper preview batches, composite sub-questions) |
work | Homework / chapter quiz | question. Chapter quizzes currently travel the homework pipeline, so use work to intercept them |
quiz | In-class quiz | question (every question of the batch) |
chapter | Chapter pages | page (URL routing, see below) |
video | Video | video.report (on natural progress reports) |
sign | Sign-in | sign.active (when a sign-in activity ID is captured) |
all | Everything above | Same as listing them all |
URL routing table for page events:
| Scope | URL fragments |
|---|---|
sign | /newsign/, /widget/sign/, /sign/ |
exam | /exam |
work | /dohomework, /work/ |
quiz | /inclass, /quiz |
video | /ananas/ |
chapter | /mycourse/studentstudy, /coursedata/, /chapter/ |
Scripts declaring @match receive page events on URL hits and do not need @scope.
6. Events
Section titled “6. Events”Subscribe with StarX.on(name, fn) and unsubscribe with StarX.off(name, fn).
6.1 question
Section titled “6.1 question”Fired when a question is dispatched:
{ scope: 'exam', // exam / work / quiz id: '123456789', // question id; composite questions use qid + "#" + sub index type: 0, // type code, see 6.6 stem: 'question text', options: ['option A', 'option B'], // may be an empty array on some pipelines ts: 1789015379277}Call StarX.question.answer(...) inside this callback to answer:
StarX.on('question', function (q) { if (q.stem.indexOf('TCP') >= 0) { StarX.question.answer('A'); // single choice / true-false } if (q.type === 1) { StarX.question.answer(['A', 'C']); // multiple choice -> "AC" } if (q.type === 2 || q.type === 4) { StarX.question.answer('three-way handshake'); // fill-in / short answer }});- Arrays are collapsed: all single-character elements join into
AC, otherwise they join with commas. - Returning
falsefromanswer()means “no usable answer this time”. - The first script that submits a non-empty answer wins; the module then skips AI and the question bank.
- The callback is synchronous and runs on the caller thread (the exam/homework parsing thread). Do not block for long.
6.2 page
Section titled “6.2 page”Fired when a WebView opens a page: { url, ts }.
6.3 sign.active
Section titled “6.3 sign.active”{ activeId, url, source, ts } where source is okhttp or webview.
6.4 video.report
Section titled “6.4 video.report”{ objectId, passed, source, preview, ts }.
6.5 tick and custom events
Section titled “6.5 tick and custom events”tick fires every 5 seconds with { ts } for scripts declaring global (or all).
StarX.emit('my-event', { hello: 1 }); // broadcast to other scripts (not back to yourself)StarX.on('my-event', function (p) { StarX.log(p.hello); });6.6 Question type codes
Section titled “6.6 Question type codes”| Value | Type |
|---|---|
| 0 | Single choice |
| 1 | Multiple choice |
| 2 | Fill in the blank |
| 3 | True / false |
| 4 | Short answer |
| -1 | Unknown |
7. Complete example: answer exam questions yourself
Section titled “7. Complete example: answer exam questions yourself”// ==UserScript==// @name Exam keyword answer// @version 1.0.0// @description Answers from local rules, otherwise asks the AI// @author you// @scope exam,work// ==/UserScript==
var RULES = { 'three-way handshake': 'three-way handshake'};
StarX.on('question', function (q) { for (var key in RULES) { if (q.stem.indexOf(key) >= 0) { StarX.log('hit rule:', key, '=>', RULES[key]); StarX.question.answer(RULES[key]); return; } } if (!StarX.ai.isConfigured()) return; var ans = StarX.ai.ask(q.stem, q.type, q.options.join('\n')); if (ans) StarX.question.answer(ans);});8. Permissions @grant
Section titled “8. Permissions @grant”Omitting @grant allows every API. Once declared, only the listed groups are allowed:
| Group | APIs |
|---|---|
ai | StarX.ai.* |
tiku | StarX.tiku.* |
answer | StarX.answer.* |
http | StarX.http.* |
storage | StarX.storage.* |
clipboard | StarX.clipboard.* |
hook | StarX.hook.* |
page | StarX.page.* |
question | StarX.question.* |
timer | setTimeout / setInterval / clearTimeout / clearInterval |
ui | StarX.toast |
A denied call returns null and writes a denied by @grant line to the script log.
9. Activation and hot reload
Section titled “9. Activation and hot reload”- File edits: reloaded within 2 seconds; nothing needs to be restarted.
- Module setting changes: the module app asks the framework to hot reload and tells you to restart the host app when the framework cannot.
- The script runtime is independent of the framework version - Rhino runs inside the module process, so API < 102 still works. Only
StarX.hook.*requires framework API 102 or newer; checkStarX.hook.available().
10. Logging and troubleshooting
Section titled “10. Logging and troubleshooting”StarX.log(...)andStarX.console.log / warn / error / debug(...)write toscripts/logs/<id>.logand to logcat under theStarXtag.- The Log button on a script card shows recent lines and lets you clear them.
- A script that fails to load (syntax error and so on) shows the error on its card and does not affect other scripts.
- Exceptions thrown inside event callbacks are caught and logged as
event xxx handler failed: ...without breaking the business pipeline.
11. Security model and known limits
Section titled “11. Security model and known limits”Security model (facts):
- Each script gets its own Rhino scope and its own single-thread executor; scripts cannot see each other’s variables.
- A
ClassShutterdenies every Java class, so scripts cannot reflect into Java through Rhino. - The full native surface is the operation list documented here - there is no other entry point.
- Script exceptions are isolated and do not affect the business pipeline or other scripts.
Limits (facts):
- Scripts can still make arbitrary HTTP requests, use the clipboard and read/write their own
data/<id>.json. Only run scripts you trust. @run-atand@noframesare metadata only today and do not affect injection scheduling.- The
chapterscope only receivespageevents; chapter quiz questions travel theworkscope. - There is no
GM_*compatibility layer; write against theStarX.*API documented here. @grantonly trims API groups, it does not restrict network destinations.