231 lines
6.6 KiB
TypeScript
231 lines
6.6 KiB
TypeScript
import { Main, DragResizableImage, render_and_copy, n_of } from "./common.tsx";
|
|
|
|
// new idea! "make your own image macro" scrollable background of various le classic meme images (imgflip)
|
|
// + images (yes, images; nobody has impact installed)
|
|
// nah. let's just do white + text-shadow
|
|
const base_url = "https://static.pyrope.net/imgflip/";
|
|
const urls = [
|
|
"aggressive-right-turn.png",
|
|
"aliens.png",
|
|
"always-has-been.png",
|
|
"balloon.png",
|
|
"batman-slapping-robin.png",
|
|
"bike-self-sabotage.png",
|
|
"buff-doge-vs-cheems.png",
|
|
"cefqrn.png",
|
|
"change-my-mind.png",
|
|
"chuck-norris.png",
|
|
"despicable-plan.png",
|
|
"distracted-boyfriend.png",
|
|
"drake.png",
|
|
"everywhere-everywhere.png",
|
|
"evil-kermit.png",
|
|
"expanding-brain.png",
|
|
"girl-smile-fire.png",
|
|
"heinous-suggestion.png",
|
|
"hide-the-pain-harold.png",
|
|
"i-am-once-again-asking.png",
|
|
"if-i-had-one.png",
|
|
"is-this-a.png",
|
|
"not-sure-if.png",
|
|
"one-does-not-simply.png",
|
|
"or-draw-25.png",
|
|
"panik-kalm-panik.png",
|
|
"psycholonials-reference.png",
|
|
"rock-the-dwayne-johnson-driving.png",
|
|
"same-picture.png",
|
|
"scroll-of-truth.png",
|
|
"slam-button.png",
|
|
"STRONG-handshake.png",
|
|
"success-kid.png",
|
|
"tap-head.png",
|
|
"thinking-about-other-women.png",
|
|
"this-is-fine.png",
|
|
"two-buttons.png",
|
|
"waiting-guy.png",
|
|
"waiting-skeleton.png",
|
|
"who-killed.png",
|
|
"woman-yelling-at-cat.png",
|
|
"you-get-a.png",
|
|
].map(x => base_url + x);
|
|
|
|
const Word = ({
|
|
children,
|
|
left = "0px",
|
|
top = "0px",
|
|
}: {
|
|
children: string;
|
|
left?: string;
|
|
top?: string;
|
|
}) => (
|
|
<div
|
|
style={{
|
|
position: "absolute",
|
|
resize: "both",
|
|
minWidth: "max-content",
|
|
minHeight: "fit-content",
|
|
width: left,
|
|
height: top,
|
|
overflow: "hidden",
|
|
display: "flex",
|
|
// justifyContent: "right",
|
|
// alignContent: "bottom",
|
|
}}
|
|
>
|
|
<h1
|
|
style={{
|
|
color: "white",
|
|
textShadow: "0px 0px 2px black",
|
|
margin: "auto 0 0 auto",
|
|
}}
|
|
>
|
|
{children}
|
|
</h1>
|
|
</div>
|
|
);
|
|
|
|
// alright, doing it the right way (https://cohost.org/blackle/post/38921-alright-cohost-it) is too hard.
|
|
// let's cheat.
|
|
// if we aren't random, and instead distribute things such that the initial setup has the least covered
|
|
// ehhhhhhhhhhhhhhhhhh
|
|
// sighhhhh let's just do it right
|
|
// generate the stupid freaking impact font
|
|
// use it as a background image
|
|
// ughhhhhh
|
|
// oo i know i'll make one image in photopea and just clip it
|
|
// that should work and be easy fingers crossed
|
|
// that'll actually be way harder to adapt lel
|
|
// ughhhh am i going to have to pull out that crappy library
|
|
// AND download an impact font
|
|
// (yes)
|
|
// tl;dr i can still use this scattering
|
|
// imagescript can't do the shadow we need (thank goodness)
|
|
// maybe imagemagick + photopea then
|
|
// i got it (KISS): photopea -> split on command line -> reference by url
|
|
// that should be workable
|
|
|
|
const words = {
|
|
THE: 6,
|
|
HOMESTUCK: 3,
|
|
MEME: 4,
|
|
IS: 4,
|
|
EGGBUG: 4,
|
|
WHEN: 2,
|
|
YOU: 5,
|
|
SUS: 1,
|
|
IMPOSTER: 1,
|
|
ME: 3,
|
|
ALIEN: 1,
|
|
ARE: 3,
|
|
A: 4,
|
|
BOTTOM: 2,
|
|
TOP: 2,
|
|
TEXT: 4,
|
|
"?": 3,
|
|
"!": 3,
|
|
NO: 3,
|
|
YES: 3,
|
|
COHOST: 2,
|
|
MEHBARK: 2,
|
|
WEBARK: 2,
|
|
THIS: 2,
|
|
POST: 2,
|
|
SUCK: 2,
|
|
"CHUCK NORRIS": 2,
|
|
FOR: 2,
|
|
S: 4,
|
|
GET: 2,
|
|
} satisfies Record<string, number>;
|
|
console.log(
|
|
`yikes. there are ${
|
|
Object.keys(words).length
|
|
} unique words and ${Object.values(words).reduce(
|
|
(a, b) => a + b
|
|
)} words in total`
|
|
);
|
|
// Object.keys(words).forEach(w => console.log(w))
|
|
const text_img_url = (text: string) =>
|
|
`https://static.pyrope.net/meme-text/${text}.png`;
|
|
|
|
const TEXT_HEIGHT = 55;
|
|
const decoder = new TextDecoder();
|
|
// crazy inefficient but idc
|
|
const get_text_width = (text: string): number =>
|
|
+decoder.decode(
|
|
new Deno.Command("identify", {
|
|
args: ["-format", "%w", `static/meme-text/${text}.png`],
|
|
}).outputSync().stdout
|
|
);
|
|
|
|
const ScatteredWords = ({ children }: { children: Record<string, number> }) => (
|
|
<>
|
|
{...Object.entries(children).flatMap(([text, count]) =>
|
|
// feels pretty snazzy ngl
|
|
n_of(Math.ceil(count), () => (
|
|
<DragResizableImage
|
|
top={Math.random() * 413}
|
|
left={Math.random() * 612}
|
|
url={text_img_url(text)}
|
|
height={TEXT_HEIGHT}
|
|
width={get_text_width(text)}
|
|
indicator_opacity={0.2}
|
|
/>
|
|
)).map(f => f())
|
|
)}
|
|
</>
|
|
);
|
|
|
|
render_and_copy(
|
|
<>
|
|
<Main
|
|
style={{ width: "100%", aspectRatio: "1" }}
|
|
aria-described-by="user-content-meme-description"
|
|
>
|
|
<ScatteredWords>{words}</ScatteredWords>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
overflow: "scroll",
|
|
alignItems: "center",
|
|
gap: "1rem",
|
|
}}
|
|
>
|
|
{...urls.map(u => (
|
|
<img
|
|
src={u}
|
|
style={{
|
|
maxHeight: "50vh",
|
|
outline: "1px solid black",
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
</Main>
|
|
<p style={{ fontSize: "0px" }}>
|
|
a horizontally scrollable list of memes with draggable words that
|
|
look like a knockoff of impact font. if you want a better and
|
|
(hopefully) more accessible version, visit imgflip.com. all of the
|
|
memes are taken from there anyway
|
|
</p>
|
|
notes as per usual i do this all th etime:
|
|
<ul>
|
|
<li>
|
|
dragresizing taken <em>entirely</em> from @blackle's{" "}
|
|
<a href="https://cohost.org/blackle/post/38921-alright-cohost-it">
|
|
excellent post
|
|
</a>
|
|
</li>
|
|
<li>
|
|
you have to get the very center to drag. @blackle put an
|
|
indicator but i made it optional and turned it off! sorry!
|
|
aesthetics! (edit: turned em back on. character growth! i did
|
|
turn the opacity down just a squidge. idk. it's late!)
|
|
</li>
|
|
<li>
|
|
i probably could have turned the resizing off too, but, you
|
|
know, it's very funny
|
|
</li>
|
|
</ul>
|
|
</>
|
|
);
|