Hacker News new | past | comments | ask | show | jobs | submit login
Faces.js, a JavaScript library for generating vector-based cartoon faces (zengm.com)
493 points by starkparker 7 months ago | hide | past | favorite | 96 comments



This would be fun to use with Chernoff Faces https://en.m.wikipedia.org/wiki/Chernoff_face


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.


Always love a good Peter Watts reference, though this one makes me want to go back and read Blindsight again as I can't remember the reference... As his website says though, my "will to live [has been] getting too strong" lately, so...


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


    Never saw such a nose in my life
    'Tis a nose of parchment
    It is six times as big but
    'tis a nose like my nose
https://www.youtube.com/watch?v=bNQKYolhZkg

https://en.wikipedia.org/wiki/The_Kiss_and_Other_Movements


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


Imagine these on SRE dashboards to determine system state


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


Someone I know has done some work to parameterize facial expressions: https://www.redblobgames.com/x/1845-face-generator/

He has a bunch of other interesting things like this, too: https://www.redblobgames.com/


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.


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)


Their post on Polygonal Map Generation for Games [1], from 2010, got me into procedural generation in general.

[1] http://www-cs-students.stanford.edu/~amitp/game-programming/...


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.


    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.


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


> 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.


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.


(faces.js dev here)

A nice thing about the current API is the face objects can be trivially serialized to JSON, which I need do in the application I originally wrote the library for.

Also the `display` function works with a DOM element as the first argument too, in which case you don't need to make up an ID. That's how I use it.

That being said, the API might not be perfect, but you should at least appreciate that it's been stable since v1 in 2015!


See other response this thread why passing in a DOM element is also not a good API.

That said, I wouldn't have spoken up if someone hadn't claimed the API was good. Any one who makes a useful library that provides useful functionality people want is great!

> it's been stable since v1 in 2015!

That's awesome!


I agree the API could be better, but note that you don't have to use IDs - you can also pass the parent element to display directly: https://github.com/zengm-games/facesjs/blob/master/src/displ...


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


As beautiful as the faces.


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.


(faces.js dev here)

What you see now is already after another contributor came through and redid all my artwork. You don't want to know what it looked like back before then lol


Agree with throwaway, the faces look great. Thanks for this library, the amount of face detail options is really cool.


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


Obviously this also needs to be a library in Zig, Rust, Go, Elixir, Haskell, Java, C#, F#, OCaml, PHP, Python, Ruby, Perl, C, C++ & Lean

So, it now lives as an Extism[0] wasm plugin you can call from those languages: https://modsurfer.dylibso.com/module?hash=2050e7f7a129a48df0...

[0]: https://github.com/extism/extism


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?)


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.


> 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.


Would you suggest something more appropriate?


I do not know Extism, but I would start from the process of verifying the security of it, and highlight what allows to check it quickly and with certainty. For example documentation of the sandbox and possibility to inspect all syscalls performed with verbose logging. These are just examples; basically I would put focus on minimal trust and maximum transparency.


Note: there can always be problems of data exfiltration or compute power theft (as part of a botnet or mining), so owning the machine is not the only risk to mitigate.


Both great points! Extism docs assume some level of familiarity with the security model of WebAssembly. Which unless you grant it granular permission, does mitigate the risks you’ve mentioned.

I agree we should do more to specifically call out these security benefits - and also how a user could impact that default security.


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


hey thank you! we are trying to make that a reality :)


Woah Extism is exactly what I need for a project where I want a plugin system, nice random find, thank you!

Question: Does extism plan to support Python as a plugin language? That seems like a big gap right now

Edit: I see this issue tracking it https://github.com/extism/extism/issues/116 and the project is ongoing https://github.com/extism/python-pdk/issues/2


Yes, we would love to add a Python PDK - and as you discovered have one that is very close.

Python is pretty tricky given most users want libraries with native/C dependencies. With those and the Python runtime, the wasm tends to bloat up to tens of MB, rather unideal for a plug-in.

If you have time, please comment on that issue though and share some thoughts or use cases so we can better prioritize support!


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.


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


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.


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


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


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.


Very cool. Here's another style! https://getavataaars.com/


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.


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


> 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)


> 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.


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.


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.


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


Love the insight - thank you!


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


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


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


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.


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...


for an easier way to import, download the module you want to import, put it next to the js file you will import it from, and use "import foo from './foo'". You might need to serve it from a local http server.


thank you!

if it helps, my last commit touches the primary aspects of modules.

overall, i’m integrating a test payment flow on https://thelanding.page

this commit[0] i export two functions from my payment debugger module (i am intentionally overloading the word module to additionally bind a view; this is a personal hot take and not general guidance, just in case you see how i use ‘@sillonious/module’).

so i expose payment-debugger.js in the index.html file import map as @sillonious/payments.

i import that module in the message-pay component.

when the user clicks buy now, i call the newPayment function (which ultimately lands in client.js, after traversing the network; in case you’re curious about the full route). i also set a timer that’ll check the payment status every five seconds for 15 minutes. displaying a timeout message is a not yet implemented edge case.

[0]: https://github.com/tylerchilds/plan98/commit/db3c037345077fe...


One command: npx.


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


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/


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


