sensivity 2.5.27 → 2.5.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/index.html CHANGED
@@ -12,10 +12,7 @@
12
12
 
13
13
  <div id="license-overlay">
14
14
  <div id="license-box">
15
- <svg class="logo-icon" viewBox="0 0 24 24">
16
- <path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z"/>
17
- <path d="M9 12l2 2 4-4"/>
18
- </svg>
15
+ <img class="logo-icon" src="/assets/logo.png" alt="Sensivity">
19
16
  <h1>Sensivity <span>License</span></h1>
20
17
  <p class="subtitle">Enter your key to unlock</p>
21
18
  <input type="text" id="license-key" placeholder="SENSIVITY-XXXX-XXXX-XXXX-XXXX-XXXXXXXX" onkeydown="if(event.key==='Enter')submitLicense()">
@@ -28,15 +25,18 @@
28
25
  <div id="sidebar"></div>
29
26
  <div id="content">
30
27
  <div id="topbar"></div>
31
- <div id="pages"></div>
28
+ <div id="workspace">
29
+ <div id="pages"></div>
30
+ <aside id="esp-preview-shell"></aside>
31
+ </div>
32
32
  </div>
33
33
  </div>
34
34
  <div id="statusbar">
35
35
  <span class="s-dot" id="status-dot"></span>
36
36
  <span class="s-text" id="status-text">Ready</span>
37
37
  <span class="s-url" id="s-url" style="flex:1;font-size:10px;color:var(--text3);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:none"></span>
38
- <button class="s-btn" id="cheat-btn" onclick="toggleCheat()" disabled>Start Cheat</button>
39
- <button class="s-btn" style="background:var(--bg4);color:var(--text2);margin-left:4px;padding:5px 10px;font-size:10px" onclick="killSensivity()">Kill</button>
38
+ <button class="s-btn" id="cheat-btn" onclick="toggleCheat()" disabled>Start</button>
39
+ <button class="s-btn kill-btn" onclick="killSensivity()">Kill</button>
40
40
  </div>
41
41
 
42
42
  <svg style="display:none" id="icons-sprite" xmlns="http://www.w3.org/2000/svg">
package/public/js/app.js CHANGED
@@ -1,107 +1,423 @@
1
1
  const SOCKET = (typeof io !== 'undefined') ? io() : null;
2
2
  let state = {}, currentSection = 0, currentSub = 0;
3
3
  let licenseAccepted = false, cheatRunning = false, listeningKeybind = null;
4
+ let espSyncTimer = null;
4
5
 
5
- function svgIcon(id, size) { size = size || 18; return `<svg width="${size}" height="${size}"><use href="#ic-${id}"></use></svg>`; }
6
+ const SECTION_GROUPS = [
7
+ { label: 'AIMBOT', ids: ['aim'] },
8
+ { label: 'TOOLS', ids: ['misc'] },
9
+ { label: 'VISUALS', ids: ['visuals'] },
10
+ { label: 'PLAYERS', ids: ['playerlist', 'vehiclelist'] },
11
+ { label: 'WORLD', ids: ['world', 'settings'] }
12
+ ];
13
+
14
+ function svgIcon(id, size) {
15
+ size = size || 18;
16
+ return `<svg width="${size}" height="${size}"><use href="#ic-${id}"></use></svg>`;
17
+ }
6
18
 
7
19
  function initState() {
8
20
  if (!SCHEMA) return;
9
- SCHEMA.sections.forEach(s => { (s.subs || []).forEach(sub => { (sub.children || []).forEach(ch => { (ch.controls || []).forEach(c => {
10
- if (!(c.key in state)) state[c.key] = c.type === 'color_checkbox' ? { value: c.def, color: [...(c.color || [1,1,1,1])] } : c.def;
11
- });});});});
21
+ SCHEMA.sections.forEach(s => (s.subs || []).forEach(sub => (sub.children || []).forEach(ch => (ch.controls || []).forEach(c => {
22
+ if (!(c.key in state)) state[c.key] = c.type === 'color_checkbox' ? { value: c.def, color: [...(c.color || [1, 1, 1, 1])] } : c.def;
23
+ }))));
24
+ }
25
+
26
+ function sectionById(id) {
27
+ return SCHEMA.sections.findIndex(s => s.id === id);
28
+ }
29
+
30
+ function currentSubData() {
31
+ const s = SCHEMA.sections[currentSection];
32
+ return ((s && s.subs) || [])[currentSub] || ((s && s.subs) || [])[0];
12
33
  }
13
34
 
