This commit is contained in:
Thorn Avery 2024-04-05 20:34:39 +13:00
commit 8ec31da055
3 changed files with 246 additions and 0 deletions

163
README.md Normal file
View file

@ -0,0 +1,163 @@
# libPicrew
a NixOS library for declaritively building [Picrews](https://picrew.me/en/image_maker/229486).
a picrew is a paper-doll-esque website for building avatars, but i really wanted to be able to declaritively define mine as part of my operating system configuration.
## Installation
this flake can be added as an input, and its library functions accessed:
```
{
description = "Some Flake";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
libpicrew.url = "git+https://git.avery.garden/thorn/libPicrew?ref=mistress";
};
outputs = { nixpkgs, ... }@inputs: {
# avaliable under inputs.libpicrew.lib
};
}
```
## Usage
this flake exposes a single meta-library function, `mkLibPicrew`, which takes an attribute set with the following items, and returns the actual library:
- `pkgs`
- `images`
- `ordering`
`pkgs` is the package set it will pull its dependencies from, `images` is a path to an image set to use (described below), and `ordering` is a list of strings to use for Z-layering (later items are layered on top of earlier ones).
```
let libPicrew = inputs.libpicrew.lib.mkLibPicrew {
inherit pkgs;
images = ./picrew_images;
ordering = [
"bg"
"skin"
"hair"
"eyes"
"mouth"
];
}
```
the `images` folder can be gotten through [unethical and dark arts](https://mincerafter42.github.io/picrew-download-bookmarklet/), which will produce a `.ora` file that can be unzipped to produce a `data` subdirectory containing the images needed.
each subdirectory and file will need to be renamed, such that the outermost directories match each item in `ordering`, with the nested items allowing any format.
`mkLibPicrew` creates an attribute set with two items, `renderPicrew` and `renderPicrews`
to use each we need to define some `defaults` and some `parts`:
a `default` is an attribute set containing variables used in the `parts`, and is intended for items such as skin colour, hair colour, and eye colour that multiple layers or items may share a naming scheme for:
```
thornDefaults = {
hair = "black";
skin = "pale";
eyes = "hazel";
};
```
a `part` is a subset of a full picrew image, that contains a grouping of items, for example an outfit, a hairstyle, or an expression.
they are functions that take a set of defaults and produce an attribute set where the attribute names correspond to directories in the `images` folder, and the values correspond to files (when appended with `.png`):
```
base = defs: {
bg = "darkpink";
skin = defs.skin;
nose = "large";
};
maid_outfit = defs: {
right_sleeve.maid = "colour1";
left_sleeve.maid = "colour1";
right_hand.closed = defs.skin;
left_hand.closed = defs.skin;
outer_shirt = "black_maid";
ears.maid_band = "colour1";
};
hair_mid = defs: {
hair_back.mid = defs.hair;
fringe.mildly_jagged = defs.hair;
};
outfit = defs: {
earrings = "red_rose";
shirt.highneck_sweater = "colour2";
};
expression_bored = defs: {
mouth = "small_sad";
eyebrows.large_bushy = defs.hair;
eyes.to_the_left = defs.eyes;
eye_glint = "mid";
};
```
### `renderPicrew`
`renderPicrew` a set of defaults, a list of parts, and a filename, and produces an image. the argument is an attribute set of the following items:
- `name`, the filename to use (will have `.png` appended)
- `parts`, a list of parts to apply
- `defaults`, the defaults to use, defaults to `{}`
- `src`, the image source to use, defaults to that passed to `mkLibPicrew`
- `ordering`, the layer order to use, defaults to that passed to `mkLibPicrew`
it produces a derivation that builds the image:
```
packages.maid-picrew = renderPicrew {
name = "maid";
defaults = thornDefaults;
parts = [
base
hair_mid
maid_outfit
expression_bored
];
}
```
### `renderPicrews`
this works similar to the above, except it applies the same defaults to multiple sets of parts to create multiple images, it takes three arguments (seperate arguments, not a set):
- `name`, the package sets name
- `defs`, the defaults to apply
- `specs`, a list of attribute sets defining each image
each item in specs has a `name` (the filename), and `parts` (a list of parts to use):
```
packages.thornsPicrews = renderPicrews
"thornsPicrews"
thornDefaults
[
{
name = "regular";
parts = [
base
hair_mid
outfit
expression_bored
];
}
{
name = "maid";
parts = [
base
hair_mid
maid_outfit
expression_bored
];
}
];
```

6
flake.nix Normal file
View file

@ -0,0 +1,6 @@
{
description = "A Nix library for creating Picrew derivations";
outputs = { ... }: {
lib = import ./picrew.nix;
};
}

77
picrew.nix Normal file
View file

@ -0,0 +1,77 @@
let
mergeSets = defaults: parts:
builtins.foldl'
(a: b: a // b)
{}
(builtins.map (f: f defaults) parts);
setToFilePaths = ordering: parts:
let
grabPaths = item: path:
if (builtins.isString item) then
["${builtins.concatStringsSep "/" path}/${item}.png"]
else
builtins.concatMap
(p: grabPaths item.${p} (path ++ [p]))
(builtins.attrNames item);
initial = spec: order:
builtins.concatMap
(o: if builtins.hasAttr o spec then
grabPaths spec.${o} [o]
else [])
order;
in
initial parts ordering;
mkLibPicrew = { pkgs, ... }@args: rec {
renderPicrew = mkRenderPicrew args;
renderPicrews = name: defs: specs:
pkgs.buildEnv {
inherit name;
paths =
builtins.map (spec: renderPicrew {
defaults = defs;
inherit (spec) name parts;
}) specs;
};
};
mkRenderPicrew = {
images,
ordering,
pkgs
}@args: {
name,
parts,
defaults ? {},
src ? images,
ordering ? args.ordering
}: let
compiledSpec = mergeSets defaults parts;
argList = setToFilePaths ordering compiledSpec;
imList =
if builtins.length argList <= 2 then
builtins.concatStringsSep " " argList
else
builtins.head argList + " "
+ builtins.concatStringsSep " -composite "
(builtins.tail argList);
in pkgs.stdenv.mkDerivation {
inherit name src;
buildInputs = [ pkgs.imagemagick ];
installPhase = ''
mkdir -p $out
convert ${imList} -composite $out/${name}.png
'';
};
in {
inherit mkLibPicrew;
}