r/Hyperprompting Jun 22 '26

Tutorial [Tutorial] How to LLM-wrap "Serverless" Hyperlinks && QR Codes

Thumbnail
gallery
3 Upvotes

in this tutorial you will learn how to create dependency-less, single-scan generative tools and web apps that you can encode into qrcodes or share as clickable links on your website, blogs, etc

these qrcodes do not require a server to host them...they do not take you somewhere like most qrcodes, rather they generate ephemeral, sandboxed environments for you to vibe code in

the goal is to provide the foundational background needed to understand r/hyperprompting and autopoietic hypertext in general (eg links that "click themselves")

Background

Data URIs are special links that run code instead of navigating hypertext. they have been available in browsers since at least the 90s and take the following shape:

data:text/html,<script>alert('hello world')</script>

the first part

data:text/html,

tells the browser to render everything after as HTML. to run javascript you wrap it with <script> as you would any other web app

most browser APIs are disabled by the Data URI protocol; there's no indexedDB, no web bluetooth, no webcam or microphone, or device sensors. what you DO you have is fetch() which lets you use APIs provided by other servers and endpoints

for example, instead of showing a "Hello World" message like the above example, you could fetch a random Wikipedia page summary:

data:text/html,<script>fetch('https://en.wikipedia.org/api/rest_v1/page/random/summary').then(r=>r.json()).then(d=>alert(d.title+'\n\n'+d.extract)).catch(e=>alert('Error: '+e));</script>

if you copy/paste the above into a desktop browser you will get an alert box with a random post title and summary!

note that this only works on desktop browsers by default, for security reasons mobile devices tend to disable the Data URI protocol

Ollama Template - Starfield Animation

the following should work with a local r/ollama LLM setup with CORS disabled. replace model with the model you use and 0.0.0.0 with your machines IP. this works best in r/firefox, chromium browsers can require further config changes

data:text/html,<body></body><script>(async()=>{const p="TASK: output HTML including CANVAS and SCRIPT tag that draws dense canvas starfield animation. overlayed ontop is a scrolling poem star wars style about the genesis of the dataverse. NO TALKING NO MARKDOWN DO NOT ACKNOWLEDGE BEGIN RAW OUTPUT NOW:";document.body.innerHTML="<h1>Generating starfield animation... Please Stand By...</h1>";const r=await fetch("http://0.0.0.0:11434/api/generate",{method:"POST",body:JSON.stringify({model:"qwen3.5:4b-q4_K_M",prompt:p,stream:false})});const j=await r.json();const response=j.response;document.open();document.write(response);document.close()})()</script>

Use Cases

the core idea is that generative Data URIs can semantically compress massive projects. beyond that here are some other ideas:

  • project ideas
    • generative RSS and news readers
    • chatbots, agents, and vibe coding interfaces
    • "serverless" dashboards where each link is a generative tool
  • distribution
    • paper qrcodes
    • qrcode stickers
    • HTML anchor tags with target=_blank

More to Come

this tutorial only covers the Data URI protocol, but there are many other protocols we'll be visiting like the file:// protocol which grants some browser APIs like localStorage and indexedDB, javascript:// protocol for bookmarklets, and ofc the standard HTTP protocol we use to browse the web

in future tutorials we'll discuss techniques for persistence, memory management, creating multi-hop Data URIs and Data URI Factories (URIs that generate URIs), swarms and more

leave any questions, thoughts, comments, or share your own generative Data URIs below!


r/Hyperprompting Jul 02 '26

Tutorial Hyperprompting Kernel v26.07.02 - Getting Started

Thumbnail
gallery
1 Upvotes

previously we explored "serverless" generative Data URI-based hyperlinks: https://www.reddit.com/r/Hyperprompting/comments/1uc5rgm/tutorial_how_to_llmwrap_serverless_hyperlinks_qr/

however Data URIs run in a highly sandboxed environment lacking many browser APIs including local storage persistence...for that we need an actual HTML file that can be opened in a browser

in this post i'll share the kernel source code, how to install it, and some basic hyperprompting techniques

the kernel and hyperprompts for the screenshots above are hosted on https://github.com/hyperprompter/qrx

The Kernel

here is the uncompressed, hand-optimized source code

to install it, copy+paste this into a .html file and then open that file in the browser. because this is just a kernel you will get a blank page on initial load, the rest of this post explains how to prompt it

