initial
This commit is contained in:
commit
8ec31da055
163
README.md
Normal file
163
README.md
Normal 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
6
flake.nix
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
description = "A Nix library for creating Picrew derivations";
|
||||
outputs = { ... }: {
|
||||
lib = import ./picrew.nix;
|
||||
};
|
||||
}
|
77
picrew.nix
Normal file
77
picrew.nix
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue