return to table of content

Faces.js, a JavaScript library for generating vector-based cartoon faces

ezequiel-garzon
12 replies
19h32m

Apologies for such a basic question. I have node installed on my machine, but clearly no idea how a JS library is included anymore (among other things...). I created an HTML file, included a div ``a div with id "my-div-id"`` as instructed, and even added type="module" in the script tag, but I get in Chrome ``Uncaught TypeError: Failed to resolve module specifier "facesjs". Relative references must start with either "/", "./", or "../".``

Any pointers on all the steps to running this? Should I expect node to create a js file that could be served together with the HTML file? Or would my hosting server need to have node, and run it every time there is a request? Thanks in advance, I'm sorry for the confusion.

tylerchilds
11 replies
18h58m

not a basic question at all— front end has jumped the shark.

you can bypass node, npm install, etc for a prototype entirely in an html file leveraging an import map.

this is the importmap i load for all my pages: https://github.com/tylerchilds/plan98/blob/6120e6a80a3d48438...

to support faces, i’d add an entry: “facesjs”: “https://esm.sh/facesjs@4.0.0”

which should get rid of the import path issue, and to support legacy browsers that still might have that error:

https://github.com/guybedford/es-module-shims

scubbo
4 replies
17h8m

jumped the shark

Genuine question - what does that phrase mean to you?

I've only ever heard it in the context of television shows (meaning "has been renewed for so many seasons that the writers have run out of ideas and have started forcing the characters into ever wackier situations to generate novelty") - and while it's intuitivve to map from that meaning to a more generic "has gone on for too long and thus become bad", the translation is fascinating. When you said this, were you intentionally using a term from another domain with a different meaning in the confidence that your audience could translate it appropriately, or does the phrase "jump the shark" really just mean "be old, and thus bad" to you?

(Asking from a purely non-prescriptivist non-judgemental perspective! I'm interested in understanding your thought process, not in judging or correcting you)

tylerchilds
1 replies
16h10m

happy days was running out of ideas and wanted to continue to retain audience attention and had The Fonz water ski and jump over a shark.

silicon valley was running out of ideas, but steve ballmer famously delivered the Developers, developers, developers speech paving the way for capturing developer market share, for a platform with platform developers is no platform at all.

there’s tooling that solves technical problems and tooling that business problems.

a system has “jumped the shark” when there are at least five ways to accomplish the same thing and the audience was just trying to have some happy days on the tubes.

my core hunch is that the ecosystem is a compile target versus a respected platform and that’s where i believe the shark has been jumped.

the web is cool, if only we stopped trying to jump it and befriend the shark already.

the long answer is, i’ve got a bespoke markdown like syntax i’m using for both a web publishing and screenplay authoring. i feel no difference between telling stories in interactive web formats or printed pages.

maybe i’m jumping the shark.

tylerchilds
0 replies
14h26m

i realize i’m making some claims here, so

server side multi page demo: https://sillyz.computer/sagas/sillyz.computer/en-us/000-000....

if you press esc in the top left, you can play with that in the repl.

if you visit: https://sillyz.computer, that same text based adventure wizard journey as an embedded widget is the lower post it note.

this is the folder i’m using for localizing that journey: https://github.com/tylerchilds/plan98/tree/plan98/client/pub...

any of the short hand web components dynamically load from: https://github.com/tylerchilds/plan98/tree/plan98/client/pub...

full circle— i’m very much playing across domains with the jumping the shark reference

icepat
0 replies
12m

Genuine question - what does that phrase mean to you?

Jumped the shark means roughly the same thing as "lost the plot". In that, the current state of affairs has entered into absurd territories.

Retr0id
0 replies
16h54m

While I'm aware of the phrase's origins, I've never heard it used to describe a TV show, only an unrelated field just like in this example.

Solvency
4 replies
17h51m

That is 10x more complicated and unorthodox than simply running "$ npm install --save facesjs".

fzzzy
3 replies
17h35m

That's not enough to get it to load in a browser. Which bundler will you use? Shark jumped.

tylerchilds
1 replies
16h44m

yeah, i thought about asking if OP was using vite, webpack, snowpack or babel, but based on the context of the question, it seemed like vanilla web, so i answered vanilla web.

ezequiel-garzon
0 replies
4h21m

Thank you very much for your help, just upvoting feels rude! I have not quite gotten there, but thank you for pointing me in the right direction. Clearly I'm an enthusiast at best, but "back in my day" you could put all the needed libraries in the script tag and the CSS under link... sigh... The moment nodejs, supposedly a back end, started being used pervasively for the front end, I lost whatever conceptual map I had. Just as a personal challenge, I'm planning to _study_ [1], which I see referenced a lot, and see if I can "get it", albeit partially. Any other such references would be welcome.

Thanks again! Great website and projects, by the way.

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...

Solvency
0 replies
17h14m

One command: npx.

philsnow
0 replies
13h45m

I’ve never heard of importmaps before, thank you.

throwaway35777
8 replies
22h58m

    import { display, generate } from "facesjs";

    // Generate a random face
    const face = generate();

    // Display in a div with id "my-div-id"
    display("my-div-id", face);
Beautiful API.

nox101
4 replies
9h13m

No, that's poor API. If it wants to generate HTML it should return it's root element.

Let's say I want to add a random face to every div with class "face". With this API have to generate ids. With an API that returns a root element it's trivial and it's not duplicating work (inserting elements into the DOM) that already exists.

Taking a selector would not be much better because it would again be duplicating work and make it harder to customize usage.

Taking a parent element for it to insert into would also be a poor API because it makes it harder to insert next to a sibling.

A good API would be one of

    const face = generate()
    someElem.appendChild(face);
or

    const face = generate()
    someElem.appendChild(face.domElement);
or

    const face = generate()
    someElem.appendChild(face.html());   // assumes it can render to something else too

nox101
0 replies
1h30m

As mentioned, that's still a poorer API than just returning a root element.

Consider...

    // insert after every link
    document.querySelectorAll('a.funny').forEach(elem =>
      const face = generate();
      const parentForFace = document.createElement('span');
      elem.appendChild(parentForFace);
      display(parentForFace);
    });
