Public
Edited
Sep 23, 2023
Importers
Insert cell
Insert cell
previewSlide({
width: 1920, height: 1080, timeMin: 0, timeMax: 35, duration: 10,
render(time, ctx) {
$.anim.time = time;
const {width, height} = this;
ctx.globalAlpha = 1;
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = 'white';
ctx.font = '20px monospace';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.fillText($.camera.scene, 10, 10);
ctx.save();
rect.camera($.camera.rect, ctx, 1080);
for (const r of Object.values($.sr)) {
r.draw(ctx);
}
for (const item of $.ssr) {
for (const r of Object.values(item)) {
r.draw(ctx);
}
}
ctx.restore();
},
}, 500)
Insert cell
previewFrame({
width: 1920, height: 1080, timeMin: 0, timeMax: 0, duration: 0,
render(ctx) {
const {width, height} = this;
ctx.globalAlpha = 1;
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, width, height);
ctx.save();
rect.camera(rect.relPad(rect.bbox([$.comp.posVec(5), $.comp.keyVec(5)]), -0.1), ctx, 1080);
for (let col=0; col<10; col++) {
drawRect(ctx, $.comp.posLabel(col));
drawRect(ctx, $.comp.posVec(col));
drawRect(ctx, $.comp.inWordLabel(col));
drawRect(ctx, $.comp.inWordVec(col));
drawRect(ctx, $.comp.inVec(col));
// drawRect(ctx, $.comp.attnVec(col));
drawRect(ctx, $.comp.valueVec(col));
drawRect(ctx, $.comp.keyVec(col));
drawRect(ctx, $.comp.queryVec(col));
if (col === 5) {
for (let row=0; row<=col; row++) {
drawRect(ctx, $.comp.storedValueVec(col, row));
drawRect(ctx, $.comp.storedKeyVec(col, row));
drawRect(ctx, $.comp.storedQueryVec(col, row));
}
}
drawRect(ctx, $.comp.neuroInVec(col));
drawRect(ctx, $.comp.neuroMidVec(col));
drawRect(ctx, $.comp.neuroOutVec(col));
}
ctx.restore();
},
}, 500)
Insert cell
$ = {
const comp = new Composition();
const anim = new Anim();
const camRatioRect = [0, 0, 1920, 1080];
const camera = anim.wrap({scene: '0', rect: [0, 0, 10, 10]});
const col = 5;
const sr = makeRects(comp, anim, col);
const ssr = makeStoredRects(comp, anim, col);
anim.reset();

anim.time = 0;
camera.scene = '0';
sr.posLabel.opacity = 1;
sr.posVec.opacity = 1;
sr.inWordVec.opacity = 1;
sr.inWordLabel.opacity = 1;
sr.inVec.opacity = 0;
sr.inVec.rect = sr.inVec.rect;
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
sr.posLabel.rect,
sr.inVec.rect,
]), -0.1));
sr.posVec.rect = sr.posVec.rect;

anim.time += 1;
camera.scene = '10';
sr.posVec.rect = sr.posVec.rect;
sr.inWordVec.rect = sr.inWordVec.rect;

anim.time += 1;
camera.scene = '20';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
sr.posLabel.rect,
sr.inVec.rect,
]), -0.1));
sr.inVec.rect = sr.inVec.rect;
sr.posVec.rect = sr.inVec.rect;
sr.inWordVec.rect = sr.inVec.rect;
sr.posVec.opacity = 1;
sr.inWordVec.opacity = 1;
sr.inVec.opacity = 0;

anim.time += 1;
camera.scene = '30';
sr.posVec.rect = sr.inVec.rect;
sr.inWordVec.rect = sr.inVec.rect;
sr.inVec.opacity = 1;
sr.posVec.opacity = 0;
sr.inWordVec.opacity = 0;
sr.posLabel.opacity = 1;
sr.inWordLabel.opacity = 1;

anim.time += 1;
camera.scene = '40';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
sr.posLabel.rect,
sr.inVec.rect,
]), -0.1));
sr.posVec.rect = sr.inVec.rect;
sr.inWordVec.rect = sr.inVec.rect;
sr.inVec.opacity = 1;
sr.posVec.opacity = 0;
sr.inWordVec.opacity = 0;
sr.posLabel.opacity = 1;
sr.inWordLabel.opacity = 1;
// sr.attnVec.opacity = 0;
// sr.attnVec.rect = sr.inVec.rect;