14
35
  function renderSidebar() {
15
36
  const el = document.getElementById('sidebar');
16
37
  if (!SCHEMA) return;
17
- el.innerHTML = SCHEMA.sections.map((s, i) =>
18
- `<button class="tab-btn${i===currentSection?' active':''}" onclick="setSection(${i})" title="${s.label}">${svgIcon(s.icon,19)}</button>`
19
- ).join('');
38
+ const grouped = SECTION_GROUPS.map(group => {
39
+ const items = group.ids.map(id => {
40
+ const index = sectionById(id);
41
+ if (index < 0) return '';
42
+ const s = SCHEMA.sections[index];
43
+ return `<button class="tab-btn${index === currentSection ? ' active' : ''}" onclick="setSection(${index})" title="${s.label}">
44
+ <span class="tab-ico">${svgIcon(s.icon, 18)}</span>
45
+ <span class="tab-label">${s.label}</span>
46
+ </button>`;
47
+ }).join('');
48
+ return items ? `<div class="nav-group"><div class="nav-heading">${group.label}</div>${items}</div>` : '';
49
+ }).join('');
50
+
51
+ el.innerHTML = `
52
+ <div class="brand"><img src="/assets/logo.png" alt="Sensivity"><span>SENSIVITY</span></div>
53
+ <div class="nav-scroll">${grouped}</div>`;
20
54
  }
21
55
 
