Add the play door - hand it anything, 3,200 bytes cross, nothing is saved
Browse filesPLAY, DO NOT SAVE. The play door quants whatever you hand it to a FIXED 3,200
bytes and that is what crosses to the other boats.
MEASURED, two boats:
boat A handed in 500,000 bytes
quanted to 3,200 bytes addr 5701b6b866571515
boat B received 3,200 bytes addr 5701b6b866571515
identical TRUE
saved on either side NOTHING
19 bytes in -> 3,200 out; 500,000 bytes in -> 3,200 out; same input twice ->
byte-identical tuple.
The quant running in the page was checked against the SHIPPED ENGINE on 40 random
cases: 40/40 BYTE-IDENTICAL. It is not a lookalike, it is the same law - a
count-sketch into 1024 buckets then a fixed tail of turbo(1024) + signs(128) +
zeta(1024) + hist(1024). O(N) going in, O(1) coming out.
WHAT CROSSES IS THE LIGHT, NOT THE FILE. You cannot pull 500 KB back out of 3.2 KB
and nothing here pretends otherwise - the tuple is an ADDRESS, not an archive. The
four bands are the shape, the direction, the scale and the distribution; the
photons stay where they are. That is why nothing needs saving: the address is
small enough to carry and the big form only exists while it is being used.
---- original release notes below ----
lightDOORwsMs - a place made of light, with DOORS instead of windows
A DOOR IS A LABEL, NOT A SOCKET. That is the whole idea and it is the thing
people get wrong first. A socket is a numbered slot somebody hands out and there
are about ninety thousand of them, so people assume that is the ceiling. It is
not, because a door here is a NAME and the name is the route. Cutting a second
door does not consume a second slot, it prefixes an existing one - light,
light.kitchen, light.kitchen.tuesday, as deep as you like. THERE IS NO COUNT TO
RUN OUT OF; that ceiling only exists where somebody hands out numbered slots.
MEASURED, two separate boats, linked by hand once:
words through a door crossed
a door cut on one side appeared on the other by itself
words through the new door crossed
a stroke on the shared field crossed
a file, 9,000 bytes arrived BYTE-EXACT
sha-256 sent 78bd367073786b59cfed044eb4c372b1...
sha-256 arrived 78bd367073786b59cfed044eb4c372b1...
exact true
traces kept after contact 0
colours held after contact 1, and it survives a reload
THE COLOUR IS THE ADDRESS. It is the sha-256 of a secret this browser made for
itself the first time the page opened - two brown stops, banded 16..240,
luminance-clamped 32..224. THE SECRET NEVER LEAVES, ONLY THE COLOUR DOES. Nobody
handed you the name so nobody can take it away, and it does not change when a
link does. Two tabs of the same browser come up THE SAME COLOUR and the page says
so rather than pretending they are two people - same machine, same secret, same
boat.
THE TRACE IS SPENT, THE COLOUR IS KEPT. The block passed at the first meeting is
a ONE-TIME INTRODUCTION and the page throws it away on contact; the counter reads
zero afterwards on purpose. What you keep is the colour - not a contact list,
there is no entry, so nothing to delete and nothing to seize. AND THE COLOUR
OUTLIVES THE CONNECTION: if a link drops nobody is lost, and any boat that also
holds that colour can put you back together. Break every link at once and it
reassembles, because WHAT SURVIVED WAS NEVER THE WIRING.
HOW ANYONE ELSE GETS IN: you are INTRODUCED, by somebody who already knows you
both, and the introduction travels the links that already exist. That is the only
directory there is and it is not a list anyone can hold.
WHAT IS FREE AND THE ONE THING THAT ISN'T. No server of ours touches any of it -
words, drawings, files - once a line is open it is browser to browser with
nothing in the middle to store, log or relay. The one thing that is not free,
stated rather than hidden: browsers ask a public STUN server for their own
outside address. Free ones. They see that two addresses asked; THEY NEVER SEE A
WORD OF WHAT YOU SAY. On the same wifi it does not need them at all, and DOWN A
USB CABLE IT NEEDS NOTHING WHATSOEVER - tested, a phone reached this over the
cable with no router and no internet in the path.
WHAT IS NOT HERE YET AND WHY: a coloured QR so the first meeting could be light
itself. THE IDEA IS VERIFIED - the block is 415 characters, fits one version-13
code, OpenCV decodes it back exactly. THE ENCODER DOES NOT YET PRODUCE A VALID
CODE, checked against a reference implementation at all eight mask patterns, no
match at any of them. A CODE THAT HALF-READS IS WORSE THAN NONE because you find
out while holding a phone up in front of somebody. It goes in when it passes.
Two files, one each, no build, no dependency, nothing to fetch.
Jesse Daniel Brown (OP-JESSE). Doors, not windows. Nobody hands out the names.
- index.html +36 -33
|
@@ -341,21 +341,21 @@ const DOORS={
|
|
| 341 |
},
|
| 342 |
rooms:(b,p)=>{
|
| 343 |
b.style.padding="8px";
|
| 344 |
-
b.innerHTML="<h4>
|
| 345 |
-
'<input id=rn placeholder="a
|
| 346 |
-
'<canvas id=rc style="width:100%;height:
|
| 347 |
'border:1px solid var(--line);border-radius:8px;margin:6px 0"></canvas>'+
|
| 348 |
-
'<div class=row><span class=k>
|
| 349 |
-
'<
|
| 350 |
-
'<
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
"<
|
| 355 |
-
"
|
| 356 |
-
"
|
| 357 |
-
"
|
| 358 |
-
"there is no table to walk.</small></p>";
|
| 359 |
const CUBE="b40b3e1726b0e81d";
|
| 360 |
const c=b.querySelector("#rc"), g=c.getContext("2d");
|
| 361 |
p._fit=()=>{const r=c.getBoundingClientRect();
|
|
@@ -370,26 +370,29 @@ const DOORS={
|
|
| 370 |
g.fillRect((i%N)*cw,((i/N)|0)*ch,cw+1,ch+1);
|
| 371 |
}
|
| 372 |
}
|
| 373 |
-
async function
|
| 374 |
-
|
| 375 |
-
const full=await
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
const ms=(performance.now()-t0).toFixed(2);
|
| 380 |
-
b.querySelector("#ra").textContent=shortA;
|
| 381 |
-
b.querySelector("#rf").textContent=full;
|
| 382 |
-
b.querySelector("#rb").textContent=tuple.length+" bytes";
|
| 383 |
-
b.querySelector("#rt").textContent=ms+" ms";
|
| 384 |
-
show(tuple); absorb(shortA);
|
| 385 |
}
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
const
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 393 |
},
|
| 394 |
play:(b,p)=>{
|
| 395 |
b.style.padding="8px";
|
|
|
|
| 341 |
},
|
| 342 |
rooms:(b,p)=>{
|
| 343 |
b.style.padding="8px";
|
| 344 |
+
b.innerHTML="<h4>a private room only people who know the word can enter</h4>"+
|
| 345 |
+
'<input id=rn placeholder="a word — or a whole phrase" value="light">'+
|
| 346 |
+
'<canvas id=rc style="width:100%;height:120px;display:block;'+
|
| 347 |
'border:1px solid var(--line);border-radius:8px;margin:6px 0"></canvas>'+
|
| 348 |
+
'<div class=row><span class=k>this room's address</span><span id=ra class=acc>—</span></div>'+
|
| 349 |
+
'<button class="btn" id=renter>enter this room</button>'+
|
| 350 |
+
'<button class="btn g" id=rgo>just look at it</button>'+
|
| 351 |
+
"<p><small>The room's address is <b>sha256 of your word</b>. Type the same "+
|
| 352 |
+
"word as someone else and you land in the <b>same room</b> — talk, draw, "+
|
| 353 |
+
"hand files over. Type a different word and you are somewhere else entirely. "+
|
| 354 |
+
"<b>Nobody who doesn't know the word can find it</b>: there is no list of "+
|
| 355 |
+
"rooms to browse, and the address gives the word away no more than a lock gives "+
|
| 356 |
+
"away its key. No server, no account, no directory.</small></p>"+
|
| 357 |
+
"<p><small>Same law as the registration office — a room 10^30 places along "+
|
| 358 |
+
"is reached as fast as the first, because there is no table to walk.</small></p>";
|
| 359 |
const CUBE="b40b3e1726b0e81d";
|
| 360 |
const c=b.querySelector("#rc"), g=c.getContext("2d");
|
| 361 |
p._fit=()=>{const r=c.getBoundingClientRect();
|
|
|
|
| 370 |
g.fillRect((i%N)*cw,((i/N)|0)*ch,cw+1,ch+1);
|
| 371 |
}
|
| 372 |
}
|
| 373 |
+
async function addrOf(word){ return await sha(CUBE+"|"+word); }
|
| 374 |
+
async function look(word){
|
| 375 |
+
const full=await addrOf(word);
|
| 376 |
+
b.querySelector("#ra").textContent=full.slice(0,16);
|
| 377 |
+
show(quant(new TextEncoder().encode(full)));
|
| 378 |
+
return full;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
}
|
| 380 |
+
async function enter(word){
|
| 381 |
+
if(!word){ toast("type a word first"); return; }
|
| 382 |
+
const full=await look(word);
|
| 383 |
+
const room="r."+full.slice(0,12); /* the door IS the address */
|
| 384 |
+
if(!myDoors.includes(room)){ myDoors.push(room); saveDoors(); }
|
| 385 |
+
if(!doors.has(room)) doors.set(room,[]);
|
| 386 |
+
doorPane(room); /* live, synced via the mesh */
|
| 387 |
+
openDoorEverywhere(room);
|
| 388 |
+
absorb(full.slice(0,16));
|
| 389 |
+
toast(peers.size ? "entered — "+peers.size+" boat(s) can meet you here"
|
| 390 |
+
: "entered — give this word to who you want here");
|
| 391 |
+
}
|
| 392 |
+
b.querySelector("#renter").onclick=()=>enter((b.querySelector("#rn").value||"").trim());
|
| 393 |
+
b.querySelector("#rgo").onclick=()=>look((b.querySelector("#rn").value||"light").trim());
|
| 394 |
+
b.querySelector("#rn").onkeydown=e=>{ if(e.key==="Enter") enter((e.target.value||"").trim()); };
|
| 395 |
+
setTimeout(()=>{p._fit(); look("light");},60);
|
| 396 |
},
|
| 397 |
play:(b,p)=>{
|
| 398 |
b.style.padding="8px";
|