anim.time += 1;
camera.scene = '50';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
sr.inVec.rect,
sr.queryVec.rect,
]), -0.1));
// sr.attnVec.opacity = 1;
// sr.attnVec.rect = sr.inVec.rect;
sr.keyVec.opacity = 0;

anim.time += 1;
camera.scene = '60';
// sr.attnVec.opacity = 1;
// sr.attnVec.rect = sr.attnVec.rect;
sr.keyVec.opacity = 0;
sr.valueVec.opacity = 0;

anim.time += 2;
camera.scene = '70';
sr.keyVec.opacity = 1;
sr.queryVec.opacity = 0;

anim.time += 2;
camera.scene = '80';
sr.keyVec.opacity = 1;
sr.queryVec.opacity = 1;
sr.valueVec.opacity = 0;
anim.time += 4;
camera.scene = '90';
sr.valueVec.opacity = 1;
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
sr.inVec.rect,
sr.queryVec.rect,
]), -0.1));
sr.keyVec.opacity = 1;
// sr.attnVec.opacity = 1;
sr.queryVec.opacity = 1;
sr.inVec.opacity = 1;
sr.posVec.opacity = 0;
sr.inWordVec.opacity = 0;
sr.posLabel.opacity = 1;
sr.inWordLabel.opacity = 1;

anim.time += 2;
camera.scene = '100';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
sr.inVec.rect,
sr.queryVec.rect,
]), -0.1));
sr.keyVec.opacity = 1;
sr.queryVec.opacity = 1;
sr.queryVec.rect = sr.queryVec.rect;
sr.valueVec.opacity = 1;
// sr.attnVec.opacity = 0;
sr.inVec.opacity = 0;
sr.posVec.opacity = 0;
sr.inWordVec.opacity = 0;
sr.posLabel.opacity = 0;
sr.inWordLabel.opacity = 0;
ssr.forEach(item => {
item.storedValueVec.opacity = 0;
item.storedQueryVec.opacity = 0;
item.storedKeyVec.opacity = 0;
item.storedQueryVec.rect = sr.queryVec.rect;
});

anim.time += 2;
camera.scene = '110';
ssr.forEach((item, num) => {
item.storedValueVec.opacity = num < col ? 1 : 0;
item.storedKeyVec.opacity = num < col ? 1 : 0;
item.storedQueryVec.opacity = 1;
item.storedQueryVec.rect = sr.queryVec.rect;
});
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
ssr[0].storedValueVec.rect,
ssr.at(-1).storedQueryVec.rect,
ssr.at(-1).storedKeyVec.rect,
sr.queryVec.rect,
]), -0.1));
sr.valueVec.rect = sr.valueVec.rect;
sr.keyVec.rect = sr.keyVec.rect;
anim.time += 2;
camera.scene = '120';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
ssr[0].storedValueVec.rect,
ssr.at(-1).storedQueryVec.rect,
ssr.at(-1).storedKeyVec.rect,
sr.queryVec.rect,
]), -0.1));
ssr.forEach((item, num) => {
item.storedValueVec.opacity = num < col ? 1 : 0;
item.storedKeyVec.opacity = num < col ? 1 : 0;
item.storedQueryVec.opacity = 1;
item.storedQueryVec.rect = sr.queryVec.rect;
});
sr.keyVec.opacity = 1;
sr.queryVec.opacity = 1;
sr.valueVec.opacity = 1;
sr.valueVec.rect = ssr[col].storedValueVec.rect;
sr.keyVec.rect = ssr[col].storedKeyVec.rect;

anim.time += 2;
camera.scene = '130';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
ssr[0].storedValueVec.rect,
ssr.at(-1).storedQueryVec.rect,
ssr.at(-1).storedKeyVec.rect,
sr.queryVec.rect,
]), -0.1));
sr.valueVec.opacity = 1;
sr.keyVec.opacity = 1;
sr.queryVec.opacity = 0;
sr.queryVec.rect = sr.queryVec.rect;
ssr.forEach((item, num) => {
item.storedValueVec.opacity = num < col ? 1 : 0;
item.storedKeyVec.opacity = num < col ? 1 : 0;
item.storedQueryVec.opacity = 1;
item.storedQueryVec.rect = item.storedQueryVec.rect;
});

