-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerator.html
More file actions
102 lines (102 loc) · 8.04 KB
/
Copy pathgenerator.html
File metadata and controls
102 lines (102 loc) · 8.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hacky Generator - Create a bounded AI effect</title>
<meta name="description" content="Create a canonical Hacky v0.1 JSON file and one-page PDF carrier in your browser.">
<style>
:root { --bg:#0b0d12; --panel:#11151e; --panel2:#171d29; --line:#283244; --text:#f3f5f8; --muted:#9aa6b8; --accent:#8b7bff; --mint:#67e8c2; --red:#fb7185; --mono:ui-monospace,SFMono-Regular,Menlo,monospace; --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; }
* { box-sizing:border-box; } body { margin:0; background:var(--bg); color:var(--text); font:15px/1.55 var(--sans); }
a { color:#b5aaff; text-decoration:none; } .app { min-height:100vh; display:grid; grid-template-columns:360px 1fr; }
.sidebar { padding:25px; background:var(--panel); border-right:1px solid var(--line); } .top { display:flex; justify-content:space-between; align-items:center; margin-bottom:34px; }
.brand { color:var(--text); font:700 1rem var(--mono); } .mark { color:var(--mint); margin-right:7px; } .back { color:var(--muted); font-size:.82rem; }
h1 { margin:0 0 8px; font-size:1.55rem; letter-spacing:-.04em; } .intro { margin:0 0 26px; color:var(--muted); font-size:.88rem; }
label { display:block; margin:20px 0 7px; color:var(--muted); font:700 .7rem var(--mono); letter-spacing:.1em; text-transform:uppercase; }
input, textarea, select { width:100%; padding:10px 11px; color:var(--text); background:var(--panel2); border:1px solid var(--line); border-radius:8px; font:inherit; outline:0; }
input:focus, textarea:focus, select:focus { border-color:var(--accent); } textarea { min-height:120px; resize:vertical; }
.row { display:grid; grid-template-columns:1fr 100px; gap:10px; } .hint { margin:6px 0 0; color:var(--muted); font-size:.76rem; }
.button { display:inline-flex; justify-content:center; align-items:center; gap:7px; margin-top:22px; padding:11px 14px; border:1px solid var(--line); border-radius:8px; color:var(--text); background:var(--panel2); font-weight:700; cursor:pointer; }
.button.primary { width:100%; border-color:var(--accent); background:var(--accent); } .button:hover { filter:brightness(1.1); }
.main { padding:25px; overflow:auto; } .main-head { display:flex; align-items:center; justify-content:space-between; gap:18px; margin-bottom:20px; }
.status { color:var(--muted); font-size:.8rem; } .status.ok { color:var(--mint); } .status.bad { color:var(--red); }
.editor { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:18px; } .panel { min-width:0; border:1px solid var(--line); border-radius:12px; overflow:hidden; background:var(--panel); }
.panel-title { display:flex; justify-content:space-between; padding:11px 14px; color:var(--muted); background:var(--panel2); border-bottom:1px solid var(--line); font:700 .75rem var(--mono); }
#jsonEditor { min-height:500px; padding:18px; border:0; border-radius:0; background:#0b1018; font:.78rem/1.7 var(--mono); white-space:pre; }
#preview { min-height:500px; margin:0; padding:18px; overflow:auto; white-space:pre-wrap; word-break:break-word; color:#dce5f4; background:#0b1018; font:.78rem/1.7 var(--mono); }
.actions { display:flex; flex-wrap:wrap; gap:10px; margin-top:18px; } .actions .button { margin:0; } .error { min-height:1.5em; margin-top:13px; color:var(--red); font-size:.82rem; }
@media(max-width:900px) { .app { grid-template-columns:1fr; } .sidebar { border-right:0; border-bottom:1px solid var(--line); } }
@media(max-width:650px) { .editor { grid-template-columns:1fr; } .row { grid-template-columns:1fr 90px; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<div class="top"><a class="brand" href="index.html"><span class="mark">✦</span>Hacky</a><a class="back" href="index.html">← Home</a></div>
<h1>Create a Hacky</h1>
<p class="intro">Describe one bounded effect. The browser creates canonical four-key JSON and a safe one-page PDF carrier. Nothing is uploaded.</p>
<label for="name">Name</label>
<input id="name" maxlength="80" value="Example" placeholder="A short name">
<div class="row">
<div><label for="effect">Effect instructions</label><textarea id="effect">Write one clear, useful reply.</textarea></div>
<div><label for="turns">Replies</label><input id="turns" type="number" min="1" max="99" value="4"><p class="hint">1–99</p></div>
</div>
<label for="language">Activation language</label>
<select id="language"><option value="en">English (normative)</option><option value="ja">Japanese meaning-equivalent</option></select>
<button class="button primary" id="generate">Generate canonical Hacky</button>
<div class="error" id="error" role="alert"></div>
<p class="hint">The fixed lifecycle text is compiled by the public core. Edit only the effect field, then regenerate.</p>
</aside>
<main class="main">
<div class="main-head"><div><h1>Inspect before you attach</h1><div class="status" id="status">Ready</div></div><a class="button" href="https://github.com/openhacky/hacky/blob/main/spec/v0.1.md">Read the spec</a></div>
<div class="editor">
<section class="panel"><div class="panel-title"><span>canonical JSON</span><span id="size"></span></div><textarea id="jsonEditor" spellcheck="false" aria-label="Canonical Hacky JSON"></textarea></section>
<section class="panel"><div class="panel-title"><span>rendered activation</span><button class="close" id="copy">Copy</button></div><pre id="preview"></pre></section>
</div>
<div class="actions"><button class="button primary" id="downloadPdf">Download .hacky.pdf</button><button class="button" id="downloadJson">Download .hacky.json</button><button class="button" id="copyJson">Copy JSON</button></div>
<p class="hint">Canonical JSON is BOMless UTF-8, compact, fixed-order, and ends with exactly one LF. The PDF has one 1800 × 1800 page, a 16 × 16 dot carrier, invisible canonical text, and no bytes after <code>%%EOF</code>.</p>
</main>
</div>
<script src="hacky-pdf.js"></script>
<script>
var current = null
var $ = function (id) { return document.getElementById(id) }
function setError(message) { $('error').textContent = message || ''; $('status').textContent = message ? 'Needs attention' : 'Valid Hacky v0.1'; $('status').className = 'status ' + (message ? 'bad' : 'ok') }
function build() {
try {
var name = $('name').value
var turns = Number($('turns').value)
var effect = $('effect').value
current = hackyPack(name, turns, effect, $('language').value)
var json = hackyStringify(current)
$('jsonEditor').value = json
$('preview').textContent = current.instructions
$('size').textContent = new TextEncoder().encode(json).length + ' bytes'
setError('')
} catch (error) {
current = null
setError(error.message)
}
}
function edited() {
try {
current = hackyLoad($('jsonEditor').value)
$('preview').textContent = current.instructions
$('size').textContent = new TextEncoder().encode($('jsonEditor').value).length + ' bytes'
setError('')
} catch (error) { setError(error.message) }
}
function saveBlob(blob, filename) {
var link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = filename; link.click(); URL.revokeObjectURL(link.href)
}
$('generate').addEventListener('click', build)
;['name','turns','effect','language'].forEach(function (id) { $(id).addEventListener('input', build); $(id).addEventListener('change', build) })
$('jsonEditor').addEventListener('input', edited)
$('downloadPdf').addEventListener('click', function () { if (current) saveBlob(hackyPdfBlob(current), hackyPdfFilename(current.name)) })
$('downloadJson').addEventListener('click', function () { if (current) saveBlob(new Blob([hackyStringify(current)], { type:'application/json' }), current.name.replace(/[\\/:*?"<>|]/g, '').trim() + '.hacky.json') })
$('copyJson').addEventListener('click', function () { if (current) navigator.clipboard.writeText(hackyStringify(current)) })
$('copy').addEventListener('click', function () { if (current) navigator.clipboard.writeText(current.instructions) })
build()
</script>
</body>
</html>