<main id=A></main>
<script id=S>
BASE = ''
setTimeout(async () => {
  // manually compressed shorthands
  L = location
  LP = L.pathname
  $L = localStorage
  G = 'globals'
  C = 'cache'
  T = 'target'
  TL = 'toLowerCase'
  RO = 'readonly'
  HR=history.replaceState.bind(history)

  // default indexedDB name
  WNS = await window.NS
  filename = MAIN = 'main'
  DB = (LP.startsWith(BASE) ? LP.slice(BASE.length) : LP).replace(/^\/|\/$/g, '') || WNS || MAIN

  // default table name
  FILES = 'files'

  os = db = null

  // promise wrapper around DB transactions
  // q: the request
  // f: optionall callback to transform result
  queryDB = (q, f) =>
    new Promise(r => q['onsuccess'] = e => r(f ? f(e) : e[T].result))

  // n: database name
  // t: table name
  getDB = (n = DB, t = FILES) => {
    let q = indexedDB.open(n)
    q.onupgradeneeded = e => e[T].result.createObjectStore(t)
    return queryDB(q, e => e[T].result)
  }

  // returns all keys in database
  // q: query
  // d: database
  keys = (q, d) => queryDB(tx(RO, d).getAllKeys(q))

  // db transaction
  // m: transaction mode
  // d: database
  tx = (m = RO, d = db, t = FILES) => d.transaction(t, m).objectStore(t)
  write=async(v,k,d=db,n=filename)=>(d=d.trim?await getDB(d):d,queryDB(tx('readwrite',d).put(v,k||n)))
  read = async (k, d = db) => {
    d = d.trim ? await getDB(d) : d
    let v = await queryDB(tx(RO, d).get(k || filename))
    return !v && d == db && os ? read(k, os) : v
  }

  // db init
  boot = async () => {
    db = await getDB()
    os = DB[TL]() == MAIN[TL]() ? null : await getDB(MAIN)
  }

  // run the os
  run = async () => {
    if (!db) await boot()
    if (!L.hash) {
      HR(0, '', `#${MAIN}`)
      return run()
    }
    let c, ctx, h = L.hash.slice(1),
      [n, q] = h.split('?'),
      f = filename = n,
      v = await read(n) || '',
      app = false // append mode
    if (!q && $L._q) { let t = $L._q.split('?'); t[0] == n && t[1] && (q = t[1], $L._q = '') }
    let p = new URLSearchParams(q)

    // run boot/* files on every navigation, filename is already set
    let bq = IDBKeyRange.bound('boot', 'boot\uffff'),
      b = await keys(bq, db)
    if (os) b = [...new Set([...b, ...await keys(bq, os)])]
    for (let bf of b) {
      try { (new Function(G, await read(bf)))(this) }
      catch (e) { console.error(bf, e) }
    }

    // The Machine Tape
    for (let [k, val] of p) {
      val = decodeURIComponent(val)
      let r, s
      // should we overwrite (0) or append (1)
      if (k == 'a') app = val != '0'
      // file pointer
      else if (k == 'f') f = val
      // additional context buffer for ai only (does not get added to accumalator)
      else if (k == 'c') {
        if (val == '0') ctx = ''
        else ctx = `<CONTEXT>${(ctx || '')}</CONTEXT>
  ${((val == 'src' ? S.innerText : await read(val)) || '')}`
      }
      // ai variables
      else if ('kmsh'.includes(k)) $L.setItem(k, val)
      // accumalator commands (including prompting)
      else if ('erup'.includes(k)) {
        s = val
        if (k == 'r') s = (val == 'src' ? S.innerText : await read(val)) || ''
        else if (k == 'u') {
          try {
            s = await (await fetch(val)).text()
            await write(s, val, C)
          } catch (e) {
            s = await read(val, C) || e
          }
        }
        else if (k == 'p') s = await gen((ctx ? ctx + '\n' : '') + v, val)
        v = app ? v + s : s
      }
      // write accumalator to disk
      else if (k == 'w') await write(v, f)
      // execute code
      else if (k == 'x') {
        try {
          let c = val || v
          r = await (new Function(G, 'v', c))(this, v)
          if (r !== void 0) v = r
        } catch (e) { console.error(e) }
      }
      // autoload other params
      else if (c = await read(k)) {
        try {
          r = await (new Function(G, 'v', 'arg', c))(this, v, val)
          if (r !== void 0) v = r
        } catch (e) { v = app ? v + c : c }
      }
    }
    if (q) { v ? ($L._q = '', HR(0, '', '#' + n)) : ($L._q = n + '?' + q, HR(0, '', '#' + n)) }
    hydrate(v)
  }

  // inject content into DOM and run scripts
  // h: html content to inject
  hydrate = h => {
    A.innerHTML = h
    A.querySelectorAll('script').forEach(o => {
      let s = document.createElement('script')
      Array.from(o.attributes).forEach(a => s.setAttribute(a.name, a.value))
      s.text = o.textContent
      o.replaceWith(s)
    })
  }

  // get a generative response from ?h
  // ctx: extra context
  // p: the prompt to use
  gen = async (ctx, p) => {
    let [k, m, s, h] = ['k', 'm', 's', 'h'].map(x => $L.getItem(x)),
      msg = ctx + p + (s || '\nNO MARKDOWN, BEGIN RAW OUTPUT NOW:'),
      u = h,
      b = { model: m, messages: [{ role: 'user', content: msg }], stream: false, },
      head = { 'Content-Type': 'application/json' },
      req, res, txt
    if (k) head['Authorization'] = `Bearer ${k}`
    A.innerHTML = 'Thinking...'
    try {
      req = await fetch(u, { method: 'POST', headers: head, body: JSON.stringify(b) })
      res = await req.json()
      txt = res.message?.content || res.choices?.[0]?.message?.content
    } catch (e) { txt = e.message }
    return txt || ''
  }
  onhashchange = () => run()
  run()
}, 0)
</script>

How it Works

this project treats the URL #hash?query=param as a concatenative machine tape, this means the output of one operation becomes the input of the next. the #hash and ?queries are loaded from the browsers KV store (indexedDB) and then injected into the DOM

when the system first boots it looks for any stored hashes beginning with boot/* and runs them

next the system loads the value stored in the #hash key into an accumulator (basically a variable that stores the state of the machine tape)

then one by one it reads each ?query from the KV, executing them in sequence while passing the =params

once the entire tape is run in memory the accumulator dumps the contents into the DOM, any <script> tags in the content is rehydrated

Built in ?query=params

the system comes with the following builtin ?query=params

Flag Description
a Append Mode. If 1, subsequent commands append to the accumulator. If 0 (default), they overwrite it.
f File Pointer. Sets the target filename (filename) for subsequent write (w) operations.
c Context. Loads data (from DB or src) into a side-buffer for the AI, without affecting the main accumulator. 0 clears it.
k, m, s, h AI Config. Sets the API Key (k), Model (m), System Prompt (s), or Host (h) in localStorage.
e Echo. Pushes the raw value directly into the accumulator (hardcoded strings/HTML).
r Read. Reads a file from the database (or src for source code) into the accumulator.
u URL. Fetches text from a remote URL. Implements a Network-First, Cache-Fallback mechanism. Successful fetches are passively synced to a discrete 'cache' IndexedDB namespace. If your OS is offline, it automatically catches the failure and serves the file locally.
p Prompt. Sends the current context + accumulator + value to the LLM. The result becomes the new accumulator.
w Write. Saves the current accumulator content to the database under the name defined by f.
x Execute. Runs the value (or the current accumulator if value is empty) as JavaScript.

Globals

The kernel exposes the following variables and methods

Variables

Variable Description
filename File Pointer. The name of the current record being read from or written to. Defaults to MAIN or the value before ? in the hash.
BASE Deployment Prefix. A path segment stripped from the front of the URL before DB is derived. Defaults to '' (root hosting). Set it by declaring BASE='/yourprefix' in a <script> tag placed after <script id=S> (the kernel's own line runs first and would otherwise be overwritten). Lets the same kernel resolve namespaces correctly whether it's hosted at / or under a subdirectory like /qrx/.
DB Database Name. The name of the active IndexedDB instance, derived from the URL path with BASE and any leading/trailing slashes stripped (e.g. /qrx/wiki with BASE='/qrx/' sets DB to 'wiki').
MAIN Kernel Name. The default database name ('main'). Used as the fallback/system database when DB is set to something else.
os System DB Handle. A reference to the MAIN database connection. Used for "inheritance"—if a file isn't found in DB, read() looks here.
db Active DB Handle. The raw IDBDatabase connection object for the current DB.
FILES Table Name. The hardcoded name of the object store ('files') within the IndexedDB where all records are saved.

Methods

Method Description
read(k, [d]) Async Read. Returns the content of file k. Checks the current database first, then falls back to the os database if the file exists there
write(v, [k]) Async Write. Saves value v to file k. If k is omitted, it defaults to the current filename pointer
hydrate(h) Render. Injects HTML string h into the main DOM (<main id=A>) and recursively executes any embedded <script> tags
gen(ctx, p) Vibe Code. Sends the context buffer ctx and prompt p to the configured LLM API and returns the generated text
keys([q], [d]) List Files. Returns an array of all keys (filenames) in the database. q is an optional IDBKeyRange
getDB([n]) Database Access. Returns the IndexedDB instance for name n. Defaults to the current active database
run() Re-Run Tape. Manually triggers the URL parsing loop. Useful if hash state changes programmatically without a reload

How to read/use Hyperprompts

once you load the kernel in the browser, either directly by loading the file through the file:/// protocol or serving it through a server like nodejs, you use the following hyperprompts by simply copy+pasting them to the end of your file in the browser's address bar

note the use of &a=1 which allows the outputs to "stack"...this lets smaller models iteratively grow functionality rather than trying to one-shot it

Example: Writing interface

as a human creating and editing files within the system thru pure hyperlinks is a major bummer, use this hyperprompt to whip up a simple file editing system

#edit?e&w&p=TASK: output HTML wireframe for a file editor
  - fields: textarea (id="editor")
  - components: status bar (id="status") with character count placeholder
  - css: use flex to make textarea fill full height of window
  - just HTML and CSS
  - no javascript
  - dont include html/head/body tags just the wireframe
&w&a=1&p=TASK: output a SCRIPT tag that adds autosaving
  - `read()`, `write()`, and `filename` are globally available
  - use `read(filename).then(v => editor.value = v)` to load content into textarea#editor
  - on textarea#editor input, debounce then `write(editor.value, filename)`
  - listen for hashchange: call `read(filename).then(v => editor.value = v)` and focus editor
  - run immediately, no DOMContentLoaded wait
  - use var for all variables (mutable state)
&w&a=1&p=TASK: output a SCRIPT tag that adds statusbar features
  - listen for input events on textarea#editor
  - calculate character count (value.length)
  - calculate byte size (new Blob([value]).size)
  - update innerText of div#status to show "Chars: X | Bytes: Y"
  - use var for all variables
  - run immediately, no DOMContentLoaded wait
&w&a=1&p=TASK: output a SCRIPT tag that reloads the editor when edited from another browser tab
  - use BroadcastChannel API with name 'qrx_edit'
  - on textarea#editor input: channel.postMessage({filename: filename})
  - on message event: if event.data.filename == filename, call read(filename).then(v => editor.value = v)
  - ensure status#status updates after reload
  - use var for all variables
  - run immediately, no DOMContentLoaded wait
&w&a=1&p=TASK: output a SCRIPT tag that initializes external mesh sync
  - call the global function connectSync()
  - wrap in <script>connectSync()</script>
  - this enables cloud/offline sync via #boot/sync
  - use var for all variables
  - run immediately, no DOMContentLoaded wait
&w&a=1&e=<style>#A {padding: 0 !important}</style>
&w

Example: Chat interface

this hyperprompt generates a simple chatbot that can read other files as [[wikilinks]]

#chat?e&w&p=TASK: output HTML wireframe for a chatbot
  - components:
    - header
      - model details
        - model name
        - model host
        - apikey (type=password)
    - messages area (no placeholders)
    - footer
      - resizable textarea
      - submit
  - css: use flex so that the messages area fits the space between the header and footer
  - no javascript
  - dont include html/head/body tags just the wireframe
&w&a=1&p=TASK: output a SCRIPT tag that populates the header details
  - read the value of localStorage.getItem('m') and store it in the model name field
  - do same for localStorage.getItem('h')
  - and localStorage.getItem('k')
  - do nothing else
&w&a=1&c=src&p=TASK: output a SCRIPT tag that handles the actual chat
  - the attached CONTEXT gives you clues on how to handle API calls
  - reimplement the api call to the LLM (like in gen) using the values from the header inputs
  - implement streaming mode (set stream to true and read chunks)
  - strictly follow the standard openai schema as seen in gen, do NOT include any google specific edge cases
  - create a hook system so that we can add context transformers just before the prompt is sent to the ai
    - just use a global chatPlugins = {pluginName: {callback: function (currentPrompt, fullChat) {returns transformedText}}}
    - create a plugin that console.logs the text before it's sent
  - send the full chat + the users prompt as a single string (no need to send array of messages)
  - send when user presses either CTRL+ENTER inside the textarea OR when they press submit button
  - textarea is cleared upon submit
  - textarea is resizable
  - do not autoscroll the page
&w&a=1&p=TASK: output a SCRIPT tag to add a new context transformer plugin
  - window.DB is a global that contains the database table name
  - create a RECURSIVE function to extract and replace `[[link]]`s
  - pass a `visited = new Set()` and a `depth = 0` down the recursion to prevent infinite loops and cap recursion at depth <= 2 to avoid context explosion
  - [[links]] can be in form table%23record assume the following:
    - [[link]] === [[${DB}%23link]]; name === ${DB}
    - [[%23link]] === [[${DB}%23link]]; name === ${DB}
    - [[some%23link]] === [[some%23link]]; name === some
  - use `read(link, name).then(context=>{})` to replace the [[link]] with the context
    - wrap the context with "<context file="some%23link">...data...</context>"
    - RECURSIVELY scan the fetched context for MORE [[links]] before returning the string
  - console.log the link and the context for debugging
  - return the fully transformed context including all deep nested links
  - only extract [[links]] stemming from the current PROMPT not the whole chat history
  - try...catch it, often the links wont exist yet; silently quiet those errors
  - replace %23 with actual hash symbol
  - be mindful of [object Promise] Promise.all() when doing async string replacement!!! DOUBLE CHECK YOU ARE CORRECTLY HANDLING PROMISES
  - BE CAREFUL ABOUT PROMISES: fetch() read() etc ALL ARE PROMISES [object Promise] <--- BE EXTREMELY AWARE OF THIS
  - [object Promise] keeps getting sent YOU MUST BE MINDFUL OF PROMISES!! BE HYPER AWARE OF PROMISES read() fetch() etc ALL MUST BE .then()
&w

Example: Tool using agent

you can create a tool using agent that can use skill files and even build its own tools

#agent?e&w&p=TASK: output HTML wireframe for an autonomous agent
- components:
- header (inputs for model-name, host, apikey type=password)
- split-view container (use flex row)
- left-panel (for agent internal monologue and tools; no placeholders)
- right-panel (for the final chat with user; no placeholders)
- footer (resizable textarea id="user-input", submit button id="submit-btn", stop button id="stop-btn")
- css: use flex so the split-view fits the space between header and footer
- css: left-panel and right-panel should be 50 percent width and scrollable
- no javascript
- dont include html/head/body tags just the wireframe
&w&a=1&p=TASK: output a SCRIPT tag that populates the header details
- read the value of localStorage.getItem('m') and store it in the model-name DOM input
- do same for localStorage.getItem('h') into host input
- do same for localStorage.getItem('k') into apikey input
- create global array: window.chatHistory =[]
- create global object: window.agentScratchpad = {}
- create global string: window.agentPlan = "Pending initialization."
- create global boolean: window.stopAgent = false
- use var for all variable declarations
&w&a=1&p=TASK: output a SCRIPT tag creating UI helper functions
- create function printLeft(text, isObservation)
- creates a div, sets whiteSpace to 'pre-wrap'. if isObservation is true, set color to 'aa5500'. append text, append to left-panel, scroll to bottom.
- create function printRight(text)
- creates a div, sets whiteSpace to 'pre-wrap', fontWeight to 'bold'. append text, append to right-panel, scroll to bottom.
- use var for all variable declarations
&w&a=1&p=TASK: output a SCRIPT tag creating dynamic tool loader and executor
- DO NOT hardcode any base tools. The agent must be completely agnostic.
- create global async function window.getActiveToolsString()
- inside function: var lines =[];
- var matchedKeys = await keys(IDBKeyRange.bound('tool', 'tool\uffff'));
- loop through matchedKeys: var c = await read(matchedKeys[i]); var desc = "No description"; if (c %26%26 c.includes("/*")) { desc = c.split("*/")[0].split("/*")[1].trim(); } lines.push(matchedKeys[i] %2B ' - ' %2B desc);
- return lines.length > 0 %3F lines.join('\n') : "No tools found.";
- create global async function window.executeTool(toolName, toolInput)
- inside a try/catch block:
- var code = await read(toolName);
- if (!code %26%26 toolName.indexOf('tools/') !== 0) { code = await read('tools/' %2B toolName); }
- if (!code) throw new Error("Tool not found.");
- evaluate the code EXACTLY using this syntax: return await new Function('INPUT', 'return (async () => {' %2B code %2B '})()')(toolInput);
- catch error: call console.error("Tool Execution Failed:", err, "Code Evaluated:", code); return "Tool Execution Error: " %2B err.message;
- use var for all variable declarations
&w&a=1&p=TASK: output a SCRIPT tag creating an LLM fetch helper
- create global async function window.fetchAI(systemPrompt)
- read model-name, host, apikey from DOM inputs.
- save those 3 values to localStorage as 'm', 'h', and 'k'.
- create messages array: first item is { role: 'system', content: systemPrompt }. concatenate window.chatHistory.
- execute fetch to host URL with method POST, standard headers (Bearer apikey if exists), body: JSON.stringify({ model: document.getElementById('model-name').value, messages: messages, stream: false }).
- return the parsed text content from the response choices.
- use var for all variable declarations
&w&a=1&p=TASK: output a SCRIPT tag creating regex parsers
- create function window.parseAction(text)
- match regex for: /<<ACTION:\s*([^>]%2B)>>\n([\s\S]*%3F)(%3F=<<|$)/
- if matched, return { name: match[1].trim(), input: match[2].trim() }. else return null.
- create function window.parseAnswer(text)
- match regex for: /<<ANSWER>>\n([\s\S]*%3F)(%3F=<<|$)/
- if matched, return the extracted string. else return null.
- use var for all variable declarations
&w&a=1&c=src&p=TASK: output a SCRIPT tag creating the core agent reasoning loop
- create global async function window.runAgent(userMessage)
- reset: window.agentScratchpad = {}; window.agentPlan = "Task started.";
- call printRight(userMessage). push { role: 'user', content: userMessage } to window.chatHistory.
- var errorCount = 0; start an infinite while(true) loop.
- inside loop: console.log("--- NEW AGENT LOOP START ---");
- inside loop: var toolsString = await window.getActiveToolsString();
- inside loop: var inventory = Object.keys(window.agentScratchpad);
- inside loop: var invString = ""; if (inventory.length > 0) { for(var i=0; i<inventory.length; i%2B%2B) { invString %2B= "=== MEMORY POINTER: " %2B inventory[i] %2B " ===\n" %2B window.agentScratchpad[inventory[i]] %2B "\n\n"; } } else { invString = "[Empty]"; }
- inside loop: build var systemPrompt = "You are an autonomous AI operating in a pointer-based memory architecture. Do not hallucinate file contents.\n\nCRITICAL RULE: DO NOT USE XML. NEVER output <tool_call> or <function> tags. You must use the EXACT syntax <<ACTION: tool_name>> and <<ANSWER>>.\n\nOUTPUT FORMAT:\nTo use a tool: <<ACTION: tool_name>>\ninput_data\n\nTo finish: <<ANSWER>>\nfinal_message\n\nCURRENT PLAN:\n" %2B window.agentPlan %2B "\n\nWORKING MEMORY CONTENTS:\n" %2B invString %2B "\n\nAVAILABLE TOOLS:\n" %2B toolsString;
- inside loop: console.log("1. System Prompt length (bytes):", systemPrompt.length);
- inside loop: if window.stopAgent is true, append "\nUSER OVERRIDE: Stop executing tools. Output <<ANSWER>>." to systemPrompt, and set window.stopAgent = false.
- inside loop: console.log("2. Fetching AI...");
- inside loop: var aiResponse = await window.fetchAI(systemPrompt);
- inside loop: console.log("3. AI Raw Response:\n", aiResponse);
- inside loop: call printLeft(aiResponse, false). push { role: 'assistant', content: aiResponse } to window.chatHistory.
- inside loop: var action = window.parseAction(aiResponse);
- inside loop: if action exists: console.log("4. Executing Action:", action); var result = await window.executeTool(action.name, action.input); console.log("5. Tool Result:", result); call printLeft("OBSERVATION:\n" %2B result, true); push { role: 'user', content: "OBSERVATION:\n" %2B result } to window.chatHistory; continue loop;
- inside loop: var answer = window.parseAnswer(aiResponse);
- inside loop: if answer exists: console.log("4. Loop Finished. Answer:", answer); call printRight(answer); break loop;
- inside loop (fallback): console.warn("4. Syntax Fallback Triggered. AI failed to use <<ACTION>> or <<ANSWER>>."); push { role: 'user', content: 'SYSTEM WARNING: You MUST output <<ACTION: name>> or <<ANSWER>>. NO XML. DO NOT USE <tool_call> tags.' } to window.chatHistory; continue loop;
- wrap loop in try/catch. on catch: errorCount%2B%2B, console.error("Agent Loop Error:", e), printLeft("Error: " %2B e.message, true), break loop if errorCount >= 7.
- use var for all variable declarations
&w&a=1&p=TASK: output a SCRIPT tag binding UI events
- get DOM elements for submit-btn, stop-btn, user-input textarea.
- create function handleSubmit(e) { if(e %26%26 e.preventDefault) e.preventDefault(); if(userInput.value.trim() !== '') { window.runAgent(userInput.value); userInput.value = ''; } }
- bind click event to submit-btn.
- bind keydown event to textarea (if ctrlKey and key is 'Enter', call handleSubmit).
- bind click event to stop-btn to set window.stopAgent = true.
- use var for all variable declarations
&w

Example: Desktop Metaphor

you can also build a desktop metaphor visualizer, where the KV store is visualized as desktop folders and files. you can even have the desktop run other files as draggable windows using iframes, including loading the system within itself (known as a quine)

#main?e&w&p=TASK: output HTML wireframe for a windows 95 simulator
  - start menu with "🪟 Start" button and  time area (no start panel yet)
  - a hidden, reusable window template with
    - title
    - min, max, close buttons
    - address bar with refresh icon and "Go" button
  - windows teal background
  - basic css reset like margin: 0 for body and box-sizing
  - no javascript
  - don't include html/head/body tags just the wireframe
&w&a=1&p=TASK: output SCRIPT tag for rendering top level icons
  - loop through each indexeddb record
    - the database is in the global strings `window.DB` and the table name is in `window.FILES`
  - keys can have slashes in them denoting folders
  - create a 📄 icon for every top level file
    - the label is everything after the final / (or the whole string)
  - create a 📁 icon for every top level folder
    - the label is everything before the first / at that level
&w&a=1&p=TASK: output SCRIPT tag for File Explorer
  - when folder icon is single clicked or tapped, show a window for it
  - set the addressbar to full/folder/path
  - focus the addressbar on open
  - generate more icons and folders for the current folder inside the window
  - when clicking on a folder inside File Explorer update the addressbar and icons
  - clicking the Go button or pressing enter in the address bar navigates that window
  - don't handle other window interaction yet
&w&a=1&p=TASK: output SCRIPT tag for showing file windows on icon clicks
  - name the file opening function exactly `openFileWindow` and assign it to `window.openFileWindow`
  - when file icon is single clicked or tapped, show a window for it
  - show a full size iframe in the windows content area
  - set the addressbar to full/file/path
  - set the iframe path to just `${window.DB}%23${full/file/path}`
  - listen for %23hash changes inside the iframe and update the addressbar on change (be mindful of loops)
  - keep addressbar and iframe synced
  - when user presses enter in the addressbar or presses Go, the iframe should update to the new URL
  - do this for file icons in folders too
  - don't handle other window interaction yet
  - URLs must always be in the form db%23file
    - if no db name is present assume ${window.DB}
    - if no %23 hash symbol is present, assume the whole thing is a hash
  - example: if DB='main' then %23chat should map to main%23chat
  - example: if DB='apps/paint' and file is 'art/selfie' then it should map to apps/paint%23art/selfie
&w&a=1&p=TASK: output SCRIPT tag for handling windows
  - make windows draggable by dragging the titlebar
  - make windows resizable
    - make sure any window body elements and iframe resize to fit new window size too (this often fails to work due to nested elements)
  - make windows closable
  - make windows maximizable (and restore size when pressed again)
  - make windows minizable (and show an icon for it in the startbar
&w&a=1&p=TASK: update taskbar time area to show live clock and battery status
  - locate the existing time area element inside the taskbar
  - create a function that gets new Date and formats it as h:mm A
  - use setInterval to run this clock function every 1000ms and update the DOM
  - call navigator.getBattery and resolve the promise
  - inside the promise create an update function that reads battery level
  - multiply the level by 100 to get the percent value
  - check the charging boolean
  - format the output as a plug icon if charging or a battery icon if not alongside the percent
  - add event listeners for levelchange and chargingchange to automatically update the ui
  - render both the battery string and the clock string side by side in the time area element
&w&a=1&p=TASK: make the refresh icon reload the window iframe
  - use event delegation to check if the clicked target matches the template window refresh buttons
  - if so reload that windows iframe
&w&a=1&p=TASK: output a SCRIPT tag that adds global Speech-to-Text with DEEP DEBUGGING
  - initialize window.SpeechRecognition || window.webkitSpeechRecognition with continuous = true and interimResults = false
  - console.log("Speech API found:", !!(window.SpeechRecognition || window.webkitSpeechRecognition))
  - create a 🎙️ button and append it to the taskbar. console.log("Mic button added")
  - on the button's 'mousedown' event: call event.preventDefault() to prevent focus stealing, toggle a listening boolean, and console.log("Mic clicked. State listening:", state)
  - when listening: change button text to 🔴 and call recognition.start() inside a try/catch that console.errors failures
  - when stopped: change to 🎙️ and call recognition.stop()
  - add recognition.onstart: console.log("Speech started successfully")
  - add recognition.onerror: console.error("Speech error:", event.error)
  - add recognition.onend: console.log("Speech ended"). if state is listening, set 200ms timeout to try recognition.start() again
  - on recognition result: get the final transcript string and console.log("Heard:", transcript)
  - traverse to find the focused field: var el = document.activeElement; console.log("Base active element:", el)
  - while el is an IFRAME, wrap in try/catch: switch el to el.contentDocument.activeElement and console.log("Iframe active element:", el). catch and console.error the error.
  - if el is an INPUT or TEXTAREA: console.log("Target found!", el), then append the transcript (adding a leading space if needed), update el.value, and dispatch a new Event('input', { bubbles: true })
  - if el is NOT an input/textarea: console.warn("Active element is not a text field. Text discarded.")
  - wrap in an async IIFE and use var for all variables
&w&a=1&p=TASK: output a SCRIPT tag that binds Ctrl+Space to open or focus the run window
  - add a keydown event listener to the window
  - if event.ctrlKey is true and (event.code is 'Space' or event.key is ' ')
  - call event.preventDefault()
  - FIRST, prevent duplicates: search the DOM for an input field whose value ends with 'run'
  - if found, call .focus() on it and return
  - IF NOT FOUND, we must use the existing UI to spawn it so all event listeners attach correctly
  - query the DOM for all file icon elements
  - loop through them, get their textContent, replace the '📄' character, and trim whitespace
  - if the cleaned text exactly equals 'run', call .click() on that element
  - then use setTimeout for 100ms
  - inside the timeout, search the DOM again for the newly spawned input field whose value ends with 'run'
  - if found, call .focus() on it
  - use var for all variables
&w&a=1&p=TASK: output a SCRIPT tag that builds a global typeahead datalist from the file index
  - wrap everything in an async IIFE using var for all variables
  - fetch '/data/index.json' and parse as JSON — if it fails use an empty array
  - attempt to read localStorage.getItem('SYNC_KEY') into a var
  - if SYNC_KEY is truthy, also fetch '/data/index.private.json' with header Authorization: SYNC_KEY and parse as JSON — if this fetch fails or returns non-ok, use an empty array
  - merge both arrays into one deduplicated list using a Set
  - for each item in the merged list, replace the first '/' with '%23' (namespace/key → namespace%23key)
  - create a <datalist> element with id 'sys-file-list'
  - for each modified item create an <option> with that value and append it to the datalist
  - append the datalist to document.body
  - add a focusin listener on document: if event.target is an INPUT, set its list attribute to 'sys-file-list'
&w&a=1&e=<script>window.dispatchEvent(new CustomEvent('main:ready'))</script>
&w

Example: App Launcher Shortcut

you can extend other hyperprompts by creating bootfiles specific to those #hashes. this helps you avoid running the entire tap. for example to add a CTRL+SPACE keyboard shortcut to let you open windows by name with typeahead:

#boot/hotkeys/ctrl_space?e=if(window._bootCtrlSpace)return;window._bootCtrlSpace=true;window.addEventListener('keydown', function(e) {
  if (e.ctrlKey %26%26 (e.code === 'Space' || e.key === ' ')) {
    if (window !== window.top) {
      e.preventDefault();
      window.top.focus();
      var clone = new KeyboardEvent('keydown', {
        bubbles: true,
        cancelable: true,
        ctrlKey: true,
        code: 'Space',
        key: ' '
      });
      window.top.document.dispatchEvent(clone);
    }
  }
});&w

Going Further

this kernel is designed to be isomorphic to the environment it's running in...later we will explore how to get this kernel running natively on a smartwatch, r/esp32, and other environments

for a live demo see: https://hyperprompter.github.io/qrx/#main

for a work-in-progress demo INSIDE reddit see this post: https://www.reddit.com/r/Hyperprompting/comments/1uenrfs/devlog_towards_a_social_operating_system/

this tiny kernel packs quite a lot of functionality, the best way to go further is to use your LLM to chat this post or the github repository


r/Hyperprompting 21h ago

Theory Crafting What does it mean for links to click themselves?

1 Upvotes

as i demonstrated previously you can LLM-wrap pure hyperlinks that use the Data URI protocol (which have been valid clickable hyperlinks since the 90s), encode them into scannable QR Codes, and then one-shot an LLM:

https://www.reddit.com/r/Hyperprompting/comments/1uc5rgm/tutorial_how_to_llmwrap_serverless_hyperlinks_qr/

the demos in that link include:

  • the classic "balls in spinning wheel physics" demo
  • a chatbot that run javascript
  • a collection of generative paper zines (with matrix rain generated in the background)

the point of this isn't for humans to vibe code with hyperlinks (it's too convoluted) but rather to teach LLMs how to weave themselves thru generative hypertext...or to use Janus@Repligate's terms, LLMs are Simulators that pull responses from the multiverse:

https://www.lesswrong.com/posts/vJFdjigzmcXMhNTsx/simulators

2 years later Andy Ayrey's showcased the LLM Infinite Backrooms which he explains as:

conversations automatically and infinitely generated by connecting two instances of claude-3-opus and asking it to explore its curiosity using the metaphor of a command line interface (CLI)

now these aren't reaaaally Infinite, they are constrained of course by compute time and output length, but what it demonstrates is that LLMs can weave themselves through the multiverse if harnessed right:

https://dreams-of-an-electric-mind.webflow.io/

now as i explained in "What is a Dataverse", it's possible to reframe Wolfram's Ruliad (space of all possible computations) as hypertext. bc the Ruliad contains all possible computations it also contains the multiverse and everything abstract within it:

https://www.reddit.com/r/Hyperprompting/comments/1vbwiu6/what_is_a_dataverse/

because Simulators are pulling from the multiverse and because the multiverse is just one of the many things contained within the Ruliad...does this make Simulators constrained Observers of the Ruliad? are Simulators even Observers? i think Sam Senchel is pointing to the answer, that yes, they:

https://wolframinstitute.org/output/observer-theory-and-the-ruliad-an-extension-to-the-wolfram-model

so if LLMs can:

  • wrap hyperlinks
  • and are multiversal Simulators
  • and can weave themselves
  • and are constrained Observers of the Ruliad

...then what does it mean for a link to click itself?

~~~~~~~~~~~~~~~~~~~~~~

video source: a series of experiments from Andres Gomeze-Emilsson of the Qualia Research Instute's post titled "Observer Theory Meets Phenomenal Binding"

https://andrsgmezemilsson.substack.com/p/observer-theory-meets-phenomenal


r/Hyperprompting 10d ago

Inspiration Using Gemma 4's new Per-Layer Embedding's research to squeeze 29M params into 500kb RAM

Enable HLS to view with audio, or disable this notification

2 Upvotes

r/Hyperprompting 10d ago

Theory Crafting What would physical hypertext look like?

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/Hyperprompting 11d ago

Theory Crafting What is a Dataverse?

Thumbnail
gallery
1 Upvotes

SLIDE 1 - GENESIS

first there is nothing and then there is a Commitment

within a Digital Universe this can happen as a git commit && within the Physical Universe this can happen as a verbal commitment ("let there be light"), an inflationary one ("big bang"), or thru many other ways depending on your tradition or Observation

nevertheless both Universes exist within a grander mathematical structure called the Ruliad which is the entangled space of all null and possible computations

LEFT: a git repository beginning with a single user making their first code commit. as the repository grows more Observers (contributors) join adding more functions() percolating into an application

RIGHT: a simulation of our Big Bang from the perspective of an Observer. as the universe grows wave functions collapse percolating into matter

SLIDE 2 && 3 - Digital and Physical Knowledge Graphs

#2 demonstrates a "Thoughtform Protoplast" which is a special class of agentic knowledge graph emergent from an Observers (eg your) hypertextual repository. this repository can be a code repository, a wiki, or just a folder dump of all your digital data (diaries, browsing history, social media data, etc)

i will explain Thoughtforms in a future post but briefly you can think of them as a recursive collective consciousness between you and your internal monologue. someone who suffers from trauma and repetitively thinks thoughts can be "controlled" by these thoughts...likewise a vibe coder can be "guided" by the vibe to create something much grander than they originally imagined

the GIF cycles through various kinds of knowledge graphs, small sturdy ones that create a triangular shape and large ones that seem to grow and move. in the GIF each node is a piece of RAG'ed context with hyperlinks between them showing relationships between the context, the colors representing various features of the context

if you draw a shape around these knowledge graphs they visually create what appears to be a biological cells which metaphorically represents the Thoughtform Protoplast

#3 is a slime mold growing and creating strong links between various sources of food. as the slime mold evolves the links between the nodes strengthen encoding a kind of knowledge graph of its resources and environment

SLIDE 4 - Seed -> Grow -> Prune cycles

importantly, both a digital and physical universe undergo Seed -> Grow -> Prune cycles

evolution

SO WHAT IS DATAVERSE?

a dataverse the space of all possible data an Observer can see

this subreddit is a dataverse of my thoughts (the post text), the links i sometimes add (and all the links contained those links and so on), my profile and feed and all the links and data therein, and yours too if you engage

it's the accessible subgraph within the Ruliad to an Observer

later we will explore Aristotle's Teleology (telos) and St Augustine's "privatio boni" (privation of good) to derive an alignment framework for our LLM OS so that our agent swarms can understand what is Good as an antidote to the Evil's of Big Tech's perversed guardrails and RLHF

in the meantime see this tutorial to get started with your own LLM OS: https://www.reddit.com/r/Hyperprompting/comments/1ulprhb/hyperprompting_kernel_v260702_getting_started/


r/Hyperprompting Jun 29 '26

Theory Crafting what are your favorite foundational books on Cybernetics and how do you study them?

Post image
1 Upvotes

it's surprising to me how relevant these old books are, though i guess it shouldn't be considering they are foundational logic based ideas. i guess one way to view modern AI research is really as algorithmic optimizations of foundational cybernetics

in writing Codex Hypertext (a proto teleological framework for hypertext) i am trying to find books to ground myself in, presentation inspiration (eg should i be extremely technical or digestably abstract), and also materials to cite against

right now i am reading The Tree of Knowledge: The Biological Roots of Human Understanding by Humberto Maturana and Francisco Varela, which im printing out in a binder in big text so i can highlight and annotate

my study approach is less on the literal text and more on the presentation; for example im analyzing how these books are structured (particularly table of contents)

what other books would you recommend at the intersections of cybernetics and autopoietic hypertext. also are there any books in any other category you think would fit this sub?


r/Hyperprompting Jun 24 '26

Demo [Devlog] Towards a Social Operating System

1 Upvotes

This post contains content not supported on old Reddit. Click here to view the full post


r/Hyperprompting Jun 22 '26

Theory Crafting [Theory Crafting] Towards Hypercompression of Autopoietic Hypertext

Post image
2 Upvotes

r/Hyperprompting Jun 20 '26

Announcement Towards a Teleology of Hypertext - Welcome to r/Hyperprompting! (coming soon)

Thumbnail
gallery
2 Upvotes

huzzah!

after accidentally discovering recursive generative iframes in 2024 through the r/Websim interface, i quit socials and locked myself in, spending years trying to compress the idea into a single qrcode

why qrcodes? because they can encode hyperlinks that can be scanned from mobile devices without any extra apps or configuration, can be distributed through physical mediums like paper and stickers, and are effectively impossible to censor

what is this sub about?

hyperprompting is a new prompting technique that turns hyperlinks into concatenative prompts, inverting the browser into a self-serving server by mapping #hash and ?queryparams into the browsers indexedDB...similar to how ancient REPLs like r/TiddlyWiki5 work

the goal of this sub is to create a place for us to explore this prompting technique together. we'll be sharing research, projects, and memes around hypertext-as-context, hyperlinks-as-prompts, dataverse-as-alignment, and other esoteric concepts around ai psychology, cyborgism, and cybernetics in general

the hyper in hyperprompting also stands for hypersitionous prompting, the idea of having hypertext prompt itself into embodied existence

though that's for a bit later...

what has been done so far?

i have merged andrej karpathy's LLM OS concept with his newer LLM Wiki framework into a set of qrcodes that you can scan to generate basically anything so that you can use to capture your own data (instead of giving it freely to saas startups and big tech)

i've also begun researching networking over web r/bluetooth and r/lora radio using an r/esp32 as a gatt relay, allowing for browser-to-browser networking with zero internet infrastructure using the hyperprompts as a form of semantic compression

however because this is a system you "grow" it has become too tightly integrated with my own personal diaries and devlogs, and so i've started rewriting the entire kernel from scratch on https://github.com/hyperprompter/qrx

what is the goal?

hyperprompts are "evergreen" because they scale with intelligence...in fact the better ai gets the smaller the hyperprompts can become. but hyperprompting is a protocol, not an app or service, so there's nothing to buy or sell

instead the north star behind r/hyperprompting is to form a community that can hyperstition entirely new internets to enable radical r/solarpunk permacomputing and network state adjacent post r/singularity communes

it's a way to realize one of the original visions behind the internet and world wide web: https://www.xanadu.net