Avatarex - Generate unique, reproducible avatars from hashed strings

Avatarex is an elixir package for generating unique, reproducible Avatars from hashed strings.
The package is inspired by Robohash

Hey everyone! I’ve been working on a personal project and was in want of some unique placeholder avatars for my users. I really love the Robohash python lib, but wanted something a bit for “functional”. So here’s what I put together this weekend.


Current Avatar sets include Birdy and Kitty avatars created using images created
by David Revoy and used under CC-BY-4.0.

You can create your own avatar sets, see the AvatarexSet docs for more details.

Images are generated using @kip’s Image elixir package.

Note: The package is currently under development but is up on hex.



Looks like there is a bug in this line:

it should be:

:avatarex |> :code.priv_dir() |> Path.join(~w[sets kitty])

Same patch should be applied to the birdy

Unfortunately current macro code does not allow it and I was in need to use it like:

defmodule Kitty do                               
  use AvatarexSet,
    dir: "deps/avatarex/priv/sets/kitty",
    keys: [:body, :eye, :fur, :mouth, :accessory]

which cannot be used in prod environment static paths are not guaranteed to work in all environments and therefore you should support: :code.priv_dir/1.

Similarly the macro does not allows to use a sigil for keys i.e.:

defmodule Kitty do                                                  
  use AvatarexSet,                                                  
    dir: "deps/avatarex/priv/sets/kitty",                                 
    keys: ~w[body eye fur mouth accessory]a
** (Protocol.UndefinedError) protocol Enumerable not implemented for {:sigil_w, [delimiter: "[", line: 5], [{:<<>>, [line: 5], ["body eye fur mouth accessory"]}, 'a']} of type Tuple. This protocol is implemented for the following type(s): Date.Range, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Range, Stream
    (elixir 1.14.4) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir 1.14.4) lib/enum.ex:166: Enumerable.reduce/3
    (elixir 1.14.4) lib/enum.ex:4307: Enum.reduce/3
    (avatarex 0.1.0) expanding macro: AvatarexSet.__using__/1

The other problem is priv/renders. Once again there should be a :code.priv_dir/1 call. To support priv directory for current project you should use otp_app and pass this option to said function. Your documentation does not mentions to create such a directory which would not work in app generated using mix new task. I would recommend to create it automatically using File.mkdir_p with combination to :code.priv_dir/1 call mentioned above.

Also why do you use AvatarexSet instead of Avatarex.Set? It’s like reserving 2 namespaces for just one package and therefore it’s not seen as a good practice.


Updated with all your suggestions.

1 Like

Already better, but you have still a lot to learn. I reserved some time, deeply investigated your code and created an example pull request with project rewrite proposal to show what code you would be able to write in future. :rocket:

If you do not understand something feel free to ask questions in this thread. :dark_sunglasses:

Have a nice day! :smiling_imp:

1 Like

I have dropped some more comments in your latest 3 commits. You still doing the same mistake i.e. you are thinking from author perspective and not from someone who would use the library. Therefore for example default values for optional options are more confusing than helpful even if they work excellent in avatarex itself. You are just used to write project and not hex dependency. Hope my comments helped.

1 Like

Thanks for the comments, they are excellent and appreciated. Yep, I’ve been definitely wrapping my head around some of the meta programming side of things and how they differ from solely project based. Particularly around the conventions for where to put things, how to spec & test, and working with AST at compile time.

1 Like

Addressed all the project rewrite suggestions in the latest push to the rewrite branch. Using it in my personal project and am quite pleased with the revised API. Wanted to get your feedback before merging that into the main branch and pushing a 0.2.0 version. Still have some features I want to add before 1.0.0.

1 Like

Updated to 0.2.0 with new API per @Eiji proposal and feedback.

1 Like