vs

    // insert after every link
    document.querySelectorAll('a.funny').forEach(elem =>
      const face = generate();
      elem.after(face.domElement);
    });
Taking a parent element is still a poor API

pc86
1 replies
3h24m

Taking a parent element for it to insert into would also be a poor API because it makes it harder to insert next to a sibling.

To extend the documentation example, wouldn't you just have "my-div-id-sibling" already and call

    display("my-div-id", face);
    display('my-div-id-sibling", someOtherFace);
Like almost all discussions that use language like "good API" or "bad API" this seems to me entirely personal preference. Personally I find anything where I end up having to call appendChild() myself a bad API.

nox101
0 replies
1h35m

No, that would not be better. Consider

    document.querySelectorAll('classIWantFacesIn').forEach(elem => {
       const face = generate();
       elem.id = `face-${crypto.randomUUID()}`; // this line should not be needed
       display(elem.id, face);
    });
With the current API I'm required to make ids and make sure they don't collide with other elements. Vs

    document.querySelectorAll('classIWantFacesIn').forEach(elem => {
       const face = generate();
       elem.appendChild(face.domElement);
    });
Now, no id is needed. It's objectively a better API to not need the id.

xg15
2 replies
22h55m

As beautiful as the faces.

throwaway35777
1 replies
22h52m

The faces are amazing! I hope if he finds an artist they don't get changed too much.

I absolutely am looking for an excuse to use faces.js somewhere.

rkagerer
0 replies
18h41m

It would be neat as a forum icon, if you got to pick one and tailor it.

pavel_lishin
2 replies
18h27m

Ooh, ooh, I get to be the one to make the Peter Watts reference today! Chernoff Faces make an appearance in Blindsight, where the ship captain Sarasti uses them. The specific details would be a spoiler, though.

082349872349872
1 replies
9h17m

In this particular case, I think there are at least two nose shapes close enough to π/2 that Sarasti would find them disturbing.

supportengineer
1 replies
17h19m

Imagine these on SRE dashboards to determine system state

itronitron
0 replies
46m

Depending on the application that could provide some real benefit as human vision is predisposed to seeing/detecting faces.

winwang
0 replies
22h23m

Thank you for evangelizing -- this is amazing and kinda hilarious. Does it count as biohacking? lol.

mnahkies
3 replies
11h15m

Interesting, I hadn't come across extism before. How hard would it be to package https://github.com/biojppm/rapidyaml in this way? (And do you have a extism for dummies guide?)

nilslice
2 replies
10h11m

Extism can be really useful for packaging up and running cross-language libraries!

The most clear information about it is at: https://extism.org, but its a bit focused on the primary use case for Extism, being a universal plugin system.

There is a C PDK (https://github.com/extism/c-pdk) which you'd probably want to use in a new wrapper around your library in C++, and compile it to wasm32 freestanding or WASI, but without emscripten. Extism doesn't currently have an interop layer to emscripten.

richardfey
1 replies
7h35m

Don't worry about what some plug-in code might do to your program. Extism is built with security as a core principle, and fully sandboxes the execution of all plug-in code.

I find the wording a bit off here. Responsible security involves transparency along the supply chain and minimum trust, certainly not talking about worries and giving them up with ease.

nilslice
0 replies
4h56m

Would you suggest something more appropriate?

foundart
0 replies
3h30m

This is the first I've heard of Extism. I like their goal! "Extism's goal is to make all software programmable." [0]

[0] https://extism.org/docs/overview

cmgriffing
5 replies
22h19m

Really cool. I would love to see an api for just passing a numeric seed value. Then users of an app can click a "refresh" button to get one they like that could persist across page loads and devices without having to store the entire face object in the db.

cypressious
2 replies
21h0m

You could serialize the JS representation to Base64 or Base10 if you want it to be numeric.

wongarsu
1 replies
20h12m

But that's a lot more data than just storing which of the ~2^50 possible faces was generated. You could serialize the entire face including the colors and scaling factors into a much smaller string, or just take one number that is used as a seed for a random number generator that sets the other parameters

pests
0 replies
15h48m

The seed version with random parameters doesn't allow you to or your users to design their own. Just random selection until you get one you like, no editing of details.

two_handfuls
0 replies
18h44m

The face object is small (it’s the parameters). You can save that.

itronitron
0 replies
48m

I did the first part of this (not the API part) a while back to generate avatar faces for minecraft with a random sequence of numbers (one per pixel, gray scale, and the faces were symmetric). I got some fun results as a wide range of anatomical facial morphologies were produced.

jlturner
1 replies
21h7m

This is pretty common in 3D work. Blender has a feature called “blend shapes” that implements a similar interface, and is commonly used for complex facial animation and general model parameterization.

Tijdreiziger
0 replies
20h25m

Duolingo did a talk at their Duocon conference about how they use parametrization to animate the characters in their app.

https://www.youtube.com/watch?v=fgOqvyPif3g

(no affiliation)

nmstoker
0 replies
18h39m

That's cool - I had been thinking with the OP site that quite a number looked like they were scowling/angry so a way to vary that is interesting to explore.

b0bb0
4 replies
10h20m

I know many around here don't love scarce digital assets but here is my take on procedural faces: https://regular.world/

My goal was to maximize variation across 10,000 faces and add warmth which is hard to do with cgi.

tvink
1 replies
9h58m

I thought "ah maybe they're saying scarce digital assets, because they don't wanna be conflated with NFT pyramid schemes".. clicked link, and found fullblown ponzinomics with "assets" paying out tokens.

And people wonder why most of us are tired of this stuff.

b0bb0
0 replies
6h2m

I don't know why you see it as any sort of ponzi.. it's just an experiment with digital assets, role-playing and world building. Involving money is a pyramid scheme? Perhaps not the thread to discuss. Guessing the reaction is because crypto is mainly grifters + money grabs.. and the cringey apes were the worst representatives.

agys
1 replies
9h37m

Those look like a total Fernando Botero rip-off!

b0bb0
0 replies
6h1m

Yes his work was the inspiration, of course.

DyslexicAtheist
2 replies
20h35m

they should have called it "4 non blondes" because there are no blonds

Minor49er
1 replies
17h17m

Using the "faces.js editor" link at the bottom of the page, it shows that you can use any color you want for the hair. Also, if it didn't allow blonds, it would probably just be called "no blonds" since there are more than 4 possible variants

DyslexicAtheist
0 replies
4h41m

sounds like you didn't get the joke. oh well.

xg15
1 replies
22h55m

Has a bit of a South Park and/or Futurama vibe to it, but why not?

rasso
0 replies
22h13m

Exactly, why not! Love it.

outime
1 replies
21h28m

I liked it a lot, including the README. The author seems to be an indie dev who creates sport management sim games [1], all of which run entirely in the browser like the linked library (which is used in the games).

[1] https://zengm.com/

criley2
0 replies
18h7m

No wonder I instantly recognized these faces as Basketball GM's art! Dumbmatter has made some very cool things.

monooso
1 replies
3h46m

I built something similar a few months back [1][2].

Among other things, it accepts an arbitrary key, and will always generate the same avatar for the same key. Very handy for apps which need to generate user-specific avatars.

[1]: https://github.com/monooso/avataraas

[2]: https://github.com/monooso/avatar

toisanji
0 replies
21h52m

very cool. Are there libraries like these that do whole characters with bodies? Would love to play with those!

thatha7777
0 replies
23h28m

i love this

red1reaper
0 replies
3h22m

Aren't those like 2d version of nintendo's MIIs? I mean, the eyes noses and mouths are very much like those of MIIs

ramijames
0 replies
22h22m

This is adorable.

jszymborski
0 replies
19h36m

When are the Faces.js NFTs going for sale? /s

jonwinstanley
0 replies
9h54m

Are there any licensing restrictions to using this library and the images it creates?

hacker_88
0 replies
22h15m

Back in the day out used to be called NFT

daltonlp
0 replies
19h32m

If you like that, you may also like:

https://pixelfaces.io/

af3d
0 replies
22h30m

Well, I didn't find the art very appealing. But I do love the idea behind it. Neat project!

Joel_Mckay
0 replies
21h15m

Very fun little project. Nice =)