anim.time += 2;
camera.scene = '140';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
ssr[0].storedValueVec.rect,
ssr.at(-1).storedQueryVec.rect,
ssr.at(-1).storedKeyVec.rect,
sr.queryVec.rect,
]), -0.1));
sr.queryVec.rect = sr.queryVec.rect;
ssr.forEach((item, num) => {
item.storedValueVec.opacity = 1;
item.storedKeyVec.opacity = 1;
item.storedQueryVec.opacity = 1;
item.storedQueryVec.rect = item.storedQueryVec.rect;
});
sr.keyVec.opacity = 0;
sr.valueVec.opacity = 0;
sr.queryVec.opacity = 0;

anim.time += 2;
camera.scene = '150';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
ssr[col].storedKeyVec.rect,
ssr[col].storedQueryVec.rect,
]), -0.1));
ssr.forEach((item, num) => {
item.storedQueryVec.rect = item.storedQueryVec.rect;
item.storedValueVec.opacity = 1;
item.storedKeyVec.opacity = 1;
item.storedQueryVec.opacity = 1;
});

anim.time += 2;
camera.scene = '160';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
ssr[col].storedKeyVec.rect,
ssr[col].storedQueryVec.rect,
]), -0.1));
ssr.forEach((item, num) => {
item.storedQueryVec.rect = item.storedQueryVec.rect;
item.storedValueVec.opacity = 1;
item.storedKeyVec.opacity = 1;
item.storedQueryVec.opacity = 1;
});

anim.time += 2;
camera.scene = '170';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
ssr[0].storedValueVec.rect,
ssr.at(-1).storedQueryVec.rect,
ssr.at(-1).storedKeyVec.rect,
sr.queryVec.rect,
]), -0.1));
ssr.forEach((item, num) => {
item.storedQueryVec.rect = item.storedQueryVec.rect;
item.storedValueVec.opacity = 1;
item.storedKeyVec.opacity = 1;
item.storedQueryVec.opacity = 1;
});

anim.time += 4;
camera.scene = '180';
camera.rect = rect.outscribe(camRatioRect, rect.relPad(rect.bbox([
ssr[0].storedValueVec.rect,
ssr.at(-1).storedQueryVec.rect,
ssr.at(-1).storedKeyVec.rect,
sr.queryVec.rect,
]), -0.1));
ssr.forEach((item, num) => {
item.storedQueryVec.rect = item.storedQueryVec.rect;
item.storedValueVec.opacity = 1;
item.storedKeyVec.opacity = 1;
item.storedQueryVec.opacity = 1;
});

