Size
5.4 KB
Version
1.0.1
Created
Feb 26, 2026
Updated
about 2 months ago
1// ==UserScript==
2// @name IXL Auto Skill Completer
3// @description Automatically solves IXL questions and completes skills
4// @version 1.0.1
5// @match https://*.ixl.com/*
6// @icon https://www.ixl.com/ixl-favicon.png
7// @grant GM.getValue
8// @grant GM.setValue
9// ==/UserScript==
10(function() {
11 'use strict';
12
13 console.log('IXL Auto Skill Completer loaded');
14
15 // Debounce function to prevent multiple rapid calls
16 function debounce(func, wait) {
17 let timeout;
18 return function executedFunction(...args) {
19 const later = () => {
20 clearTimeout(timeout);
21 func(...args);
22 };
23 clearTimeout(timeout);
24 timeout = setTimeout(later, wait);
25 };
26 }
27
28 // Function to extract the question text from the page
29 function getQuestionText() {
30 const questionSection = document.querySelector('.question-and-submission-view');
31 if (!questionSection) return null;
32
33 // Get the question text, excluding the input field and button
34 const clone = questionSection.cloneNode(true);
35 const inputs = clone.querySelectorAll('input');
36 inputs.forEach(input => input.remove());
37 const buttons = clone.querySelectorAll('button');
38 buttons.forEach(button => button.remove());
39
40 return clone.textContent.trim();
41 }
42
43 // Function to solve the question using AI
44 async function solveQuestion() {
45 try {
46 const questionText = getQuestionText();
47 if (!questionText) {
48 console.log('No question found');
49 return;
50 }
51
52 console.log('Question:', questionText);
53
54 // Use AI to solve the question
55 const answer = await RM.aiCall(
56 `Solve this math problem and provide ONLY the numerical answer (no explanation, no units, just the number): ${questionText}`,
57 {
58 type: "json_schema",
59 json_schema: {
60 name: "math_answer",
61 schema: {
62 type: "object",
63 properties: {
64 answer: { type: "string" }
65 },
66 required: ["answer"]
67 }
68 }
69 }
70 );
71
72 console.log('AI Answer:', answer.answer);
73
74 // Fill in the answer
75 const inputField = document.querySelector('input.fillIn');
76 if (inputField) {
77 inputField.value = answer.answer;
78 inputField.dispatchEvent(new Event('input', { bubbles: true }));
79 inputField.dispatchEvent(new Event('change', { bubbles: true }));
80
81 // Wait a moment then submit
82 setTimeout(() => {
83 const submitButton = document.querySelector('button.crisp-button');
84 if (submitButton && submitButton.textContent.includes('Submit')) {
85 console.log('Submitting answer...');
86 submitButton.click();
87 }
88 }, 500);
89 }
90
91 } catch (error) {
92 console.error('Error solving question:', error);
93 }
94 }
95
96 // Function to handle the "Continue" button after answering
97 function clickContinueIfPresent() {
98 const continueButton = document.querySelector('button.crisp-button');
99 if (continueButton && (continueButton.textContent.includes('Continue') || continueButton.textContent.includes('Next'))) {
100 console.log('Clicking continue button...');
101 setTimeout(() => {
102 continueButton.click();
103 }, 1000);
104 }
105 }
106
107 // Observer to watch for DOM changes
108 const observer = new MutationObserver(debounce(() => {
109 // Check if we're on a skill page
110 if (!window.location.pathname.includes('/math/') && !window.location.pathname.includes('/ela/')) {
111 return;
112 }
113
114 // Check for new question
115 const questionSection = document.querySelector('.question-and-submission-view');
116 const inputField = document.querySelector('input.fillIn');
117 const submitButton = document.querySelector('button.crisp-button');
118
119 if (questionSection && inputField && submitButton && submitButton.textContent.includes('Submit')) {
120 // New question detected, solve it
121 if (!inputField.value) {
122 console.log('New question detected, solving...');
123 solveQuestion();
124 }
125 } else {
126 // Check for continue button
127 clickContinueIfPresent();
128 }
129 }, 1000));
130
131 // Start observing
132 function init() {
133 console.log('Starting IXL Auto Skill Completer...');
134
135 // Observe the entire document for changes
136 observer.observe(document.body, {
137 childList: true,
138 subtree: true
139 });
140
141 // Try to solve the current question if one exists
142 setTimeout(() => {
143 const inputField = document.querySelector('input.fillIn');
144 if (inputField && !inputField.value) {
145 solveQuestion();
146 }
147 }, 2000);
148 }
149
150 // Wait for page to be ready
151 if (document.readyState === 'loading') {
152 document.addEventListener('DOMContentLoaded', init);
153 } else {
154 init();
155 }
156
157})();