agex 0.2.8 → 0.2.11
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/README.md +30 -0
- package/assets/assets/cursor.js +115 -37
- package/assets/assets/effects.js +193 -9
- package/assets/scripts/ab-click.sh +137 -0
- package/assets/scripts/ab-close.sh +3 -3
- package/assets/scripts/ab-record-start.sh +2 -2
- package/assets/scripts/ab-record.sh +2 -2
- package/assets/scripts/ab-toggle-animations.sh +15 -0
- package/assets/scripts/ab-type.sh +39 -0
- package/assets/scripts/agent-browser-wrapper.sh +2 -1
- package/assets/scripts/fx-highlight.sh +11 -3
- package/assets/scripts/fx-subtitle.sh +14 -0
- package/dist/{chunk-FCCNIKUD.js → chunk-EL4QILVU.js} +103 -30
- package/dist/cli.js +392 -25
- package/dist/index.js +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -75,6 +75,36 @@ agex prove "youtube homepage shows at least 6 video thumbnails with titles and v
|
|
|
75
75
|
|
|
76
76
|
---
|
|
77
77
|
|
|
78
|
+
### `agex demo` - Record demo videos
|
|
79
|
+
|
|
80
|
+
Record a narrated browser walkthrough as a video. The agent opens a URL, performs the task, and captures the session.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Record a demo of selecting a brand design from a menu
|
|
84
|
+
agex demo "how to select a brand design from the menu" --url https://example.com
|
|
85
|
+
|
|
86
|
+
# With subtitles and custom colors (via task text)
|
|
87
|
+
agex demo "how to create a new project. use subtitles with white text on red background" \
|
|
88
|
+
--url https://app.example.com --agent cursor
|
|
89
|
+
|
|
90
|
+
# Non-headless for debugging
|
|
91
|
+
agex demo "sign up for a free trial" --url https://example.com --no-headless
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| Flag | Description | Default |
|
|
95
|
+
|------|-------------|---------|
|
|
96
|
+
| `--agent, -a` | Agent to use: `cursor`, `claude`, `codex` | auto-detected |
|
|
97
|
+
| `--url, -u` | URL to navigate to | - |
|
|
98
|
+
| `--output, -o` | Output directory | `./demo-results` |
|
|
99
|
+
| `--video` | Enable video recording | `true` |
|
|
100
|
+
| `--screenshots` | Enable screenshots | `true` |
|
|
101
|
+
| `--model, -m` | Model to use | - |
|
|
102
|
+
| `--timeout, -t` | Timeout in ms | `300000` |
|
|
103
|
+
| `--viewport` | Viewport size (WxH) | `1920x1080` |
|
|
104
|
+
| `--headless` | Run headless | `true` |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
78
108
|
### `agex prove-pr` - PR verification in CI
|
|
79
109
|
|
|
80
110
|
Run it in your CI. It reads the diff, thinks, acts, and reports autonomously.
|
package/assets/assets/cursor.js
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
let clickRippleEnabled = true;
|
|
4
4
|
let trailEnabled = false;
|
|
5
5
|
let trailPoints = [];
|
|
6
|
+
let currentMode = 'default'; // 'default' or 'pointer'
|
|
7
|
+
let animationLock = false; // when true, mousemove won't update demo cursor position
|
|
8
|
+
|
|
9
|
+
const ARROW_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
|
|
10
|
+
<path d="M8.5 3L8.5 24.2l5-5.6 3.6 7.7 3.5-1.5-3.7-7.6 7.1-.5L8.5 3z" fill="#000" stroke="#fff" stroke-width="1.8" stroke-linejoin="round"></path>
|
|
11
|
+
</svg>`;
|
|
12
|
+
|
|
13
|
+
const POINTER_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
|
|
14
|
+
<g transform="rotate(-20, 16, 16)">
|
|
15
|
+
<path d="M14 2 C14 2 11.5 2 11.5 4.5 L11.5 15 L10 13.5 C10 13.5 8.5 12 7 12.5 C5.5 13 5.8 14.5 6.5 15.8 L10.5 22.5 C12 25.5 14.5 27.5 18 27.5 L19.5 27.5 C23.5 27.5 26.5 24 26.5 20 L26.5 15.5 C26.5 14 25 13 23.5 13.5 C23 13.7 22.5 14.2 22.5 15 L22.5 14 C22.5 12.5 21 11.5 19.5 12 C19 12.2 18.5 12.7 18.5 13.5 L18.5 12.5 C18.5 11 17 10 15.5 10.5 C15 10.7 14.5 11.3 14.5 12 L14.5 4.5 C14.5 4.5 14.5 2 14 2 Z" fill="#000" stroke="#fff" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round"/>
|
|
16
|
+
<line x1="18.5" y1="13" x2="18.5" y2="17" stroke="#fff" stroke-width="0.6" opacity="0.3"/><line x1="22.5" y1="14.5" x2="22.5" y2="17" stroke="#fff" stroke-width="0.6" opacity="0.3"/>
|
|
17
|
+
</g>
|
|
18
|
+
</svg>`;
|
|
6
19
|
|
|
7
20
|
function createCursor() {
|
|
8
21
|
if (document.getElementById('agex-cursor')) return;
|
|
@@ -10,21 +23,36 @@
|
|
|
10
23
|
const cursor = document.createElement('div');
|
|
11
24
|
cursor.id = 'agex-cursor';
|
|
12
25
|
cursor.style.cssText = `
|
|
13
|
-
width: 24px;
|
|
14
|
-
height: 24px;
|
|
15
|
-
background: rgba(255, 50, 50, 0.85);
|
|
16
|
-
border: 2px solid white;
|
|
17
|
-
border-radius: 50%;
|
|
18
26
|
position: fixed;
|
|
19
27
|
pointer-events: none;
|
|
20
28
|
z-index: 2147483647;
|
|
21
|
-
transform: translate(-50%, -50%);
|
|
22
|
-
box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
|
|
23
29
|
left: -100px;
|
|
24
30
|
top: -100px;
|
|
25
31
|
opacity: 0;
|
|
26
|
-
transition:
|
|
32
|
+
transition: opacity 0.15s, transform 0.1s ease-out;
|
|
33
|
+
transform-origin: 2px 2px;
|
|
34
|
+
will-change: left, top;
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
const dot = document.createElement('div');
|
|
38
|
+
dot.className = 'agex-cursor-dot';
|
|
39
|
+
dot.style.cssText = `
|
|
40
|
+
position: absolute;
|
|
41
|
+
width: 38px;
|
|
42
|
+
height: 38px;
|
|
43
|
+
border-radius: 50%;
|
|
44
|
+
background: rgb(251, 255, 0, 0.45);
|
|
45
|
+
top: -16px;
|
|
46
|
+
left: -10px;
|
|
47
|
+
pointer-events: none;
|
|
27
48
|
`;
|
|
49
|
+
|
|
50
|
+
const svg = document.createElement('div');
|
|
51
|
+
svg.className = 'agex-cursor-svg';
|
|
52
|
+
svg.innerHTML = ARROW_SVG;
|
|
53
|
+
|
|
54
|
+
cursor.appendChild(dot);
|
|
55
|
+
cursor.appendChild(svg);
|
|
28
56
|
document.body.appendChild(cursor);
|
|
29
57
|
|
|
30
58
|
const style = document.createElement('style');
|
|
@@ -33,20 +61,28 @@
|
|
|
33
61
|
.agex-cursor-ripple {
|
|
34
62
|
position: fixed;
|
|
35
63
|
border-radius: 50%;
|
|
36
|
-
background: rgba(255, 50, 50, 0.4);
|
|
37
64
|
pointer-events: none;
|
|
38
65
|
z-index: 2147483646;
|
|
39
66
|
transform: translate(-50%, -50%) scale(0);
|
|
40
|
-
animation: agex-ripple 0.
|
|
67
|
+
animation: agex-ripple 0.5s ease-out forwards;
|
|
68
|
+
}
|
|
69
|
+
.agex-cursor-ripple-ring {
|
|
70
|
+
position: fixed;
|
|
71
|
+
border-radius: 50%;
|
|
72
|
+
border: 3px solid rgba(0, 0, 0, 0.4);
|
|
73
|
+
pointer-events: none;
|
|
74
|
+
z-index: 2147483646;
|
|
75
|
+
transform: translate(-50%, -50%) scale(0);
|
|
76
|
+
animation: agex-ripple 0.6s ease-out forwards;
|
|
41
77
|
}
|
|
42
78
|
@keyframes agex-ripple {
|
|
43
79
|
to { transform: translate(-50%, -50%) scale(1); opacity: 0; }
|
|
44
80
|
}
|
|
45
81
|
.agex-cursor-trail {
|
|
46
82
|
position: fixed;
|
|
47
|
-
width:
|
|
48
|
-
height:
|
|
49
|
-
background: rgba(
|
|
83
|
+
width: 6px;
|
|
84
|
+
height: 6px;
|
|
85
|
+
background: rgba(0, 0, 0, 0.12);
|
|
50
86
|
border-radius: 50%;
|
|
51
87
|
pointer-events: none;
|
|
52
88
|
z-index: 2147483645;
|
|
@@ -55,16 +91,29 @@
|
|
|
55
91
|
`;
|
|
56
92
|
document.head.appendChild(style);
|
|
57
93
|
|
|
94
|
+
const CLICKABLE = 'a, button, [role="button"], input[type="submit"], input[type="button"], select, label[for], [onclick], [data-action], summary, [tabindex]';
|
|
95
|
+
|
|
58
96
|
document.addEventListener('mousemove', (e) => {
|
|
59
97
|
const c = document.getElementById('agex-cursor');
|
|
60
98
|
if (c) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
hasMoved
|
|
65
|
-
|
|
99
|
+
if (!animationLock) {
|
|
100
|
+
c.style.left = `${e.clientX}px`;
|
|
101
|
+
c.style.top = `${e.clientY}px`;
|
|
102
|
+
if (!hasMoved) {
|
|
103
|
+
hasMoved = true;
|
|
104
|
+
c.style.opacity = '1';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const hovered = document.elementFromPoint(e.clientX, e.clientY);
|
|
109
|
+
const isClickable = hovered && hovered.closest(CLICKABLE);
|
|
110
|
+
const newMode = isClickable ? 'pointer' : 'default';
|
|
111
|
+
if (newMode !== currentMode) {
|
|
112
|
+
currentMode = newMode;
|
|
113
|
+
const svgEl = c.querySelector('.agex-cursor-svg');
|
|
114
|
+
if (svgEl) svgEl.innerHTML = currentMode === 'pointer' ? POINTER_SVG : ARROW_SVG;
|
|
66
115
|
}
|
|
67
|
-
|
|
116
|
+
|
|
68
117
|
if (trailEnabled) {
|
|
69
118
|
createTrailPoint(e.clientX, e.clientY);
|
|
70
119
|
}
|
|
@@ -74,9 +123,8 @@
|
|
|
74
123
|
document.addEventListener('mousedown', (e) => {
|
|
75
124
|
const c = document.getElementById('agex-cursor');
|
|
76
125
|
if (c) {
|
|
77
|
-
c.style.transform = '
|
|
78
|
-
|
|
79
|
-
|
|
126
|
+
c.style.transform = 'scale(0.85)';
|
|
127
|
+
|
|
80
128
|
if (clickRippleEnabled) {
|
|
81
129
|
createClickRipple(e.clientX, e.clientY);
|
|
82
130
|
}
|
|
@@ -86,21 +134,30 @@
|
|
|
86
134
|
document.addEventListener('mouseup', () => {
|
|
87
135
|
const c = document.getElementById('agex-cursor');
|
|
88
136
|
if (c) {
|
|
89
|
-
c.style.transform = '
|
|
90
|
-
c.style.background = 'rgba(255, 50, 50, 0.85)';
|
|
137
|
+
c.style.transform = 'scale(1)';
|
|
91
138
|
}
|
|
92
139
|
}, true);
|
|
93
140
|
}
|
|
94
141
|
|
|
95
142
|
function createClickRipple(x, y) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
143
|
+
const fill = document.createElement('div');
|
|
144
|
+
fill.className = 'agex-cursor-ripple';
|
|
145
|
+
fill.style.left = `${x}px`;
|
|
146
|
+
fill.style.top = `${y}px`;
|
|
147
|
+
fill.style.width = '50px';
|
|
148
|
+
fill.style.height = '50px';
|
|
149
|
+
fill.style.background = 'rgba(251, 255, 0, 0.35)';
|
|
150
|
+
document.body.appendChild(fill);
|
|
151
|
+
setTimeout(() => fill.remove(), 500);
|
|
152
|
+
|
|
153
|
+
const ring = document.createElement('div');
|
|
154
|
+
ring.className = 'agex-cursor-ripple-ring';
|
|
155
|
+
ring.style.left = `${x}px`;
|
|
156
|
+
ring.style.top = `${y}px`;
|
|
157
|
+
ring.style.width = '70px';
|
|
158
|
+
ring.style.height = '70px';
|
|
159
|
+
document.body.appendChild(ring);
|
|
160
|
+
setTimeout(() => ring.remove(), 600);
|
|
104
161
|
}
|
|
105
162
|
|
|
106
163
|
function createTrailPoint(x, y) {
|
|
@@ -122,15 +179,16 @@
|
|
|
122
179
|
}, 400);
|
|
123
180
|
}
|
|
124
181
|
|
|
125
|
-
// Expose cursor configuration API
|
|
126
182
|
window.__agexCursor = {
|
|
183
|
+
setAnimationLock(locked) {
|
|
184
|
+
animationLock = locked;
|
|
185
|
+
},
|
|
127
186
|
setSize(size) {
|
|
128
187
|
const cursor = document.getElementById('agex-cursor');
|
|
129
188
|
if (!cursor) return;
|
|
130
|
-
const
|
|
131
|
-
const s =
|
|
132
|
-
cursor.style.
|
|
133
|
-
cursor.style.height = `${s}px`;
|
|
189
|
+
const scales = { normal: 0.75, large: 1, 'extra-large': 1.3 };
|
|
190
|
+
const s = scales[size] || scales.large;
|
|
191
|
+
cursor.style.transform = `scale(${s})`;
|
|
134
192
|
},
|
|
135
193
|
setClickRipple(enabled) {
|
|
136
194
|
clickRippleEnabled = enabled;
|
|
@@ -143,6 +201,26 @@
|
|
|
143
201
|
if (options.clickRipple !== undefined) this.setClickRipple(options.clickRipple);
|
|
144
202
|
if (options.trail !== undefined) this.setTrail(options.trail);
|
|
145
203
|
},
|
|
204
|
+
setMode(mode) {
|
|
205
|
+
const cursor = document.getElementById('agex-cursor');
|
|
206
|
+
if (!cursor) return;
|
|
207
|
+
const svgEl = cursor.querySelector('.agex-cursor-svg');
|
|
208
|
+
if (!svgEl) return;
|
|
209
|
+
if (mode === 'pointer') {
|
|
210
|
+
currentMode = 'pointer';
|
|
211
|
+
svgEl.innerHTML = POINTER_SVG;
|
|
212
|
+
} else {
|
|
213
|
+
currentMode = 'default';
|
|
214
|
+
svgEl.innerHTML = ARROW_SVG;
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
showClickRipple() {
|
|
218
|
+
const cursor = document.getElementById('agex-cursor');
|
|
219
|
+
if (!cursor) return;
|
|
220
|
+
const x = parseFloat(cursor.style.left) || 0;
|
|
221
|
+
const y = parseFloat(cursor.style.top) || 0;
|
|
222
|
+
createClickRipple(x, y);
|
|
223
|
+
},
|
|
146
224
|
sync() {
|
|
147
225
|
const cursor = document.getElementById('agex-cursor');
|
|
148
226
|
if (!cursor) return Promise.resolve('no cursor');
|
package/assets/assets/effects.js
CHANGED
|
@@ -95,6 +95,18 @@
|
|
|
95
95
|
0%, 100% { box-shadow: 0 0 20px var(--color, #ff4444), inset 0 0 20px var(--color, #ff4444); }
|
|
96
96
|
50% { box-shadow: 0 0 35px var(--color, #ff4444), inset 0 0 35px var(--color, #ff4444); }
|
|
97
97
|
}
|
|
98
|
+
.${EFFECTS_ID}-input-focus {
|
|
99
|
+
position: absolute;
|
|
100
|
+
pointer-events: none;
|
|
101
|
+
z-index: 2147483639;
|
|
102
|
+
border-radius: 6px;
|
|
103
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5), 0 0 16px rgba(59, 130, 246, 0.3);
|
|
104
|
+
animation: ${EFFECTS_ID}-input-focus-pulse 1.5s ease-in-out infinite;
|
|
105
|
+
}
|
|
106
|
+
@keyframes ${EFFECTS_ID}-input-focus-pulse {
|
|
107
|
+
0%, 100% { box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5), 0 0 16px rgba(59, 130, 246, 0.3); }
|
|
108
|
+
50% { box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.7), 0 0 24px rgba(59, 130, 246, 0.5); }
|
|
109
|
+
}
|
|
98
110
|
.${EFFECTS_ID}-highlight.pulse {
|
|
99
111
|
animation: ${EFFECTS_ID}-pulse 1s ease-in-out infinite;
|
|
100
112
|
border: 3px solid var(--color, #ff4444);
|
|
@@ -150,17 +162,33 @@
|
|
|
150
162
|
font-family: system-ui, sans-serif;
|
|
151
163
|
transition: all 0.3s ease;
|
|
152
164
|
}
|
|
165
|
+
@keyframes ${EFFECTS_ID}-subtitle-slide-down {
|
|
166
|
+
from { opacity: 0; transform: translateX(-50%) translateY(-20px); }
|
|
167
|
+
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
168
|
+
}
|
|
153
169
|
.${EFFECTS_ID}-subtitle {
|
|
154
170
|
position: fixed;
|
|
155
171
|
left: 50%;
|
|
156
172
|
transform: translateX(-50%);
|
|
157
|
-
background: rgba(0, 0, 0, 0.8);
|
|
158
|
-
color: white;
|
|
173
|
+
background: var(--subtitle-bg, rgba(0, 0, 0, 0.8));
|
|
174
|
+
color: var(--subtitle-fg, white);
|
|
159
175
|
padding: 12px 24px;
|
|
160
176
|
border-radius: 8px;
|
|
161
177
|
font-size: 18px;
|
|
162
178
|
max-width: 80%;
|
|
163
179
|
text-align: center;
|
|
180
|
+
animation: ${EFFECTS_ID}-subtitle-slide-down 0.35s ease-out;
|
|
181
|
+
overflow: hidden;
|
|
182
|
+
}
|
|
183
|
+
.${EFFECTS_ID}-subtitle-progress {
|
|
184
|
+
position: absolute;
|
|
185
|
+
bottom: 0;
|
|
186
|
+
left: 0;
|
|
187
|
+
height: 2px;
|
|
188
|
+
background: color-mix(in srgb, var(--subtitle-fg, white) 15%, transparent);
|
|
189
|
+
border-radius: 0 0 8px 8px;
|
|
190
|
+
width: 0%;
|
|
191
|
+
transition: none;
|
|
164
192
|
}
|
|
165
193
|
.${EFFECTS_ID}-drawing-canvas {
|
|
166
194
|
position: fixed;
|
|
@@ -182,6 +210,7 @@
|
|
|
182
210
|
// HIGHLIGHT
|
|
183
211
|
highlight: {
|
|
184
212
|
add(selector, { color = '#ff4444', style = 'border', duration } = {}) {
|
|
213
|
+
injectStyles();
|
|
185
214
|
const el = utils.getElement(selector);
|
|
186
215
|
if (!el) return false;
|
|
187
216
|
|
|
@@ -213,6 +242,7 @@
|
|
|
213
242
|
// ANNOTATION
|
|
214
243
|
annotation: {
|
|
215
244
|
add(selector, { text, position = 'top', color = '#333', arrow = true } = {}) {
|
|
245
|
+
injectStyles();
|
|
216
246
|
const el = utils.getElement(selector);
|
|
217
247
|
if (!el) return false;
|
|
218
248
|
|
|
@@ -247,6 +277,7 @@
|
|
|
247
277
|
// SPOTLIGHT
|
|
248
278
|
spotlight: {
|
|
249
279
|
show(selector, { opacity = 0.7, label = '' } = {}) {
|
|
280
|
+
injectStyles();
|
|
250
281
|
const el = utils.getElement(selector);
|
|
251
282
|
if (!el) return false;
|
|
252
283
|
|
|
@@ -355,10 +386,9 @@
|
|
|
355
386
|
const cursor = document.getElementById('agex-cursor');
|
|
356
387
|
if (!cursor) return;
|
|
357
388
|
|
|
358
|
-
const
|
|
359
|
-
const s =
|
|
360
|
-
cursor.style.
|
|
361
|
-
cursor.style.height = `${s}px`;
|
|
389
|
+
const scales = { normal: 0.75, large: 1, 'extra-large': 1.3 };
|
|
390
|
+
const s = scales[size] || 1;
|
|
391
|
+
cursor.style.transform = `scale(${s})`;
|
|
362
392
|
|
|
363
393
|
cursor.dataset.clickRipple = clickRipple;
|
|
364
394
|
cursor.dataset.trail = trail;
|
|
@@ -390,7 +420,7 @@
|
|
|
390
420
|
return true;
|
|
391
421
|
},
|
|
392
422
|
|
|
393
|
-
showClick(x, y, color = '
|
|
423
|
+
showClick(x, y, color = 'rgba(0, 0, 0, 0.15)') {
|
|
394
424
|
const ripple = utils.createElement('div', {
|
|
395
425
|
position: 'fixed',
|
|
396
426
|
left: `${x}px`,
|
|
@@ -457,6 +487,91 @@
|
|
|
457
487
|
await this.moveTo(points[i + 1].x, points[i + 1].y, segmentDuration);
|
|
458
488
|
}
|
|
459
489
|
return true;
|
|
490
|
+
},
|
|
491
|
+
|
|
492
|
+
_lastPos: null,
|
|
493
|
+
|
|
494
|
+
animateToPosition(targetX, targetY) {
|
|
495
|
+
const c = document.getElementById('agex-cursor');
|
|
496
|
+
if (!c) return 0;
|
|
497
|
+
|
|
498
|
+
// Lock demo cursor so native mousemove won't fight the animation
|
|
499
|
+
if (window.__agexCursor) window.__agexCursor.setAnimationLock(true);
|
|
500
|
+
|
|
501
|
+
const vh = window.innerHeight;
|
|
502
|
+
const wasHidden = c.style.opacity === '0' || c.style.opacity === '' || c.style.left === '-100px';
|
|
503
|
+
const startX = wasHidden ? (this._lastPos ? this._lastPos.x : 0) : parseFloat(c.style.left) || 0;
|
|
504
|
+
const startY = wasHidden ? (this._lastPos ? this._lastPos.y : vh / 2) : parseFloat(c.style.top) || vh / 2;
|
|
505
|
+
|
|
506
|
+
c.style.transition = 'none';
|
|
507
|
+
c.style.left = startX + 'px';
|
|
508
|
+
c.style.top = startY + 'px';
|
|
509
|
+
c.style.opacity = '1';
|
|
510
|
+
c.offsetHeight;
|
|
511
|
+
|
|
512
|
+
if (isNaN(targetX) || isNaN(targetY)) {
|
|
513
|
+
if (window.__agexCursor) window.__agexCursor.setAnimationLock(false);
|
|
514
|
+
return 0;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
this._lastPos = { x: targetX, y: targetY };
|
|
518
|
+
|
|
519
|
+
const dist = Math.sqrt((targetX - startX) ** 2 + (targetY - startY) ** 2);
|
|
520
|
+
const duration = Math.max(1200, Math.round(dist / 0.3));
|
|
521
|
+
const start = performance.now();
|
|
522
|
+
const self = this;
|
|
523
|
+
|
|
524
|
+
const step = (now) => {
|
|
525
|
+
const elapsed = now - start;
|
|
526
|
+
const t = Math.min(elapsed / duration, 1);
|
|
527
|
+
const ease = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
528
|
+
c.style.left = (startX + (targetX - startX) * ease) + 'px';
|
|
529
|
+
c.style.top = (startY + (targetY - startY) * ease) + 'px';
|
|
530
|
+
if (t < 1) {
|
|
531
|
+
requestAnimationFrame(step);
|
|
532
|
+
} else {
|
|
533
|
+
// Animation done — release lock
|
|
534
|
+
if (window.__agexCursor) window.__agexCursor.setAnimationLock(false);
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
requestAnimationFrame(step);
|
|
538
|
+
return duration;
|
|
539
|
+
},
|
|
540
|
+
|
|
541
|
+
showInputFocus(selector) {
|
|
542
|
+
this.clearInputFocus();
|
|
543
|
+
var el = utils.getElement(selector);
|
|
544
|
+
if (!el) return;
|
|
545
|
+
var rect = el.getBoundingClientRect();
|
|
546
|
+
var overlay = document.createElement('div');
|
|
547
|
+
overlay.id = EFFECTS_ID + '-input-focus';
|
|
548
|
+
overlay.className = EFFECTS_ID + '-input-focus';
|
|
549
|
+
overlay.style.left = (rect.left + window.scrollX - 2) + 'px';
|
|
550
|
+
overlay.style.top = (rect.top + window.scrollY - 2) + 'px';
|
|
551
|
+
overlay.style.width = (rect.width + 4) + 'px';
|
|
552
|
+
overlay.style.height = (rect.height + 4) + 'px';
|
|
553
|
+
document.body.appendChild(overlay);
|
|
554
|
+
},
|
|
555
|
+
|
|
556
|
+
clearInputFocus() {
|
|
557
|
+
var el = document.getElementById(EFFECTS_ID + '-input-focus');
|
|
558
|
+
if (el) el.remove();
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
setPosition(x, y) {
|
|
562
|
+
var c = document.getElementById('agex-cursor');
|
|
563
|
+
if (!c) return;
|
|
564
|
+
c.style.transition = 'none';
|
|
565
|
+
c.style.left = x + 'px';
|
|
566
|
+
c.style.top = y + 'px';
|
|
567
|
+
this._lastPos = { x: x, y: y };
|
|
568
|
+
},
|
|
569
|
+
|
|
570
|
+
fadeOut() {
|
|
571
|
+
const c = document.getElementById('agex-cursor');
|
|
572
|
+
if (!c) return;
|
|
573
|
+
c.style.transition = 'opacity 0.4s ease-out';
|
|
574
|
+
c.style.opacity = '0';
|
|
460
575
|
}
|
|
461
576
|
},
|
|
462
577
|
|
|
@@ -1289,22 +1404,45 @@
|
|
|
1289
1404
|
});
|
|
1290
1405
|
},
|
|
1291
1406
|
|
|
1292
|
-
showSubtitle(text, duration = 3000, position = 'bottom') {
|
|
1407
|
+
showSubtitle(text, duration = 3000, position = 'bottom', fg = '', bg = '') {
|
|
1408
|
+
injectStyles();
|
|
1293
1409
|
this.clear();
|
|
1294
1410
|
const subtitle = utils.createElement('div', {
|
|
1295
1411
|
[position]: '40px'
|
|
1296
1412
|
}, `${EFFECTS_ID}-subtitle`);
|
|
1297
1413
|
subtitle.classList.add(`${EFFECTS_ID}-subtitle`);
|
|
1414
|
+
if (fg) subtitle.style.setProperty('--subtitle-fg', fg);
|
|
1415
|
+
if (bg) subtitle.style.setProperty('--subtitle-bg', bg);
|
|
1298
1416
|
subtitle.textContent = text;
|
|
1417
|
+
|
|
1418
|
+
var bar = document.createElement('div');
|
|
1419
|
+
bar.className = `${EFFECTS_ID}-subtitle-progress`;
|
|
1420
|
+
subtitle.appendChild(bar);
|
|
1421
|
+
|
|
1422
|
+
var startTime = performance.now();
|
|
1423
|
+
var barDuration = duration > 0 ? duration : 30000;
|
|
1424
|
+
var rafId = 0;
|
|
1425
|
+
function tick() {
|
|
1426
|
+
var elapsed = performance.now() - startTime;
|
|
1427
|
+
var pct = Math.min(elapsed / barDuration * 100, 100);
|
|
1428
|
+
bar.style.width = pct + '%';
|
|
1429
|
+
if (pct < 100) rafId = requestAnimationFrame(tick);
|
|
1430
|
+
}
|
|
1431
|
+
rafId = requestAnimationFrame(tick);
|
|
1432
|
+
|
|
1299
1433
|
document.body.appendChild(subtitle);
|
|
1300
1434
|
|
|
1301
1435
|
if (duration > 0) {
|
|
1302
|
-
setTimeout(()
|
|
1436
|
+
setTimeout(function() {
|
|
1437
|
+
cancelAnimationFrame(rafId);
|
|
1438
|
+
subtitle.remove();
|
|
1439
|
+
}, duration);
|
|
1303
1440
|
}
|
|
1304
1441
|
},
|
|
1305
1442
|
|
|
1306
1443
|
clear() {
|
|
1307
1444
|
utils.removeElements(`#${EFFECTS_ID}-subtitle`);
|
|
1445
|
+
utils.removeElements(`.${EFFECTS_ID}-subtitle`);
|
|
1308
1446
|
if ('speechSynthesis' in window) {
|
|
1309
1447
|
speechSynthesis.cancel();
|
|
1310
1448
|
}
|
|
@@ -1499,6 +1637,26 @@
|
|
|
1499
1637
|
if (el) el.scrollIntoView({ block: 'center', behavior: 'instant' });
|
|
1500
1638
|
},
|
|
1501
1639
|
|
|
1640
|
+
scrollElementToCenter(selector) {
|
|
1641
|
+
var el = typeof selector === 'string' ? document.querySelector(selector) : selector;
|
|
1642
|
+
if (!el) return false;
|
|
1643
|
+
el.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'instant' });
|
|
1644
|
+
return true;
|
|
1645
|
+
},
|
|
1646
|
+
|
|
1647
|
+
scrollElementToCenterSmooth(selector) {
|
|
1648
|
+
var el = typeof selector === 'string' ? document.querySelector(selector) : selector;
|
|
1649
|
+
if (!el) return 0;
|
|
1650
|
+
var rect = el.getBoundingClientRect();
|
|
1651
|
+
var viewH = window.innerHeight;
|
|
1652
|
+
var centerY = rect.top + rect.height / 2;
|
|
1653
|
+
if (centerY > viewH * 0.2 && centerY < viewH * 0.8) return 0;
|
|
1654
|
+
var dist = Math.abs(centerY - viewH / 2);
|
|
1655
|
+
var duration = Math.max(600, Math.min(2000, Math.round(dist * 1.5)));
|
|
1656
|
+
el.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'smooth' });
|
|
1657
|
+
return duration;
|
|
1658
|
+
},
|
|
1659
|
+
|
|
1502
1660
|
scrollToCoords(y, viewportHeight, elHeight) {
|
|
1503
1661
|
window.scrollTo({
|
|
1504
1662
|
top: window.scrollY + y - (viewportHeight / 2) + (elHeight / 2),
|
|
@@ -1543,6 +1701,31 @@
|
|
|
1543
1701
|
}
|
|
1544
1702
|
};
|
|
1545
1703
|
|
|
1704
|
+
// Enable or disable page CSS animations & transitions (preserves agex effects)
|
|
1705
|
+
function setPageAnimations(enabled) {
|
|
1706
|
+
var id = EFFECTS_ID + '-disable-animations';
|
|
1707
|
+
var existing = document.getElementById(id);
|
|
1708
|
+
if (enabled) {
|
|
1709
|
+
if (existing) existing.remove();
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
if (existing) return;
|
|
1713
|
+
var style = document.createElement('style');
|
|
1714
|
+
style.id = id;
|
|
1715
|
+
style.textContent = `
|
|
1716
|
+
*:not(.${EFFECTS_ID}):not(.${EFFECTS_ID} *) {
|
|
1717
|
+
animation: none !important;
|
|
1718
|
+
animation-delay: 0s !important;
|
|
1719
|
+
animation-duration: 0s !important;
|
|
1720
|
+
transition: none !important;
|
|
1721
|
+
transition-delay: 0s !important;
|
|
1722
|
+
transition-duration: 0s !important;
|
|
1723
|
+
scroll-behavior: auto !important;
|
|
1724
|
+
}
|
|
1725
|
+
`;
|
|
1726
|
+
document.head.appendChild(style);
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1546
1729
|
// Clear all effects
|
|
1547
1730
|
function clearAll() {
|
|
1548
1731
|
effects.highlight.clear();
|
|
@@ -1578,6 +1761,7 @@
|
|
|
1578
1761
|
window.__agexEffects = {
|
|
1579
1762
|
apply,
|
|
1580
1763
|
clearAll,
|
|
1764
|
+
setPageAnimations,
|
|
1581
1765
|
banner,
|
|
1582
1766
|
proof,
|
|
1583
1767
|
...effects,
|