[HN Gopher] Faces.js, a JavaScript library for generating vector...
       ___________________________________________________________________
        
       Faces.js, a JavaScript library for generating vector-based cartoon
       faces
        
       Author : starkparker
       Score  : 408 points
       Date   : 2024-04-06 18:37 UTC (1 days ago)
        
 (HTM) web link (zengm.com)
 (TXT) w3m dump (zengm.com)
        
       | thatha7777 wrote:
       | i love this
        
       | gkoberger wrote:
       | Very cool. Here's another style! https://getavataaars.com/
        
       | throwaway35777 wrote:
       | 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.
        
         | xg15 wrote:
         | As beautiful as the faces.
        
           | throwaway35777 wrote:
           | 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 wrote:
             | It would be neat as a forum icon, if you got to pick one
             | and tailor it.
        
         | nox101 wrote:
         | 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
        
           | pc86 wrote:
           | > 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 wrote:
             | 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.
        
           | yoavm wrote:
           | 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...
        
             | nox101 wrote:
             | 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
        
       | xg15 wrote:
       | Has a bit of a South Park and/or Futurama vibe to it, but why
       | not?
        
         | rasso wrote:
         | Exactly, why not! Love it.
        
       | krebby wrote:
       | This would be fun to use with Chernoff Faces
       | https://en.m.wikipedia.org/wiki/Chernoff_face
        
         | winwang wrote:
         | Thank you for evangelizing -- this is amazing and kinda
         | hilarious. Does it count as biohacking? lol.
        
         | pavel_lishin wrote:
         | 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 wrote:
           | In this particular case, I think there are at least two nose
           | shapes close enough to p/2 that Sarasti would find them
           | disturbing.
        
             | defrost wrote:
             | 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
        
         | supportengineer wrote:
         | Imagine these on SRE dashboards to determine system state
        
           | itronitron wrote:
           | Depending on the application that could provide some real
           | benefit as human vision is predisposed to seeing/detecting
           | faces.
        
       | af3d wrote:
       | Well, I didn't find the art very appealing. But I do love the
       | idea behind it. Neat project!
        
       | ramijames wrote:
       | This is adorable.
        
       | cmgriffing wrote:
       | 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 wrote:
         | You could serialize the JS representation to Base64 or Base10
         | if you want it to be numeric.
        
           | wongarsu wrote:
           | 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 wrote:
             | 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 wrote:
         | The face object is small (it's the parameters). You can save
         | that.
        
         | itronitron wrote:
         | 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.
        
       | hacker_88 wrote:
       | Back in the day out used to be called NFT
        
       | toisanji wrote:
       | very cool. Are there libraries like these that do whole
       | characters with bodies? Would love to play with those!
        
       | rented_mule wrote:
       | 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/
        
         | jlturner wrote:
         | 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 wrote:
           | 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)
        
         | sabellito wrote:
         | 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/...
        
         | nmstoker wrote:
         | 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.
        
       | outime wrote:
       | 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 wrote:
         | No wonder I instantly recognized these faces as Basketball GM's
         | art! Dumbmatter has made some very cool things.
        
       | Joel_Mckay wrote:
       | Very fun little project. Nice =)
        
       | SiempreViernes wrote:
       | Aww, it's not making Chernoff faces :(
       | 
       | (https://en.wikipedia.org/wiki/Chernoff_face)
        
       | DyslexicAtheist wrote:
       | they should have called it "4 non blondes" because there are no
       | blonds
        
         | Minor49er wrote:
         | 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 wrote:
           | sounds like you didn't get the joke. oh well.
        
       | jszymborski wrote:
       | When are the Faces.js NFTs going for sale? /s
        
       | daltonlp wrote:
       | If you like that, you may also like:
       | 
       | https://pixelfaces.io/
        
       | ezequiel-garzon wrote:
       | 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 wrote:
         | 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
        
           | Solvency wrote:
           | That is 10x more complicated and unorthodox than simply
           | running "$ npm install --save facesjs".
        
             | fzzzy wrote:
             | That's not enough to get it to load in a browser. Which
             | bundler will you use? Shark jumped.
        
               | Solvency wrote:
               | One command: npx.
        
               | tylerchilds wrote:
               | 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 wrote:
               | 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...
        
           | scubbo wrote:
           | > 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)
        
             | Retr0id wrote:
             | 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.
        
             | tylerchilds wrote:
             | 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 wrote:
               | 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/c
               | lient/pub...
               | 
               | full circle-- i'm very much playing across domains with
               | the jumping the shark reference
        
             | icepat wrote:
             | > 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.
        
           | philsnow wrote:
           | I've never heard of importmaps before, thank you.
        
       | nilslice wrote:
       | 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
        
         | mnahkies wrote:
         | 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 wrote:
           | 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 wrote:
             | > 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 wrote:
               | Would you suggest something more appropriate?
        
         | foundart wrote:
         | 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
        
       | b0bb0 wrote:
       | 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 wrote:
         | 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 wrote:
           | 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 wrote:
         | Those look like a total Fernando Botero rip-off!
        
           | b0bb0 wrote:
           | Yes his work was the inspiration, of course.
        
       | jonwinstanley wrote:
       | Are there any licensing restrictions to using this library and
       | the images it creates?
        
       | bitwize wrote:
       | Spinnaker's Face Maker
       | (https://www.youtube.com/watch?v=5K4ovkVLp8Y) for the modern era!
        
       | monooso wrote:
       | 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
        
         | snissn wrote:
         | Here's a demo of my project shape faces https://shapefaces.com/
        
       | red1reaper wrote:
       | Aren't those like 2d version of nintendo's MIIs? I mean, the eyes
       | noses and mouths are very much like those of MIIs
        
       ___________________________________________________________________
       (page generated 2024-04-07 23:01 UTC)