Thanks for plugging my main project, I came too late to this thread to do it!


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


Here's a demo of my project shape faces https://shapefaces.com/


If you like that, you may also like:

https://pixelfaces.io/


Aww, it's not making Chernoff faces :(

(https://en.wikipedia.org/wiki/Chernoff_face)


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


Exactly, why not! Love it.


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.


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.


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.


>Perhaps not the thread to discuss.

So you can't deny it's a Ponzi scheme, but you just don't want to discuss it here? But YOU brought it up!

This thread is a FINE place to discuss it, since YOU started the top level thread by shilling your Ponzi scheme here all by yourself, before suddenly trying to cut off the discussion when it didn't go the way you planned, so let's discuss it anyway:

Yes it's a Ponzi scheme on its face (or rather on Fernando Botero's faces ;), and worse yet, it's based on misappropriation of an artist's work, plus you also blatantly infringe on and dilute many trademarks at the same time, for money.

You're not the victim here, so don't try to act hurt that "many around here don't love scarce digital assets" and surprised that "I don't know why you see it as any sort of ponzi". Yes you do know, because it obviously is, and you even tried to make a dishonest weasley disclaimer "I know ... but ..." when you first shilled it here, as if it's wrong and unfair to you that people hate Ponzi schemes and stealing art and infringing and diluting trademarks and shilling on Hacker News.

Dan Olson (Folding Ideas): Line Goes Up – The Problem With NFTs

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

>If someone pitches you on a "great" Web3 project, ask them if it requires buying or selling crypto to do what they say it does.

Chris Natsuume (Ninesquirrels): Let me explain Blockchain gaming and Play-to-Earn.

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

>NFTs are a pure scam. Blockchain gaming is a pyramid scheme. Play-to-Earn is not only a scam, it's deeply immoral.

Chris Natsuume (Ninesquirrels): Using NFTs to own ingame objects: Also pretty much a scam.

https://www.youtube.com/watch?v=8IYjsWBbmKI

>In this video, I'd like to clarify and further explain: Using NFTs to own ingame objects is an unnecessarily inefficient byproduct of a larger scam.


Well you sound very angry. I didn't want to hijack another persons post to discuss an unrelated topic, but happy to discuss. I wasn't shilling anything I was sharing a procedural project related to this very post. These links are great for context on the tone of your reply, but say nothing of my project. As charming as Dan Olsen is (/s) there is a place in this world for digital scarcity, it's interesting, it's valid and even if 95% of the crypto ecosystem is cringe and scams, there are a lot of good people doing good work.


Those look like a total Fernando Botero rip-off!


Yes his work was the inspiration, of course.


So we should trust you that it's not a Ponzi scheme, but it steals an artist's designs without giving them credit (I searched your site for his name and there is no mention of Fernando Botero), and it makes promises of: "Earn a Salary: Every project needs its own token. Claim your salary in $REG token." "Collect Art: Spend your token in our store, and buy unique digital art and other items."

Do you get permission to use his work and pay Fernando Botero's estate a licensing fee? Will you at least give him credit on your site, since you're actively trying to make money off of his admittedly inspirational artwork, and at the same time denying in spite of all the hard evidence on your own site that you're not running a Ponzi scheme? Is that just because they don't look like apes?

https://en.wikipedia.org/wiki/Fernando_Botero

>He was considered the most recognized and quoted artist from Latin America in his lifetime, and his art can be found in highly visible places around the world, such as Park Avenue in New York City and the Champs-Élysées in Paris, at different times.

>His art is collected by many major international museums, corporations, and private collectors, sometimes selling for millions of dollars. In 2012, he received the International Sculpture Center's Lifetime Achievement in Contemporary Sculpture Award.

And what exactly is this page, with the "Connect Wallet" button prominently in the upper right corner? Has your "Not A Ponzi Scheme" received any cease-and-desist letters about trademark infringement and dilution yet?

https://regular.world/companies


Yes I referenced the "most recognized and quoted artist from Latin America" and you think this is some sort of gotchya? I interpreted Botero's style into 10,000 cgi characters as mentioned many many times when speaking about the project.

Using a token to sell community art is not a Ponzi scheme. Selling digital assets? Not a Ponzi scheme.

If you don't know what the 'connect wallet' button does, you have never interacted with the Ethereum ecosystem. I suggest you look slightly beneath the surface as it's not nearly as black and white as the "Number Go Up" wants you to believe.

And yes, I very well may receive a cease and desist from McDonalds or Hot Pockets for using their logos in the corporate narrative of this fictional world.. you find this offensive?


Stop shilling your Ponzi schemes on Hacker News, and to the rest of the universe, scammer.


Answer the questions.. or just regurgitate headlines with a skin deep understanding of the topic, that will get you far indeed.


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


(faces.js dev here)

Code is Apache license, and you can do whatever you want with the output. If you want to be nice, lmk if you use it somewhere, I like seeing it in the wild!


Spinnaker's Face Maker (https://www.youtube.com/watch?v=5K4ovkVLp8Y) for the modern era!


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


This is adorable.


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


Very fun little project. Nice =)


i love this


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


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


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


* 4 can also be "for"

* There is a band called "4 non blondes"


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


Back in the day out used to be called NFT




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: