← Spreadsheet results

Spreadsheet

GPT 5.6 terra · typescript

Initial view of Spreadsheet

Browser check: Artifact runtime error. This is a technical check, not a quality review.

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 17,613 bytes · SHA-256 83b7a95dca49
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sheet — Formula Spreadsheet</title>
<style>
/* ── css: base ── */
*{box-sizing:border-box}html,body,#app{height:100%;margin:0}body{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#202124;background:#f8fafd}.sheet-app{height:100%;min-width:760px;display:flex;flex-direction:column;background:white}.topbar{height:58px;display:flex;align-items:center;gap:14px;padding:0 20px;border-bottom:1px solid #e5e9ef;background:#fff;flex:none}.brand{font-size:22px;font-weight:730;letter-spacing:-.7px;color:#1a73e8}.brand span{color:#fbbc04}.icon-btn{border:0;background:transparent;font-size:25px;color:#5f6368;padding:2px 7px}.file-name{font-size:15px;color:#3c4043;font-weight:500;white-space:nowrap}.saved{font-size:11px;font-weight:600;color:#188038;background:#e6f4ea;border-radius:10px;padding:3px 7px;margin-left:7px}.toolbar{margin-left:auto;display:flex;gap:8px}.toolbar button{height:30px;border:1px solid #d6dce5;border-radius:5px;background:#fff;color:#3c4043;font:600 12px inherit;padding:0 10px;cursor:pointer}.toolbar button:hover{border-color:#1a73e8;color:#1a73e8;background:#f4f8ff}.formula-area{height:46px;display:flex;align-items:center;padding:7px 20px;gap:10px;border-bottom:1px solid #dfe3e8;background:#fff;flex:none}.cell-ref{width:56px;text-align:center;font-size:13px;font-weight:650;color:#1a73e8;border-right:1px solid #e3e7eb;padding-right:10px}.fx{font-family:Georgia,serif;font-style:italic;font-size:18px;color:#5f6368;border-right:1px solid #e3e7eb;padding:0 10px 0 2px}#formulaInput{height:30px;min-width:0;flex:1;border:0;outline:0;font:14px ui-monospace,SFMono-Regular,Menlo,monospace;color:#202124;background:transparent}.grid-shell{flex:1;overflow:auto;position:relative;background:#fff}.statusbar{height:28px;flex:none;border-top:1px solid #e4e8ee;background:#f8fafd;padding:0 18px;display:flex;justify-content:space-between;align-items:center;color:#65717d;font-size:11px}table{border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:13px}th,td{height:25px;border-right:1px solid #e6e9ed;border-bottom:1px solid #e6e9ed;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}thead th{height:28px;position:sticky;top:0;z-index:3;background:#f8f9fa;color:#5f6368;font-size:12px;font-weight:600;text-align:center;border-bottom:1px solid #cfd5dc}th.corner{left:0;z-index:5;width:50px;min-width:50px;background:#f1f3f4}th.row-head{position:sticky;left:0;z-index:2;width:50px;min-width:50px;text-align:right;padding-right:10px;background:#f8f9fa;color:#69737d;font-size:11px;font-weight:500}td{width:112px;min-width:112px;padding:3px 7px;background:#fff;outline:none;cursor:cell;color:#202124}td.selected{position:relative;z-index:1;box-shadow:inset 0 0 0 2px #1a73e8;background:#f8fbff}td.editing{padding:0;box-shadow:inset 0 0 0 2px #1a73e8}td.editing input{width:100%;height:100%;padding:3px 7px;border:0;outline:0;font:13px ui-monospace,SFMono-Regular,Menlo,monospace;color:#202124;background:#fff}td.number{text-align:right;font-variant-numeric:tabular-nums}td.error{color:#d93025;font-weight:600}th.active-head{background:#e8f0fe;color:#1967d2}tr:last-child td,tr:last-child th{border-bottom:0}
</style>
</head>
<body>
<div class="sheet-app"><header class="topbar"><div class="brand">Sheet<span>•</span></div><button id="undoBtn" class="icon-btn" title="Undo" disabled="">↶</button><div class="file-name">Untitled spreadsheet <span class="saved" id="saveState">Saved</span></div><div class="toolbar"><button id="insertRowBtn">+ Row</button><button id="deleteRowBtn">− Row</button><button id="insertColBtn">+ Column</button><button id="deleteColBtn">− Column</button></div></header><section class="formula-area"><div id="cellRef" class="cell-ref">A1</div><div class="fx">fx</div><input id="formulaInput" aria-label="Formula bar" autocomplete="off" spellcheck="false" placeholder="Enter a value or formula"></section><main class="grid-shell"><table id="sheetGrid" aria-label="Spreadsheet grid"></table></main><footer class="statusbar"><span id="statusMessage">Ready</span><span>26 columns · 100 rows</span></footer></div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* Tunable constants */
const COLS = 26, ROWS = 100, STORAGE_KEY = 'sheet-formula-v1';
/* Address helpers */
const colName = (n) => String.fromCharCode(65 + n);
const idOf = (r, c) => `${colName(c)}${r + 1}`;
function pos(id) { const m = /^([A-Z])([1-9]\d*)$/.exec(id); return m ? { r: +m[2] - 1, c: m[1].charCodeAt(0) - 65 } : null; }
function valid(id) { const p = pos(id); return !!p && p.c < COLS && p.r < ROWS; }
function tokens(s) { const a = []; let i = 0; while (i < s.length) {
    if (/\s/.test(s[i])) {
        i++;
        continue;
    }
    const rest = s.slice(i), n = /^(?:\d+\.?\d*|\.\d+)/.exec(rest), ref = /^[A-Za-z][1-9]\d*/.exec(rest), word = /^[A-Za-z]+/.exec(rest);
    if (n) {
        a.push({ t: 'num', s: n[0] });
        i += n[0].length;
    }
    else if (ref) {
        a.push({ t: 'ref', s: ref[0].toUpperCase() });
        i += ref[0].length;
    }
    else if (word) {
        a.push({ t: 'word', s: word[0].toUpperCase() });
        i += word[0].length;
    }
    else if ('+-*/(),:'.includes(s[i])) {
        a.push({ t: s[i], s: s[i++] });
    }
    else
        throw Error('token');
} a.push({ t: 'end', s: '' }); return a; }
function parseFormula(raw) { const a = tokens(raw.slice(1)), deps = []; let i = 0; const eat = (t) => { if (a[i].t !== t)
    throw Error('parse'); return a[i++]; }; const expression = () => { let x = term(); while (a[i].t === '+' || a[i].t === '-') {
    const op = a[i++].t;
    x = { k: 'bin', op, l: x, r: term() };
} return x; }; const term = () => { let x = factor(); while (a[i].t === '*' || a[i].t === '/') {
    const op = a[i++].t;
    x = { k: 'bin', op, l: x, r: factor() };
} return x; }; const factor = () => { if (a[i].t === '-') {
    i++;
    return { k: 'un', x: factor() };
} if (a[i].t === 'num')
    return { k: 'num', v: +a[i++].s }; if (a[i].t === 'ref') {
    const x = eat('ref').s;
    if (a[i].t === ':') {
        i++;
        return { k: 'range', a: x, b: eat('ref').s };
    }
    return { k: 'ref', id: x };
} if (a[i].t === 'word') {
    const n = eat('word').s;
    eat('(');
    const args = [];
    if (a[i].t !== ')') {
        args.push(expression());
        while (a[i].t === ',') {
            i++;
            args.push(expression());
        }
    }
    eat(')');
    if (!['SUM', 'AVG', 'AVERAGE', 'MIN', 'MAX', 'COUNT'].includes(n))
        throw Error('function');
    return { k: 'fn', n, args };
} if (a[i].t === '(') {
    i++;
    const x = expression();
    eat(')');
    return x;
} throw Error('factor'); }; const ast = expression(); if (a[i].t !== 'end')
    throw Error('trailing'); return ast; }
function refs(ast, out = new Set()) { if (ast.k === 'ref')
    out.add(ast.id);
else if (ast.k === 'range') {
    const x = pos(ast.a), y = pos(ast.b);
    if (x && y)
        for (let r = Math.min(x.r, y.r); r <= Math.max(x.r, y.r); r++)
            for (let c = Math.min(x.c, y.c); c <= Math.max(x.c, y.c); c++)
                out.add(idOf(r, c));
    else {
        out.add(ast.a);
        out.add(ast.b);
    }
}
else if (ast.k === 'un')
    refs(ast.x, out);
else if (ast.k === 'bin') {
    refs(ast.l, out);
    refs(ast.r, out);
}
else if (ast.k === 'fn')
    ast.args.forEach(x => refs(x, out)); return out; }
/* Model, dependency graph and incremental recalculation */
const raw = new Map(), output = new Map(), asts = new Map(), dependents = new Map();
function rebuild() { asts.clear(); dependents.clear(); raw.forEach((v, id) => { if (v.startsWith('=')) {
    try {
        const ast = parseFormula(v);
        asts.set(id, ast);
        refs(ast).forEach(d => { let x = dependents.get(d); if (!x)
            dependents.set(d, x = new Set); x.add(id); });
    }
    catch { }
} }); }
function evalAst(ast, get) { const num = (z) => { if (z.error)
    return z; if (typeof z.value === 'number')
    return z; const n = Number(z.value); return z.value !== '' && !Number.isNaN(n) ? { value: n } : { value: NaN, error: '#ERR!' }; }; const vals = (x) => { if (x.k === 'range') {
    const a = pos(x.a), b = pos(x.b);
    if (!a || !b)
        return [{ value: '', error: '#REF!' }];
    const z = [];
    for (let r = Math.min(a.r, b.r); r <= Math.max(a.r, b.r); r++)
        for (let c = Math.min(a.c, b.c); c <= Math.max(a.c, b.c); c++)
            z.push(get(idOf(r, c)));
    return z;
} return [evalAst(x, get)]; }; if (ast.k === 'num')
    return { value: ast.v }; if (ast.k === 'ref')
    return get(ast.id); if (ast.k === 'range')
    return { value: '', error: '#ERR!' }; if (ast.k === 'un') {
    const x = num(evalAst(ast.x, get));
    return x.error ? x : { value: -x.value };
} if (ast.k === 'bin') {
    const l = num(evalAst(ast.l, get)), r = num(evalAst(ast.r, get));
    if (l.error)
        return l;
    if (r.error)
        return r;
    const lv = l.value, rv = r.value;
    if (ast.op === '/' && rv === 0)
        return { value: '', error: '#DIV/0!' };
    return { value: ast.op === '+' ? lv + rv : ast.op === '-' ? lv - rv : ast.op === '*' ? lv * rv : lv / rv };
} const all = ast.args.flatMap(vals); const bad = all.find(x => x.error); if (bad)
    return bad; const ns = all.map(x => typeof x.value === 'number' ? x.value : (x.value !== '' ? Number(x.value) : NaN)).filter(x => !Number.isNaN(x)); if (ast.n === 'COUNT')
    return { value: ns.length }; if (ast.n === 'SUM')
    return { value: ns.reduce((a, b) => a + b, 0) }; if (!ns.length)
    return { value: 0 }; if (ast.n === 'MIN')
    return { value: Math.min(...ns) }; if (ast.n === 'MAX')
    return { value: Math.max(...ns) }; return { value: ns.reduce((a, b) => a + b, 0) / ns.length }; }
function recalc(changed) { const impacted = new Set(); if (changed) {
    const q = [changed];
    while (q.length) {
        const x = q.pop();
        if (impacted.has(x))
            continue;
        impacted.add(x);
        dependents.get(x)?.forEach(y => q.push(y));
    }
}
else
    raw.forEach((_v, k) => impacted.add(k)); const state = new Map(), stack = [], cycle = new Set(); const calc = (id) => { if (!valid(id))
    return { value: '', error: '#REF!' }; if (!impacted.has(id))
    return output.get(id) ?? { value: raw.get(id) ?? '' }; const st = state.get(id) || 0; if (st === 2)
    return output.get(id); if (st === 1) {
    const at = stack.indexOf(id);
    stack.slice(at).forEach(x => cycle.add(x));
    return { value: '', error: '#CYCLE!' };
} state.set(id, 1); stack.push(id); const text = raw.get(id) ?? ''; let v; if (!text.startsWith('='))
    v = { value: text };
else {
    const ast = asts.get(id);
    if (!ast)
        v = { value: '', error: '#ERR!' };
    else
        v = evalAst(ast, calc);
} stack.pop(); if (cycle.has(id))
    v = { value: '', error: '#CYCLE!' }; output.set(id, v); state.set(id, 2); return v; }; impacted.forEach(calc); renderCells(); }
/* Grid UI and editing */
const table = document.querySelector('#sheetGrid'), formula = document.querySelector('#formulaInput'), refLabel = document.querySelector('#cellRef'), status = document.querySelector('#statusMessage');
let selected = 'A1', editor = null;
function makeGrid() { let html = '<thead><tr><th class="corner"></th>'; for (let c = 0; c < COLS; c++)
    html += `<th data-col="${c}">${colName(c)}</th>`; html += '</tr></thead><tbody>'; for (let r = 0; r < ROWS; r++) {
    html += `<tr><th class="row-head" data-row="${r}">${r + 1}</th>`;
    for (let c = 0; c < COLS; c++)
        html += `<td data-id="${idOf(r, c)}"></td>`;
    html += '</tr>';
} table.innerHTML = html + '<tbody>'; }
function show(v) { return v.error ?? (v.value === undefined ? '' : String(v.value)); }
function renderCells() { table.querySelectorAll('td[data-id]').forEach(td => { if (td.classList.contains('editing'))
    return; const id = td.dataset.id, v = output.get(id) ?? { value: raw.get(id) ?? '' }; td.textContent = show(v); td.className = ''; if (id === selected)
    td.classList.add('selected'); if (v.error)
    td.classList.add('error');
else if (typeof v.value === 'number' || (v.value !== '' && !Number.isNaN(Number(v.value))))
    td.classList.add('number'); }); refLabel.textContent = selected; formula.value = raw.get(selected) ?? ''; const p = pos(selected); table.querySelectorAll('th.active-head').forEach(x => x.classList.remove('active-head')); table.querySelector(`th[data-col="${p.c}"]`)?.classList.add('active-head'); table.querySelector(`th[data-row="${p.r}"]`)?.classList.add('active-head'); }
function select(id) { if (!valid(id))
    return; if (editor)
    commit(); selected = id; renderCells(); }
function save() { localStorage.setItem(STORAGE_KEY, JSON.stringify([...raw])); status.textContent = 'Saved'; }
function commit(value) { if (!editor && value === undefined)
    return; const v = value ?? editor.value; const old = raw.get(selected) ?? ''; if (v)
    raw.set(selected, v);
else
    raw.delete(selected); editor?.remove(); editor = null; rebuild(); recalc(selected); save(); if (old !== v)
    status.textContent = 'Recalculated'; }
function beginEdit(seed) { const td = table.querySelector(`td[data-id="${selected}"]`); if (editor)
    return; editor = document.createElement('input'); editor.value = seed ?? (raw.get(selected) ?? ''); td.textContent = ''; td.className = 'editing selected'; td.append(editor); editor.focus(); editor.setSelectionRange(editor.value.length, editor.value.length); editor.addEventListener('keydown', e => { if (e.key === 'Enter') {
    e.preventDefault();
    commit();
    move(1, 0);
}
else if (e.key === 'Tab') {
    e.preventDefault();
    commit();
    move(0, e.shiftKey ? -1 : 1);
}
else if (e.key === 'Escape') {
    editor?.remove();
    editor = null;
    renderCells();
} }); editor.addEventListener('blur', () => { if (editor)
    commit(); }); }
function move(dr, dc) { const p = pos(selected); select(idOf(Math.max(0, Math.min(ROWS - 1, p.r + dr)), Math.max(0, Math.min(COLS - 1, p.c + dc)))); }
table.addEventListener('mousedown', e => { const td = e.target.closest('td[data-id]'); if (td)
    select(td.dataset.id); });
table.addEventListener('dblclick', e => { const td = e.target.closest('td[data-id]'); if (td) {
    select(td.dataset.id);
    beginEdit();
} });
document.addEventListener('keydown', e => { if (editor || document.activeElement === formula)
    return; if (e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
    e.preventDefault();
    move(e.key === 'ArrowDown' ? 1 : e.key === 'ArrowUp' ? -1 : 0, e.key === 'ArrowRight' ? 1 : e.key === 'ArrowLeft' ? -1 : 0);
}
else if (e.key === 'Delete' || e.key === 'Backspace') {
    e.preventDefault();
    commit('');
}
else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey)
    beginEdit(e.key); });
formula.addEventListener('input', () => { raw.set(selected, formula.value); rebuild(); recalc(selected); save(); });
formula.addEventListener('keydown', e => { if (e.key === 'Enter') {
    e.preventDefault();
    formula.blur();
    move(1, 0);
} });
/* Structural editing: rewrite A1 references in every formula */
function rewrite(axis, at, del) { const rewriteText = (s) => s.replace(/\b([A-Z])([1-9]\d*)\b/g, (_m, letter, num) => { let c = letter.charCodeAt(0) - 65, r = +num - 1, n = axis === 'row' ? r : c; if (del && n === at)
    return '#REF!'; if (n > (at) || (!del && n >= at)) {
    if (axis === 'row')
        r += del ? -1 : 1;
    else
        c += del ? -1 : 1;
} return idOf(r, c); }); raw.forEach((v, k) => { if (v.startsWith('='))
    raw.set(k, rewriteText(v)); }); rebuild(); recalc(); save(); status.textContent = `${del ? 'Deleted' : 'Inserted'} ${axis}`; }
document.querySelector('#insertRowBtn').addEventListener('click', () => rewrite('row', pos(selected).r, false));
document.querySelector('#deleteRowBtn').addEventListener('click', () => rewrite('row', pos(selected).r, true));
document.querySelector('#insertColBtn').addEventListener('click', () => rewrite('col', pos(selected).c, false));
document.querySelector('#deleteColBtn').addEventListener('click', () => rewrite('col', pos(selected).c, true));
/* Startup persistence */
try {
    const saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
    saved.forEach(([k, v]) => { if (valid(k) && typeof v === 'string')
        raw.set(k, v); });
}
catch {
    localStorage.removeItem(STORAGE_KEY);
}
makeGrid();
rebuild();
recalc();
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"openai/gpt-5.6-terra","provider":"openrouter","persona":"typescript","sessionId":"6960bdcf-4b2f-48f9-9c8f-12ac386b1b16","tokensIn":595463,"tokensOut":13338,"tokensTotal":608801,"turns":44,"toolCalls":49,"failedToolCalls":1,"timestamp":"2026-07-31T17:48:24.459Z"} -->