anim.time += 2;
camera.scene = '190';
sr.valueVec.rect = ssr[col].storedValueVec.rect;
sr.keyVec.rect = ssr[col].storedKeyVec.rect;
sr.queryVec.rect = ssr[col].storedQueryVec.rect;
sr.keyVec.opacity = 0;
sr.queryVec.opacity = 0;
sr.valueVec.opacity = 0;
// sr.attnVec.opacity = 0;
sr.inVec.opacity = 0;
sr.posVec.opacity = 0;
sr.inWordVec.opacity = 0;
sr.posLabel.opacity = 0;
sr.inWordLabel.opacity = 0;
return {
anim,
camera,
comp,
sr,
ssr,
}
}
Insert cell
Insert cell
function makeRect(anim, rect) {
return anim.wrap({
rect,
opacity: 0,
draw(ctx) {
ctx.globalAlpha = this.opacity;
drawRect(ctx, this.rect);
ctx.globalAlpha = 1;
}
})
}
Insert cell
function makeRects(comp, anim, col) {
const mr = rect => makeRect(anim, rect);
return {
posLabel: mr(comp.posLabel(col)),
posVec: mr(comp.posVec(col)),
inWordLabel: mr(comp.inWordLabel(col)),
inWordVec: mr(comp.inWordVec(col)),
inVec: mr(comp.inVec(col)),
// attnVec: mr(comp.attnVec(col)),
valueVec: mr(comp.valueVec(col)),
keyVec: mr(comp.keyVec(col)),
queryVec: mr(comp.queryVec(col)),
neuroInVec: mr(comp.neuroInVec(col)),
neuroMidVec: mr(comp.neuroMidVec(col)),
neuroOutVec: mr(comp.neuroOutVec(col)),
}
}
Insert cell
function makeStoredRects(comp, anim, col) {
const mr = rect => makeRect(anim, rect);
return new Array(col + 1).fill(0).map((_, row) => ({
storedValueVec: mr(comp.storedValueVec(col, row)),
storedKeyVec: mr(comp.storedKeyVec(col, row)),
storedQueryVec: mr(comp.storedQueryVec(col, row)),
}));
}
Insert cell
class Composition {
neuroInVec(col) {
const x0 = col * colWidth;
const y0 = 800;
return [x0, y0, vecWidth, vecHeight, `neuroIn #${col}`];
}
neuroMidVec(col) {
const x0 = col * colWidth;
const y0 = 1000;
return [x0, y0, vecWidth, vecHeight, `neuroMid #${col}`];
}
neuroOutVec(col) {
const x0 = col * colWidth;
const y0 = 1200;
return [x0, y0, vecWidth, vecHeight, `neuroOut #${col}`];
}
storedValueVec(col, row) {
const res = rect.centeredAroundPt(
[0, 0, vecWidth, vecHeight],
vec.add(
rect.center(this.valueVec(col)),
[-250, -100 - (col - row) * 180],
),
);
return [...res, `sval #${col}/${row}`];
}
storedKeyVec(col, row) {
const res = rect.centeredAroundPt(
[0, 0, shortVecWidth, vecHeight],
vec.add(
rect.center(this.valueVec(col)),
[800, -100 - (col - row) * 180],
),
);
return [...res, `skey #${col}/${row}`];
}
storedQueryVec(col, row) {
const res = rect.centeredAroundPt(
[0, 0, shortVecWidth, vecHeight],
vec.add(
rect.center(this.valueVec(col)),
[800, -100 - (col - row) * 180 + 80],
),
);
return [...res, `squery #${col}/${row}`];
}
valueVec(col) {
const x0 = col * colWidth;
const y0 = 800;
return [x0, y0, vecWidth, vecHeight, `value #${col}`];
}
keyVec(col) {
const res = rect.centeredAroundPt(
[0, 0, shortVecWidth, vecHeight],
vec.add(
rect.center(this.inVec(col)),
[-300, 300],
),
);
return [...res, `key #${col}`];
}
queryVec(col) {
const res = rect.centeredAroundPt(
[0, 0, shortVecWidth, vecHeight],
vec.add(
rect.center(this.inVec(col)),
[300, 300],
),
);
return [...res, `query #${col}`];
}
// attnVec(col) {
// const x0 = col * colWidth;
// const y0 = 800;
// return [x0, y0, vecWidth, vecHeight, `attn #${col}`];
// }
posVec(col) {
const x0 = col * colWidth;
const y0 = 0;
return [x0, y0, vecWidth, vecHeight, `pos #${col}`];
}
posLabel(col) {
const x0 = col * colWidth;
const y0 = 0;
const res = rect.centeredAroundPt(
[0, 0, 250, 150],
utils.vec.sub(
rect.center(this.posVec(col)),
[0, 120],
),
);
return [...res, `#${col}`];
}
inWordVec(col) {
const x0 = col * colWidth;
const y0 = 400;
return [x0, y0, vecWidth, vecHeight, `word #${col}`];
}
inWordLabel(col) {
const x0 = col * colWidth;
const y0 = 0;
const res = rect.centeredAroundPt(
[0, 0, 500, 150],
utils.vec.sub(
rect.center(this.inWordVec(col)),
[0, 120],
),
)
return [...res, `word ${col}`];
}
inVec(col) {
const x0 = col * colWidth;
const y0 = 600;
return [x0, y0, vecWidth, vecHeight, `in #${col}`];
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function drawRect(ctx, [x0, y0, w, h, label]) {
ctx.strokeStyle = 'white';
ctx.lineWidth = 2;
ctx.strokeRect(x0, y0, w, h);
ctx.fillStyle = 'white';
ctx.font = `${h * 0.8}px monospace`;
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
const [cx, cy] = [x0 + w / 2, y0 + h / 2];
ctx.fillText(label || '', cx, cy);
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more