···
+
background-color: rgba(0, 0, 0, 0.7);
+
transition: opacity 0.2s ease-in-out;
+
background-color: #ffffff;
+
border: 2px solid #808080;
+
inset -2px -2px #c0c0c0,
+
0 0 10px rgba(0, 0, 0, 0.5);
+
animation: fadeIn 0.2s ease-in-out;
+
position: relative; /* Ensure proper positioning of close button */
+
transform: translateY(-20px);
+
transform: translateY(0);
+
font-family: "Courier Prime", "Courier New", monospace;
+
border: 2px inset #c0c0c0;
+
border: 1px solid #c0c0c0;
+
justify-content: space-between;
+
border-bottom: 1px solid #c0c0c0;
+
background-color: #f0f0f0;
+
border: 1px solid #c0c0c0;
+
background-color: #c0c0c0;
+
border: 1px solid #808080;
+
inset -1px -1px #404040,
+
background-color: #c0c0c0;
+
inset -1px -1px #ffffff;
+
<div id="help-modal" class="modal">
+
<div class="modal-content">
+
<div class="title-bar">
+
onclick="hideModal('help-modal')"
+
aria-label="Close help modal"
+
<div class="modal-body">
+
<h2>Keyboard Shortcuts:</h2>
+
<li><strong>F1</strong>: Show this help screen</li>
+
<strong>F2</strong>: Save the current page state
+
<li><strong>F3</strong>: Load a saved page state</li>
+
<li><strong>Esc</strong>: Close modals</li>
+
<strong>Ctrl+Enter</strong>: Execute code in the
+
<h2>How to Use PLASTIC:</h2>
+
Type a description of what you want to change in the
+
Press Ctrl+Enter or click the "GENERATE & EXECUTE"
+
PLASTIC will modify itself according to your
+
<li>Use F2 to save your modified system</li>
+
<li>Use F3 to load a previously saved state</li>
+
<h2>About PLASTIC:</h2>
+
PLASTIC.EXE is a self-modifying system that lets you
+
transform its interface and functionality through
+
natural language commands.
+
<div style="text-align: center; margin-top: 15px">
+
<div class="button" onclick="hideModal('help-modal')">
+
<div id="save-modal" class="modal">
+
<div class="modal-content">
+
<div class="title-bar">
+
onclick="hideModal('save-modal')"
+
aria-label="Close save modal"
+
<div class="modal-body">
+
<h2>Save Current State</h2>
+
<div class="input-group">
+
<label for="save-name">Name:</label>
+
placeholder="Enter save name"
+
justify-content: center;
+
<div class="button" onclick="saveCurrentHTML()">
+
<div class="button" onclick="hideModal('save-modal')">
+
<div id="save-message"></div>
+
<div id="saved-list" class="save-list"></div>
+
<div id="load-modal" class="modal">
+
<div class="modal-content">
+
<div class="title-bar">
+
onclick="hideModal('load-modal')"
+
aria-label="Close load modal"
+
<div class="modal-body">
+
<h2>Load Saved State</h2>
+
<div id="load-list" class="save-list"></div>
+
<div id="load-message"></div>
+
<div style="text-align: center; margin-top: 15px">
+
<div class="button" onclick="hideModal('load-modal')">
+
C:\PLASTIC.EXE - [Self-Modifying System v3.0]
···
<h2>System Information:</h2>
+
<p>PLASTIC v3.0 - Self-Modifying Code System</p>
<p>Copyright (C) 1995 DUNKIRK Corp.</p>
All rights reserved. Licensed to: REGISTERED USER under MIT
···
+
><span class="hotkey" onclick="showHelp()">F1=Help</span>
+
<span class="hotkey" onclick="showSaveModal()"
+
<span class="hotkey" onclick="showLoadModal()"
+
<span id="time">12:00</span>
···
return window.toolCallbacks[func](
···
console.log("Cleaned response:", cleanResponse);
// For safety, preprocess JavaScript code in JSON to escape problematic characters
+
cleanResponse = cleanResponse.replace(
+
/"code"\s*:\s*(`|")([^`"]*?)(`|")/g,
+
function (match, q1, code, q3) {
+
// Replace all literal backslashes with double backslashes in the code string
+
const escapedCode = code.replace(/\\/g, "\\\\");
+
return `"code":${q1}${escapedCode}${q3}`;
// Check if response contains tool calls
···
// Preprocess JavaScript code in JSON to escape problematic characters
+
let cleanJson = jsonMatch[0].replace(
+
/"code"\s*:\s*(`|")([^`"]*?)(`|")/g,
+
function (match, q1, code, q3) {
+
// Replace all literal backslashes with double backslashes in the code string
+
const escapedCode = code.replace(
+
return `"code":${q1}${escapedCode}${q3}`;
const toolResponse = safeJsonParse(cleanJson);
toolResponse.tool_calls &&
···
console.error("JSON parse error:", error);
console.error("Problem JSON:", jsonString);
// Try to escape any unescaped control characters
+
const escapedJson = jsonString.replace(
+
"0000" + match.charCodeAt(0).toString(16)
return JSON.parse(escapedJson);
+
"Second parse attempt failed:",
throw error; // Throw the original error
+
function deleteSave(key) {
+
if (confirm("Are you sure you want to delete this save?")) {
+
localStorage.removeItem(key);
+
// Refresh the load modal to show updated list
+
// Handle keyboard shortcuts
+
function setupKeyboardHandlers() {
const codeEditor = document.getElementById("codeEditor");
// Remove any previous event listeners first (to avoid duplicates)
+
codeEditor.removeEventListener("keydown", editorKeyHandler);
// Add a new event listener
+
codeEditor.addEventListener("keydown", editorKeyHandler);
console.error("codeEditor element not found, will retry");
// Retry after a short delay
+
setTimeout(setupKeyboardHandlers, 100);
+
// Global keyboard shortcuts
+
document.addEventListener("keydown", function (e) {
+
else if (e.key === "F2") {
+
else if (e.key === "F3") {
+
// Escape key - Close any open modal
+
else if (e.key === "Escape") {
+
document.querySelectorAll(".modal").forEach((modal) => {
+
if (modal.style.display === "block") {
+
// Return focus to the editor after closing modal
+
document.getElementById("codeEditor");
+
// Define the editor key handler function
+
function editorKeyHandler(e) {
if (e.ctrlKey && e.key === "Enter") {
+
// Set up the handlers immediately
+
setupKeyboardHandlers();
+
// Also ensure they're set up when the DOM is fully loaded
+
function showModal(modalId) {
+
const modal = document.getElementById(modalId);
+
modal.style.display = "block";
+
// Prevent body scrolling when modal is open
+
document.body.style.overflow = "hidden";
+
// Make the modal appear with a nice fade-in effect
+
modal.style.opacity = "0";
+
modal.style.opacity = "1";
+
// Add/refresh click handler for closing when clicking outside
+
const outsideClickHandler = function (e) {
+
if (e.target === modal) {
+
// Remove any existing handlers to avoid duplicates
+
modal.removeEventListener("click", outsideClickHandler);
+
modal.addEventListener("click", outsideClickHandler);
+
// Trap focus within the modal
+
const focusableElements = modal.querySelectorAll(
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"]), .modal-close, .button',
+
if (focusableElements.length > 0) {
+
const firstElement = focusableElements[0];
+
focusableElements[focusableElements.length - 1];
+
// Focus the first element
+
// Add key event handler for tab key to trap focus
+
const handleTabKey = function (e) {
+
document.activeElement === firstElement
+
document.activeElement === lastElement
+
// Remove any existing handler first
+
modal.removeEventListener("keydown", handleTabKey);
+
modal.addEventListener("keydown", handleTabKey);
+
// Store the handler on the modal object for later cleanup
+
modal._tabHandler = handleTabKey;
+
function hideModal(modalId) {
+
const modal = document.getElementById(modalId);
+
modal.style.opacity = "0";
+
// Hide the modal after animation
+
modal.style.display = "none";
+
// Restore body scrolling when modal is closed
+
document.body.style.overflow = "auto";
+
// Return focus to editor when modal is closed
+
const editor = document.getElementById("codeEditor");
+
// Clear any error messages
+
const messageElements = document.querySelectorAll(
+
"#save-message, #load-message",
+
messageElements.forEach((el) => {
+
if (el) el.textContent = "";
+
showModal("help-modal");
+
function showSaveModal() {
+
document.getElementById("save-name").value = "";
+
showModal("save-modal");
+
// Focus the input field and select any existing text
+
const saveNameInput = document.getElementById("save-name");
+
saveNameInput.select();
+
function showLoadModal() {
+
// Populate the load list
+
const loadList = document.getElementById("load-list");
+
loadList.innerHTML = "";
+
// Get all keys in localStorage that start with 'plastic-save-'
+
for (let i = 0; i < localStorage.length; i++) {
+
const key = localStorage.key(i);
+
if (key && key.startsWith("plastic-save-")) {
+
const saveName = key.replace("plastic-save-", "");
+
// Try to extract timestamp if it's a JSON object
+
const saveData = JSON.parse(
+
localStorage.getItem(key),
+
timestamp = saveData.timestamp;
+
// Old format, no timestamp available
+
if (saves.length === 0) {
+
'<div class="save-item">No saves found</div>';
+
// Sort saves by timestamp (newest first) or alphabetically if no timestamp
+
if (a.timestamp && b.timestamp) {
+
return b.timestamp - a.timestamp; // Newest first
+
} else if (a.timestamp) {
+
return -1; // a comes first
+
} else if (b.timestamp) {
+
return 1; // b comes first
+
return a.name.localeCompare(b.name); // Alphabetically
+
saves.forEach((save) => {
+
const saveItem = document.createElement("div");
+
saveItem.className = "save-item";
+
// Format timestamp if available
+
const date = new Date(save.timestamp);
+
dateStr = ` <span style="font-size: 12px; color: #808080;">(${date.toLocaleString()})</span>`;
+
<span>${save.name}${dateStr}</span>
+
<span class="hotkey" onclick="loadSave('${save.key}')" tabindex="0" role="button" aria-label="Load save ${save.name}">Load</span>
+
<span class="separator">|</span>
+
<span class="hotkey" onclick="deleteSave('${save.key}')" tabindex="0" role="button" aria-label="Delete save ${save.name}">Delete</span>
+
// Add double-click support to load the save directly
+
saveItem.addEventListener("dblclick", () =>
+
loadList.appendChild(saveItem);
+
showModal("load-modal");
+
function saveCurrentHTML() {
+
const saveName = document
+
.getElementById("save-name")
+
const saveMessage = document.getElementById("save-message");
+
saveMessage.textContent =
+
"Please enter a name for your save";
+
saveMessage.style.color = "#ff0000";
+
saveMessage.textContent = "";
+
// Ensure all modals are closed in the saved HTML
+
// First make a clone of the current document state
+
const tempDiv = document.createElement("div");
+
tempDiv.innerHTML = document.documentElement.outerHTML;
+
// Find and hide all modals in the clone
+
const modalElements = tempDiv.querySelectorAll(".modal");
+
modalElements.forEach((modal) => {
+
modal.style.display = "none";
+
// Save the current state
+
html: tempDiv.innerHTML,
+
timestamp: new Date().getTime(),
+
`plastic-save-${saveName}`,
+
JSON.stringify(saveData),
+
const saveMessage = document.getElementById("save-message");
+
saveMessage.textContent = `Saved as "${saveName}"`;
+
saveMessage.style.color = "#008000";
+
saveMessage.textContent = "";
+
hideModal("save-modal");
+
const saveMessage = document.getElementById("save-message");
+
saveMessage.textContent = `Error saving: ${e.message}`;
+
saveMessage.style.color = "#ff0000";
+
saveMessage.textContent = "";
+
// Add keyboard support for modals
+
document.addEventListener("DOMContentLoaded", function () {
+
const saveNameInput = document.getElementById("save-name");
+
// Remove any existing listeners to prevent duplicates
+
const saveInputHandler = function (e) {
+
if (e.key === "Enter") {
+
saveNameInput.removeEventListener(
+
saveNameInput.addEventListener("keydown", saveInputHandler);
+
.querySelectorAll(".modal-close")
+
.forEach((closeBtn) => {
+
closeBtn.addEventListener("keydown", function (e) {
+
if (e.key === "Enter" || e.key === " ") {
+
const modalId = this.closest(".modal").id;
+
function loadSave(key) {
+
const savedData = localStorage.getItem(key);
+
saveObj = JSON.parse(savedData);
+
saveObj = { html: savedData };
+
"Loading will replace the current page. Continue?",
+
hideModal("load-modal");
+
document.addEventListener('DOMContentLoaded', function() {
+
// Ensure all modals are hidden
+
document.querySelectorAll('.modal').forEach(modal => {
+
modal.style.display = "none";
+
// Re-setup keyboard handlers
+
if (typeof setupKeyboardHandlers === 'function') {
+
setupKeyboardHandlers();
+
// Load the saved HTML with the added script
+
document.write(saveObj.html + scriptToAdd);
+
document.getElementById("load-message");
+
loadMessage.textContent = "Save not found";
+
loadMessage.style.color = "#ff0000";
+
loadMessage.textContent = "";
+
const loadMessage = document.getElementById("load-message");
+
loadMessage.textContent = `Error loading: ${e.message}`;
+
loadMessage.style.color = "#ff0000";
+
loadMessage.textContent = "";