art
August 26 2023
Hearthstone Battlegrounds has this knack, it's sticky.
Hearthstone Battlegrounds has this knack, it's sticky. Twice, you place seventh. Tough luck, you think. Two rounds straight, both no cigar. Your mind tickles towards, what's the point? A whisper of giving it up. Then, bam, you land first or second. Pride swells. A soft glow envelops you. You're hooked. You want more. You can't stop.
These fuckers at Blizzard really nailed the Gambler's Fallacy lmao.
But unlike the casino where the house always wins, no one wins (outside of useless MMR)
never forget sora chopping actual buildings in half like tofu
August 25 2023
and perhaps a discord was born?
Mulling over a comfy spot for my small projects, I had a twinkling—Discord could be it. Each bot could handle its own chore, instead of firing up a whole stack.
The good parts are clear as day:
- It works with mobile and desktop.
- Any user could get chummy with their own curated list of bots.
- No need to craft baffling UIs for mainly, well, text-based tasks—like function calls or database lookups.
- I've long since resolved that the output of p5 makes more sense as pictures or movies than code for end users—unless someone wants to sow their own seed data for an image, I can manage that with bots as well.
- A community? I could grow one.
- Channel-specific invites, they're a thing.
- A stable (ish) API.
- An app store to lure an audience—no need to don the hat of a content creator.
- Wonky CSS, not my problem.
- Templates for multiple bots, no sweat.
But, clouds have their silver lining:
- Running a discord server, well, that's on me.
- I might lock myself in a discord bot world, straying from the freedom of the open web.
An appeal to reason is 80% appeal, 20% reason.
Discord Bot Command Ideas
PSA: BAKI IS BACK – HE'S FINALLY FIGHTING YUJIRO
August 23 2023
Out-of-towners often mistake Manhattan as the whole of NYC, I feel.
Out-of-towners often mistake Manhattan as the whole of NYC, I feel. Take the time to explore spots like Bay Ridge, or Cortelyou Road.
You'll find calm there, perhaps even a surprising dose of the suburban. The real perk of living in an area like Bay Ridge vs a suburb outside of Corpus Christi? A train line linking you straight to the heart of Union Square or Grand Central in under an hour.
When you see those tier 7 minions in your game, do me a favor, grab Tess. Just trust me on this.
I am the one who decides.
The gallery feature on Ubud is acting up. Beats me why.
Trying out Spear in Discord. Maybe it's something that could tickle the fancy of vault members, make them feel special. Definitely can picture it being a neat bonus!
Another day done, neatly cut into boxes of time. This time block journal, it's kind of become a friend. Excited to think where I might be in a few months - maybe a master at wrestling time.
GPT helps me to write, and I like that. It’s like the words I jot down aren't my own, they’re not precious. So, when it comes to chopping them up and pruning them, I don't flinch. And, there's something cool about typing in shorthand, or even in low key, lowercase letters. GPT just takes it, and churns out sentences that sound as real as rain splattering on a windowpane.
August 22 2023
New season of Hearthstone! Goodbye, next forty-eight hours.
New season of Hearthstone! Goodbye, next forty-eight hours. I'll be captive to this relentless obsession. Alongside Baldur's Gate 3, of course.
This patch, it sucks from the get-go. Bannana Slammas for life, I suppose.
The billboards up in Soho stir something within me. Something McLuhan might've coined, about the package being more valuable more than the item inside. The ads on NYC's billboards, uncountable as they are, most fade from memory like a worn-out jazz record. But their very existence on the giant sized wall, catching the eye of the odd twenty-somethings, mid-pilgrimage to their temple of Equinox, that broadcasts its own message. Sure, I could plaster an ad on some wall in a silent town but that lacks the jazz, the hum and pulse of the viewer's gaze, which makes all the difference in selling the song. Plenty artists wallow unseen, only a handful get to wallow under the spotlight.
Leaders need this one thing more than anything else: good sense. It's the same when it comes to your body, your thoughts, your work life. Be your own arbiter of good judgement.
Photos...they've been the game for me on Instagram lately, kind of like a guilty pleasure I suppose. Don't know why.
It's ludicrous when you think about how I'm using Instagram, disregarding entirely how they mapped out the service. Truly not giving a flying fuckkk. It's like a Finstagram, but taken to the logical conclusion of really only using Instagram for a glorified photo storage service. Picture it: me following no one, completely ignoring ads on the feed the company worked so hard on to build! A strange way to play, right?
But in its way, it's transformative. Instagram morphs into something else, a simple yet miraculous platform for my photos, a sanctuary. It's effortless to stick in my favorite tunes too, lending a voice to every image. And the filters? Oh, the filters. An array of options with a single, easy tap. Quite something, isn't it?
Oddly enough, I found myself the central character in some LLM tutorial – an instructional piece about using these LLMs for cold outreach on LinkedIn, of all things. Seeing this offered some clarity, unsheathing the mystery of the spam deluge that keeps finding me. Particularly from the VCs, the constant hum in the background. Leave me alone dammit!
Random post logic – all credit goes to the original creator: milkythemes!
<script>
function loadScript(url, callback) {
const head = document.head;
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onreadystatechange = callback;
script.onload = callback;
head.appendChild(script);
}
function luckyPost() {
let ghostVersion = typeof version == 'undefined' ? 'v3.0' : version;
let apiKey =
typeof key == 'undefined' ?
console.error('Ghost integration API key is missing. Please refer to documentation at https://milkythemes.com/plugins/lucky-post') : key;
const pageUrl = `${window.location.protocol}//${window.location.hostname}`;
const api = new GhostContentAPI({
url: pageUrl,
key: apiKey,
version: ghostVersion
});
const postUrl = [];
const randomBtn = document.getElementsByClassName("btn-random");
const stringHostUrl = `[href="${pageUrl}/#rdm-post/"]`
const randomPost = document.querySelector(stringHostUrl);
const randomPostSelector = document.querySelectorAll('[href="https://www.bramadams.dev/rdm-post/"]');
for (let i = 0; i < randomPostSelector.length; i++) {
randomPostSelector[i].text = `Loading...`
}
api.posts
.browse({ limit: 250 })
.then((posts) => {
posts.forEach((post) => {
postUrl.push(post.slug)
});
})
.then(() => {
const randomPostSelector = document.querySelectorAll('[href="https://www.bramadams.dev/rdm-post/"]');
for (let i = 0; i < randomPostSelector.length; i++) {
randomPostSelector[i].text = `Open Random Post!`
randomPostSelector[i].href = `${pageUrl}/${randomUrl(postUrl)}`
}
}).catch(() => {
const randomPostSelector = document.querySelectorAll('[href="https://www.bramadams.dev/rdm-post/"]');
for (let i = 0; i < randomPostSelector.length; i++) {
randomPostSelector[i].text = `OOPS!`
randomPostSelector[i].href = `https://www.bramadams.dev/`
}
});
// The randomUrl function is used to grab a random array from the list
function randomUrl(postUrl) {
return postUrl[Math.floor(Math.random() * postUrl.length)];
}
}
loadScript('https://unpkg.com/@tryghost/content-api@latest/umd/content-api.min.js', luckyPost);
</script>
Blue Lock got dark!
Hey, the kid's scored a page on Wikipedia!
Sticky Header for Ubud! (Put this in the code injection header)
<style>
.c-header{
position: sticky;
z-index: 1;
top: 0;
background: var(--background-primary);
}
</style>
August 21 2023
Instabrams are back baby! Thanks to Alfred, Obsidian, Ghost, and GPT that is!
I found out today that, oddly enough, my dislike for food—and smells, as an offshoot—liberates my ears. I can fill them with all kinds of sounds, just like I fill my mind with all sorts of books. And who knows, this might make my understanding richer, deeper. After all, tastes and sounds, they both bring in similar complexities, don't they? What's the science behind this, I wonder?
Planning with time blocks using the Time Block Planner is something else, I tell you. Just staring at how my hours roll out in reality, versus where I believe in my mind that they're going.
It really makes me treasure those fresh hours each morning when I draft the plan. But, damn it, they do race by like comets while I'm knee-deep in living them. Sure makes one thing clear though - there's still quite a road ahead of me to align my time better with the stuff that sits front-row in my priorities.
Today, I cranked out a couple scripts that just might fan the flame back into my inconsistent habit of creating Instabrams. Knocked up one heck of a pipeline for DALL-E, taking chunky texts, wringing them dry into neat, crisp summaries, and morphing them into fetching cover art.
Then there's the second script. What does it do? Well, simple: it chews up shorthand blurb, like the one you're picking through now, and spits it back out in the flavor of a certain author close to my heart, our man Murakami himself. Now, you can sneak a peek at both these scripts down below and take in the art piece a notch above.
Both scripts neatly tuck away the outputs onto my clipboard. Handy for the lazybones that like me, can use ‘em just about anywhere across the machine. Embrace sloth!
i wrote two scripts today that should hopefully harken the return of instabrams. i created a dall-e pipeline that takes text, summarizes it and turns into a cover art.
in addition i wrote a script that rewrites shorthand like you are reading now into the style of one of my favorite authors, haurki muarkami. you can see both of the scripts below, and the art for this peice in the image above.
importantly, both copy results to clipboard for usage anywhere across my machine. let's go laziness!
Really would be nowhere without these amazing tools that devs have built (Ghost, Obsidian, GPT). I merely build the ligaments that connect the very solid bones.
GitHub rang the bell for the 700th star on chat gpt md today. It's been awhile since any updates were added, and I can't help but feel a twinge of regret. But the open source world - well, it can be a free ride for some folks, especially amongst the Obsidian folks. It's like being a chef with everyone sampling your soup, but no one foots the bill.
there was an enormous disconnect between how we think open source works and what is actually happening on the ground today. There is a long, and growing, tail of projects that don’t fit the typical model of collaboration. Such projects include Bootstrap, a popular design framework used by an estimated 20% of all websites, where three developers have authored over 73% of commits. Another example is Godot, a software framework for making games, where two developers respond to more than 120 issues opened on their project per week.† -- Working in Public: The Making and Maintenance of Open Source Software
Create a Ghost Cover Image with DallE
import dotenv from "dotenv";
dotenv.config();
import OpenAI from "openai";
import clipboard from "clipboardy";
import fs from "fs";
import fetch from "node-fetch";
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
async function summarizeClipboard() {
const text = clipboard.readSync();
// console.log(`Summarizing: ${text}`);
const completion = await openai.chat.completions.create({
messages: [
{
role: "system",
content:
"Summarize the following into a theme and create an art prompt from the feel of the text aesthetically along the lines of: 'an abstract of [some unique lesser known art style from history] version of {x}' where x is the feel of the text aesthetically. Just return the art prompt, say nothing else." +
text,
},
],
model: "gpt-4",
});
// console.log(`Summary: ${completion.choices[0].message.content}`);
return completion.choices[0].message.content;
}
async function saveImgFromUrl(url) {
const response = await fetch(url);
const buffer = await response.buffer();
const filename = `./dalle-images/${Date.now()}.jpg`;
fs.writeFile(filename, buffer, () => console.log("finished downloading!"));
return filename;
}
async function appendToLog(logItem) {
const log = JSON.parse(fs.readFileSync("./log.json"));
log.push(logItem);
fs.writeFileSync("./log.json", JSON.stringify(log, null, 2));
}
async function main() {
let prompt = await summarizeClipboard();
prompt = prompt.replace("Art Prompt: ", "").trim();
const image = await openai.images.generate({ prompt: prompt });
const imageUrl = image.data[0].url;
const imgFilename = await saveImgFromUrl(imageUrl);
const log = {
query: clipboard.readSync(),
prompt: prompt,
imageUrl: imageUrl,
imgFilename: imgFilename,
};
await appendToLog(log);
// save prompt to clipboard
clipboard.writeSync(prompt);
console.log("./dalle-images/" + imgFilename.replace("./dalle-images/", ""));
}
main();
Rewrite Chicken Scratch as Murakami
import dotenv from "dotenv";
dotenv.config();
import OpenAI from "openai";
import clipboard from "clipboardy";
import fs from "fs";
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
async function rewriteClipboard() {
const text = clipboard.readSync();
// console.log(`Rewriting: ${text}`);
const completion = await openai.chat.completions.create({
messages: [
{
role: "system",
content:
"Rewrite the following in the style of Haruki Murakami, using short, punchy, easy to read, simple words that flow. Almost as if spoken cadence. Text:\n" +
text,
},
],
model: "gpt-4",
});
// console.log(`Rewrite: ${completion.choices[0].message.content}`);
return completion.choices[0].message.content;
}
async function appendToLog(logItem) {
const log = JSON.parse(fs.readFileSync("./log.json"));
log.push(logItem);
fs.writeFileSync("./log.json", JSON.stringify(log, null, 2));
}
async function main() {
let prompt = await rewriteClipboard();
prompt = prompt.replace("Rewrite: ", "").trim();
const log = {
query: clipboard.readSync(),
prompt: prompt,
};
await appendToLog(log);
// save prompt to clipboard
clipboard.writeSync(prompt);
console.log("Prompt saved to clipboard");
}
main();
Images From the Script
These have wriggled under my skin, becoming my favorites of the day. You can make buckets of them without breaking much of a sweat. Keep your eyes on the blog – there's more visual feast on the way!
Half a decade past, this is where I lived.
I snapped this photo, and soon after found myself in a nearby bar, nursing a drink and ruminating on the past five years. I had some predictions right - walking away from full-time software engineering to chase dreams of startups and artistry. But there were surprises too - who could've predicted a pandemic, or AI taking great leaps ahead?
I pondered over the goals I set for myself in 2018 - many still unmet, many still echoing around my head. Is that a good thing or a bad thing? Not sure. But one thing I've learnt is this: success is a recipe. It calls for dogged effort, an accreting outlet for said effort (think: investment returns), a dash of lady luck, and being at the right place just when it's the right time. Voila, dreams come true and they'll call it fate.
Like Ging said to Gon, "I can't get there quite yet, but I'm relishing the ride."
"Five years ahead?" I reckon I'll be there, right at the threshold of that old, worn out door of mine.
Oddly enough, it seems as if my eyes on the photo on the right been brushed with a dash of guyliner. Can't make heads or tails of that, honestly.
bramadams.dev is a reader-supported published Zettelkasten. Both free and paid subscriptions are available. If you want to support my work, the best way is by taking out a paid subscription.
Dipping My Toes Back Into Generative Art
A little play with pixel sorting!
I missed this shit! Generative art is so fun!
Expect more stuff like this soon! (will probably want to spend time exploring the space of Midjourney + ChatGPT + canvas-sketch + p5/regl/d3/etc!)
Code
Pixel Sorting and 3D mix chat with GPT
The 3d shape in question
Loading an image into canvas sketch
const canvasSketch = require("canvas-sketch");
const convexHull = require("convex-hull");
const cameraProject = require("camera-project");
const createCamera = require("perspective-camera");
const { mat4, vec3 } = require("gl-matrix");
const BezierEasing = require("bezier-easing");
const load = require("load-asset");
const Random = require("canvas-sketch-util/random");
const settings = {
duration: 8,
animate: true,
playbackRate: "throttle",
fps: 24,
};
function brightness(r, g, b) {
return Math.sqrt(0.299 * r * r + 0.587 * g * g + 0.114 * b * b);
}
// Other helper functions go here...
// ... (stroke, drawCells, drawCellsNoOverlap, createMesh) ...
// A utility that creates a 3D "crystal" mesh
// The return value is { positions, cells }
const createMesh = () => {
// Our crystal mesh is the convex hull of N random points on a sphere
const pointCount = 10;
const radius = 1;
const positions = Array.from(new Array(pointCount)).map(() => {
return Random.onSphere(radius);
});
// Now let's center the mesh by finding its "centroid"
const centroid = positions.reduce((sum, pos) => {
return vec3.add(sum, sum, pos);
}, [ 0, 0, 0 ]);
if (positions.length >= 1) {
vec3.scale(centroid, centroid, 1 / positions.length);
}
// Translate all the points in the mesh away from centroid
positions.forEach(pos => {
vec3.sub(pos, pos, centroid);
});
// And now get the triangles (i.e. cells) of the 3D mesh
const cells = convexHull(positions);
return { cells, positions };
};
// A utility to stroke an array of 2D points
const stroke = (context, points) => {
context.beginPath();
points.forEach(p => context.lineTo(p[0], p[1]));
context.lineWidth = 3;
context.lineJoin = 'round';
context.lineCap = 'round';
context.strokeStyle = '#fff';
context.stroke();
};
// A simple and fast way to draw a mesh of 2D positions and cells (triangles)
// This will lead to overlapping edges where two triangles meet
const drawCells = (context, positions, cells) => {
cells.forEach(cell => {
// A 'cell' holds indices into our positions array, so get 2D points
const points = cell.map(i => positions[i]);
// make sure to close the path before drawing the triangle
points.push(points[0]);
// stroke the path
stroke(context, points);
});
};
// One quick n' dirty way to fix the above issue of overlapping
// lines is to instead draw each line as a unique segment, like so:
const drawCellsNoOverlap = (context, positions, cells) => {
const edgeMap = {};
cells.forEach(cell => {
// For each cell, get a pair of edges
// Give the pair a 'key' name and ensure it is unique
for (let i = 0; i < cell.length; i++) {
const a = cell[i];
const b = cell[(i + 1) % cell.length];
const edge = [ a, b ].sort();
const edgeKey = edge.join(':');
if (!(edgeKey in edgeMap)) {
edgeMap[edgeKey] = true;
}
}
});
// Get all unique keys and find positions from indices
const keys = Object.keys(edgeMap);
keys.forEach(pair => {
const indices = pair.split(':');
const points = indices.map(i => positions[i]);
// Stroke the line segment A->B
stroke(context, points);
});
};
const sketch = async ({ update }) => {
// Await the image loader, it returns the loaded <img>
const image = await load("assets/bramses_A_dissected_view_of_a_formidable_metal_vault_its_numero_059f975b-d628-4803-af73-52c8f5707c00.png");
// Update the output settings to match the image
update({
dimensions: [image.width, image.height],
});
// Setup a 3D perspective camera
const camera = createCamera({
fov: 80 * Math.PI / 180,
near: 0.01,
far: 1000,
viewport: [ 0, 0, image.width, image.height ]
});
// Create our 3D mesh
const { positions, cells } = createMesh();
// Define some easing functions
const easeA = new BezierEasing(0.14, 0.28, 0.48, 0.45);
const easeB = new BezierEasing(0.14, 0.28, 0.67, 0.46);
return ({ context, playhead, width, height }) => {
// Draw the loaded image to the canvas
context.drawImage(image, 0, 0, width, height);
// Extract bitmap pixel data
const pixels = context.getImageData(0, 0, width, height);
const data = pixels.data;
// Create an array of indices
const indices = [...Array(data.length / 4).keys()];
// Sort indices based on pixel brightness
indices.sort((a, b) => {
const offsetA = a * 3.4;
const offsetB = b * 3.93;
const brightnessA = brightness(
data[offsetA],
data[offsetA + 1],
data[offsetA + 2]
);
const brightnessB = brightness(
data[offsetB],
data[offsetB + 1],
data[offsetB + 2]
);
return brightnessA - brightnessB;
});
// Create a new pixel array
const sortedData = new Uint8ClampedArray(data.length);
// Populate the new array with the sorted pixels
for (let i = 0; i < indices.length; i++) {
const sortedIndex = indices[i] * 4;
const originalIndex = i * 4;
sortedData[originalIndex] = data[sortedIndex];
sortedData[originalIndex + 1] = data[sortedIndex + 1];
sortedData[originalIndex + 2] = data[sortedIndex + 2];
sortedData[originalIndex + 3] = data[sortedIndex + 3];
}
// Create new ImageData and put it back into canvas
const sortedPixels = new ImageData(sortedData, width, height);
context.putImageData(sortedPixels, 0, 0);
// Now we can draw our 3D mesh
const viewport = [ 0, 0, width, height ];
camera.viewport = viewport;
// Make the camera swing back/forward a little
const zOffset = Math.sin(playhead * Math.PI * -2) * 0.5;
// Reset camera position, translate it outward, then look at world center
camera.identity();
camera.translate([ 0, 0, 3 + zOffset ]);
camera.lookAt([ 0, 0, 0 ]);
camera.update();
// A 3D scene is made up of:
// - 4x4 Projection Matrix (defines perspective)
// - 4x4 View Matrix (inverse of camera transformation matrix)
// - 4x4 Model Matrix (the mesh transformations like rotation, scale, etc)
const projection = camera.projection;
const view = camera.view;
const model = mat4.identity([]);
// Rotate the mesh in place
mat4.rotateY(model, model, easeA(playhead) * Math.PI * 2);
mat4.rotateX(model, model, easeB(playhead) * Math.PI * 2);
// Get a combined (projection * view * model) matrix
const combined = mat4.identity([]);
mat4.multiply(combined, view, model);
mat4.multiply(combined, projection, combined);
// "Project" the 3D positions into 2D [ x, y ] points in pixel space
const points = positions.map(position => {
return cameraProject([], position, viewport, combined);
});
// Draw the mesh
drawCellsNoOverlap(context, points, cells);
};
};
canvasSketch(sketch, settings);
bramadams.dev is a reader-supported published Zettelkasten. Both free and paid subscriptions are available. If you want to support my work, the best way is by taking out a paid subscription.
June 13 2023
glitch art, chat loops, farms, code poetry
Videos
I built a plugin that works like a DIY code interpreter where an end user decides what rules GPT should check against. GPT is smart enough to facilitate it's own retry logic, which is neat as hell!
Photos
the town of yakima has a really active git profile
Art
Code
One thing I do a lot is append text to specific headings in a MD file, so this Python script helps with just that!!
Playing around with the e2e experience of a Readwise quote > app (or pseudocode). I also just got an iPad so I'm playing with the Freeform app :)
Poetry
Experimenting with Code Poetry more as an art form. Here's a few GPT results from my favorite song rn, Ascencionism:
Python:
Visual Basic:
Class Desire ' Well, I know what you want from me
Property Reflection As Boolean ' You want someone to be your reflection
Property Deception As Boolean ' Your bitter deception
Function SetFree() ' Setting you free
' So you take what you want and leave
Return True
End Function
End Class
Class Mystery ' Who made you like this?
Property BodyLanguage As String ' Who encrypted your dark gospel in body language?
Property BlissfulAnguish As Boolean ' Synapses snap back in blissful anguish
End Class
Class PastLife ' Tell me you met me in past lives, past life
Property InsideEating As Boolean ' Past what might be eating me from the inside, darling
Property RhythmHalfDeity As Boolean ' Half of a rhythm, half deity
Property GlitchesOrGaps As String ' Glitches in the code or gaps in a strange dream
End Class
Class Fantasy ' Tell me you guessed my future and it mapped onto your fantasy
Property Mannequin As Boolean ' Turn me into your mannequin
Property PuppetQueen As Boolean ' and I'll turn you into my puppet queen
End Class
Class DanceInTheDark ' Won't you come and dance in the dark with me?
' Show me what you are, I am desperate to know
Property PerfectEnemy As Boolean ' Nobody better than the perfect enemy
Property DigitalDemons As Boolean ' Digital demons make the night feel heavenly
End Class
Class Reality ' Make it real
' 'Cause anything's better than the way I feel right now
Property BlacklitParadise As Boolean ' I can offer you a blacklit paradise
Property DiamondsInTrees As Boolean ' Diamonds in the trees, pentagrams in the night sky
Property LipstickChemtrailsRedflagsPinkNails As Boolean ' Lipstick, chemtrails, red flags, pink nails
End Class
Class Eye
Property Door As Boolean ' With one eye on the door
Property Rail As Boolean ' other eye on a rail
Property ScarletTrail As Boolean ' Other, other eye following a scarlet trail
Property HolyGrail As Boolean ' And the last few drops from the Holy Grail, now
End Class
Class DarkFashion
' Rose gold chains, ripped lace, cut glass
' Blood stains on the collar, please, just don't ask
Function Feast() ' Be the first to the feast, let's choke on the past
' And take to the broken skies at last
Return True
End Function
End Class
Class Ascend ' You cannot watch me ascend
' And I know what you want from me
Property Same As Boolean ' You want the same as me
Property Redemption As Boolean ' My redemption, eternal ascension
Function SetFree() ' Setting me free
' So I'll take what I want then leave
Return True
End Function
End Class
Class Disappear ' You make me wish I could disappear, oh
' You make me wish I could disappear
Function Wish() As Boolean
Return True
End Function
End Class
bramadams.dev is a reader-supported published Zettelkasten. Both free and paid subscriptions are available. If you want to support my work, the best way is by taking out a paid subscription.
https://t.co/bXEqFi8zqr
Imagine creativity just turns out to be a subset of computation. Imagine that the logic leaps of conjecture and discovering good explanations is just an eigenvector calculation in the frontal lobe or some shit.