22
56
  function renderTopbar() {
23
- const s = SCHEMA.sections[currentSection], subs = s.subs || [], sub = subs[currentSub] || subs[0];
57
+ const s = SCHEMA.sections[currentSection];
58
+ const subs = s.subs || [];
59
+ const sub = currentSubData();
24
60
  document.getElementById('topbar').innerHTML = `
25
- ${sub&&sub.icon?`<span class="tb-icon">${svgIcon(sub.icon,16)}</span>`:''}
26
- <span class="title">${s.label}</span><span class="sep">/</span><span class="sub">${sub?sub.label:''}</span>
27
- ${subs.length>1?`<select onchange="setSub(this.value)">${subs.map((x,i)=>`<option value="${i}"${i===currentSub?' selected':''}>${x.label}</option>`).join('')}</select>`:''}`;
61
+ <div class="top-title">
62
+ <span class="tb-icon">${svgIcon((sub && sub.icon) || s.icon, 17)}</span>
63
+ <div>
64
+ <span class="top-primary">${s.label}</span>
65
+ <span class="top-secondary">${sub ? sub.label : ''}</span>
66
+ </div>
67
+ </div>
68
+ <div class="sub-tabs">
69
+ ${subs.map((x, i) => `<button class="sub-tab${i === currentSub ? ' active' : ''}" onclick="setSub(${i})">${x.label}</button>`).join('')}
70
+ </div>
71
+ <div class="profile-dot"><img src="/assets/logo.png" alt=""></div>`;
28
72
  }
29
73
 
30
74
  function renderPage() {
31
- const sub = (SCHEMA.sections[currentSection].subs||[])[currentSub];
75
+ const sub = currentSubData();
32
76
  const pg = document.getElementById('pages');
33
- if (!sub||!sub.children||!sub.children.length) { pg.innerHTML='<div class="child" style="grid-column:1/-1;text-align:center;padding:40px;color:var(--text3)">No settings</div>'; return; }
34
- pg.innerHTML = sub.children.map(ch=>`<div class="child"><h3>${ch.label}</h3>${(ch.controls||[]).map(ctrl).join('')}</div>`).join('');
77
+ const showPreview = shouldShowEspPreview();
78
+ const workspace = document.getElementById('workspace');
79
+ if (workspace) workspace.classList.toggle('has-preview', showPreview);
80
+ if (!sub || !sub.children || !sub.children.length) {
81
+ pg.innerHTML = '<div class="child empty-state">No settings</div>';
82
+ renderEspPreviewShell(false);
83
+ return;
84
+ }
85
+
86
+ const children = sub.children.map(ch => `<div class="child"><h3>${ch.label}</h3>${(ch.controls || []).map(ctrl).join('')}</div>`).join('');
87
+ pg.innerHTML = children;
88
+ renderEspPreviewShell(showPreview);
89
+ }
90
+
91
+ function prettyLabel(key) {
92
+ return String(key).replace(/^Enable\s+/i, '').replace(/\s+ESP$/i, ' ESP');
35
93
  }
36
94
 
37
95
  function ctrl(c) {
38
- const v = state[c.key], vs = c.type==='color_checkbox'?v?.value:v, id = 'c_'+c.key.replace(/[^a-zA-Z0-9]/g,'_');
39
- switch(c.type) {
96
+ const v = state[c.key];
97
+ const vs = c.type === 'color_checkbox' ? v?.value : v;
98
+ const id = 'c_' + c.key.replace(/[^a-zA-Z0-9]/g, '_');
99
+ switch (c.type) {
40
100
  case 'checkbox':
41
- return `<div class="ctrl"><label>${c.key}</label><label class="tgl"><input type="checkbox" id="${id}"${vs?' checked':''} onchange="set('${c.key}','checkbox',this.checked)"><span class="track"><span class="knob"></span></span></label></div>`;
101
+ return `<div class="ctrl"><label>${prettyLabel(c.key)}</label><label class="tgl"><input type="checkbox" id="${id}"${vs ? ' checked' : ''} onchange="set('${c.key}','checkbox',this.checked)"><span class="track"><span class="knob"></span></span></label></div>`;
42
102
  case 'slider_int':
43
- return `<div class="ctrl"><label>${c.key}</label><div class="rng"><input type="range" id="${id}" min="${c.min||0}" max="${c.max||100}" value="${vs||0}" oninput="sliderUp('${c.key}','slider_int',this)"><span class="rng-val">${vs||0}</span></div></div>`;
103
+ return `<div class="ctrl range-ctrl"><label>${prettyLabel(c.key)}</label><div class="rng"><span class="rng-val">${vs || 0}</span><input type="range" id="${id}" min="${c.min || 0}" max="${c.max || 100}" value="${vs || 0}" oninput="sliderUp('${c.key}','slider_int',this)"></div></div>`;
44
104
  case 'slider_float':
45
- return `<div class="ctrl"><label>${c.key}</label><div class="rng"><input type="range" id="${id}" min="${c.min||0}" max="${c.max||100}" step="${c.step||0.1}" value="${vs||0}" oninput="sliderUp('${c.key}','slider_float',this)"><span class="rng-val">${parseFloat(vs||0).toFixed(1)}</span></div></div>`;
105
+ return `<div class="ctrl range-ctrl"><label>${prettyLabel(c.key)}</label><div class="rng"><span class="rng-val">${parseFloat(vs || 0).toFixed(1)}</span><input type="range" id="${id}" min="${c.min || 0}" max="${c.max || 100}" step="${c.step || 0.1}" value="${vs || 0}" oninput="sliderUp('${c.key}','slider_float',this)"></div></div>`;
46
106
  case 'dropdown':
47
- return `<div class="ctrl"><label>${c.key}</label><select id="${id}" onchange="set('${c.key}','dropdown',this.selectedIndex)">${(c.items||[]).map((x,i)=>`<option value="${i}"${i===vs?' selected':''}>${x}</option>`).join('')}</select></div>`;
48
- case 'color_checkbox':{
49
- const clr = v?.color||[1,1,1,1], hex = '#'+clr.slice(0,3).map(x=>('0'+Math.round(x*255).toString(16)).slice(-2)).join('');
50
- return `<div class="ctrl"><label>${c.key}</label><label class="tgl"><input type="checkbox"${v?.value?' checked':''} onchange="set('${c.key}','color_checkbox',{value:this.checked,color:(state['${c.key}']?.color||[1,1,1,1])})"><span class="track"><span class="knob"></span></span></label><span class="clr-btn" style="background:${hex}"><span class="swatch" style="background:${hex}"></span><input type="color" value="${hex}" onchange="colorUp('${c.key}',this.value)"></span></div>`;}
107
+ return `<div class="ctrl"><label>${prettyLabel(c.key)}</label><select id="${id}" onchange="set('${c.key}','dropdown',this.selectedIndex)">${(c.items || []).map((x, i) => `<option value="${i}"${i === vs ? ' selected' : ''}>${x}</option>`).join('')}</select></div>`;
108
+ case 'color_checkbox': {
109
+ const clr = v?.color || [1, 1, 1, 1], hex = colorToHex(clr);
110
+ return `<div class="ctrl color-row"><label>${prettyLabel(c.key)}</label><div class="color-actions"><label class="tgl"><input type="checkbox"${v?.value ? ' checked' : ''} onchange="set('${c.key}','color_checkbox',{value:this.checked,color:(state['${c.key}']?.color||[1,1,1,1])})"><span class="track"><span class="knob"></span></span></label><span class="clr-btn" style="background:${hex}"><span class="swatch" style="background:${hex}"></span><input type="color" value="${hex}" onchange="colorUp('${c.key}',this.value)"></span></div></div>`;
111
+ }
51
112
  case 'keybind':
52
- return `<div class="ctrl"><label>${c.key}</label><button class="key-btn${listeningKeybind===c.key?' listening':''}" id="${id}" onclick="keyStart('${c.key}')">${vkName(vs||0)}</button></div>`;
53
- }return '';
113
+ return `<div class="ctrl"><label>${prettyLabel(c.key)}</label><button class="key-btn${listeningKeybind === c.key ? ' listening' : ''}" id="${id}" onclick="keyStart('${c.key}')">${vkName(vs || 0)}</button></div>`;
114
+ }
115
+ return '';
116
+ }
117
+
118
+ function set(k, t, v) {
119
+ if (t === 'color_checkbox') {
120
+ state[k] = state[k] || { value: false, color: [1, 1, 1, 1] };
121
+ if (typeof v === 'object') state[k] = v;
122
+ } else state[k] = v;
123
+ if (shouldAutoEnablePlayerEsp(k, t, state[k])) {
124
+ state['Enable ESP'] = true;
125
+ emit('Enable ESP', 'checkbox', true);
126
+ }
127
+ emit(k, t, state[k]);
128
+ queuePlayerEspSync(k);
129
+ rerender();
130
+ }
131
+
132
+ function sliderUp(k, t, el) {
133
+ const v = t === 'slider_int' ? parseInt(el.value) : parseFloat(el.value);
134
+ state[k] = v;
135
+ el.previousElementSibling.textContent = t === 'slider_int' ? v : v.toFixed(1);
136
+ emit(k, t, v);
137
+ queuePlayerEspSync(k);
138
+ if (shouldShowEspPreview()) updateEspPreview();
139
+ }
140
+
141
+ function colorUp(k, hex) {
142
+ const r = parseInt(hex.slice(1, 3), 16) / 255, g = parseInt(hex.slice(3, 5), 16) / 255, b = parseInt(hex.slice(5, 7), 16) / 255;
143
+ const cur = state[k] || { value: false, color: [1, 1, 1, 1] };
144
+ cur.color = [r, g, b, cur.color[3] || 1];
145
+ state[k] = cur;
146
+ emit(k, 'color_checkbox', cur);
147
+ queuePlayerEspSync(k);
148
+ rerender();
149
+ }
150
+
151
+ function emit(k, t, v) {
152
+ if (SOCKET && SOCKET.connected) SOCKET.emit('setConfig', { key: k, type: t, value: v });
153
+ }
154
+
155
+ function visualPlayerControls() {
156
+ const visuals = SCHEMA.sections.find(s => s.id === 'visuals');
157
+ const player = visuals && (visuals.subs || []).find(sub => sub.id === 'vplayer');
158
+ if (!player) return [];
159
+ return (player.children || []).flatMap(ch => ch.controls || []);
160
+ }
161
+
162
+ function shouldAutoEnablePlayerEsp(key, type, value) {
163
+ if (key === 'Enable ESP' || type !== 'color_checkbox') return false;
164
+ if (!visualPlayerControls().some(c => c.key === key)) return false;
165
+ return !!(value && value.value) && !state['Enable ESP'];
166
+ }
167
+
168
+ function queuePlayerEspSync(changedKey) {
169
+ const controls = visualPlayerControls();
170
+ if (!controls.some(c => c.key === changedKey)) return;
171
+ clearTimeout(espSyncTimer);
172
+ espSyncTimer = setTimeout(() => {
173
+ controls.forEach(c => {
174
+ if (state[c.key] !== undefined) emit(c.key, c.type, state[c.key]);
175
+ });
176
+ }, 35);
177
+ }
178
+
179
+ function setSection(i) {
180
+ currentSection = i;
181
+ currentSub = 0;
182
+ rerender();
183
+ }
184
+
185
+ function setSub(i) {
186
+ currentSub = parseInt(i, 10);
187
+ rerender();
54
188
  }
55
189
 
56
- function set(k,t,v){ if(t==='color_checkbox'){state[k]=state[k]||{value:false,color:[1,1,1,1]};if(typeof v==='object')state[k]=v;}else state[k]=v; emit(k,t,state[k]); rerender(); }
57
- function sliderUp(k,t,el){ const v=t==='slider_int'?parseInt(el.value):parseFloat(el.value); state[k]=v; el.nextElementSibling.textContent=t==='slider_int'?v:v.toFixed(1); emit(k,t,v); }
58
- function colorUp(k,hex){ const r=parseInt(hex.slice(1,3),16)/255,g=parseInt(hex.slice(3,5),16)/255,b=parseInt(hex.slice(5,7),16)/255; const cur=state[k]||{value:false,color:[1,1,1,1]}; cur.color=[r,g,b,cur.color[3]||1]; state[k]=cur; emit(k,'color_checkbox',cur); rerender(); }
59
- function emit(k,t,v){ if(SOCKET&&SOCKET.connected) SOCKET.emit('setConfig',{key:k,type:t,value:v}); }
60
- function setSection(i){ currentSection=i;currentSub=0;rerender(); } function setSub(i){ currentSub=parseInt(i);rerender(); }
190
+ function rerender() {
191
+ renderSidebar();
192
+ renderTopbar();
193
+ renderPage();
194
+ }
195
+
196
+ function vkName(vk) {
197
+ const m = { 0: 'None', 1: 'LMB', 2: 'RMB', 4: 'MMB', 5: 'XB1', 6: 'XB2', 8: 'Back', 9: 'Tab', 13: 'Enter', 16: 'Shift', 17: 'Ctrl', 18: 'Alt', 20: 'Caps', 27: 'Esc', 32: 'Space', 33: 'PgUp', 34: 'PgDn', 37: 'Left', 38: 'Up', 39: 'Right', 40: 'Down', 44: 'PrtSc', 45: 'Ins', 46: 'Del', 160: 'LShift', 161: 'RShift', 162: 'LCtrl', 163: 'RCtrl', 164: 'LAlt', 165: 'RAlt' };
198
+ for (let i = 48; i <= 57; i++) m[i] = String(i - 48);
199
+ for (let i = 65; i <= 90; i++) m[i] = String.fromCharCode(i);
200
+ for (let i = 96; i <= 105; i++) m[i] = 'Num' + String(i - 96);
201
+ for (let i = 112; i <= 135; i++) m[i] = 'F' + (i - 111);
202
+ return m[vk] || ('VK' + vk);
203
+ }
204
+
205
+ function keyStart(key) {
206
+ if (listeningKeybind === key) {
207
+ listeningKeybind = null;
208
+ rerender();
209
+ return;
210
+ }
211
+ listeningKeybind = key;
212
+ rerender();
213
+ }
214
+
215
+ function submitLicense() {
216
+ const k = document.getElementById('license-key').value.trim();
217
+ if (!k) return;
218
+ const b = document.getElementById('license-btn'), m = document.getElementById('license-msg');
219
+ b.disabled = true;
220
+ b.textContent = 'Checking...';
221
+ m.textContent = '';
222
+ m.className = 'msg';
223
+ if (SOCKET) SOCKET.emit('checkLicense', k);
224
+ }
225
+
226
+ document.addEventListener('keydown', function(e) {
227
+ if (!listeningKeybind) return;
228
+ e.preventDefault();
229
+ set(listeningKeybind, 'keybind', e.keyCode);
230
+ listeningKeybind = null;
231
+ rerender();
232
+ });
233
+
234
+ document.addEventListener('mousedown', function(e) {
235
+ if (!listeningKeybind) return;
236
+ e.preventDefault();
237
+ set(listeningKeybind, 'keybind', { 0: 1, 1: 4, 2: 2 }[e.button] || 0);
238
+ listeningKeybind = null;
239
+ rerender();
240
+ });
241
+
242
+ function toggleCheat() {
243
+ if (!SOCKET || !SOCKET.connected) return;
244
+ SOCKET.emit(cheatRunning ? 'stopCheat' : 'startCheat');
245
+ }
246
+
247
+ function updateStatus() {
248
+ const d = document.getElementById('status-dot'), t = document.getElementById('status-text'), b = document.getElementById('cheat-btn');
249
+ if (cheatRunning) {
250
+ d.className = 's-dot live';
251
+ t.textContent = 'Running';
252
+ b.textContent = 'Stop';
253
+ b.className = 's-btn stop';
254
+ } else {
255
+ d.className = 's-dot';
256
+ t.textContent = 'Ready';
257
+ b.textContent = 'Start';
258
+ b.className = 's-btn';
259
+ }
260
+ }
261
+
262
+ function colorToHex(color) {
263
+ return '#' + (color || [1, 1, 1]).slice(0, 3).map(x => ('0' + Math.round(Math.max(0, Math.min(1, x)) * 255).toString(16)).slice(-2)).join('');
264
+ }
265
+
266
+ function ctrlValue(key) {
267
+ const v = state[key];
268
+ return v && typeof v === 'object' && 'value' in v ? v.value : v;
269
+ }
270
+
271
+ function ctrlColor(key, fallback) {
272
+ return colorToHex((state[key] && state[key].color) || fallback || [1, 1, 1, 1]);
273
+ }
274
+
275
+ function shouldShowEspPreview() {
276
+ const section = SCHEMA.sections[currentSection];
277
+ const sub = currentSubData();
278
+ return section && section.id === 'visuals' && sub && sub.id === 'vplayer';
279
+ }
280
+
281
+ function renderEspPreviewCard() {
282
+ return `<div class="esp-preview-panel"><h3>Live Preview</h3><div class="esp-stage" id="esp-stage">${espPreviewMarkup()}</div></div>`;
283
+ }
61
284
 
62
- function rerender(){ renderSidebar();renderTopbar();renderPage(); }
285
+ function renderEspPreviewShell(showPreview) {
286
+ const shell = document.getElementById('esp-preview-shell');
287
+ if (!shell) return;
288
+ shell.innerHTML = showPreview ? renderEspPreviewCard() : '';
289
+ }
63
290
 
64
- function vkName(vk){
65
- const m={0:'None',1:'LMB',2:'RMB',4:'MMB',5:'XB1',6:'XB2',8:'Back',9:'Tab',13:'Enter',16:'Shift',17:'Ctrl',18:'Alt',20:'Caps',27:'Esc',32:'Space',33:'PgUp',34:'PgDn',37:'Left',38:'Up',39:'Right',40:'Down',44:'PrtSc',45:'Ins',46:'Del',160:'LShift',161:'RShift',162:'LCtrl',163:'RCtrl',164:'LAlt',165:'RAlt'};
66
- for(let i=48;i<=57;i++)m[i]=String(i-48); for(let i=65;i<=90;i++)m[i]=String.fromCharCode(i);
67
- for(let i=96;i<=105;i++)m[i]='Num'+String(i-96); for(let i=112;i<=135;i++)m[i]='F'+(i-111);
68
- return m[vk]||('VK'+vk);
291
+ function updateEspPreview() {
292
+ const stage = document.getElementById('esp-stage');
293
+ if (stage) stage.innerHTML = espPreviewMarkup();
69
294
  }
70
295
 
71
- function keyStart(key){ if(listeningKeybind===key){listeningKeybind=null;rerender();return;} listeningKeybind=key;rerender(); }
72
- function submitLicense(){ const k=document.getElementById('license-key').value.trim(); if(!k)return; const b=document.getElementById('license-btn'),m=document.getElementById('license-msg'); b.disabled=true;b.textContent='Checking...';m.textContent='';m.className='msg'; if(SOCKET)SOCKET.emit('checkLicense',k); }
296
+ function placementClass(key) {
297
+ const map = ['bottom', 'top', 'left-upper', 'right-upper', 'left-lower', 'right-lower'];
298
+ return map[Number(state[key] || 0)] || 'bottom';
299
+ }
73
300
 
74
- document.addEventListener('keydown',function(e){ if(!listeningKeybind)return; e.preventDefault(); set(listeningKeybind,'keybind',e.keyCode); listeningKeybind=null;rerender(); });
75
- document.addEventListener('mousedown',function(e){ if(!listeningKeybind)return; e.preventDefault(); set(listeningKeybind,'keybind',{0:1,1:4,2:2}[e.button]||0); listeningKeybind=null;rerender(); });
301
+ function espPreviewMarkup() {
302
+ const espOn = !!ctrlValue('Enable ESP');
303
+ const boxOn = !!ctrlValue('Enable Box ESP');
304
+ const skeletonOn = !!ctrlValue('Enable Skeleton ESP');
305
+ const headOn = !!ctrlValue('Enable Head ESP');
306
+ const lineOn = !!ctrlValue('Enable Line ESP');
307
+ const healthOn = !!ctrlValue('Enable Health Bar ESP');
308
+ const armorOn = !!ctrlValue('Enable Armor Bar ESP');
309
+ const tracerOn = !!ctrlValue('Enable Tracer ESP');
310
+ const offscreenOn = !!ctrlValue('Enable Offscreen ESP');
311
+ const nameOn = !!ctrlValue('Enable Name ESP');
312
+ const idOn = !!ctrlValue('Enable ID ESP');
313
+ const distOn = !!ctrlValue('Enable Distance ESP');
314
+ const weaponOn = !!ctrlValue('Enable Weapon ESP');
315
+ const boxColor = ctrlColor('Enable Box ESP');
316
+ const skelColor = ctrlColor('Enable Skeleton ESP');
317
+ const headColor = ctrlColor('Enable Head ESP');
318
+ const lineColor = ctrlColor('Enable Line ESP');
319
+ const healthColor = ctrlColor('Enable Health Bar ESP', [0, 1, 0, 1]);
320
+ const armorColor = ctrlColor('Enable Armor Bar ESP', [0, 0.45, 1, 1]);
321
+ const tracerColor = ctrlColor('Enable Tracer ESP');
322
+ const offscreenColor = ctrlColor('Enable Offscreen ESP', [1, 0, 0, 1]);
323
+ const boxType = Number(state['Box Type'] || 0);
324
+ const boxLine = Number(state['Box Line Type'] || 0);
325
+ const skeletonLine = Number(state['Skeleton Line Type'] || 0);
326
+ const linePlacement = Number(state['Line Placement'] || 0);
327
+ const boxThickness = Number(state['Box Line Thickness'] || 1);
328
+ const skeletonThickness = Number(state['Skeleton Line Thickness'] || 1);
329
+ const headSize = Number(state['Head Size'] || 10);
330
+ const lineThickness = Number(state['Line Thickness'] || 1);
331
+ const tracerThickness = Number(state['Tracer Thickness'] || 2);
76
332
 
77
- function toggleCheat(){ if(!SOCKET||!SOCKET.connected)return; SOCKET.emit(cheatRunning?'stopCheat':'startCheat'); }
78
- function updateStatus(){ const d=document.getElementById('status-dot'),t=document.getElementById('status-text'),b=document.getElementById('cheat-btn'); if(cheatRunning){ d.className='s-dot live';t.textContent='Cheat running';b.textContent='Stop';b.className='s-btn stop';}else{ d.className='s-dot';t.textContent='Ready';b.textContent='Start Cheat';b.className='s-btn';} }
333
+ return `
334
+ <div class="esp-grid-bg"></div>
335
+ <div class="esp-horizon"></div>
336
+ <div class="esp-crosshair"></div>
337
+ <div class="esp-target ${espOn ? 'is-on' : 'is-off'}">
338
+ ${boxOn ? `<div class="esp-box ${boxType ? 'corner' : 'full'} ${boxLine ? 'solid' : 'dashed'}" style="--esp-color:${boxColor};--esp-thick:${Math.max(1, Math.min(6, boxThickness))}px"></div>` : ''}
339
+ ${healthOn ? `<div class="esp-bar health" style="--esp-color:${healthColor}"><span></span></div>` : ''}
340
+ ${armorOn ? `<div class="esp-bar armor" style="--esp-color:${armorColor}"><span></span></div>` : ''}
341
+ ${headOn ? `<div class="esp-head" style="--esp-color:${headColor};--head-size:${Math.max(8, Math.min(42, headSize))}px"></div>` : ''}
342
+ ${skeletonOn ? `<div class="esp-skeleton ${skeletonLine ? 'solid' : 'dashed'}" style="--esp-color:${skelColor};--esp-thick:${Math.max(1, Math.min(6, skeletonThickness))}px"><span class="spine"></span><span class="arms"></span><span class="leg left"></span><span class="leg right"></span></div>` : ''}
343
+ ${nameOn ? `<span class="esp-text ${placementClass('Name Placement')}" style="--esp-color:${ctrlColor('Enable Name ESP')}">Player_24</span>` : ''}
344
+ ${idOn ? `<span class="esp-text ${placementClass('ID Placement')}" style="--esp-color:${ctrlColor('Enable ID ESP')}">ID 182</span>` : ''}
345
+ ${distOn ? `<span class="esp-text ${placementClass('Distance Placement')}" style="--esp-color:${ctrlColor('Enable Distance ESP')}">128m</span>` : ''}
346
+ ${weaponOn ? `<span class="esp-text ${placementClass('Weapon Placement')}" style="--esp-color:${ctrlColor('Enable Weapon ESP')}">Rifle</span>` : ''}
347
+ </div>
348
+ ${lineOn ? `<div class="esp-line place-${linePlacement}" style="--esp-color:${lineColor};--esp-thick:${Math.max(1, Math.min(8, lineThickness))}px"></div>` : ''}
349
+ ${tracerOn ? `<div class="esp-tracer" style="--esp-color:${tracerColor};--esp-thick:${Math.max(1, Math.min(8, tracerThickness))}px"></div>` : ''}
350
+ ${offscreenOn ? `<div class="esp-offscreen" style="--esp-color:${offscreenColor}"></div>` : ''}
351
+ <div class="esp-caption">${espOn ? 'ESP Enabled' : 'ESP Disabled'}</div>`;
352
+ }
79
353
 
80
- if(SOCKET){ SOCKET.on('connect',()=>{fetch('/api/url').then(r=>r.json()).then(d=>{if(d.url)document.getElementById('s-url').textContent=d.url}).catch(()=>{});}); SOCKET.on('licenseResult',(r)=>{ const b=document.getElementById('license-btn'),m=document.getElementById('license-msg'); b.disabled=false;b.textContent='Authenticate'; if(r.ok){ licenseAccepted=true; m.textContent=r.message||'Accepted';m.className='msg ok'; document.getElementById('cheat-btn').disabled=false; setTimeout(()=>{document.getElementById('license-overlay').style.display='none';rerender();},300); }else{ m.textContent=r.message||'Invalid key';m.className='msg err'; } }); SOCKET.on('configSync',(c)=>{Object.assign(state,c);rerender();}); SOCKET.on('status',(s)=>{cheatRunning=s.running;updateStatus();}); SOCKET.on('killed',()=>{document.body.innerHTML='<div style="display:flex;align-items:center;justify-content:center;height:100vh;color:var(--danger);font-size:18px;font-family:var(--font)">Sensivity Terminated</div>';}); SOCKET.on('ytTrigger',(d)=>{const el=document.getElementById('qr-overlay');if(d.active){el.classList.add('show');document.getElementById('qr-url').textContent=d.url;document.getElementById('qr-img').src='/api/qr.png?'+Date.now();}else{el.classList.remove('show');}}); }
354
+ if (SOCKET) {
355
+ SOCKET.on('connect', () => {
356
+ fetch('/api/url').then(r => r.json()).then(d => {
357
+ if (d.url) document.getElementById('s-url').textContent = d.url;
358
+ }).catch(() => {});
359
+ });
360
+ SOCKET.on('licenseResult', (r) => {
361
+ const b = document.getElementById('license-btn'), m = document.getElementById('license-msg');
362
+ b.disabled = false;
363
+ b.textContent = 'Authenticate';
364
+ if (r.ok) {
365
+ licenseAccepted = true;
366
+ m.textContent = r.message || 'Accepted';
367
+ m.className = 'msg ok';
368
+ document.getElementById('cheat-btn').disabled = false;
369
+ setTimeout(() => {
370
+ document.getElementById('license-overlay').style.display = 'none';
371
+ rerender();
372
+ }, 300);
373
+ } else {
374
+ m.textContent = r.message || 'Invalid key';
375
+ m.className = 'msg err';
376
+ }
377
+ });
378
+ SOCKET.on('configSync', (c) => { Object.assign(state, c); rerender(); });
379
+ SOCKET.on('status', (s) => { cheatRunning = s.running; updateStatus(); });
380
+ SOCKET.on('killed', () => { document.body.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100vh;color:var(--danger);font-size:18px;font-family:var(--font)">Sensivity Terminated</div>'; });
381
+ SOCKET.on('ytTrigger', (d) => {
382
+ const el = document.getElementById('qr-overlay');
383
+ if (d.active) {
384
+ el.classList.add('show');
385
+ document.getElementById('qr-url').textContent = d.url;
386
+ document.getElementById('qr-img').src = '/api/qr.png?' + Date.now();
387
+ } else {
388
+ el.classList.remove('show');
389
+ }
390
+ });
391
+ }
81
392
 
82
- function killSensivity(){ if(!SOCKET||!SOCKET.connected)return; SOCKET.emit('killSensivity'); }
393
+ function killSensivity() {
394
+ if (!SOCKET || !SOCKET.connected) return;
395
+ SOCKET.emit('killSensivity');
396
+ }
83
397
 
84
398
  function drawQR(url) {
85
- const c=document.getElementById('qr-canvas'),ctx=c.getContext('2d');
86
- const s=8,m=4,qrSize=21;
87
- c.width=c.height=(qrSize+2*m)*s;
88
- ctx.fillStyle='#fff';ctx.fillRect(0,0,c.width,c.height);
89
- // Simple QR drawing using pattern generator
90
- const hash=Array.from(url).reduce((a,c)=>((a<<5)-a)+c.charCodeAt(0),0);
91
- ctx.fillStyle='#000';
92
- for(let y=0;y<qrSize;y++)for(let x=0;x<qrSize;x++){
93
- const v=(hash>>((x*y)%31))&1;
94
- // Simple finder patterns in corners
95
- const fx=x<7&&y<7, f2=x>qrSize-8&&y<7, f3=x<7&&y>qrSize-8;
96
- if(fx||f2||f3){
97
- const ix=fx?x:f2?x-(qrSize-7):x, iy=fx?y:f2?y:y-(qrSize-7);
98
- if(!(ix===0||ix===6||iy===0||iy===6||(ix>=2&&ix<=4&&iy>=2&&iy<=4)||ix===1||ix===5||iy===1||iy===5)){
99
- ctx.fillRect((x+m)*s,(y+m)*s,s,s);
399
+ const c = document.getElementById('qr-canvas');
400
+ if (!c) return;
401
+ const ctx = c.getContext('2d');
402
+ const s = 8, m = 4, qrSize = 21;
403
+ c.width = c.height = (qrSize + 2 * m) * s;
404
+ ctx.fillStyle = '#fff';
405
+ ctx.fillRect(0, 0, c.width, c.height);
406
+ const hash = Array.from(url).reduce((a, ch) => ((a << 5) - a) + ch.charCodeAt(0), 0);
407
+ ctx.fillStyle = '#000';
408
+ for (let y = 0; y < qrSize; y++) for (let x = 0; x < qrSize; x++) {
409
+ const v = (hash >> ((x * y) % 31)) & 1;
410
+ const fx = x < 7 && y < 7, f2 = x > qrSize - 8 && y < 7, f3 = x < 7 && y > qrSize - 8;
411
+ if (fx || f2 || f3) {
412
+ const ix = fx ? x : f2 ? x - (qrSize - 7) : x, iy = fx ? y : f2 ? y : y - (qrSize - 7);
413
+ if (!(ix === 0 || ix === 6 || iy === 0 || iy === 6 || (ix >= 2 && ix <= 4 && iy >= 2 && iy <= 4) || ix === 1 || ix === 5 || iy === 1 || iy === 5)) {
414
+ ctx.fillRect((x + m) * s, (y + m) * s, s, s);
100
415
  }
101
- } else if(v&&x>0&&y>0){
102
- ctx.fillRect((x+m)*s,(y+m)*s,s,s);
416
+ } else if (v && x > 0 && y > 0) {
417
+ ctx.fillRect((x + m) * s, (y + m) * s, s, s);
103
418
  }
104
419
  }
105
420
  }
106
421
 
107
- initState(); rerender();
422
+ initState();
423
+ rerender();
@@ -191,7 +191,7 @@ const SCHEMA = {
191
191
  label: 'Player',
192
192
  children: [
193
193
  { id: 'espMain', label: 'ESP Settings', controls: [
194
- { key: 'Enable ESP', type: 'checkbox', def: false },
194
+ { key: 'Enable ESP', type: 'checkbox', def: false, bind: true },
195
195
  { key: 'ESP Distance', type: 'slider_int', def: 0, min: 0, max: 3000 },
196
196
  { key: 'ESP Show Local Player', type: 'checkbox', def: false },
197
197
  { key: 'ESP Ignore Invisible', type: 'checkbox', def: false },
@@ -343,7 +343,13 @@ const SCHEMA = {
343
343
  subs: [{
344
344
  id: 'wmain',
345
345
  label: 'Teleport',
346
- children: []
346
+ children: [
347
+ { id: 'worldTeleport', label: 'World Teleport', controls: [
348
+ { key: 'Enable Freecam', type: 'checkbox', def: false, bind: true },
349
+ { key: 'Freecam Speed', type: 'slider_float', def: 100, min: 1, max: 1000, step: 1 },
350
+ { key: 'Freecam Teleport', type: 'checkbox', def: false, bind: true },
351
+ ]},
352
+ ]
347
353
  }]
348
354
  },
349
355
  {