self modifying website
1<!doctype html>
2<html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>C:\PLASTIC.EXE - Self-Modifying System</title>
7 <style>
8 @import url("https://fonts.googleapis.com/css2?family=Courier+Prime:wght@400;700&display=swap");
9
10 body {
11 background: #f0f0f0;
12 font-family: "Courier Prime", "Courier New", monospace;
13 color: #000000;
14 margin: 0;
15 padding: 20px;
16 line-height: 1.2;
17 font-size: 14px;
18 }
19
20 .terminal {
21 background: #ffffff;
22 border: 2px solid #808080;
23 box-shadow:
24 inset -2px -2px #c0c0c0,
25 inset 2px 2px #404040;
26 max-width: 800px;
27 margin: 0 auto;
28 padding: 0;
29 }
30
31 .title-bar {
32 background: #c0c0c0;
33 color: #000000;
34 padding: 4px 8px;
35 font-weight: bold;
36 border-bottom: 1px solid #808080;
37 font-size: 12px;
38 }
39
40 .content {
41 padding: 10px;
42 background: #ffffff;
43 }
44
45 .prompt {
46 color: #000000;
47 margin: 0;
48 }
49
50 .cursor {
51 background: #000000;
52 color: #ffffff;
53 animation: blink 1s infinite;
54 }
55
56 @keyframes blink {
57 0%,
58 50% {
59 opacity: 1;
60 }
61 51%,
62 100% {
63 opacity: 0;
64 }
65 }
66
67 h1 {
68 color: #000000;
69 font-size: 24px;
70 margin: 10px 0;
71 text-transform: uppercase;
72 }
73
74 h2 {
75 color: #000000;
76 font-size: 16px;
77 margin: 15px 0 5px 0;
78 text-transform: uppercase;
79 }
80
81 .command {
82 color: #ffffff;
83 background: #808080;
84 padding: 2px 4px;
85 display: inline-block;
86 margin: 2px;
87 }
88
89 .button {
90 background: #c0c0c0;
91 color: #000000;
92 border: 2px outset #c0c0c0;
93 padding: 4px 8px;
94 font-family: inherit;
95 font-size: 12px;
96 cursor: pointer;
97 margin: 5px 2px;
98 display: inline-block;
99 text-decoration: none;
100 text-transform: uppercase;
101 }
102
103 .button:active {
104 border: 2px inset #c0c0c0;
105 }
106
107 .button:hover {
108 background: #d0d0d0;
109 }
110
111 .editor {
112 width: calc(100% - 20px);
113 height: 150px;
114 background: #0000ff;
115 color: #ffffff;
116 font-family: inherit;
117 margin: 10px 0;
118 padding: 10px;
119 border: 2px inset #c0c0c0;
120 font-size: 12px;
121 resize: none;
122 }
123
124 .status-bar {
125 background: #c0c0c0;
126 color: #000000;
127 padding: 2px 8px;
128 border-top: 1px solid #808080;
129 font-size: 11px;
130 display: flex;
131 justify-content: space-between;
132 }
133
134 .file-listing {
135 margin: 10px 0;
136 }
137
138 .file-line {
139 margin: 2px 0;
140 font-family: inherit;
141 }
142
143 .dir {
144 color: #000080;
145 }
146
147 .exe {
148 color: #000000;
149 }
150
151 .txt {
152 color: #000000;
153 }
154
155 .error {
156 color: #ffffff;
157 background: #ff0000;
158 padding: 2px 4px;
159 }
160
161 ul {
162 margin: 5px 0;
163 padding-left: 20px;
164 }
165
166 li {
167 margin: 2px 0;
168 }
169
170 .separator {
171 color: #808080;
172 margin: 10px 0;
173 }
174
175 .ascii-art {
176 color: #000000;
177 font-size: 10px;
178 line-height: 1;
179 white-space: pre;
180 margin: 10px 0;
181 }
182 </style>
183 </head>
184 <body>
185 <div class="terminal">
186 <div class="title-bar">
187 C:\PLASTIC.EXE - [Self-Modifying System v2.1]
188 </div>
189
190 <div class="content">
191 <p class="prompt">C:\PLASTIC> PLASTIC.EXE</p>
192
193 <pre class="ascii-art">
194██████╗ ██╗ █████╗ ███████╗████████╗██╗ ██████╗
195██╔══██╗██║ ██╔══██╗██╔════╝╚══██╔══╝██║██╔════╝
196██████╔╝██║ ███████║███████╗ ██║ ██║██║
197██╔═══╝ ██║ ██╔══██║╚════██║ ██║ ██║██║
198██║ ███████╗██║ ██║███████║ ██║ ██║╚██████╗
199╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═════╝</pre
200 >
201
202 <h2>System Information:</h2>
203 <p>PLASTIC v2.1 - Self-Modifying Code System</p>
204 <p>Copyright (C) 1995 DUNKIRK Corp.</p>
205 <p>
206 All rights reserved. Licensed to: REGISTERED USER under MIT
207 </p>
208
209 <div class="separator">
210 ════════════════════════════════════════════════════════════
211 </div>
212
213 <h2>About This System:</h2>
214 <p>
215 PLASTIC.EXE is an experimental self-modifying executable
216 that allows real-time code injection and system
217 modification. WARNING: Use at your own risk. System may
218 become unstable.
219 </p>
220
221 <h2>Experimental Code Generator:</h2>
222 <p>Describe changes to make to the page:</p>
223 <textarea
224 class="editor"
225 id="codeEditor"
226 placeholder="e.g., 'Add a retro calculator widget', 'Change theme to green terminal', or 'Completely redesign as a DOS file manager'"
227 ></textarea>
228 <div class="button" onclick="generateAndExecute()">
229 GENERATE & EXECUTE
230 </div>
231 <div class="button" onclick="clearEditor()">CLEAR</div>
232 <div
233 id="statusDisplay"
234 style="color: #000080; margin-top: 10px"
235 ></div>
236
237 <h2>System Features:</h2>
238 <ul>
239 <li>
240 Real-time <span class="command">EXEC</span> code
241 modification
242 </li>
243 <li>Compatible with DOS 6.22 and Windows 95</li>
244 <li>640K memory optimized</li>
245 <li>No TSR conflicts detected</li>
246 <li>Supports EGA/VGA graphics modes</li>
247 </ul>
248
249 <div class="separator">
250 ════════════════════════════════════════════════════════════
251 </div>
252
253 <p>
254 Runtime: <span id="runtime">00:13:37</span> | Memory:
255 <span id="memory">589K free</span> | CPU: 80486DX-33
256 </p>
257 </div>
258
259 <div class="status-bar">
260 <span>F1=Help F2=Save F3=Load F10=Menu</span>
261 <span>12:00</span>
262 </div>
263 </div>
264
265 <script>
266 // Tool call system for AI to interact with the page
267 window.toolCallbacks = {
268 replaceElement: function (selector, newHTML) {
269 const element = document.querySelector(selector);
270 if (element) {
271 element.outerHTML = newHTML;
272 return {
273 success: true,
274 message: `Replaced element: ${selector}`,
275 };
276 }
277 return {
278 success: false,
279 message: `Element not found: ${selector}`,
280 };
281 },
282
283 updateElement: function (selector, newContent) {
284 const element = document.querySelector(selector);
285 if (element) {
286 element.innerHTML = newContent;
287 return {
288 success: true,
289 message: `Updated element: ${selector}`,
290 };
291 }
292 return {
293 success: false,
294 message: `Element not found: ${selector}`,
295 };
296 },
297
298 addElement: function (
299 parentSelector,
300 newHTML,
301 position = "beforeend",
302 ) {
303 const parent = document.querySelector(parentSelector);
304 if (parent) {
305 parent.insertAdjacentHTML(position, newHTML);
306 return {
307 success: true,
308 message: `Added element to: ${parentSelector}`,
309 };
310 }
311 return {
312 success: false,
313 message: `Parent not found: ${parentSelector}`,
314 };
315 },
316
317 removeElement: function (selector) {
318 const element = document.querySelector(selector);
319 if (element) {
320 element.remove();
321 return {
322 success: true,
323 message: `Removed element: ${selector}`,
324 };
325 }
326 return {
327 success: false,
328 message: `Element not found: ${selector}`,
329 };
330 },
331
332 updateStyle: function (selector, styleObj) {
333 const element = document.querySelector(selector);
334 if (element) {
335 Object.assign(element.style, styleObj);
336 return {
337 success: true,
338 message: `Updated styles for: ${selector}`,
339 };
340 }
341 return {
342 success: false,
343 message: `Element not found: ${selector}`,
344 };
345 },
346
347 executeJS: function (code) {
348 try {
349 const result = eval(code);
350 return {
351 success: true,
352 message: "JavaScript executed",
353 result: result,
354 };
355 } catch (error) {
356 return {
357 success: false,
358 message: `JS Error: ${error.message}`,
359 };
360 }
361 },
362 };
363
364 function executeToolCall(toolCall) {
365 const { function: func, arguments: args } = toolCall;
366 console.log("Executing tool call:", func, args);
367
368 if (window.toolCallbacks[func]) {
369 try {
370 // Handle different function signatures
371 if (func === "removeElement") {
372 // removeElement expects just a selector
373 const selector =
374 args.selector ||
375 Object.keys(args)[0] ||
376 Object.values(args)[0];
377 return window.toolCallbacks[func](selector);
378 } else if (func === "updateStyle" && args.styleObj) {
379 return window.toolCallbacks[func](
380 args.selector,
381 args.styleObj,
382 );
383 } else if (func === "executeJS") {
384 return window.toolCallbacks[func](args.code);
385 } else if (func === "updateElement") {
386 return window.toolCallbacks[func](
387 args.selector,
388 args.newContent,
389 );
390 } else if (func === "replaceElement") {
391 return window.toolCallbacks[func](
392 args.selector,
393 args.newHTML,
394 );
395 } else if (func === "addElement") {
396 return window.toolCallbacks[func](
397 args.parentSelector,
398 args.newHTML,
399 args.position,
400 );
401 } else {
402 // Fallback: use all argument values in order
403 return window.toolCallbacks[func](
404 ...Object.values(args),
405 );
406 }
407 } catch (error) {
408 return {
409 success: false,
410 message: `Error executing ${func}: ${error.message}`,
411 };
412 }
413 }
414 return { success: false, message: `Unknown tool: ${func}` };
415 }
416
417 async function generateAndExecute() {
418 const userPrompt = document.getElementById("codeEditor").value;
419 const statusDiv = document.getElementById("statusDisplay");
420
421 if (userPrompt.trim() === "") {
422 statusDiv.textContent = "ERROR: No description provided";
423 return;
424 }
425
426 statusDiv.textContent = "CONNECTING TO AI SYSTEM...";
427
428 try {
429 const currentPageHTML = document.documentElement.outerHTML;
430
431 const response = await fetch(
432 "https://ai.hackclub.com/chat/completions",
433 {
434 method: "POST",
435 headers: {
436 "Content-Type": "application/json",
437 },
438 body: JSON.stringify({
439 messages: [
440 {
441 role: "user",
442 content: `Here is the current HTML page:\n\n${currentPageHTML}\n\nUser request: "${userPrompt}"\n\nIMPORTANT: You must respond with ONLY one of these two formats:\n\nFORMAT 1 - Tool calls (for precise modifications):\n{"tool_calls": [{"function": "functionName", "arguments": {"param": "value"}}]}\n\nFORMAT 2 - Raw HTML (to append to page):\n<div>Your HTML content here</div>\n\nDO NOT include any explanatory text, markdown formatting, or additional commentary. Respond with ONLY the JSON or HTML.\n\nAvailable tools with correct argument formats:\n1. removeElement: {"function": "removeElement", "arguments": {"selector": ".class-name"}}\n2. updateElement: {"function": "updateElement", "arguments": {"selector": ".class-name", "newContent": "new content"}}\n3. replaceElement: {"function": "replaceElement", "arguments": {"selector": ".class-name", "newHTML": "<div>new html</div>"}}\n4. addElement: {"function": "addElement", "arguments": {"parentSelector": ".parent", "newHTML": "<div>content</div>", "position": "beforeend"}}\n5. updateStyle: {"function": "updateStyle", "arguments": {"selector": ".class-name", "styleObj": {"color": "#000000"}}}\n6. executeJS: {"function": "executeJS", "arguments": {"code": "console.log('hello');"}}\n\nUse DOS/retro aesthetic with flat colors: #000000 (black), #ffffff (white), #c0c0c0 (gray), #000080 (blue), #ff0000 (red). Use monospace fonts.`,
443 },
444 ],
445 }),
446 },
447 );
448
449 if (!response.ok) {
450 throw new Error(
451 `HTTP ${response.status}: ${response.statusText}`,
452 );
453 }
454
455 statusDiv.textContent = "AI PROCESSING...";
456
457 const data = await response.json();
458 console.log("API Response:", data);
459
460 let generatedContent;
461 if (
462 data.choices &&
463 data.choices[0] &&
464 data.choices[0].message
465 ) {
466 generatedContent = data.choices[0].message.content;
467 } else if (data.content) {
468 generatedContent = data.content;
469 } else if (data.response) {
470 generatedContent = data.response;
471 } else if (typeof data === "string") {
472 generatedContent = data;
473 } else {
474 throw new Error("Unexpected API response format");
475 }
476
477 statusDiv.textContent = "EXECUTING COMMANDS...";
478
479 // Clean up response and extract JSON if present
480 let cleanResponse = generatedContent.trim();
481
482 // Remove markdown formatting
483 cleanResponse = cleanResponse
484 .replace(/```json\n?/g, "")
485 .replace(/```\n?/g, "");
486
487 // Try to extract JSON from mixed content
488 const jsonMatch = cleanResponse.match(
489 /\{[\s\S]*"tool_calls"[\s\S]*\}/,
490 );
491 if (jsonMatch) {
492 cleanResponse = jsonMatch[0];
493 }
494
495 console.log("Cleaned response:", cleanResponse);
496
497 // For safety, preprocess JavaScript code in JSON to escape problematic characters
498 cleanResponse = cleanResponse.replace(/"code"\s*:\s*(`|")([^`"]*?)(`|")/g, function(match, q1, code, q3) {
499 // Replace all literal backslashes with double backslashes in the code string
500 const escapedCode = code.replace(/\\/g, "\\\\");
501 return `"code":${q1}${escapedCode}${q3}`;
502 });
503
504 // Check if response contains tool calls
505 try {
506 const toolResponse = safeJsonParse(cleanResponse);
507 if (
508 toolResponse.tool_calls &&
509 Array.isArray(toolResponse.tool_calls)
510 ) {
511 // Execute tool calls
512 const results = [];
513 for (const toolCall of toolResponse.tool_calls) {
514 const result = executeToolCall(toolCall);
515 results.push(result);
516 console.log("Tool call result:", result);
517 }
518 statusDiv.textContent = `EXECUTED ${results.length} COMMANDS`;
519
520 // Send feedback to AI about tool results
521 setTimeout(
522 () => sendToolFeedback(userPrompt, results),
523 100,
524 );
525 } else {
526 throw new Error("Invalid tool call format");
527 }
528 } catch (jsonError) {
529 console.log("JSON parse error:", jsonError);
530 console.log("Raw response:", generatedContent);
531 console.log("Attempting to parse as HTML...");
532
533 // Not JSON, treat as HTML code
534 let cleanCode = generatedContent
535 .replace(/```html\n?/g, "")
536 .replace(/```\n?/g, "");
537
538 statusDiv.textContent = "INJECTING CODE...";
539 document.querySelector(".content").innerHTML +=
540 cleanCode;
541 statusDiv.textContent = "CODE EXECUTION SUCCESSFUL";
542 }
543
544 document.getElementById("codeEditor").value = "";
545
546 // Clear status after 3 seconds
547 setTimeout(() => {
548 statusDiv.textContent = "";
549 }, 3000);
550 } catch (error) {
551 statusDiv.textContent = `SYSTEM ERROR: ${error.message}`;
552 console.error("Error:", error);
553 }
554 }
555
556 function clearEditor() {
557 document.getElementById("codeEditor").value = "";
558 document.getElementById("statusDisplay").textContent = "";
559 }
560
561 async function sendToolFeedback(originalPrompt, toolResults) {
562 const statusDiv = document.getElementById("statusDisplay");
563
564 try {
565 statusDiv.textContent = "SENDING FEEDBACK TO AI...";
566
567 const currentPageHTML = document.documentElement.outerHTML;
568 const resultsText = toolResults
569 .map(
570 (r) =>
571 `${r.success ? "✓" : "✗"} ${r.message}${r.result ? ` (result: ${r.result})` : ""}`,
572 )
573 .join("\n");
574
575 const response = await fetch(
576 "https://ai.hackclub.com/chat/completions",
577 {
578 method: "POST",
579 headers: {
580 "Content-Type": "application/json",
581 },
582 body: JSON.stringify({
583 messages: [
584 {
585 role: "user",
586 content: `Previous request: "${originalPrompt}"\n\nTool execution results:\n${resultsText}\n\nCurrent page state:\n${currentPageHTML}\n\nBased on the tool results, do you need to make any follow-up modifications? If everything looks good, respond with "COMPLETE". If you need to make adjustments, respond with tool calls or HTML.\n\nIMPORTANT: Respond with ONLY one of these formats:\n- "COMPLETE" (if satisfied)\n- {"tool_calls": [...]} (for modifications)\n- Raw HTML (to append content)\n\nDO NOT include explanatory text.`,
587 },
588 ],
589 }),
590 },
591 );
592
593 if (!response.ok) {
594 throw new Error(
595 `HTTP ${response.status}: ${response.statusText}`,
596 );
597 }
598
599 const data = await response.json();
600 let followUpContent;
601
602 if (
603 data.choices &&
604 data.choices[0] &&
605 data.choices[0].message
606 ) {
607 followUpContent = data.choices[0].message.content;
608 } else if (data.content) {
609 followUpContent = data.content;
610 } else if (data.response) {
611 followUpContent = data.response;
612 } else {
613 throw new Error("Unexpected API response format");
614 }
615
616 followUpContent = followUpContent.trim();
617 console.log("Follow-up response:", followUpContent);
618
619 if (
620 followUpContent === "COMPLETE" ||
621 followUpContent === '"COMPLETE"'
622 ) {
623 statusDiv.textContent = "AI SATISFIED - TASK COMPLETE";
624 setTimeout(() => (statusDiv.textContent = ""), 3000);
625 return;
626 }
627
628 // Process follow-up commands
629 statusDiv.textContent = "AI MAKING ADJUSTMENTS...";
630
631 // Try to parse as tool calls
632 try {
633 const jsonMatch = followUpContent.match(
634 /\{[\s\S]*"tool_calls"[\s\S]*\}/,
635 );
636 if (jsonMatch) {
637 // Preprocess JavaScript code in JSON to escape problematic characters
638 let cleanJson = jsonMatch[0].replace(/"code"\s*:\s*(`|")([^`"]*?)(`|")/g, function(match, q1, code, q3) {
639 // Replace all literal backslashes with double backslashes in the code string
640 const escapedCode = code.replace(/\\/g, "\\\\");
641 return `"code":${q1}${escapedCode}${q3}`;
642 });
643
644 const toolResponse = safeJsonParse(cleanJson);
645 if (
646 toolResponse.tool_calls &&
647 Array.isArray(toolResponse.tool_calls)
648 ) {
649 const followUpResults = [];
650 for (const toolCall of toolResponse.tool_calls) {
651 const result = executeToolCall(toolCall);
652 followUpResults.push(result);
653 console.log(
654 "Follow-up tool result:",
655 result,
656 );
657 }
658 statusDiv.textContent = `AI EXECUTED ${followUpResults.length} ADJUSTMENTS`;
659 }
660 } else {
661 // Treat as HTML
662 let cleanCode = followUpContent
663 .replace(/```html\n?/g, "")
664 .replace(/```\n?/g, "");
665 document.querySelector(".content").innerHTML +=
666 cleanCode;
667 statusDiv.textContent =
668 "AI ADDED FOLLOW-UP CONTENT";
669 }
670 } catch (error) {
671 console.log("Follow-up parsing error:", error);
672 statusDiv.textContent = "AI FEEDBACK ERROR";
673 }
674
675 setTimeout(() => (statusDiv.textContent = ""), 4000);
676 } catch (error) {
677 statusDiv.textContent = `FEEDBACK ERROR: ${error.message}`;
678 console.error("Feedback error:", error);
679 setTimeout(() => (statusDiv.textContent = ""), 3000);
680 }
681 }
682
683 // Debug helper for JSON parsing issues
684 function safeJsonParse(jsonString) {
685 try {
686 return JSON.parse(jsonString);
687 } catch (error) {
688 console.error("JSON parse error:", error);
689 console.error("Problem JSON:", jsonString);
690 // Try to escape any unescaped control characters
691 const escapedJson = jsonString.replace(/[\u0000-\u001F]/g, match => {
692 return '\\u' + ('0000' + match.charCodeAt(0).toString(16)).slice(-4);
693 });
694 try {
695 return JSON.parse(escapedJson);
696 } catch (secondError) {
697 console.error("Second parse attempt failed:", secondError);
698 throw error; // Throw the original error
699 }
700 }
701 }
702
703 // Handle Ctrl+Enter in textarea
704 function setupCtrlEnterHandler() {
705 const codeEditor = document.getElementById("codeEditor");
706 if (codeEditor) {
707 // Remove any previous event listeners first (to avoid duplicates)
708 codeEditor.removeEventListener("keydown", ctrlEnterHandler);
709 // Add a new event listener
710 codeEditor.addEventListener("keydown", ctrlEnterHandler);
711 } else {
712 console.error("codeEditor element not found, will retry");
713 // Retry after a short delay
714 setTimeout(setupCtrlEnterHandler, 100);
715 }
716 }
717
718 // Define the handler function separately so it can be added/removed consistently
719 function ctrlEnterHandler(e) {
720 if (e.ctrlKey && e.key === "Enter") {
721 e.preventDefault();
722 generateAndExecute();
723 }
724 }
725
726 // Set up the handler immediately
727 setupCtrlEnterHandler();
728
729 // Also ensure it's set up when the DOM is fully loaded
730 window.addEventListener("DOMContentLoaded", setupCtrlEnterHandler);
731 window.addEventListener("load", setupCtrlEnterHandler);
732
733 // Update time in status bar
734 setInterval(() => {
735 const now = new Date();
736 const timeStr = now.toLocaleTimeString([], {
737 hour: "2-digit",
738 minute: "2-digit",
739 hour12: false,
740 });
741 const statusBarTime = document.querySelector(
742 ".status-bar span:last-child",
743 );
744 if (statusBarTime) {
745 statusBarTime.textContent = timeStr;
746 }
747
748 // Update memory in status bar based on actual tab memory usage
749 const memoryUsage = Math.round(
750 performance.memory
751 ? performance.memory.usedJSHeapSize / 1024
752 : 0,
753 );
754
755 const memoryStr = `${589 - Math.min(Math.round(memoryUsage / 1024), 500)}K free`;
756 const memory = document.getElementById("memory");
757 if (memory) {
758 memory.textContent = memoryStr;
759 }
760
761 // Update runtime in status bar - based on how long the page has been open
762 const pageOpenTime = performance.timing
763 ? performance.timing.navigationStart || Date.now()
764 : Date.now();
765 const timeOpen = Math.floor((Date.now() - pageOpenTime) / 1000);
766 const hours = Math.floor(timeOpen / 3600)
767 .toString()
768 .padStart(2, "0");
769 const minutes = Math.floor((timeOpen % 3600) / 60)
770 .toString()
771 .padStart(2, "0");
772 const seconds = Math.floor(timeOpen % 60)
773 .toString()
774 .padStart(2, "0");
775 const runtimeStr = `${hours}:${minutes}:${seconds}`;
776 const runtime = document.getElementById("runtime");
777 if (runtime) {
778 runtime.textContent = runtimeStr;
779 }
780 }, 1000);
781 </script>
782 </body>
783</html>