diff --git a/index.html b/index.html
index ccb9e7b..067ee89 100644
--- a/index.html
+++ b/index.html
@@ -3,9 +3,12 @@
 <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
     <link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
-    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
+    <!-- PyScript CSS -->
+    <link rel="stylesheet" href="https://pyscript.net/releases/2024.10.2/core.css">
+
+    <!-- This script tag bootstraps PyScript -->
+    <script type="module" src="https://pyscript.net/releases/2024.10.2/core.js"></script>
     <title>pipdev</title>
     <style>
         main,
@@ -122,97 +125,6 @@
         </div>
     </div>
 </main>
-<py-script>
-    from js import window, document, window
-    from pyodide import create_proxy
-    from pipdev import check_version, generate_versions_table
-
-    # Elements:
-    output_el = document.getElementById('js-output')
-    source_el = document.getElementById('js-source')
-    check_el = document.getElementById('js-check')
-
-    ex0_el = document.getElementById('js-example-0')
-    ex1_el = document.getElementById('js-example-1')
-    ex2_el = document.getElementById('js-example-2')
-
-    def get_url_param(name):
-        params = str(window.location.search).strip('?').replace('%3E', '>').replace('%3C', '<').replace('%7E', '~')
-        if params == '':
-            return False
-        params = params.split('&')
-        for param in params:
-            if param.startswith(name + '='):
-                param = param.lstrip(name + '=')
-                if param != '':
-                    return param
-        return False
-
-    def do_check():
-        if check_el.value == '' or source_el.value == '':
-            check_el.setAttribute('aria-invalid', '')
-            return
-
-        try:
-            is_valid = check_version(check_el.value, source_el.value)
-        except:
-            check_el.setAttribute('aria-invalid', '')
-        else:
-            check_el.setAttribute('aria-invalid', 'false' if is_valid else 'true')
-
-    def do_update(value):
-        try:
-            table_content = generate_versions_table(value, fmt='html')
-        except:
-            source_el.setAttribute('aria-invalid', 'true')
-            output_el.innerHTML = ''
-        else:
-            if table_content.strip() == "":
-                source_el.setAttribute('aria-invalid', 'true')
-                output_el.innerHTML = ''
-            else:
-                source_el.setAttribute('aria-invalid', 'false')
-                table_el = document.createElement('table')
-                table_el.innerHTML = table_content
-                table_el.classList.add('ms-table')
-                output_el.innerHTML = ''
-                output_el.appendChild(table_el)
-        do_check()
-
-    def manage_update(e):
-        do_update(e.target.value)
-
-    source_el.addEventListener('input', create_proxy(manage_update))
-    source_el.addEventListener('propertychange', create_proxy(manage_update))
-
-    def manage_check(e):
-        do_check()
-
-    check_el.addEventListener('input', create_proxy(manage_check))
-    check_el.addEventListener('propertychange', create_proxy(manage_check))
-
-    ex0_el.addEventListener('click', create_proxy(lambda e: set_spec(ex0_el.textContent)))
-    ex1_el.addEventListener('click', create_proxy(lambda e: set_spec(ex1_el.textContent)))
-    ex2_el.addEventListener('click', create_proxy(lambda e: set_spec(ex2_el.textContent)))
-
-    def set_spec(value):
-        source_el.value = value
-        do_update(value)
-
-    def set_vers(value):
-        check_el.value = value
-
-    vers = get_url_param('vers')
-    vers = vers if vers else '1.2.1'
-    set_vers(vers)
-
-    spec = get_url_param('spec')
-    spec = spec if spec else '~=1.2'
-    set_spec(spec)
-
-    source_el.focus()
-    body_el = document.getElementsByTagName('html')[0]
-    body_el.className += ' is-loaded'
-</py-script>
+<script type="py" src="./main.py" config="./pyscript.toml"></script>
 </body>
 </html>
\ No newline at end of file
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..2076449
--- /dev/null
+++ b/main.py
@@ -0,0 +1,92 @@
+import sys
+from js import window, document, window
+from pyodide.ffi import create_proxy
+
+from pipdev import check_version, generate_versions_table
+
+# Elements:
+output_el = document.getElementById('js-output')
+source_el = document.getElementById('js-source')
+check_el = document.getElementById('js-check')
+
+ex0_el = document.getElementById('js-example-0')
+ex1_el = document.getElementById('js-example-1')
+ex2_el = document.getElementById('js-example-2')
+
+def get_url_param(name):
+    params = str(window.location.search).strip('?').replace('%3E', '>').replace('%3C', '<').replace('%7E', '~')
+    if params == '':
+        return False
+    params = params.split('&')
+    for param in params:
+        if param.startswith(name + '='):
+            param = param.lstrip(name + '=')
+            if param != '':
+                return param
+    return False
+
+def do_check():
+    if check_el.value == '' or source_el.value == '':
+        check_el.setAttribute('aria-invalid', '')
+        return
+
+    try:
+        is_valid = check_version(check_el.value, source_el.value)
+    except:
+        check_el.setAttribute('aria-invalid', '')
+    else:
+        check_el.setAttribute('aria-invalid', 'false' if is_valid else 'true')
+
+def do_update(value):
+    try:
+        table_content = generate_versions_table(value, fmt='html')
+    except:
+        source_el.setAttribute('aria-invalid', 'true')
+        output_el.innerHTML = ''
+    else:
+        if table_content.strip() == "":
+            source_el.setAttribute('aria-invalid', 'true')
+            output_el.innerHTML = ''
+        else:
+            source_el.setAttribute('aria-invalid', 'false')
+            table_el = document.createElement('table')
+            table_el.innerHTML = table_content
+            table_el.classList.add('ms-table')
+            output_el.innerHTML = ''
+            output_el.appendChild(table_el)
+    do_check()
+
+def manage_update(e):
+    do_update(e.target.value)
+
+source_el.addEventListener('input', create_proxy(manage_update))
+source_el.addEventListener('propertychange', create_proxy(manage_update))
+
+def manage_check(e):
+    do_check()
+
+check_el.addEventListener('input', create_proxy(manage_check))
+check_el.addEventListener('propertychange', create_proxy(manage_check))
+
+ex0_el.addEventListener('click', create_proxy(lambda e: set_spec(ex0_el.textContent)))
+ex1_el.addEventListener('click', create_proxy(lambda e: set_spec(ex1_el.textContent)))
+ex2_el.addEventListener('click', create_proxy(lambda e: set_spec(ex2_el.textContent)))
+
+def set_spec(value):
+    source_el.value = value
+    do_update(value)
+
+def set_vers(value):
+    check_el.value = value
+
+vers = get_url_param('vers')
+vers = vers if vers else '1.2.1'
+set_vers(vers)
+
+spec = get_url_param('spec')
+spec = spec if spec else '~=1.2'
+set_spec(spec)
+
+source_el.focus()
+body_el = document.getElementsByTagName('html')[0]
+body_el.className += ' is-loaded'
\ No newline at end of file
diff --git a/pyscript.toml b/pyscript.toml
new file mode 100644
index 0000000..381ff97
--- /dev/null
+++ b/pyscript.toml
@@ -0,0 +1,10 @@
+# https://docs.pyscript.net/2024.10.2/user-guide/configuration/
+name = "pipdev"
+description = "It's an interactive tool for developers to test defined specifiers for version handling."
+
+packages = ["packaging>=23.0", "tabulate>=0.8", "colorama>=0.4"]
+
+[[fetch]]
+files = ['__init__.py', 'pipdev.py']
+from = 'pipdev'
+to_folder = 'pipdev'
\ No newline at end of file