Repository: dankamongmen/notcurses (language: python)

Issue:
standardize on behavior of 0 when specifying geometries
A number of functions take geometries, with `ncplane_as_rgba()` as an example. Some take an upper-left and lower-right point; some take an origin and lengths. This disparity is bad enough, but then we also sometimes support 0,0 to indicate "everything" and sometimes require -1,-1 for same, with 0,0 being an error.

I'd like to normalize these before ABI3. Let's get a list of all entry points taking a geometry as input, and see if there are any which require/prefer one or the other form. If not (I can't imagine why they would), let's figure out whether 0,0 ought be an error, or "everything left", and the same for negative values.

Regarding this last, there's a discontinuity when we go to "everything" regardless of whether it's at -1,-1 or 0,0, since 1,1 gets at most 1 cell, and it's been decreasing from the maximum to get there. If all the negatives work, and 0,0 does as well (or if both classes are errors), there are only two total discontinuities. If one or the other works, there are 3. If the caller is using unsigneds and coercing them to ints, it makes more sense to consider all negatives an error, imho. If the caller is writing a natural algorithm, one that terminates at 0,0, it makes more sense to consider 0,0 an error imho. But such a caller would then need to check for the error, in which case they could just check for 0,0, and avoid the call. From a convenience perspective, having 0,0 be "everything left" seems more attrative imho than -1,-1, but the biggest issue for convenience is probably simply consistent handling of arguments.

I'm inclined to think negatives ought always be errors, so that overflow due to truncated unsigned parameters is always caught. If that's what we do, convenience demands that the 0,0 option remain for "everything else". So I'm inclined to handle it that way:

 - one or two negative arguments is an error
 - one zero argument is an error
 - two zero arguments means "specified origin through lower right"
 - two positive arguments means "specified area"
 - origin outside the target is an error
 - lower right, when specified, outside the target is an error
Normalize geometry arguments across all functions
We take geometries in more than a dozen functions as parameters. We were handling them differently in different places: sometimes -1 meant "all available", sometimes 0 did (and negatives were all errors), for some any non-positive number was an error. All geometries and lenghts are now passed as `unsigned`, and 0 means "everything" where that is appropriate. Closes #1696.
eliminate recursion in ncplane_polyfill_yx()
We earlier found `ncvisual_polyfill_yx()` to be blowing up due to recursing too deep. I'd forgotten all about `ncplane_polyfill_yx()`'s existence. It has the same issue. Clean it up. Make sure there's a unit test or two on it, also.


Discussion / hints:
relevant functions: `ncplane_resize()`, `ncplane_resize_simple()`, `ncplane_contents()`, `ncplane_hline_interp()`, `ncplane_vline_interp()`, `ncplane_box()`, `ncplane_gradient()`, `ncplane_highgradient()`, `ncplane_gradient_sized()`, `ncplane_highgradient_sized()`, `ncplane_mergedown()`, `ncplane_erase_region()`, `ncvisual_from_plane()`, `ncvisual_render()`, `ncplane_as_rgba()`, and their direct mode relatives.
Here's another question: `keepy` and `keepx` (wrt `ncplane_resize()`) must be within the old plane, but `keeplenx` and `keepleny` only need be within the new one. why wouldn't `keepleny + keepy` and `keeplenx + keepx` need to be within the old plane, as well? this leads to output like:

 ```
ncplane_resize_internal:742:70x80 @ 0/0 → 70/80 @ 0/0 (keeping 70x80 from 0/0)
ncplane_resize_internal:742:14x80 @ 0/0 → 14/80 @ 0/0 (keeping 14x80 from 0/0)
```

which looks wrong and jarring (how can i keep 70x80 from 0x0?), even if it's not actually leading to a false copy.
> ```
> ncplane_resize_internal:742:70x80 @ 0/0 → 70/80 @ 0/0 (keeping 70x80 from 0/0)
> ncplane_resize_internal:742:14x80 @ 0/0 → 14/80 @ 0/0 (keeping 14x80 from 0/0)
> ```
> which looks wrong and jarring (how can i keep 70x80 from 0x0?), even if it's not actually leading to a false copy.

replacing " from " with "@" clears up a lot of the confusion here
`resize`: upper-left corner of area to keep, geom to keep, upper-left corner of kept target area, geom to target (no all)
`resize_simple`: geom to target (no all)
`contents`: upper-left corner of area to return, geom of area (-1 for all)
`hline`: length of line (no all)
`vline`: length of line (no all)
`box`: lower-right corner of area to boxify (no all)
`gradient`: lower-right corner of target area (no all)
`highgradient`: same
`gradient_sized`, `highgradient_sized`: area of target (no all)
`mergedown`: upper-left of source, length of source, and...i'm unsure what purpose `dsty`/`dstx` serve honestly
`erase_region`: upper left and geom (0 all)
`from_plane`: upper left and geom (no all)
`render`: n/a
`as_rgba`: upper left and geometry (-1 all)
`visual_blit`: upper left and geom (0 all)

well, that's pretty fucking messy! glad we looked through this.
realizing that `visual_blit` is also involved here locks in 0 as full length, given that we don't want to invalidate every default-initialized `ncvisual_options` in existence.
so we need change:
* ~~resize: move to unsigned~~
* ~~contents: 0 for all, not -1~~
* ~~hline: 0 ought be error, move to unsigned~~
* ~~vline: 0 ought be error, move to unsigned~~
* ~~box: move to unsigned, 0 size is error~~
* ~~box_sized: move to unsigned~~
* gradient: same as box
* ~~mergedown: 0 for all~~
* ~~from_plane: 0 for all~~
* ~~as_rgba: 0 for all, unsigned~~

do not change:
* erase_region
* visual_blit

basically if you're area (lengths), you ought be using unsigned, and 0 ought indicate all in that dimension (always right and down). ~~if you're using endpoints (coordinates), you ought be using signed, it ought work in both directions, and there ought not be any special values.~~ let's get this done for 2.4.9.
ugh i really hate all this churn for something of such questionable value. you've gotta figure at least one subtle bug snuck in on this branch. is it worth it?
What about `ncplane_dim_yx`, which still expects *int* for the dimensions?
> What about `ncplane_dim_yx`, which still expects _int_ for the dimensions?

pointers did not change with this PR. they might with #1777. i started down that road and the churn would be deafening. i'm completely unsure as to whether it's worthwhile.
> > What about `ncplane_dim_yx`, which still expects _int_ for the dimensions?
> 
> pointers did not change with this PR. they might with #1777. i started down that road and the churn would be deafening. i'm completely unsure as to whether it's worthwhile.

Ah ok. I'm a big fan of having as much type consistency in the library as possible. But yeah you'll have to decide how much churn is worthwhile...
> > > What about `ncplane_dim_yx`, which still expects _int_ for the dimensions?
> > 
> > 
> > pointers did not change with this PR. they might with #1777. i started down that road and the churn would be deafening. i'm completely unsure as to whether it's worthwhile.
> 
> Ah ok. I'm a big fan of having as much type consistency in the library as possible. But yeah you'll have to decide how much churn is worthwhile...

it is truly immense, if i go all the way through and make them `unsigned` internally. if i held it at the API point, it would be less tremendous. perhaps that's a reasonable halfway point for 3.0.0.
> if i held it at the API point, it would be less tremendous. perhaps that's a reasonable halfway point for 3.0.0.

indeed, doing it incrementally sounds reasonable
hrmmmmmmmmmmmm.

i'm suddenly wondering if we don't actually want to admit `int` rather than `unsigned` for position at all entry points, to indicate "use the current cursor location as the origin". that's what we do for e.g. `ncplane_*_yx()` and `ncplane_erase_region()`.

hrmmmmmmmmmmmm.

ugh, yeah, this was a mistake. lengths as `unsigned` are fine, lower-right coordinate as `unsigned` are fine, but we really ought allow `-1` to mean "current cursor position in this dimension". actually, hrmmm, maybe we want to allow that for bottom-right as well, so you can easily say e.g. "0,0 to current cursor."

yep, i fucked this up. oh well, glad it didn't get released. all coordinates are going to go back to `int`, and we're going to implement that semantic on all of them. @joseluis , hope this doesn't cause you to throw away too much work =[. but i think this is a useful generalization, and it brings these functions into line with others. if that's our goal (normalization), we need support this everywhere. oh well! man, my heart knew something was wrong with this work.
try, fail, learn, try again :) it's the loop of success!

I'm thinking another option would be to interpret `UINTMAX_MAX` (which has the same bits representation as int `-1`) for "current cursor position", and has the advantage of enforcing the semantics of "no valid negative values", but I'm guessing maybe that's not as ergonomic or convenient for cultural reasons...

In Rust it's easier to express these semantics by using an `Option` enum wrapper, so that you can pass `None` to indicate no value or `Some(val)` to pass the magnitude, with `val` being the right type for the job, and everything is clear.

Anyhow the decision must be made according to what makes most sense for the C Api. If that's what your heart tells you then that's it, and I'll wrap around it no prob.
> I'm thinking another option would be to interpret `UINTMAX_MAX` (which has the same bits representation as int `-1`) for "current cursor position", and has the advantage of enforcing the semantics of "no valid negative values", but I'm guessing maybe that's not as ergonomic or convenient for cultural reasons...

indeed, only the USA, Liberia, and Myanmar still refuse to use metric types. what the rest of the world calls `UINTMAX_MAX` (btw i think you mean `UINT_MAX` there; `UINTMAX_MAX` is the maximum value of a `uintmax_t`) we call `FOOTIELARGE`; it's 5039 footies or about 2^50 - 1815. while you might think the 1815 a reference to el Rey Felón's triumphant entry to Valencia, i assure you no one in my country knows who Ferdinand VII is. statistically, i don't even know who he is. if asked, most would likely guess that he was the patron of christopher columbus, or perhaps the archduke of serbia or the person who assassinated the archduke of serbia, but either way they're pretty sure he controlled germany from its capital in seville. remember the maine!

i would worry about the ability for wrappers to access this preprocessor definition, and also given that the internals are gonna stay ints...

> In Rust it's easier to express these semantics by using an `Option` enum wrapper, so that you can pass `None` to indicate no value or `Some(val)` to pass the magnitude, with `val` being the right type for the job, and everything is clear.

i wholeheartedly support you exposing it in this fashion.

> Had I the heavens' embroidered cloths,
Enwrought with golden and silver light,
The blue and the dim and the dark cloths
Of night and light and the half light,
I would spread the cloths under your feet:
But I, being poor, have only my dreams;
I have spread my dreams under your feet;
Tread softly because you tread on my dreams.
--william butler yeats

> Anyhow the decision must be made according to what makes most sense for the C Api. If that's what your heart tells you then that's it, and I'll wrap around it no prob.

tell you what i'm gonna do i'm get on my knees and put it in the Lord's hands. coincidentally, He's also colloquially known as FOOTIELARGE, caps and everything.
Yeah I meant UINT_MAX...

I just found another case where FOOTIELARGE has to make a decision. I'm seeing all of the fields in ncvgeom are `int` but I suspect several of them could probably be `uint`, or are they using the negative side for something else?
> Yeah I meant UINT_MAX...
> 
> I just found another case where FOOTIELARGE has to make a decision. I'm seeing all of the fields in ncvgeom are `int` but I suspect several of them could probably be `uint`, or are they using the negative side for something else?

those can and probably ought all be unsigned

> those can and probably ought all be unsigned

that's great.

BTW do you know which of fields can have a valid 0 value? I'm guessing `lenx` & `leny`, are there any more?
in ncvgeom?

if you pass a NULL `nc`, only pixy and pixx will be non-zero.
if you pass a NULL `n`, only maxpixel{yx}, cdim{yx}, and scale{yx} can be non-zero.
otherwise:
* leny/lenx and beg{yx} are whatever are supplied in `vopts`, 0 by default
* maxpixel{yx} are 0 if there are no maxima for bitmaps
* pix{yx}, cdim{yx}, rcell{yx}, scale{yx} are always non-0 in this case
it also needs diagnostics.

Fix patch:
diff --git a/.drone.yml b/.drone.yml
index f5649c967f..cc90a0eeac 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -74,7 +74,7 @@ name: alpine-edge
 
 steps:
 - name: alpine-edge
-  image: dankamongmen/edge_builder:2021-08-05
+  image: dankamongmen/edge_builder:2021-11-08a
   commands:
     - export LANG=en_US.UTF-8
     - export TERM=vt100
diff --git a/NEWS.md b/NEWS.md
index aca75b9b2c..41deb7bcf3 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -12,6 +12,13 @@ rearrangements of Notcurses.
     deprecated functionality, ABI3 ought require small changes, if any.
 
 * 2.4.9 (not yet released)
+  * Added `ncnmetric()`, which uses `snprintf()` internally. `ncmetric()`
+    was reimplemented as a trivial wrapper around `ncnmetric()`.
+  * `qprefix()`, `bprefix()`, and `iprefix()` have been renamed
+    `ncqprefix()`, `ncbprefix()`, and `nciprefix()`, respectively.
+    All related constants have been prefixed with `NC`, and the old
+    definitions will be removed for abi3.
+    The former forms have been deprecated, and will be removed in abi3.
   * `notcurses_mice_enable()` and `notcurses_mouse_disable()` replace
     `notcurses_mouse_enable()` and `notcurses_mouse_disable()`, which
     have been deprecated, and will be removed in ABI3.
@@ -28,7 +35,13 @@ rearrangements of Notcurses.
     which all used -1. A length of zero passed to line-drawing functions is
     now an error. Several line-drawing functions now reliably return errors
     as opposed to short successes. Dimensions of 0 to `ncplane_mergedown()`
-    now mean "everything".
+    now mean "everything". Almost all coordinates now accept -1 to indicate the
+    current cursor position in that dimension. `ncplane_highgradient()` has
+    been deprecated in favor of the new `ncplane_gradient2x1()`, which takes
+    origin coordinates. `ncplane_format()` and `ncplane_stain()` now take
+    origin coordinates. All now interpret their `unsigned` argument as
+    lengths rather than closing coordinates, observing the same semantics as
+    outlined above.
   * `ncvisual_geom()` has been introduced, using the `ncvgeom` struct
     introduced for direct mode. This allows complete statement of geometry
     for an `ncvisual`. It replaces `ncvisual_blitter_geom()`, which has been
diff --git a/USAGE.md b/USAGE.md
index 6ee6d7d2e1..681883a446 100644
--- a/USAGE.md
+++ b/USAGE.md
@@ -230,7 +230,7 @@ int ncpile_render_to_file(struct ncplane* p, FILE* fp);
 // Retrieve the contents of the specified cell as last rendered. The EGC is
 // returned, or NULL on error. This EGC must be free()d by the caller. The
 // styles and channels are written to 'attrword' and 'channels', respectively.
-char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff,
+char* notcurses_at_yx(struct notcurses* nc, unsigned yoff, unsigned xoff,
                       uint16_t* styles, uint64_t* channels);
 ```
 
@@ -248,14 +248,14 @@ const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
 
 // notcurses_stdplane(), plus free bonus dimensions written to non-NULL y/x!
 static inline struct ncplane*
-notcurses_stddim_yx(struct notcurses* nc, int* restrict y, int* restrict x){
+notcurses_stddim_yx(struct notcurses* nc, unsigned* restrict y, unsigned* restrict x){
   struct ncplane* s = notcurses_stdplane(nc); // can't fail
   ncplane_dim_yx(s, y, x); // accepts NULL
   return s;
 }
 
 static inline const struct ncplane*
-notcurses_stddim_yx_const(const struct notcurses* nc, int* restrict y, int* restrict x){
+notcurses_stddim_yx_const(const struct notcurses* nc, unsigned* restrict y, unsigned* restrict x){
   const struct ncplane* s = notcurses_stdplane_const(nc); // can't fail
   ncplane_dim_yx(s, y, x); // accepts NULL
   return s;
@@ -279,8 +279,8 @@ struct ncplane* notcurses_bottom(struct notcurses* n);
 
 // Return our current idea of the terminal dimensions in rows and cols.
 static inline void
-notcurses_term_dim_yx(const struct notcurses* n, int* restrict rows,
-                      int* restrict cols){
+notcurses_term_dim_yx(const struct notcurses* n, unsigned* restrict rows,
+                      unsigned* restrict cols){
   ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
 }
 
@@ -289,7 +289,7 @@ notcurses_term_dim_yx(const struct notcurses* n, int* restrict rows,
 // primarily useful if the screen is externally corrupted, or if an
 // NCKEY_RESIZE event has been read and you're not yet ready to render. The
 // current screen geometry is returned in 'y' and 'x', if they are not NULL.
-int notcurses_refresh(struct notcurses* n, int* restrict y, int* restrict x);
+int notcurses_refresh(struct notcurses* n, unsigned* restrict y, unsigned* restrict x);
 
 // Enable or disable the terminal's cursor, if supported, placing it at
 // 'y', 'x'. Immediate effect (no need for a call to notcurses_render()).
@@ -451,7 +451,7 @@ are available for direct mode:
 // Read a (heap-allocated) newline-delimited chunk of text. Returns NULL on
 // failure. The NCDIRECT_OPTION_INHIBIT_CBREAK flag ought not be used together
 // with this function, or the line-editing keybindings cannot be honored.
-API char* ncdirect_readline(struct ncdirect* nc, const char* prompt);
+char* ncdirect_readline(struct ncdirect* nc, const char* prompt);
 
 int ncdirect_fg_rgb(struct ncdirect* nc, unsigned rgb);
 int ncdirect_bg_rgb(struct ncdirect* nc, unsigned rgb);
@@ -498,7 +498,7 @@ int ncdirect_cursor_down(struct ncdirect* nc, int num);
 // Get the cursor position, when supported. This requires writing to the
 // terminal, and then reading from it. If the terminal doesn't reply, or
 // doesn't reply in a way we understand, the results might be deleterious.
-int ncdirect_cursor_yx(struct ncdirect* n, int* y, int* x);
+int ncdirect_cursor_yx(struct ncdirect* n, unsigned* y, unsigned* x);
 
 // Push or pop the cursor location to the terminal's stack. The depth of this
 // stack, and indeed its existence, is terminal-dependent.
@@ -919,17 +919,17 @@ struct ncplane* ncplane_dup(struct ncplane* n, void* opaque);
 // Merge the ncplane 'src' down onto the ncplane 'dst'. This is most rigorously
 // defined as "write to 'dst' the frame that would be rendered were the entire
 // stack made up only of the specified subregion of 'src' and, below it, the
-// subregion of 'dst' having the specified origin. Merging is independent of
+// subregion of 'dst' having the specified origin. Supply -1 to indicate the
+// current cursor position in the relevant dimension. Merging is independent of
 // the position of 'src' viz 'dst' on the z-axis. It is an error to define a
 // subregion that is not entirely contained within 'src'. It is an error to
 // define a target origin such that the projected subregion is not entirely
 // contained within 'dst'.  Behavior is undefined if 'src' and 'dst' are
 // equivalent. 'dst' is modified, but 'src' remains unchanged. Neither 'src'
 // nor 'dst' may have sprixels. Lengths of 0 mean "everything left".
-int ncplane_mergedown(struct ncplane* restrict src, struct ncplane* restrict dst,
-                      unsigned begsrcy, unsigned begsrcx,
-                      unsigned leny, unsigned lenx,
-                      unsigned dsty, unsigned dstx);
+int ncplane_mergedown(struct ncplane* RESTRICT src, struct ncplane* RESTRICT dst,
+                      int begsrcy, int begsrcx, unsigned leny, unsigned lenx,
+                      int dsty, int dstx);
 
 // Merge the entirety of 'src' down onto the ncplane 'dst'. If 'src' does not
 // intersect with 'dst', 'dst' will not be changed, but it is not an error.
@@ -1064,16 +1064,16 @@ int ncplane_abs_y(const struct ncplane* n);
 int ncplane_abs_x(const struct ncplane* n);
 
 // Return the dimensions of this ncplane.
-void ncplane_dim_yx(struct ncplane* n, int* restrict rows, int* restrict cols);
+void ncplane_dim_yx(struct ncplane* n, unsigned* restrict rows, unsigned* restrict cols);
 
-static inline int
+static inline unsigned
 ncplane_dim_y(const struct ncplane* n){
   int dimy;
   ncplane_dim_yx(n, &dimy, NULL);
   return dimy;
 }
 
-static inline int
+static inline unsigned
 ncplane_dim_x(const struct ncplane* n){
   int dimx;
   ncplane_dim_yx(n, NULL, &dimx);
@@ -1084,9 +1084,10 @@ ncplane_dim_x(const struct ncplane* n){
 // ('celldimy', 'celldimx'), and the maximum displayable bitmap ('maxbmapy',
 // 'maxbmapx'). If bitmaps are not supported, 'maxbmapy' and 'maxbmapx' will
 // be 0. Any of the geometry arguments may be NULL.
-void ncplane_pixelgeom(struct ncplane* n, int* restrict pxy, int* restrict pxx,
-                       int* restrict celldimy, int* restrict celldimx,
-                       int* restrict maxbmapy, int* restrict maxbmapx);
+void ncplane_pixelgeom(struct ncplane* n,
+                       unsigned* restrict pxy, unsigned* restrict pxx,
+                       unsigned* restrict celldimy, unsigned* restrict celldimx,
+                       unsigned* restrict maxbmapy, unsigned* restrict maxbmapx);
 
 // provided a coordinate relative to the origin of 'src', map it to the same
 // absolute coordinate relative to the origin of 'dst'. either or both of 'y'
@@ -1131,7 +1132,7 @@ int ncplane_set_base_cell(struct ncplane* n, const nccell* c);
 // anywhere that the ncplane's gcluster is 0. Note that the base cell is not
 // affected by ncplane_erase(). 'egc' must be an extended grapheme cluster.
 int ncplane_set_base(struct ncplane* n, const char* egc,
-                     uint32_t stylemask, uint64_t channels);
+                     uint16_t stylemask, uint64_t channels);
 
 // Extract the ncplane's base cell into 'c'. The reference is invalidated if
 // 'ncp' is destroyed.
@@ -1232,7 +1233,8 @@ uint32_t* ncplane_as_rgba(const struct ncplane* n, ncblitter_e blit,
 // 'n'. Start at the plane's 'begy'x'begx' coordinate (which must lie on the
 // plane), continuing for 'leny'x'lenx' cells. Either or both of 'leny' and
 // 'lenx' can be specified as 0 to go through the boundary of the plane.
-char* ncplane_contents(const struct ncplane* nc, unsigned begy, unsigned begx,
+// -1 can be specified for 'begx'/'begy' to use the current cursor location.
+char* ncplane_contents(const struct ncplane* nc, int begy, int begx,
                        unsigned leny, unsigned lenx);
 
 // Manipulate the opaque user pointer associated with this plane.
@@ -1583,7 +1585,7 @@ ncplane_perimeter(struct ncplane* n, const nccell* ul, const nccell* ur,
 }
 
 static inline int
-ncplane_rounded_box(struct ncplane* n, uint32_t attr, uint64_t channels,
+ncplane_rounded_box(struct ncplane* n, uint16_t attr, uint64_t channels,
                     int ystop, int xstop, unsigned ctlword){
   int ret = 0;
   nccell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
@@ -1599,7 +1601,7 @@ ncplane_rounded_box(struct ncplane* n, uint32_t attr, uint64_t channels,
 }
 
 static inline int
-ncplane_rounded_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels,
+ncplane_rounded_box_sized(struct ncplane* n, uint16_t attr, uint64_t channels,
                           int ylen, int xlen, unsigned ctlword){
   int y, x;
   ncplane_cursor_yx(n, &y, &x);
@@ -1608,7 +1610,7 @@ ncplane_rounded_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels,
 }
 
 static inline int
-ncplane_double_box(struct ncplane* n, uint32_t attr, uint64_t channels,
+ncplane_double_box(struct ncplane* n, uint16_t attr, uint64_t channels,
                    int ystop, int xstop, unsigned ctlword){
   int ret = 0;
   nccell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
@@ -1624,7 +1626,7 @@ ncplane_double_box(struct ncplane* n, uint32_t attr, uint64_t channels,
 }
 
 static inline int
-ncplane_double_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels,
+ncplane_double_box_sized(struct ncplane* n, uint16_t attr, uint64_t channels,
                          int ylen, int xlen, unsigned ctlword){
   int y, x;
   ncplane_cursor_yx(n, &y, &x);
@@ -1641,10 +1643,12 @@ Similarly, areas can be filled with a cell.
 // target. We do the same to all cardinally-connected cells having this same
 // fill target. Returns the number of cells polyfilled. An invalid initial y, x
 // is an error. Returns the number of cells filled, or -1 on error.
-int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const nccell* c);
+int ncplane_polyfill_yx(struct ncplane* n, unsigned y, unsigned x, const nccell* c);
 
-// Draw a gradient with its upper-left corner at the current cursor position,
-// stopping at 'ystop'x'xstop'. The glyph composed of 'egc' and 'styles' is
+// Draw a gradient with its upper-left corner at the position specified by 'y'/'x',
+// where -1 means the current cursor position in that dimension. The area is
+// specified by 'ylen'/'xlen', where 0 means "everything remaining below or
+// to the right, respectively." The glyph composed of 'egc' and 'styles' is
 // used for all cells. The channels specified by 'ul', 'ur', 'll', and 'lr'
 // are composed into foreground and background gradients. To do a vertical
 // gradient, 'ul' ought equal 'ur' and 'll' ought equal 'lr'. To do a
@@ -1652,40 +1656,38 @@ int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const nccell* c);
 // color everything the same, all four channels should be equivalent. The
 // resulting alpha values are equal to incoming alpha values. Returns the
 // number of cells filled on success, or -1 on failure.
-int ncplane_gradient(struct ncplane* n, const char* egc, uint32_t styles,
-                     uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr,
-                     int ystop, int xstop);
-
-// Draw a gradient with its upper-left corner at the current cursor position,
-// having dimensions 'ylen'x'xlen'. See ncplane_gradient for more information.
-static inline int
-ncplane_gradient_sized(struct ncplane* n, const char* egc, uint32_t styles,
-                       uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr,
-                       int ylen, int xlen){
-  int y, x;
-  ncplane_cursor_yx(n, &y, &x);
-  return ncplane_gradient(n, egc, styles, ul, ur, ll, lr, y + ylen - 1, x + xlen - 1);
-}
+int ncplane_gradient(struct ncplane* n, int y, int x, unsigned ylen,
+                     unsigned xlen, const char* egc, uint16_t styles,
+                     uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr);
 
 // Do a high-resolution gradient using upper blocks and synced backgrounds.
 // This doubles the number of vertical gradations, but restricts you to
 // half blocks (appearing to be full blocks). Returns the number of cells
 // filled on success, or -1 on error.
-int ncplane_highgradient(struct ncplane* n, uint32_t ul, uint32_t ur,
-                         uint32_t ll, uint32_t lr, int ystop, int xstop);
-
-// ncplane_gradent_sized() meets ncplane_highgradient().
-int ncplane_highgradient_sized(struct ncplane* n, uint32_t ul, uint32_t ur,
-                               uint32_t ll, uint32_t lr, int ylen, int xlen);
+int ncplane_gradient2x1(struct ncplane* n, int y, int x, unsigned ylen,
+                        unsigned xlen, uint32_t ul, uint32_t ur,
+                        uint32_t ll, uint32_t lr);
 
 // Set the given style throughout the specified region, keeping content and
-// channels unchanged. Returns the number of cells set, or -1 on failure.
-int ncplane_format(struct ncplane* n, int ystop, int xstop, uint32_t styles);
+// channels unchanged. The upper left corner is at 'x', 'y', and -1 may be
+// specified to indicate the cursor's position in that dimension. The area
+// is specified by 'xlen', 'ylen', and 0 may be specified to indicate everything
+// remaining to the right and below, respectively. It is an error for any
+// coordinate to be outside the plane. Returns the number of cells set,
+// or -1 on failure.
+int ncplane_format(struct ncplane* n, int y, int x, unsigned ylen,
+                   unsigned xlen, uint16_t stylemask);
 
 // Set the given channels throughout the specified region, keeping content and
-// attributes unchanged. Returns the number of cells set, or -1 on failure.
-int ncplane_stain(struct ncplane* n, int ystop, int xstop,
-                  uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr);
+// channels unchanged. The upper left corner is at 'x', 'y', and -1 may be
+// specified to indicate the cursor's position in that dimension. The area
+// is specified by 'xlen', 'ylen', and 0 may be specified to indicate everything
+// remaining to the right and below, respectively. It is an error for any
+// coordinate to be outside the plane. Returns the number of cells set,
+// or -1 on failure.
+int ncplane_stain(struct ncplane* n, int y, int x, unsigned ylen,
+                  unsigned xlen, uint64_t ul, uint64_t ur,
+                  uint64_t ll, uint64_t lr);
 ```
 
 My 14 year-old self would never forgive me if we didn't have sweet palette
@@ -2037,7 +2039,7 @@ int nccell_load(struct ncplane* n, nccell* c, const char* gcluster);
 // nccell_load(), plus blast the styling with 'attr' and 'channels'.
 static inline int
 nccell_prime(struct ncplane* n, nccell* c, const char* gcluster,
-           uint32_t stylemask, uint64_t channels){
+             uint16_t stylemask, uint64_t channels){
   c->stylemask = stylemask;
   c->channels = channels;
   int ret = nccell_load(n, c, gcluster);
@@ -2151,7 +2153,7 @@ nccellcmp(const struct ncplane* n1, const nccell* RESTRICT c1,
 // have loaded before the error are nccell_release()d. There must be at least
 // six EGCs in gcluster.
 static inline int
-nccells_load_box(struct ncplane* n, uint32_t style, uint64_t channels,
+nccells_load_box(struct ncplane* n, uint16_t style, uint64_t channels,
                  nccell* ul, nccell* ur, nccell* ll, nccell* lr,
                  nccell* hl, nccell* vl, const char* gclusters){
   int ulen;
@@ -2178,13 +2180,13 @@ nccells_load_box(struct ncplane* n, uint32_t style, uint64_t channels,
 
 
 static inline int
-nccells_rounded_box(struct ncplane* n, uint32_t attr, uint64_t channels,
+nccells_rounded_box(struct ncplane* n, uint16_t attr, uint64_t channels,
                     nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, "╭╮╰╯─│");
 }
 
 static inline int
-nccells_double_box(struct ncplane* n, uint32_t attr, uint64_t channels,
+nccells_double_box(struct ncplane* n, uint16_t attr, uint64_t channels,
                    nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, "╔╗╚╝═║");
 }
@@ -3328,15 +3330,15 @@ it was built up:
 // blitters actually supported by this environment. if no ncvisual was
 // supplied, only cdimy/cdimx are filled in.
 typedef struct ncvgeom {
-  int pixy, pixx;     // true pixel geometry of ncvisual data
-  int cdimy, cdimx;   // terminal cell geometry when this was calculated
-  int rpixy, rpixx;   // rendered pixel geometry (per visual_options)
-  int rcelly, rcellx; // rendered cell geometry (per visual_options)
-  int scaley, scalex; // pixels per filled cell (scale == c for bitmaps)
-  int maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
-  int begy, begx;     // upper-left corner of used section
-  int leny, lenx;     // geometry of used section
-  ncblitter_e blitter;// blitter that will be used
+  unsigned pixy, pixx;     // true pixel geometry of ncvisual data
+  unsigned cdimy, cdimx;   // terminal cell geometry when this was calculated
+  unsigned rpixy, rpixx;   // rendered pixel geometry (per visual_options)
+  unsigned rcelly, rcellx; // rendered cell geometry (per visual_options)
+  unsigned scaley, scalex; // pixels per filled cell (scale == c for bitmaps)
+  unsigned begy, begx;     // upper-left corner of used section
+  unsigned leny, lenx;     // geometry of used section
+  unsigned maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
+  ncblitter_e blitter;     // blitter that will be used
 } ncvgeom;
 
 // all-purpose ncvisual geometry solver. one or both of 'nc' and 'n' must be
@@ -3360,13 +3362,15 @@ int ncvisual_resize(struct ncvisual* n, int rows, int cols);
 int ncvisual_resize_noninterpolative(struct ncvisual* n, int rows, int cols);
 
 // Polyfill at the specified location within the ncvisual 'n', using 'rgba'.
-int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba);
+int ncvisual_polyfill_yx(struct ncvisual* n, unsigned y, unsigned x, uint32_t rgba);
 
 // Get the specified pixel from the specified ncvisual.
-int ncvisual_at_yx(const struct ncvisual* n, int y, int x, uint32_t* pixel);
+int ncvisual_at_yx(const struct ncvisual* n, unsigned y, unsigned x,
+                   uint32_t* pixel);
 
 // Set the specified pixel in the specified ncvisual.
-int ncvisual_set_yx(const struct ncvisual* n, int y, int x, uint32_t pixel);
+int ncvisual_set_yx(const struct ncvisual* n, unsigned y, unsigned x,
+                    uint32_t pixel);
 
 // If a subtitle ought be displayed at this time, return a new plane (bound
 // to 'parent' containing the subtitle, which might be text or graphics
@@ -3522,7 +3526,8 @@ a QR code for arbitrary data.
 // returned. Otherwise, the QR code "version" (size) is returned. The QR code
 // is (version * 4 + 17) columns wide, and ⌈version * 4 + 17⌉ rows tall (the
 // properly-scaled values are written back to '*ymax' and '*xmax').
-int ncplane_qrcode(struct ncplane* n, int* ymax, int* xmax, const void* data, size_t len);
+int ncplane_qrcode(struct ncplane* n, unsigned* ymax, unsigned* xmax,
+                   const void* data, size_t len);
 ```
 
 ### Multimedia
diff --git a/cffi/src/notcurses/notcurses.py b/cffi/src/notcurses/notcurses.py
index ebf9afde41..cce37ff70d 100755
--- a/cffi/src/notcurses/notcurses.py
+++ b/cffi/src/notcurses/notcurses.py
@@ -103,8 +103,8 @@ def putEGCYX(self, y, x, egc):
         return ret
 
     def getDimensions(self):
-        y = ffi.new("int *")
-        x = ffi.new("int *")
+        y = ffi.new("unsigned int *")
+        x = ffi.new("unsigned int *")
         lib.ncplane_dim_yx(self.n, y, x)
         return (y[0], x[0])
 
diff --git a/doc/man/man1/notcurses-demo.1.md b/doc/man/man1/notcurses-demo.1.md
index 54f081998d..2c9adb7b5e 100644
--- a/doc/man/man1/notcurses-demo.1.md
+++ b/doc/man/man1/notcurses-demo.1.md
@@ -74,7 +74,7 @@ terminal, and will refuse to run in anything smaller than 80x24.
 **-V**|**--version**: Print the program name and version, and exit with success.
 
 ***demospec***: Select which demos to run, and what order to run them in. The
-default is **ixetunchmdbkywgarvlsfjqzo**. See above for a list of demos.
+default is **ixetunchmdbkywjgarvlsfqzo**. See above for a list of demos.
 
 Default margins are all 0, and thus the full screen will be rendered. Using
 **-m**, margins can be supplied. Provide a single number to set all four margins
diff --git a/doc/man/man3/notcurses_direct.3.md b/doc/man/man3/notcurses_direct.3.md
index 4332d93324..897f1d9198 100644
--- a/doc/man/man3/notcurses_direct.3.md
+++ b/doc/man/man3/notcurses_direct.3.md
@@ -38,9 +38,9 @@ notcurses_direct - minimal notcurses instances for styling text
 
 **int ncdirect_set_bg_palindex(struct ncdirect* ***nc***, int ***pidx***);**
 
-**int ncdirect_dim_x(const struct ncdirect* ***nc***);**
+**unsigned ncdirect_dim_x(const struct ncdirect* ***nc***);**
 
-**int ncdirect_dim_y(const struct ncdirect* ***nc***);**
+**unsigned ncdirect_dim_y(const struct ncdirect* ***nc***);**
 
 **unsigned ncdirect_supported_styles(const struct ncdirect* ***nc***);**
 
@@ -58,6 +58,8 @@ notcurses_direct - minimal notcurses instances for styling text
 
 **int ncdirect_cursor_move_yx(struct ncdirect* ***n***, int ***y***, int ***x***);**
 
+**int ncdirect_cursor_yx(struct ncdirect* ***n***, unsigned* ***y***, unsigned* ***x***);**
+
 **int ncdirect_cursor_enable(struct ncdirect* ***nc***);**
 
 **int ncdirect_cursor_disable(struct ncdirect* ***nc***);**
diff --git a/doc/man/man3/notcurses_lines.3.md b/doc/man/man3/notcurses_lines.3.md
index 8eeca69b67..c8c4cc1f00 100644
--- a/doc/man/man3/notcurses_lines.3.md
+++ b/doc/man/man3/notcurses_lines.3.md
@@ -37,46 +37,68 @@ notcurses_lines - operations on lines and boxes
 
 **static inline int ncplane_perimeter(struct ncplane* ***n***, const nccell* ***ul***, const nccell* ***ur***, const nccell* ***ll***, const nccell* ***lr***, const nccell* ***hline***, const nccell* ***vline***, unsigned ***ctlword***)**
 
-**static inline int nccells_load_box(struct ncplane* ***n***, uint32_t ***styles***, uint64_t ***channels***, nccell* ***ul***, nccell* ***ur***, nccell* ***ll***, nccell* ***lr***, nccell* ***hl***, nccell* ***vl***, const char* ***gclusters***);**
+**static inline int nccells_load_box(struct ncplane* ***n***, uint16_t ***styles***, uint64_t ***channels***, nccell* ***ul***, nccell* ***ur***, nccell* ***ll***, nccell* ***lr***, nccell* ***hl***, nccell* ***vl***, const char* ***gclusters***);**
 
-**static inline int nccells_rounded_box(struct ncplane* ***n***, uint32_t ***styles***, uint64_t ***channels***, nccell* ***ul***, nccell* ***ur***, nccell* ***ll***, nccell* ***lr***, nccell* ***hl***, nccell* ***vl***);**
+**static inline int nccells_rounded_box(struct ncplane* ***n***, uint16_t ***styles***, uint64_t ***channels***, nccell* ***ul***, nccell* ***ur***, nccell* ***ll***, nccell* ***lr***, nccell* ***hl***, nccell* ***vl***);**
 
-**static inline int ncplane_rounded_box(struct ncplane* ***n***, uint32_t ***styles***, uint64_t ***channels***, int ***ystop***, int ***xstop***, unsigned ***ctlword***);**
+**static inline int ncplane_rounded_box(struct ncplane* ***n***, uint16_t ***styles***, uint64_t ***channels***, int ***ystop***, int ***xstop***, unsigned ***ctlword***);**
 
-**static inline int ncplane_rounded_box_sized(struct ncplane* ***n***, uint32_t ***styles***, uint64_t ***channels***, int ***ylen***, int ***xlen***, unsigned ***ctlword***);**
+**static inline int ncplane_rounded_box_sized(struct ncplane* ***n***, uint16_t ***styles***, uint64_t ***channels***, int ***ylen***, int ***xlen***, unsigned ***ctlword***);**
 
-**static inline int nccells_double_box(struct ncplane* ***n***, uint32_t ***styles***, uint64_t ***channels***, nccell* ***ul***, nccell* ***ur***, nccell* ***ll***, nccell* ***lr***, nccell* ***hl***, nccell* ***vl***);**
+**static inline int nccells_double_box(struct ncplane* ***n***, uint16_t ***styles***, uint64_t ***channels***, nccell* ***ul***, nccell* ***ur***, nccell* ***ll***, nccell* ***lr***, nccell* ***hl***, nccell* ***vl***);**
 
-**static inline int ncplane_double_box(struct ncplane* ***n***, uint32_t ***styles***, uint64_t ***channels***, int ***ystop***, int ***xstop***, unsigned ***ctlword***);**
+**static inline int ncplane_double_box(struct ncplane* ***n***, uint16_t ***styles***, uint64_t ***channels***, int ***ystop***, int ***xstop***, unsigned ***ctlword***);**
 
-**static inline int ncplane_double_box_sized(struct ncplane* ***n***, uint32_t ***styles***, uint64_t ***channels***, int ***ylen***, int ***xlen***, unsigned ***ctlword***);**
+**static inline int ncplane_double_box_sized(struct ncplane* ***n***, uint16_t ***styles***, uint64_t ***channels***, int ***ylen***, int ***xlen***, unsigned ***ctlword***);**
 
-**int ncplane_polyfill_yx(struct ncplane* ***n***, int ***y***, int ***x***, const nccell* ***c***);**
+**int ncplane_polyfill_yx(struct ncplane* ***n***, unsigned ***y***, unsigned ***x***, const nccell* ***c***);**
 
-**int ncplane_gradient(struct ncplane* ***n***, const char* ***egc***, uint32_t ***stylemask***, uint64_t ***ul***, uint64_t ***ur***, uint64_t ***ll***, uint64_t ***lr***, int ***ystop***, int ***xstop***);**
+**int ncplane_gradient(struct ncplane* ***n***, int ***y***, int ***x***, unsigned ***ylen***, unsigned ***xlen***, const char* ***egc***, uint16_t ***stylemask***, uint64_t ***ul***, uint64_t ***ur***, uint64_t ***ll***, uint64_t ***lr***);**
 
-**static inline int ncplane_gradient_sized(struct ncplane* ***n***, const char* ***egc***, uint32_t ***stylemask***, uint64_t ***ul***, uint64_t ***ur***, uint64_t ***ll***, uint64_t ***lr***, int ***ylen***, int ***xlen***);**
+**int ncplane_highgradient2x1(struct ncplane* ***n***, int ***y***, int ***x***, unsigned ***ylen***, unsigned ***xlen***, uint32_t ***ul***, uint32_t ***ur***, uint32_t ***ll***, uint32_t ***lr***);**
 
-**int ncplane_highgradient(struct ncplane* ***n***, uint32_t ***ul***, uint32_t ***ur***, uint32_t ***ll***, uint32_t ***lr***, int ***ystop***, int ***xstop***);**
+**int ncplane_format(struct ncplane* ***n***, int ***y***, int ***x***, unsigned ***ylen***, unsigned ***xlen***, uint16_t ***stylemask***);**
 
-**int ncplane_highgradient_sized(struct ncplane* ***n***, uint32_t ***ul***, uint32_t ***ur***, uint32_t ***ll***, uint32_t ***lr***, int ***ylen***, int ***xlen***);**
+**int ncplane_stain(struct ncplane* ***n***, int ***y***, int ***x***, unsigned ***ylen***, unsigned ***xlen***, uint64_t ***ul***, uint64_t ***ur***, uint64_t ***ll***, uint64_t ***lr***);**
 
-**int ncplane_format(struct ncplane* ***n***, int ***ystop***, int ***xstop***, uint32_t ***stylemask***);**
+# DESCRIPTION
 
-**int ncplane_stain(struct ncplane* ***n***, int ***ystop***, int ***xstop***, uint64_t ***ul***, uint64_t ***ur***, uint64_t ***ll***, uint64_t ***lr***);**
+**ncplane_polyfill_yx** starts at the specified ***y*** and ***x*** (provide
+-1 to use the cursor's position in the relevant dimension). The cell at
+these coordinates is replaced with ***c***. All connected cells having the
+same content as this original cell are replaced with ***c***, recursively.
+Two cells are connected if they are vertical or horizontal neighbors of one
+another.
 
-# DESCRIPTION
+**ncplane_gradient** replaces all glyphs in the specified area with
+***egc***, and colors them with the specified gradient. All content
+within the specified area is destroyed.
+
+**ncplane_gradient2x1** draws a high-definition gradient in the specified
+area. It will return an error if UTF8 is not being used. The gradient is
+drawn using the UPPER HALF BLOCK glyph, with two vertical steps and one
+horizontal step in each cell. Since cells are often about twice as tall as
+they are wide, this tends to result in very even color differences. All
+content within the specified area is destroyed.
 
 **ncplane_format** sets the attributes of every cell in the region having its
-upper-left corner at the cursor's current position, and its lower-right corner
-at **ystop**, **xstop**.
+upper-left corner at ***y*** and ***x*** (provide -1 to use the cursor's
+position in the relevant dimension), and its area defined by ***ylen*** and
+***xlen*** (provide 0 to use all remaining area to the right and below,
+respectively). Channels and glyphs will be unaffected.
+
+**ncplane_stain** works the same way, but sets channels. Standard linear
+interpolation is applied between the provided corner channels. Glyphs
+and their attributes will be unaffected.
 
 Box- and line-drawing is unaffected by a plane's scrolling status.
 
 # RETURN VALUES
 
-**ncplane_format** returns -1 if either **ystop** or **xstop** is less than the
-current equivalent position, otherwise 0.
+**ncplane_format**, **ncplane_stain**, **ncplane_gradient**,
+**ncplane_gradient2x1**, and **ncplane_polyfill_yx** return -1 if
+any coordinates are outside the plane, and otherwise the number of cells
+affected.
 
 **ncplane_hline_interp**, **ncplane_hline**, **ncplane_vline_interp**, and
 **ncplane_vline** all return the number of glyphs drawn on success, or -1
diff --git a/doc/man/man3/notcurses_metric.3.md b/doc/man/man3/notcurses_metric.3.md
index 80fa238a1e..c6b41aec8b 100644
--- a/doc/man/man3/notcurses_metric.3.md
+++ b/doc/man/man3/notcurses_metric.3.md
@@ -11,33 +11,33 @@ notcurses_metric - fixed-width numeric output with metric suffixes
 **#include <notcurses/notcurses.h>**
 
 ```c
-#define PREFIXCOLUMNS 7
-#define IPREFIXCOLUMNS 8
-#define BPREFIXCOLUMNS 9
-#define PREFIXSTRLEN (PREFIXCOLUMNS + 1)
-#define IPREFIXSTRLEN (IPREFIXCOLUMNS + 1)
-#define BPREFIXSTRLEN (BPREFIXCOLUMNS + 1)
+#define NCPREFIXCOLUMNS 7
+#define NCIPREFIXCOLUMNS 8
+#define NCBPREFIXCOLUMNS 9
+#define NCPREFIXSTRLEN (NCPREFIXCOLUMNS + 1)
+#define NCIPREFIXSTRLEN (NCIPREFIXCOLUMNS + 1)
+#define NCBPREFIXSTRLEN (NCBPREFIXCOLUMNS + 1)
 #define NCMETRICFWIDTH(x, cols) ((int)(strlen(x) - ncstrwidth(x) + (cols)))
-#define PREFIXFMT(x) NCMETRICFWIDTH((x), PREFIXCOLUMNS), (x)
-#define IPREFIXFMT(x) NCMETRIXFWIDTH((x), IPREFIXCOLUMNS), (x)
-#define BPREFIXFMT(x) NCMETRICFWIDTH((x), BPREFIXCOLUMNS), (x)
+#define NCPREFIXFMT(x) NCMETRICFWIDTH((x), NCPREFIXCOLUMNS), (x)
+#define NCIPREFIXFMT(x) NCMETRIXFWIDTH((x), NCIPREFIXCOLUMNS), (x)
+#define NCBPREFIXFMT(x) NCMETRICFWIDTH((x), NCBPREFIXCOLUMNS), (x)
 ```
 
 **const char* ncmetric(uintmax_t ***val***, uintmax_t ***decimal***, char* ***buf***, int ***omitdec***, unsigned ***mult***, int ***uprefix***);**
 
-**static inline const char* qprefix(uintmax_t ***val***, uintmax_t ***decimal***, char* ***buf***, int ***omitdec***);**
+**static inline const char* ncqprefix(uintmax_t ***val***, uintmax_t ***decimal***, char* ***buf***, int ***omitdec***);**
 
-**static inline const char* iprefix(uintmax_t ***val***, uintmax_t ***decimal***, char* ***buf***, int ***omitdec***);**
+**static inline const char* nciprefix(uintmax_t ***val***, uintmax_t ***decimal***, char* ***buf***, int ***omitdec***);**
 
-**static inline const char* bprefix(uintmax_t ***val***, uintmax_t ***decimal***, char* ***buf***, int ***omitdec***);**
+**static inline const char* ncbprefix(uintmax_t ***val***, uintmax_t ***decimal***, char* ***buf***, int ***omitdec***);**
 
 # DESCRIPTION
 
 **ncmetric** (and the helper wrappers **qprefix** and **bprefix**) accept
 very large (or very small) non-negative numbers, and prepare formatted output
 of a maximum width using metric suffixes. The suffix can represent arbitrary
-amounts of growth, but is designed for 1000 (**PREFIX**) or 1024
-(**IPREFIX**). 1024 is used for "digital units of information", i.e. kibibytes
+amounts of growth, but is designed for 1000 (**NCPREFIX**) or 1024
+(**NCIPREFIX**). 1024 is used for "digital units of information", i.e. kibibytes
 and gibibits. **ncmetric** supports the large suffixes KMGTPEZY (Kilo, Mega,
 Giga, Tera, Peta, Exa, Zetta, and Yotta) and the small suffixes mµnpfazy
 (Milli, Micro, Nano, Pico, Femto, Atto, Zepto, and Yocto). This covers the
@@ -49,28 +49,28 @@ a 64-bit **uintmax_t**.
 should be larger than **val**. The output will be written to **buf**, which
 must be at least:
 
-* **PREFIXSTRLEN** + 1 bytes for a 1000-based value
-* **IPREFIXSTRLEN** + 1 bytes for a 1024-based value
-* **BPREFIXSTRLEN** + 1 bytes for a 1024-based value with an 'i' suffix
+* **NCPREFIXSTRLEN** + 1 bytes for a 1000-based value
+* **NCIPREFIXSTRLEN** + 1 bytes for a 1024-based value
+* **NCBPREFIXSTRLEN** + 1 bytes for a 1024-based value with an 'i' suffix
 
 Three helper functions are provided to simplify these common cases:
 
 ```
-// Mega, kilo, gigafoo. Use PREFIXSTRLEN + 1 and PREFIXCOLUMNS.
+// Mega, kilo, gigafoo. Use NCPREFIXSTRLEN + 1 and NCPREFIXCOLUMNS.
 static inline const char*
-qprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+ncqprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
   return ncmetric(val, decimal, buf, omitdec, 1000, '\0');
 }
 
-// Mibi, kebi, gibibytes sans 'i' suffix. Use IPREFIXSTRLEN + 1.
+// Mibi, kebi, gibibytes sans 'i' suffix. Use NCIPREFIXSTRLEN + 1.
 static inline const char*
-iprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+nciprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
   return ncmetric(val, decimal, buf, omitdec, 1024, '\0');
 }
 
-// Mibi, kebi, gibibytes. Use BPREFIXSTRLEN + 1 and BPREFIXCOLUMNS.
+// Mibi, kebi, gibibytes. Use NCBPREFIXSTRLEN + 1 and NCBPREFIXCOLUMNS.
 static inline const char*
-bprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+ncbprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
   return ncmetric(val, decimal, buf, omitdec, 1024, 'i');
 }
 ```
@@ -86,9 +86,9 @@ bytes, since Unicode doesn't necessarily map to single-byte characters
 (including the 'µ' micro suffix). The corresponding defines for maximum column
 length are:
 
-* **PREFIXCOLUMNS** (7)
-* **IPREFIXCOLUMNS** (8)
-* **BPREFIXCOLUMNS** (9)
+* **NCPREFIXCOLUMNS** (7)
+* **NCIPREFIXCOLUMNS** (8)
+* **NCBPREFIXCOLUMNS** (9)
 
 In general, the maximum-width output will take the form **CCC.mmMu**, where C
 are digits of the characteristic (up to ceil(log10(**mult**)) digits), the
@@ -101,15 +101,15 @@ Three more defines are provided to simplify formatted fixed-width output using
 the results of **ncmetric**. Each of these macros accepts a character buffer
 holding the result of the call, and expand to *two* arguments:
 
-* **PREFIXFMT(x)**
-* **IPREFIXFMT(x)**
-* **BPREFIXFMT(x)**
+* **NCPREFIXFMT(x)**
+* **NCIPREFIXFMT(x)**
+* **NCBPREFIXFMT(x)**
 
 These can be used in e.g. the following ungainly fashion:
 
-**ncplane_printf(n, "%*s", PREFIXFMT(buf));**
+**ncplane_printf(n, "%*s", NCPREFIXFMT(buf));**
 
-to ensure that the output is always **PREFIXCOLUMNS** wide.
+to ensure that the output is always **NCPREFIXCOLUMNS** wide.
 
 # RETURN VALUES
 
diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md
index 6cdf71f7b6..2c403092f3 100644
--- a/doc/man/man3/notcurses_plane.3.md
+++ b/doc/man/man3/notcurses_plane.3.md
@@ -91,7 +91,7 @@ typedef struct ncplane_options {
 
 **int ncplane_set_base_cell(struct ncplane* ***ncp***, const nccell* ***c***);**
 
-**int ncplane_set_base(struct ncplane* ***ncp***, const char* ***egc***, uint32_t ***stylemask***, uint64_t ***channels***);**
+**int ncplane_set_base(struct ncplane* ***ncp***, const char* ***egc***, uint16_t ***stylemask***, uint64_t ***channels***);**
 
 **int ncplane_base(struct ncplane* ***ncp***, nccell* ***c***);**
 
@@ -125,19 +125,19 @@ typedef struct ncplane_options {
 
 **uint32_t* ncplane_as_rgba(const struct ncplane* ***nc***, ncblitter_e ***blit***, unsigned ***begy***, unsigned ***begx***, unsigned ***leny***, unsigned ***lenx***, unsigned* ***pxdimy***, unsigned* ***pxdimx***);**
 
-**char* ncplane_contents(const struct ncplane* ***nc***, unsigned ***begy***, unsigned ***begx***, unsigned ***leny***, unsigned ***lenx***);**
+**char* ncplane_contents(const struct ncplane* ***nc***, int ***begy***, int ***begx***, unsigned ***leny***, unsigned ***lenx***);**
 
 **void* ncplane_set_userptr(struct ncplane* ***n***, void* ***opaque***);**
 
 **void* ncplane_userptr(struct ncplane* ***n***);**
 
-**void ncplane_dim_yx(const struct ncplane* ***n***, int* restrict ***rows***, int* restrict ***cols***);**
+**void ncplane_dim_yx(const struct ncplane* ***n***, unsigned* restrict ***rows***, unsigned* restrict ***cols***);**
 
-**static inline int ncplane_dim_y(const struct ncplane* ***n***);**
+**static inline unsigned ncplane_dim_y(const struct ncplane* ***n***);**
 
-**static inline int ncplane_dim_x(const struct ncplane* ***n***);**
+**static inline unsigned ncplane_dim_x(const struct ncplane* ***n***);**
 
-**void ncplane_cursor_yx(const struct ncplane* ***n***, int* restrict ***y***, int* restrict ***x***);**
+**void ncplane_cursor_yx(const struct ncplane* ***n***, unsigned* restrict ***y***, unsigned* restrict ***x***);**
 
 **void ncplane_translate(const struct ncplane* ***src***, const struct ncplane* ***dst***, int* restrict ***y***, int* restrict ***x***);**
 
@@ -205,7 +205,7 @@ typedef struct ncplane_options {
 
 **void notcurses_drop_planes(struct notcurses* ***nc***);**
 
-**int ncplane_mergedown(struct ncplane* ***src***, struct ncplane* ***dst***, unsigned ***begsrcy***, unsigned ***begsrcx***, unsigned ***leny***, unsigned ***lenx***, unsigned ***dsty***, unsigned ***dstx***);**
+**int ncplane_mergedown(struct ncplane* ***src***, struct ncplane* ***dst***, int ***begsrcy***, int ***begsrcx***, unsigned ***leny***, unsigned ***lenx***, int ***dsty***, int ***dstx***);**
 
 **int ncplane_mergedown_simple(struct ncplane* restrict ***src***, struct ncplane* restrict ***dst***);**
 
@@ -225,7 +225,7 @@ typedef struct ncplane_options {
 
 **int ncplane_rotate_ccw(struct ncplane* ***n***);**
 
-**void ncplane_pixelgeom(struct notcurses* ***n***, int* restrict ***pxy***, int* restrict ***pxx***, int* restrict ***celldimy***, int* restrict ***celldimx***, int* restrict ***maxbmapy***, int* restrict ***maxbmapx***);**
+**void ncplane_pixelgeom(const struct notcurses* ***n***, unsigned* restrict ***pxy***, unsigned* restrict ***pxx***, unsigned* restrict ***celldimy***, unsigned* restrict ***celldimx***, unsigned* restrict ***maxbmapy***, unsigned* restrict ***maxbmapx***);**
 
 **int ncplane_set_name(struct ncplane* ***n***, const char* ***name***);**
 
diff --git a/doc/man/man3/notcurses_refresh.3.md b/doc/man/man3/notcurses_refresh.3.md
index 1e7e0225bb..10247c41bf 100644
--- a/doc/man/man3/notcurses_refresh.3.md
+++ b/doc/man/man3/notcurses_refresh.3.md
@@ -10,7 +10,7 @@ notcurses_refresh - redraw an externally-damaged display
 
 **#include <notcurses/notcurses.h>**
 
-**int notcurses_refresh(const struct notcurses* ***nc***, int* restrict ***rows***, int* restrict ***cols***);**
+**int notcurses_refresh(const struct notcurses* ***nc***, unsigned* restrict ***rows***, unsigned* restrict ***cols***);**
 
 # DESCRIPTION
 
diff --git a/doc/man/man3/notcurses_render.3.md b/doc/man/man3/notcurses_render.3.md
index 9fec2f695e..a2f85d2621 100644
--- a/doc/man/man3/notcurses_render.3.md
+++ b/doc/man/man3/notcurses_render.3.md
@@ -16,7 +16,7 @@ notcurses_render - sync the physical display to a virtual pile
 
 **int notcurses_render(struct notcurses* ***nc***);**
 
-**char* notcurses_at_yx(struct notcurses* ***nc***, int ***yoff***, int ***xoff***, uint16_t* ***styles***, uint64_t* ***channels***);**
+**char* notcurses_at_yx(struct notcurses* ***nc***, unsigned ***yoff***, unsigned ***xoff***, uint16_t* ***styles***, uint64_t* ***channels***);**
 
 **int ncpile_render_to_file(struct ncplane* ***p***, FILE* ***fp***);**
 
diff --git a/doc/man/man3/notcurses_stdplane.3.md b/doc/man/man3/notcurses_stdplane.3.md
index eeaa2b9720..8593abfd9c 100644
--- a/doc/man/man3/notcurses_stdplane.3.md
+++ b/doc/man/man3/notcurses_stdplane.3.md
@@ -14,9 +14,9 @@ notcurses_stdplane - acquire the standard ncplane
 
 **const struct ncplane* notcurses_stdplane_const(const struct notcurses* ***nc***);**
 
-**static inline struct ncplane* notcurses_stddim_yx(struct notcurses* ***nc***, int* restrict ***y***, int* restrict ***x***);**
+**static inline struct ncplane* notcurses_stddim_yx(struct notcurses* ***nc***, unsigned* restrict ***y***, unsigned* restrict ***x***);**
 
-**static inline const struct ncplane* notcurses_stddim_yx_const(const struct notcurses* ***nc***, int* restrict ***y***, int* restrict ***x***);**
+**static inline const struct ncplane* notcurses_stddim_yx_const(const struct notcurses* ***nc***, unsigned* restrict ***y***, unsigned* restrict ***x***);**
 
 **int notcurses_enter_alternate_screen(struct notcurses* ***nc***);**
 
diff --git a/doc/man/man3/notcurses_visual.3.md b/doc/man/man3/notcurses_visual.3.md
index 20ddc6f429..6b73627ce5 100644
--- a/doc/man/man3/notcurses_visual.3.md
+++ b/doc/man/man3/notcurses_visual.3.md
@@ -53,15 +53,15 @@ struct ncvisual_options {
 typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*);
 
 typedef struct ncvgeom {
-  int pixy, pixx;     // true pixel geometry of ncvisual data
-  int cdimy, cdimx;   // terminal cell geometry when this was calculated
-  int rpixy, rpixx;   // rendered pixel geometry (per visual_options)
-  int rcelly, rcellx; // rendered cell geometry (per visual_options)
-  int scaley, scalex; // pixels per filled cell (scale == c for bitmaps)
-  int maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
-  int begy, begx;     // upper-left corner of used section
-  int leny, lenx;     // geometry of used section
-  ncblitter_e blitter;// blitter that will be used
+  unsigned pixy, pixx;     // true pixel geometry of ncvisual data
+  unsigned cdimy, cdimx;   // terminal cell geometry when this was calculated
+  unsigned rpixy, rpixx;   // rendered pixel geometry (per visual_options)
+  unsigned rcelly, rcellx; // rendered cell geometry (per visual_options)
+  unsigned scaley, scalex; // pixels per filled cell (scale == c for bitmaps)
+  unsigned begy, begx;     // upper-left corner of used section
+  unsigned leny, lenx;     // geometry of used section
+  unsigned maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
+  ncblitter_e blitter;i    // blitter that will be used
 } ncvgeom;
 ```
 
@@ -103,9 +103,9 @@ typedef struct ncvgeom {
 
 **int ncvisual_polyfill_yx(struct ncvisual* ***n***, int ***y***, int ***x***, uint32_t ***rgba***);**
 
-**int ncvisual_at_yx(const struct ncvisual* ***n***, int ***y***, int ***x***, uint32_t* ***pixel***);**
+**int ncvisual_at_yx(const struct ncvisual* ***n***, unsigned ***y***, unsigned ***x***, uint32_t* ***pixel***);**
 
-**int ncvisual_set_yx(const struct ncvisual* ***n***, int ***y***, int ***x***, uint32_t ***pixel***);**
+**int ncvisual_set_yx(const struct ncvisual* ***n***, unsigned ***y***, unsigned ***x***, uint32_t ***pixel***);**
 
 **struct ncplane* ncvisual_subtitle_plane(struct ncplane* ***parent***, const struct ncvisual* ***ncv***);**
 
@@ -119,7 +119,7 @@ typedef struct ncvgeom {
 
 **ncblitter_e ncvisual_media_defblitter(const struct notcurses ***nc***, ncscale_e ***scaling***);**
 
-**int ncplane_qrcode(struct ncplane* ***n***, int* ***ymax***, int* ***xmax***, const void* ***data***, size_t ***len***)**
+**int ncplane_qrcode(struct ncplane* ***n***, unsigned* ***ymax***, unsigned* ***xmax***, const void* ***data***, size_t ***len***)**
 
 # DESCRIPTION
 
diff --git a/include/ncpp/Direct.hh b/include/ncpp/Direct.hh
index cad03b27b6..3b62f18d5b 100644
--- a/include/ncpp/Direct.hh
+++ b/include/ncpp/Direct.hh
@@ -75,14 +75,14 @@ namespace ncpp
 			return error_guard (ncdirect_set_bg_palindex (direct, pidx), -1);
 		}
 
-		int get_dim_x () const NOEXCEPT_MAYBE
+		unsigned get_dim_x () const NOEXCEPT_MAYBE
 		{
-			return error_guard<int> (ncdirect_dim_x (direct), -1);
+			return ncdirect_dim_x (direct);
 		}
 
-		int get_dim_y () const NOEXCEPT_MAYBE
+		unsigned get_dim_y () const NOEXCEPT_MAYBE
 		{
-			return error_guard<int> (ncdirect_dim_y (direct), -1);
+			return ncdirect_dim_y (direct);
 		}
 
 		unsigned get_palette_size () const noexcept
@@ -140,12 +140,12 @@ namespace ncpp
 			return error_guard (ncdirect_cursor_disable (direct), -1);
 		}
 
-		void get_cursor_yx (int *y, int *x) const noexcept
+		void get_cursor_yx (unsigned *y, unsigned *x) const noexcept
 		{
 			ncdirect_cursor_yx (direct, y, x);
 		}
 
-		void get_cursor_yx (int &y, int &x) const noexcept
+		void get_cursor_yx (unsigned &y, unsigned &x) const noexcept
 		{
 			get_cursor_yx (&y, &x);
 		}
diff --git a/include/ncpp/NotCurses.hh b/include/ncpp/NotCurses.hh
index 6142b609fd..416ad28483 100644
--- a/include/ncpp/NotCurses.hh
+++ b/include/ncpp/NotCurses.hh
@@ -69,19 +69,19 @@ namespace ncpp
 			return ::ncmetric (val, decimal, buf, omitdec, mult, uprefix);
 		}
 
-		static const char* qprefix (uintmax_t val, uintmax_t decimal, char *buf, int omitdec) noexcept
+		static const char* ncqprefix (uintmax_t val, uintmax_t decimal, char *buf, int omitdec) noexcept
 		{
-			return ::qprefix (val, decimal, buf, omitdec);
+			return ::ncqprefix (val, decimal, buf, omitdec);
 		}
 
-		static const char* iprefix (uintmax_t val, uintmax_t decimal, char *buf, int omitdec) noexcept
+		static const char* nciprefix (uintmax_t val, uintmax_t decimal, char *buf, int omitdec) noexcept
 		{
-			return ::iprefix (val, decimal, buf, omitdec);
+			return ::nciprefix (val, decimal, buf, omitdec);
 		}
 
-		static const char* bprefix (uintmax_t val, uintmax_t decimal, char *buf, int omitdec) noexcept
+		static const char* ncbprefix (uintmax_t val, uintmax_t decimal, char *buf, int omitdec) noexcept
 		{
-			return ::bprefix (val, decimal, buf, omitdec);
+			return ::ncbprefix (val, decimal, buf, omitdec);
 		}
 
 		static const char* version () noexcept
@@ -200,22 +200,22 @@ namespace ncpp
 			return error_guard (notcurses_render (nc), -1);
 		}
 
-		void get_term_dim (int *rows, int *cols) const noexcept
+		void get_term_dim (unsigned *rows, unsigned *cols) const noexcept
 		{
 			notcurses_term_dim_yx (nc, rows, cols);
 		}
 
-		void get_term_dim (int &rows, int &cols) const noexcept
+		void get_term_dim (unsigned &rows, unsigned &cols) const noexcept
 		{
 			get_term_dim (&rows, &cols);
 		}
 
-		bool refresh (int* rows, int* cols) const NOEXCEPT_MAYBE
+		bool refresh (unsigned* rows, unsigned* cols) const NOEXCEPT_MAYBE
 		{
 			return error_guard (notcurses_refresh (nc, rows, cols), -1);
 		}
 
-		bool refresh (int& rows, int& cols) const NOEXCEPT_MAYBE
+		bool refresh (unsigned& rows, unsigned& cols) const NOEXCEPT_MAYBE
 		{
 			return refresh (&rows, &cols);
 		}
@@ -308,7 +308,7 @@ namespace ncpp
 			return new Plane (notcurses_stdplane (nc), true);
 		}
 
-		Plane* get_stdplane (int *y, int *x)
+		Plane* get_stdplane (unsigned *y, unsigned *x)
 		{
 			if (y == nullptr)
 				throw invalid_argument ("'y' must be a valid pointer");
@@ -318,7 +318,7 @@ namespace ncpp
 			return get_stdplane (*y, *x);
 		}
 
-		Plane* get_stdplane (int &y, int &x) noexcept
+		Plane* get_stdplane (unsigned &y, unsigned &x) noexcept
 		{
 			return new Plane (notcurses_stddim_yx (nc, &y, &x));
 		}
diff --git a/include/ncpp/Plane.hh b/include/ncpp/Plane.hh
index 80bd1f9aa5..0bf306ac60 100644
--- a/include/ncpp/Plane.hh
+++ b/include/ncpp/Plane.hh
@@ -80,7 +80,7 @@ namespace ncpp
 			plane = create_plane (n, rows, cols, yoff, xoff, opaque);
 		}
 
-		explicit Plane (int rows, int cols, int yoff, int xoff, void *opaque = nullptr, NotCurses *ncinst = nullptr)
+		explicit Plane (unsigned rows, unsigned cols, int yoff, int xoff, void *opaque = nullptr, NotCurses *ncinst = nullptr)
 			: Root (ncinst)
 		{
 			ncplane_options nopts = {
@@ -213,24 +213,14 @@ namespace ncpp
 			return error_guard (ncplane_pulse (plane, ts, fader, curry), -1);
 		}
 
-		int gradient (const char* egc, uint16_t stylemask, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ystop, int xstop) const NOEXCEPT_MAYBE
+		int gradient (int y, int x, unsigned ylen, unsigned xlen, const char* egc, uint16_t stylemask, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr) const NOEXCEPT_MAYBE
 		{
-			return error_guard<int> (ncplane_gradient (plane, egc, stylemask, ul, ur, ll, lr, ystop, xstop), -1);
+			return error_guard<int> (ncplane_gradient (plane, y, x, ylen, xlen, egc, stylemask, ul, ur, ll, lr), -1);
 		}
 
-		int gradient_sized (const char* egc, uint16_t stylemask, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ylen, int xlen) const NOEXCEPT_MAYBE
+		int gradient2x1 (int y, int x, unsigned ylen, unsigned xlen, uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr) const NOEXCEPT_MAYBE
 		{
-			return error_guard<int> (ncplane_gradient_sized (plane, egc, stylemask, ul, ur, ll, lr, ylen, xlen), -1);
-		}
-
-		int high_gradient (uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr, int ylen, int xlen) const NOEXCEPT_MAYBE
-		{
-			return error_guard<int> (ncplane_highgradient (plane, ul, ur, ll, lr, ylen, xlen), -1);
-		}
-
-		int high_gradient_sized (uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr, int ylen, int xlen) const NOEXCEPT_MAYBE
-		{
-			return error_guard<int> (ncplane_highgradient_sized (plane, ul, ur, ll, lr, ylen, xlen), -1);
+			return error_guard<int> (ncplane_gradient2x1 (plane, y, x, ylen, xlen, ul, ur, ll, lr), -1);
 		}
 
 		void greyscale () const noexcept
@@ -323,22 +313,22 @@ namespace ncpp
 			return error_guard<int> (ncplane_valign (plane, static_cast<ncalign_e>(align), r), INT_MAX);
 		}
 
-		void get_dim (int *rows, int *cols) const noexcept
+		void get_dim (unsigned *rows, unsigned *cols) const noexcept
 		{
 			ncplane_dim_yx (plane, rows, cols);
 		}
 
-		void get_dim (int &rows, int &cols) const noexcept
+		void get_dim (unsigned &rows, unsigned &cols) const noexcept
 		{
 			get_dim (&rows, &cols);
 		}
 
-		int get_dim_x () const noexcept
+		unsigned get_dim_x () const noexcept
 		{
 			return ncplane_dim_x (plane);
 		}
 
-		int get_dim_y () const noexcept
+		unsigned get_dim_y () const noexcept
 		{
 			return ncplane_dim_y (plane);
 		}
@@ -457,7 +447,7 @@ namespace ncpp
 			return mergedown (&dst, begsrcy, begsrcx, leny, lenx, dsty, dstx);
 		}
 
-		bool mergedown (Plane *dst, unsigned begsrcy, unsigned begsrcx, unsigned leny, unsigned lenx, unsigned dsty, unsigned dstx) const
+		bool mergedown (Plane *dst, int begsrcy, int begsrcx, unsigned leny, unsigned lenx, int dsty, int dstx) const
 		{
 			if (plane == dst->plane)
 				throw invalid_argument ("'dst' must refer to a different plane than the one this method is called on");
@@ -483,12 +473,12 @@ namespace ncpp
 			return error_guard (ncplane_cursor_move_yx (plane, y, x), -1);
 		}
 
-		void get_cursor_yx (int *y, int *x) const noexcept
+		void get_cursor_yx (unsigned *y, unsigned *x) const noexcept
 		{
 			ncplane_cursor_yx (plane, y, x);
 		}
 
-		void get_cursor_yx (int &y, int &x) const noexcept
+		void get_cursor_yx (unsigned &y, unsigned &x) const noexcept
 		{
 			get_cursor_yx (&y, &x);
 		}
@@ -958,14 +948,14 @@ namespace ncpp
 			ncplane_off_styles (plane, static_cast<unsigned>(styles));
 		}
 
-		int format (int ystop, int xstop, uint16_t stylemask) const NOEXCEPT_MAYBE
+		int format (int y, int x, unsigned ylen, unsigned xlen, uint16_t stylemask) const NOEXCEPT_MAYBE
 		{
-			return error_guard<int> (ncplane_format (plane, ystop, xstop, stylemask), -1);
+			return error_guard<int> (ncplane_format (plane, y, x, ylen, xlen, stylemask), -1);
 		}
 
-		int stain (int ystop, int xstop, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr) const NOEXCEPT_MAYBE
+		int stain (int y, int x, unsigned ylen, unsigned xlen, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr) const NOEXCEPT_MAYBE
 		{
-			return error_guard<int> (ncplane_stain (plane, ystop, xstop, ul, ur, ll, lr), -1);
+			return error_guard<int> (ncplane_stain (plane, y, x, ylen, xlen, ul, ur, ll, lr), -1);
 		}
 
 		Plane* get_below () const noexcept
@@ -1225,7 +1215,7 @@ namespace ncpp
 			return error_guard_cond<bool, bool> (ret, ret);
 		}
 
-		int qrcode (int* ymax, int* xmax, const void *data, size_t len) const NOEXCEPT_MAYBE
+		int qrcode (unsigned* ymax, unsigned* xmax, const void *data, size_t len) const NOEXCEPT_MAYBE
 		{
 			int ret = ncplane_qrcode (plane, ymax, xmax, data, len);
 			return error_guard_cond<int> (ret, ret < 0);
@@ -1301,7 +1291,7 @@ namespace ncpp
 		static void unmap_plane (Plane *p) noexcept;
 
 	private:
-		ncplane* create_plane (const Plane &n, int rows, int cols, int yoff, int xoff, void *opaque)
+		ncplane* create_plane (const Plane &n, unsigned rows, unsigned cols, int yoff, int xoff, void *opaque)
 		{
 			ncplane_options nopts = {
 				.y = yoff,
@@ -1318,7 +1308,7 @@ namespace ncpp
 			return create_plane (n, nopts);
 		}
 
-		ncplane* create_plane (Plane &n, int rows, int cols, int yoff, NCAlign align, void *opaque)
+		ncplane* create_plane (Plane &n, unsigned rows, unsigned cols, int yoff, NCAlign align, void *opaque)
 		{
 			ncplane_options nopts = {
 				yoff,
diff --git a/include/notcurses/direct.h b/include/notcurses/direct.h
index e416661872..063a88e20c 100644
--- a/include/notcurses/direct.h
+++ b/include/notcurses/direct.h
@@ -194,14 +194,15 @@ ncdirect_bg_default(struct ncdirect* nc){
 }
 
 // Get the current number of columns/rows.
-API int ncdirect_dim_x(struct ncdirect* nc) __attribute__ ((nonnull (1)));
-API int ncdirect_dim_y(struct ncdirect* nc) __attribute__ ((nonnull (1)));
+API unsigned ncdirect_dim_x(struct ncdirect* nc) __attribute__ ((nonnull (1)));
+API unsigned ncdirect_dim_y(struct ncdirect* nc) __attribute__ ((nonnull (1)));
 
 // Returns a 16-bit bitmask of supported curses-style attributes
 // (NCSTYLE_UNDERLINE, NCSTYLE_BOLD, etc.) The attribute is only
 // indicated as supported if the terminal can support it together with color.
 // For more information, see the "ncv" capability in terminfo(5).
-API unsigned ncdirect_supported_styles(const struct ncdirect* nc);
+API unsigned ncdirect_supported_styles(const struct ncdirect* nc)
+  __attribute__ ((nonnull (1)));
 
 // ncplane_styles_*() analogues
 API int ncdirect_set_styles(struct ncdirect* n, unsigned stylebits)
@@ -240,7 +241,7 @@ API int ncdirect_cursor_down(struct ncdirect* nc, int num)
 // Get the cursor position, when supported. This requires writing to the
 // terminal, and then reading from it. If the terminal doesn't reply, or
 // doesn't reply in a way we understand, the results might be deleterious.
-API int ncdirect_cursor_yx(struct ncdirect* n, int* y, int* x)
+API int ncdirect_cursor_yx(struct ncdirect* n, unsigned* y, unsigned* x)
   __attribute__ ((nonnull (1)));
 
 // Push or pop the cursor location to the terminal's stack. The depth of this
diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h
index f368966f0b..cb9ce6f78c 100644
--- a/include/notcurses/notcurses.h
+++ b/include/notcurses/notcurses.h
@@ -532,7 +532,7 @@ static inline uint64_t
 ncchannels_set_fg_default(uint64_t* channels){
   uint32_t channel = ncchannels_fchannel(*channels);
   ncchannel_set_default(&channel);
-  *channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
+  ncchannels_set_fchannel(channels, channel);
   return *channels;
 }
 
@@ -684,7 +684,7 @@ API int nccell_load(struct ncplane* n, nccell* c, const char* gcluster);
 // nccell_load(), plus blast the styling with 'attr' and 'channels'.
 static inline int
 nccell_prime(struct ncplane* n, nccell* c, const char* gcluster,
-             uint32_t stylemask, uint64_t channels){
+             uint16_t stylemask, uint64_t channels){
   c->stylemask = stylemask;
   c->channels = channels;
   int ret = nccell_load(n, c, gcluster);
@@ -781,7 +781,7 @@ nccell_extended_gcluster(const struct ncplane* n, const nccell* c);
 
 // return the number of columns occupied by 'c'. see ncstrwidth() for an
 // equivalent for multiple EGCs.
-static inline int
+static inline unsigned
 nccell_cols(const nccell* c){
   return c->width ? c->width : 1;
 }
@@ -1169,7 +1169,7 @@ API int notcurses_linesigs_enable(struct notcurses* n)
 // primarily useful if the screen is externally corrupted, or if an
 // NCKEY_RESIZE event has been read and you're not yet ready to render. The
 // current screen geometry is returned in 'y' and 'x', if they are not NULL.
-API int notcurses_refresh(struct notcurses* n, int* RESTRICT y, int* RESTRICT x)
+API int notcurses_refresh(struct notcurses* n, unsigned* RESTRICT y, unsigned* RESTRICT x)
   __attribute__ ((nonnull (1)));
 
 // Extract the Notcurses context to which this plane is attached.
@@ -1180,7 +1180,7 @@ API const struct notcurses* ncplane_notcurses_const(const struct ncplane* n)
   __attribute__ ((nonnull (1)));
 
 // Return the dimensions of this ncplane. y or x may be NULL.
-API void ncplane_dim_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x)
+API void ncplane_dim_yx(const struct ncplane* n, unsigned* RESTRICT y, unsigned* RESTRICT x)
   __attribute__ ((nonnull (1)));
 
 // Get a reference to the standard plane (one matching our current idea of the
@@ -1191,53 +1191,54 @@ API const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
 
 // notcurses_stdplane(), plus free bonus dimensions written to non-NULL y/x!
 static inline struct ncplane*
-notcurses_stddim_yx(struct notcurses* nc, int* RESTRICT y, int* RESTRICT x){
+notcurses_stddim_yx(struct notcurses* nc, unsigned* RESTRICT y, unsigned* RESTRICT x){
   struct ncplane* s = notcurses_stdplane(nc); // can't fail
   ncplane_dim_yx(s, y, x); // accepts NULL
   return s;
 }
 
 static inline const struct ncplane*
-notcurses_stddim_yx_const(const struct notcurses* nc, int* RESTRICT y, int* RESTRICT x){
+notcurses_stddim_yx_const(const struct notcurses* nc, unsigned* RESTRICT y, unsigned* RESTRICT x){
   const struct ncplane* s = notcurses_stdplane_const(nc); // can't fail
   ncplane_dim_yx(s, y, x); // accepts NULL
   return s;
 }
 
-static inline int
+static inline unsigned
 ncplane_dim_y(const struct ncplane* n){
-  int dimy;
+  unsigned dimy;
   ncplane_dim_yx(n, &dimy, NULL);
   return dimy;
 }
 
-static inline int
+static inline unsigned
 ncplane_dim_x(const struct ncplane* n){
-  int dimx;
+  unsigned dimx;
   ncplane_dim_yx(n, NULL, &dimx);
   return dimx;
 }
 
 // Retrieve pixel geometry for the display region ('pxy', 'pxx'), each cell
 // ('celldimy', 'celldimx'), and the maximum displayable bitmap ('maxbmapy',
-// 'maxbmapx'). If bitmaps are not supported, 'maxbmapy' and 'maxbmapx' will
-// be 0. Any of the geometry arguments may be NULL. These results are
-// invalidated by a terminal resize.
-API void ncplane_pixelgeom(const struct ncplane* n, int* RESTRICT pxy, int* RESTRICT pxx,
-                           int* RESTRICT celldimy, int* RESTRICT celldimx,
-                           int* RESTRICT maxbmapy, int* RESTRICT maxbmapx)
+// 'maxbmapx'). If bitmaps are not supported, or if there is no artificial
+// limit on bitmap size, 'maxbmapy' and 'maxbmapx' will be 0. Any of the
+// geometry arguments may be NULL.
+API void ncplane_pixelgeom(const struct ncplane* n,
+                           unsigned* RESTRICT pxy, unsigned* RESTRICT pxx,
+                           unsigned* RESTRICT celldimy, unsigned* RESTRICT celldimx,
+                           unsigned* RESTRICT maxbmapy, unsigned* RESTRICT maxbmapx)
   __attribute__ ((nonnull (1)));
 
 // Return our current idea of the terminal dimensions in rows and cols.
 static inline void
-notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows, int* RESTRICT cols){
+notcurses_term_dim_yx(const struct notcurses* n, unsigned* RESTRICT rows, unsigned* RESTRICT cols){
   ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
 }
 
 // Retrieve the contents of the specified cell as last rendered. Returns the EGC
 // or NULL on error. This EGC must be free()d by the caller. The stylemask and
 // channels are written to 'stylemask' and 'channels', respectively.
-API char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff,
+API char* notcurses_at_yx(struct notcurses* nc, unsigned yoff, unsigned xoff,
                           uint16_t* stylemask, uint64_t* channels)
   __attribute__ ((nonnull (1)));
 
@@ -1260,8 +1261,8 @@ API char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff,
 typedef struct ncplane_options {
   int y;            // vertical placement relative to parent plane
   int x;            // horizontal placement relative to parent plane
-  int rows;         // rows, must be positive (unless NCPLANE_OPTION_MARGINALIZED)
-  int cols;         // columns, must be positive (unless NCPLANE_OPTION_MARGINALIZED)
+  unsigned rows;    // rows, must be >0 unless NCPLANE_OPTION_MARGINALIZED
+  unsigned cols;    // columns, must be >0 unless NCPLANE_OPTION_MARGINALIZED
   void* userptr;    // user curry, may be NULL
   const char* name; // name (used only for debugging), may be NULL
   int (*resizecb)(struct ncplane*); // callback when parent is resized
@@ -1603,10 +1604,10 @@ API int ncplane_resize(struct ncplane* n, int keepy, int keepx,
 // shrinking in some dimension). Keep the origin where it is.
 static inline int
 ncplane_resize_simple(struct ncplane* n, unsigned ylen, unsigned xlen){
-  int oldy, oldx;
+  unsigned oldy, oldx;
   ncplane_dim_yx(n, &oldy, &oldx); // current dimensions of 'n'
-  unsigned keepleny = (unsigned)oldy > ylen ? ylen : (unsigned)oldy;
-  unsigned keeplenx = (unsigned)oldx > xlen ? xlen : (unsigned)oldx;
+  unsigned keepleny = oldy > ylen ? ylen : oldy;
+  unsigned keeplenx = oldx > xlen ? xlen : oldx;
   return ncplane_resize(n, 0, 0, keepleny, keeplenx, 0, 0, ylen, xlen);
 }
 
@@ -1626,7 +1627,7 @@ API int ncplane_set_base_cell(struct ncplane* n, const nccell* c);
 // affected by ncplane_erase(). 'egc' must be an extended grapheme cluster.
 // Returns the number of bytes copied out of 'gcluster', or -1 on failure.
 API int ncplane_set_base(struct ncplane* n, const char* egc,
-                         uint32_t stylemask, uint64_t channels);
+                         uint16_t stylemask, uint64_t channels);
 
 // Extract the ncplane's base nccell into 'c'. The reference is invalidated if
 // 'ncp' is destroyed.
@@ -1783,7 +1784,8 @@ API int ncplane_at_yx_cell(struct ncplane* n, int y, int x, nccell* c);
 // 'n'. Start at the plane's 'begy'x'begx' coordinate (which must lie on the
 // plane), continuing for 'leny'x'lenx' cells. Either or both of 'leny' and
 // 'lenx' can be specified as 0 to go through the boundary of the plane.
-API char* ncplane_contents(struct ncplane* n, unsigned begy, unsigned begx,
+// -1 can be specified for 'begx'/'begy' to use the current cursor location.
+API char* ncplane_contents(struct ncplane* n, int begy, int begx,
                            unsigned leny, unsigned lenx);
 
 // Manipulate the opaque user pointer associated with this plane.
@@ -1806,7 +1808,7 @@ API void ncplane_center_abs(const struct ncplane* n, int* RESTRICT y,
 // Only glyphs from the specified ncblitset may be present. If 'pxdimy' and/or
 // 'pxdimx' are non-NULL, they will be filled in with the total pixel geometry.
 API ALLOC uint32_t* ncplane_as_rgba(const struct ncplane* n, ncblitter_e blit,
-                                    unsigned begy, unsigned begx,
+                                    int begy, int begx,
                                     unsigned leny, unsigned lenx,
                                     unsigned* pxdimy, unsigned* pxdimx)
   __attribute__ ((nonnull (1)));
@@ -1861,7 +1863,7 @@ API void ncplane_home(struct ncplane* n)
   __attribute__ ((nonnull (1)));
 
 // Get the current position of the cursor within n. y and/or x may be NULL.
-API void ncplane_cursor_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x)
+API void ncplane_cursor_yx(const struct ncplane* n, unsigned* RESTRICT y, unsigned* RESTRICT x)
   __attribute__ ((nonnull (1)));
 
 // Get the current channels or attribute word for ncplane 'n'.
@@ -2234,12 +2236,12 @@ API int ncplane_box(struct ncplane* n, const nccell* ul, const nccell* ur,
 static inline int
 ncplane_box_sized(struct ncplane* n, const nccell* ul, const nccell* ur,
                   const nccell* ll, const nccell* lr, const nccell* hline,
-                  const nccell* vline, unsigned ylen, unsigned xlen,
+                  const nccell* vline, unsigned ystop, unsigned xstop,
                   unsigned ctlword){
-  int y, x;
+  unsigned y, x;
   ncplane_cursor_yx(n, &y, &x);
-  return ncplane_box(n, ul, ur, ll, lr, hline, vline, y + ylen - 1,
-                     x + xlen - 1, ctlword);
+  return ncplane_box(n, ul, ur, ll, lr, hline, vline, y + ystop - 1,
+                     x + xstop - 1, ctlword);
 }
 
 static inline int
@@ -2249,7 +2251,7 @@ ncplane_perimeter(struct ncplane* n, const nccell* ul, const nccell* ur,
   if(ncplane_cursor_move_yx(n, 0, 0)){
     return -1;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   return ncplane_box_sized(n, ul, ur, ll, lr, hline, vline, dimy, dimx, ctlword);
 }
@@ -2259,10 +2261,13 @@ ncplane_perimeter(struct ncplane* n, const nccell* ul, const nccell* ur,
 // target. We do the same to all cardinally-connected cells having this same
 // fill target. Returns the number of cells polyfilled. An invalid initial y, x
 // is an error. Returns the number of cells filled, or -1 on error.
-API int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const nccell* c);
+API int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const nccell* c)
+  __attribute__ ((nonnull (1, 4)));
 
-// Draw a gradient with its upper-left corner at the current cursor position,
-// stopping at 'ystop'x'xstop'. The glyph composed of 'egc' and 'stylemask' is
+// Draw a gradient with its upper-left corner at the position specified by 'y'/'x',
+// where -1 means the current cursor position in that dimension. The area is
+// specified by 'ylen'/'xlen', where 0 means "everything remaining below or
+// to the right, respectively." The glyph composed of 'egc' and 'styles' is
 // used for all cells. The channels specified by 'ul', 'ur', 'll', and 'lr'
 // are composed into foreground and background gradients. To do a vertical
 // gradient, 'ul' ought equal 'ur' and 'll' ought equal 'lr'. To do a
@@ -2270,7 +2275,6 @@ API int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const nccell* c);
 // color everything the same, all four channels should be equivalent. The
 // resulting alpha values are equal to incoming alpha values. Returns the
 // number of cells filled on success, or -1 on failure.
-//
 // Palette-indexed color is not supported.
 //
 // Preconditions for gradient operations (error otherwise):
@@ -2280,44 +2284,40 @@ API int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const nccell* c);
 //  1x1: all four colors must be the same
 //  1xN: both top and both bottom colors must be the same (vertical gradient)
 //  Nx1: both left and both right colors must be the same (horizontal gradient)
-API int ncplane_gradient(struct ncplane* n, const char* egc, uint32_t stylemask,
-                         uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr,
-                         int ystop, int xstop);
+API int ncplane_gradient(struct ncplane* n, int y, int x, unsigned ylen,
+                         unsigned xlen, const char* egc, uint16_t styles,
+                         uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr)
+  __attribute__ ((nonnull (1, 6)));
 
 // Do a high-resolution gradient using upper blocks and synced backgrounds.
 // This doubles the number of vertical gradations, but restricts you to
 // half blocks (appearing to be full blocks). Returns the number of cells
 // filled on success, or -1 on error.
-API int ncplane_highgradient(struct ncplane* n, uint32_t ul, uint32_t ur,
-                             uint32_t ll, uint32_t lr, int ystop, int xstop);
-
-// Draw a gradient with its upper-left corner at the current cursor position,
-// having dimensions 'ylen'x'xlen'. See ncplane_gradient for more information.
-static inline int
-ncplane_gradient_sized(struct ncplane* n, const char* egc, uint32_t stylemask,
-                       uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr,
-                       int ylen, int xlen){
-  if(ylen < 1 || xlen < 1){
-    return -1;
-  }
-  int y, x;
-  ncplane_cursor_yx(n, &y, &x);
-  return ncplane_gradient(n, egc, stylemask, ul, ur, ll, lr,
-                          y + ylen - 1, x + xlen - 1);
-}
-
-// ncplane_gradent_sized() meets ncplane_highgradient().
-API int ncplane_highgradient_sized(struct ncplane* n, uint32_t ul, uint32_t ur,
-                                   uint32_t ll, uint32_t lr, int ylen, int xlen);
+API int ncplane_gradient2x1(struct ncplane* n, int y, int x, unsigned ylen,
+                            unsigned xlen, uint32_t ul, uint32_t ur,
+                            uint32_t ll, uint32_t lr)
+  __attribute__ ((nonnull (1)));
 
 // Set the given style throughout the specified region, keeping content and
-// channels unchanged. Returns the number of cells set, or -1 on failure.
-API int ncplane_format(struct ncplane* n, int ystop, int xstop, uint32_t stylemask);
+// channels unchanged. The upper left corner is at 'x', 'y', and -1 may be
+// specified to indicate the cursor's position in that dimension. The lower
+// right corner is specified by 'xstop', 'ystop'. It is an error for any
+// coordinate to be outside the plane. Returns the number of cells set,
+// or -1 on failure.
+API int ncplane_format(struct ncplane* n, int y, int x, unsigned ystop,
+                       unsigned xstop, uint16_t stylemask)
+  __attribute__ ((nonnull (1)));
 
 // Set the given channels throughout the specified region, keeping content and
-// attributes unchanged. Returns the number of cells set, or -1 on failure.
-API int ncplane_stain(struct ncplane* n, int ystop, int xstop, uint64_t ul,
-                      uint64_t ur, uint64_t ll, uint64_t lr);
+// attributes unchanged. The upper left corner is at 'x', 'y', and -1 may be
+// specified to indicate the cursor's position in that dimension. The lower
+// right corner is specified by 'xstop', 'ystop'. It is an error for any
+// coordinate to be outside the plane. Returns the number of cells set,
+// or -1 on failure.
+API int ncplane_stain(struct ncplane* n, int y, int x, unsigned ystop,
+                      unsigned xstop, uint64_t ul, uint64_t ur,
+                      uint64_t ll, uint64_t lr)
+  __attribute__ ((nonnull (1)));
 
 // Merge the entirety of 'src' down onto the ncplane 'dst'. If 'src' does not
 // intersect with 'dst', 'dst' will not be changed, but it is not an error.
@@ -2328,7 +2328,8 @@ API int ncplane_mergedown_simple(struct ncplane* RESTRICT src,
 // Merge the ncplane 'src' down onto the ncplane 'dst'. This is most rigorously
 // defined as "write to 'dst' the frame that would be rendered were the entire
 // stack made up only of the specified subregion of 'src' and, below it, the
-// subregion of 'dst' having the specified origin. Merging is independent of
+// subregion of 'dst' having the specified origin. Supply -1 to indicate the
+// current cursor position in the relevant dimension. Merging is independent of
 // the position of 'src' viz 'dst' on the z-axis. It is an error to define a
 // subregion that is not entirely contained within 'src'. It is an error to
 // define a target origin such that the projected subregion is not entirely
@@ -2337,9 +2338,9 @@ API int ncplane_mergedown_simple(struct ncplane* RESTRICT src,
 // nor 'dst' may have sprixels. Lengths of 0 mean "everything left".
 API int ncplane_mergedown(struct ncplane* RESTRICT src,
                           struct ncplane* RESTRICT dst,
-                          unsigned begsrcy, unsigned begsrcx,
+                          int begsrcy, int begsrcx,
                           unsigned leny, unsigned lenx,
-                          unsigned dsty, unsigned dstx)
+                          int dsty, int dstx)
   __attribute__ ((nonnull (1, 2)));
 
 // Erase every cell in the ncplane (each cell is initialized to the null glyph
@@ -2614,37 +2615,44 @@ typedef int (*fadecb)(struct notcurses* nc, struct ncplane* n,
 // modification (if the terminal uses a palette, our ability to fade planes is
 // limited, and affected by the complexity of the rest of the screen).
 API int ncplane_fadeout(struct ncplane* n, const struct timespec* ts,
-                        fadecb fader, void* curry);
+                        fadecb fader, void* curry)
+  __attribute__ ((nonnull (1)));
 
 // Fade the ncplane in over the specified time. Load the ncplane with the
 // target cells without rendering, then call this function. When it's done, the
 // ncplane will have reached the target levels, starting from zeroes.
 API int ncplane_fadein(struct ncplane* n, const struct timespec* ts,
-                       fadecb fader, void* curry);
+                       fadecb fader, void* curry)
+  __attribute__ ((nonnull (1)));
 
 // Rather than the simple ncplane_fade{in/out}(), ncfadectx_setup() can be
 // paired with a loop over ncplane_fade{in/out}_iteration() + ncfadectx_free().
-API struct ncfadectx* ncfadectx_setup(struct ncplane* n);
+API ALLOC struct ncfadectx* ncfadectx_setup(struct ncplane* n)
+  __attribute__ ((nonnull (1)));
 
 // Return the number of iterations through which 'nctx' will fade.
-API int ncfadectx_iterations(const struct ncfadectx* nctx);
+API int ncfadectx_iterations(const struct ncfadectx* nctx)
+  __attribute__ ((nonnull (1)));
 
 // Fade out through 'iter' iterations, where
 // 'iter' < 'ncfadectx_iterations(nctx)'.
 API int ncplane_fadeout_iteration(struct ncplane* n, struct ncfadectx* nctx,
-                                  int iter, fadecb fader, void* curry);
+                                  int iter, fadecb fader, void* curry)
+  __attribute__ ((nonnull (1, 2)));
 
 // Fade in through 'iter' iterations, where
 // 'iter' < 'ncfadectx_iterations(nctx)'.
 API int ncplane_fadein_iteration(struct ncplane* n, struct ncfadectx* nctx,
-                                  int iter, fadecb fader, void* curry);
+                                  int iter, fadecb fader, void* curry)
+  __attribute__ ((nonnull (1, 2)));
 
 // Pulse the plane in and out until the callback returns non-zero, relying on
 // the callback 'fader' to initiate rendering. 'ts' defines the half-period
 // (i.e. the transition from black to full brightness, or back again). Proper
 // use involves preparing (but not rendering) an ncplane, then calling
 // ncplane_pulse(), which will fade in from black to the specified colors.
-API int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry);
+API int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry)
+  __attribute__ ((nonnull (1)));
 
 // Release the resources associated with 'nctx'.
 API void ncfadectx_free(struct ncfadectx* nctx);
@@ -2679,18 +2687,18 @@ nccells_load_box(struct ncplane* n, uint32_t styles, uint64_t channels,
   return -1;
 }
 
-API int nccells_rounded_box(struct ncplane* n, uint32_t styles, uint64_t channels,
+API int nccells_rounded_box(struct ncplane* n, uint16_t styles, uint64_t channels,
                             nccell* ul, nccell* ur, nccell* ll,
                             nccell* lr, nccell* hl, nccell* vl);
 
 static inline int
-nccells_ascii_box(struct ncplane* n, uint32_t attr, uint64_t channels,
+nccells_ascii_box(struct ncplane* n, uint16_t attr, uint64_t channels,
                   nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXASCII);
 }
 
 static inline int
-nccells_light_box(struct ncplane* n, uint32_t attr, uint64_t channels,
+nccells_light_box(struct ncplane* n, uint16_t attr, uint64_t channels,
                   nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   if(notcurses_canutf8(ncplane_notcurses(n))){
     return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXLIGHT);
@@ -2699,7 +2707,7 @@ nccells_light_box(struct ncplane* n, uint32_t attr, uint64_t channels,
 }
 
 static inline int
-nccells_heavy_box(struct ncplane* n, uint32_t attr, uint64_t channels,
+nccells_heavy_box(struct ncplane* n, uint16_t attr, uint64_t channels,
                   nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   if(notcurses_canutf8(ncplane_notcurses(n))){
     return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXHEAVY);
@@ -2708,8 +2716,8 @@ nccells_heavy_box(struct ncplane* n, uint32_t attr, uint64_t channels,
 }
 
 static inline int
-ncplane_rounded_box(struct ncplane* n, uint32_t styles, uint64_t channels,
-                    int ystop, int xstop, unsigned ctlword){
+ncplane_rounded_box(struct ncplane* n, uint16_t styles, uint64_t channels,
+                    unsigned ystop, unsigned xstop, unsigned ctlword){
   int ret = 0;
   nccell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
   nccell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
@@ -2724,12 +2732,12 @@ ncplane_rounded_box(struct ncplane* n, uint32_t styles, uint64_t channels,
 }
 
 static inline int
-ncplane_perimeter_rounded(struct ncplane* n, uint32_t stylemask,
+ncplane_perimeter_rounded(struct ncplane* n, uint16_t stylemask,
                           uint64_t channels, unsigned ctlword){
   if(ncplane_cursor_move_yx(n, 0, 0)){
     return -1;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   nccell ul = CELL_TRIVIAL_INITIALIZER;
   nccell ur = CELL_TRIVIAL_INITIALIZER;
@@ -2748,27 +2756,27 @@ ncplane_perimeter_rounded(struct ncplane* n, uint32_t stylemask,
 }
 
 static inline int
-ncplane_rounded_box_sized(struct ncplane* n, uint32_t styles, uint64_t channels,
-                          int ylen, int xlen, unsigned ctlword){
-  int y, x;
+ncplane_rounded_box_sized(struct ncplane* n, uint16_t styles, uint64_t channels,
+                          unsigned ylen, unsigned xlen, unsigned ctlword){
+  unsigned y, x;
   ncplane_cursor_yx(n, &y, &x);
   return ncplane_rounded_box(n, styles, channels, y + ylen - 1,
                              x + xlen - 1, ctlword);
 }
 
-API int nccells_double_box(struct ncplane* n, uint32_t styles, uint64_t channels,
+API int nccells_double_box(struct ncplane* n, uint16_t styles, uint64_t channels,
                            nccell* ul, nccell* ur, nccell* ll,
                            nccell* lr, nccell* hl, nccell* vl);
 
 static inline int
-ncplane_double_box(struct ncplane* n, uint32_t styles, uint64_t channels,
-                   int ystop, int xstop, unsigned ctlword){
+ncplane_double_box(struct ncplane* n, uint16_t styles, uint64_t channels,
+                   unsigned ylen, unsigned xlen, unsigned ctlword){
   int ret = 0;
   nccell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
   nccell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
   nccell hl = CELL_TRIVIAL_INITIALIZER, vl = CELL_TRIVIAL_INITIALIZER;
   if((ret = nccells_double_box(n, styles, channels, &ul, &ur, &ll, &lr, &hl, &vl)) == 0){
-    ret = ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword);
+    ret = ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, ylen, xlen, ctlword);
   }
   nccell_release(n, &ul); nccell_release(n, &ur);
   nccell_release(n, &ll); nccell_release(n, &lr);
@@ -2777,12 +2785,12 @@ ncplane_double_box(struct ncplane* n, uint32_t styles, uint64_t channels,
 }
 
 static inline int
-ncplane_perimeter_double(struct ncplane* n, uint32_t stylemask,
+ncplane_perimeter_double(struct ncplane* n, uint16_t stylemask,
                          uint64_t channels, unsigned ctlword){
   if(ncplane_cursor_move_yx(n, 0, 0)){
     return -1;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   nccell ul = CELL_TRIVIAL_INITIALIZER;
   nccell ur = CELL_TRIVIAL_INITIALIZER;
@@ -2801,9 +2809,9 @@ ncplane_perimeter_double(struct ncplane* n, uint32_t stylemask,
 }
 
 static inline int
-ncplane_double_box_sized(struct ncplane* n, uint32_t styles, uint64_t channels,
-                         int ylen, int xlen, unsigned ctlword){
-  int y, x;
+ncplane_double_box_sized(struct ncplane* n, uint16_t styles, uint64_t channels,
+                         unsigned ylen, unsigned xlen, unsigned ctlword){
+  unsigned y, x;
   ncplane_cursor_yx(n, &y, &x);
   return ncplane_double_box(n, styles, channels, y + ylen - 1,
                             x + xlen - 1, ctlword);
@@ -2862,7 +2870,7 @@ API ALLOC struct ncvisual* ncvisual_from_palidx(const void* data, int rows,
 // Lengths of 0 are interpreted to mean "all available remaining area".
 API ALLOC struct ncvisual* ncvisual_from_plane(const struct ncplane* n,
                                                ncblitter_e blit,
-                                               unsigned begy, unsigned begx,
+                                               int begy, int begx,
                                                unsigned leny, unsigned lenx)
   __attribute__ ((nonnull (1)));
 
@@ -2894,8 +2902,8 @@ struct ncvisual_options {
   // pass an origin of 0, 0 and a size of 0, 0 (or the true height and width).
   // these numbers are all in terms of ncvisual pixels. negative values are
   // prohibited.
-  int begy, begx; // origin of rendered section
-  int leny, lenx; // size of rendered section
+  unsigned begy, begx; // origin of rendered section
+  unsigned leny, lenx; // size of rendered section
   // use NCBLIT_DEFAULT if you don't care, an appropriate blitter will be
   // chosen for your terminal, given your scaling. NCBLIT_PIXEL is never
   // chosen for NCBLIT_DEFAULT.
@@ -2927,15 +2935,15 @@ struct ncvisual_options {
 // blitters actually supported by this environment. if no ncvisual was
 // supplied, only cdimy/cdimx are filled in.
 typedef struct ncvgeom {
-  int pixy, pixx;     // true pixel geometry of ncvisual data
-  int cdimy, cdimx;   // terminal cell geometry when this was calculated
-  int rpixy, rpixx;   // rendered pixel geometry (per visual_options)
-  int rcelly, rcellx; // rendered cell geometry (per visual_options)
-  int scaley, scalex; // pixels per filled cell (scale == c for bitmaps)
-  int maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
-  int begy, begx;     // upper-left corner of used section
-  int leny, lenx;     // geometry of used section
-  ncblitter_e blitter;// blitter that will be used
+  unsigned pixy, pixx;     // true pixel geometry of ncvisual data
+  unsigned cdimy, cdimx;   // terminal cell geometry when this was calculated
+  unsigned rpixy, rpixx;   // rendered pixel geometry (per visual_options)
+  unsigned rcelly, rcellx; // rendered cell geometry (per visual_options)
+  unsigned scaley, scalex; // pixels per filled cell (scale == c for bitmaps)
+  unsigned begy, begx;     // upper-left corner of used section
+  unsigned leny, lenx;     // geometry of used section
+  unsigned maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
+  ncblitter_e blitter;     // blitter that will be used
 } ncvgeom;
 
 // all-purpose ncvisual geometry solver. one or both of 'nc' and 'n' must be
@@ -2979,15 +2987,17 @@ API int ncvisual_resize_noninterpolative(struct ncvisual* n, int rows, int cols)
   __attribute__ ((nonnull (1)));
 
 // Polyfill at the specified location within the ncvisual 'n', using 'rgba'.
-API int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba)
+API int ncvisual_polyfill_yx(struct ncvisual* n, unsigned y, unsigned x, uint32_t rgba)
   __attribute__ ((nonnull (1)));
 
 // Get the specified pixel from the specified ncvisual.
-API int ncvisual_at_yx(const struct ncvisual* n, int y, int x, uint32_t* pixel)
+API int ncvisual_at_yx(const struct ncvisual* n, unsigned y, unsigned x,
+                       uint32_t* pixel)
   __attribute__ ((nonnull (1, 4)));
 
 // Set the specified pixel in the specified ncvisual.
-API int ncvisual_set_yx(const struct ncvisual* n, int y, int x, uint32_t pixel)
+API int ncvisual_set_yx(const struct ncvisual* n, unsigned y, unsigned x,
+                        uint32_t pixel)
   __attribute__ ((nonnull (1)));
 
 // Render the decoded frame according to the provided options (which may be
@@ -3068,7 +3078,8 @@ API ALLOC struct ncplane* ncvisual_subtitle_plane(struct ncplane* parent,
 //  - otherwise NCBLIT_3x2
 // NCBLIT_2x2 and NCBLIT_3x2 both distort the original aspect ratio, thus
 // NCBLIT_2x1 is used outside of NCSCALE_STRETCH.
-API ncblitter_e ncvisual_media_defblitter(const struct notcurses* nc, ncscale_e scale);
+API ncblitter_e ncvisual_media_defblitter(const struct notcurses* nc, ncscale_e scale)
+  __attribute__ ((nonnull (1)));
 
 // Called for each frame rendered from 'ncv'. If anything but 0 is returned,
 // the streaming operation ceases immediately, and that value is propagated out.
@@ -3080,7 +3091,8 @@ typedef int (*ncstreamcb)(struct ncvisual*, struct ncvisual_options*,
 // If you'd like subtitles to be decoded, provide an ncplane as the curry. If the
 // curry is NULL, subtitles will not be displayed.
 API int ncvisual_simple_streamer(struct ncvisual* ncv, struct ncvisual_options* vopts,
-                                 const struct timespec* tspec, void* curry);
+                                 const struct timespec* tspec, void* curry)
+  __attribute__ ((nonnull (1)));
 
 // Stream the entirety of the media, according to its own timing. Blocking,
 // obviously. streamer may be NULL; it is otherwise called for each frame, and
@@ -3093,7 +3105,8 @@ API int ncvisual_simple_streamer(struct ncvisual* ncv, struct ncvisual_options*
 // supply 'timescale' less than or equal to 0.
 API int ncvisual_stream(struct notcurses* nc, struct ncvisual* ncv,
                         float timescale, ncstreamcb streamer,
-                        const struct ncvisual_options* vopts, void* curry);
+                        const struct ncvisual_options* vopts, void* curry)
+  __attribute__ ((nonnull (1, 2)));
 
 // Blit a flat array 'data' of RGBA 32-bit values to the ncplane 'vopts->n',
 // which mustn't be NULL. the blit begins at 'vopts->y' and 'vopts->x' relative
@@ -3103,20 +3116,24 @@ API int ncvisual_stream(struct notcurses* nc, struct ncvisual* ncv,
 // 'leny'x'lenx' fields from 'vopts'. Returns the number of pixels blitted, or
 // -1 on error.
 API int ncblit_rgba(const void* data, int linesize,
-                    const struct ncvisual_options* vopts);
+                    const struct ncvisual_options* vopts)
+  __attribute__ ((nonnull (1)));
 
 // Same as ncblit_rgba(), but for BGRx.
 API int ncblit_bgrx(const void* data, int linesize,
-                    const struct ncvisual_options* vopts);
+                    const struct ncvisual_options* vopts)
+  __attribute__ ((nonnull (1)));
 
 // Supply an alpha value [0..255] to be applied throughout.
 API int ncblit_rgb_packed(const void* data, int linesize,
-                          const struct ncvisual_options* vopts, int alpha);
+                          const struct ncvisual_options* vopts, int alpha)
+  __attribute__ ((nonnull (1)));
 
 // Supply an alpha value [0..255] to be applied throughout. linesize must be
 // a multiple of 4 for this RGBx data.
 API int ncblit_rgb_loose(const void* data, int linesize,
-                         const struct ncvisual_options* vopts, int alpha);
+                         const struct ncvisual_options* vopts, int alpha)
+  __attribute__ ((nonnull (1)));
 
 // The ncpixel API facilitates direct management of the pixels within an
 // ncvisual (ncvisuals keep a backing store of 32-bit RGBA pixels, and render
@@ -3350,42 +3367,48 @@ API const char* ncmetric(uintmax_t val, uintmax_t decimal, char* buf,
                          int omitdec, uintmax_t mult, int uprefix)
   __attribute__ ((nonnull (3)));
 
+// uses snprintf() internally with the argument 's' as its bound
+API const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal,
+                          char* buf, int omitdec, uintmax_t mult,
+                          int uprefix)
+  __attribute__ ((nonnull (4)));
+
 // The number of columns is one fewer, as the STRLEN expressions must leave
-// an extra byte open in case 'µ' (U+00B5, 0xC2 0xB5) shows up. PREFIXCOLUMNS
+// an extra byte open in case 'µ' (U+00B5, 0xC2 0xB5) shows up. NCPREFIXCOLUMNS
 // is the maximum number of columns used by a mult == 1000 (standard)
-// ncmetric() call. IPREFIXCOLUMNS is the maximum number of columns used by a
-// mult == 1024 (digital information) ncmetric(). BPREFIXSTRLEN is the maximum
+// ncmetric() call. NCIPREFIXCOLUMNS is the maximum number of columns used by a
+// mult == 1024 (digital information) ncmetric(). NCBPREFIXSTRLEN is the maximum
 // number of columns used by a mult == 1024 call making use of the 'i' suffix.
 // This is the true number of columns; to set up a printf()-style maximum
-// field width, you should use [IB]PREFIXFMT (see below).
-#define PREFIXCOLUMNS 7
-#define IPREFIXCOLUMNS 8
-#define BPREFIXCOLUMNS 9
-#define PREFIXSTRLEN (PREFIXCOLUMNS + 1)  // Does not include a '\0' (xxx.xxU)
-#define IPREFIXSTRLEN (IPREFIXCOLUMNS + 1) //  Does not include a '\0' (xxxx.xxU)
-#define BPREFIXSTRLEN (BPREFIXCOLUMNS + 1) // Does not include a '\0' (xxxx.xxUi), i == prefix
+// field width, you should use NC[IB]PREFIXFMT (see below).
+#define NCPREFIXCOLUMNS 7
+#define NCIPREFIXCOLUMNS 8
+#define NCBPREFIXCOLUMNS 9
+#define NCPREFIXSTRLEN (NCPREFIXCOLUMNS + 1)  // Does not include a '\0' (xxx.xxU)
+#define NCIPREFIXSTRLEN (NCIPREFIXCOLUMNS + 1) //  Does not include a '\0' (xxxx.xxU)
+#define NCBPREFIXSTRLEN (NCBPREFIXCOLUMNS + 1) // Does not include a '\0' (xxxx.xxUi), i == prefix
 // Used as arguments to a variable field width (i.e. "%*s" -- these are the *).
 // We need this convoluted grotesquery to properly handle 'µ'.
 #define NCMETRICFWIDTH(x, cols) ((int)(strlen(x) - ncstrwidth(x) + (cols)))
-#define PREFIXFMT(x) NCMETRICFWIDTH((x), PREFIXCOLUMNS), (x)
-#define IPREFIXFMT(x) NCMETRIXFWIDTH((x), IPREFIXCOLUMNS), (x)
-#define BPREFIXFMT(x) NCMETRICFWIDTH((x), BPREFIXCOLUMNS), (x)
+#define NCPREFIXFMT(x) NCMETRICFWIDTH((x), NCPREFIXCOLUMNS), (x)
+#define NCIPREFIXFMT(x) NCMETRIXFWIDTH((x), NCIPREFIXCOLUMNS), (x)
+#define NCBPREFIXFMT(x) NCMETRICFWIDTH((x), NCBPREFIXCOLUMNS), (x)
 
 // Mega, kilo, gigafoo. Use PREFIXSTRLEN + 1 and PREFIXCOLUMNS.
 static inline const char*
-qprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+ncqprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
   return ncmetric(val, decimal, buf, omitdec, 1000, '\0');
 }
 
 // Mibi, kebi, gibibytes sans 'i' suffix. Use IPREFIXSTRLEN + 1.
 static inline const char*
-iprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+nciprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
   return ncmetric(val, decimal, buf, omitdec, 1024, '\0');
 }
 
 // Mibi, kebi, gibibytes. Use BPREFIXSTRLEN + 1 and BPREFIXCOLUMNS.
 static inline const char*
-bprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+ncbprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
   return ncmetric(val, decimal, buf, omitdec, 1024, 'i');
 }
 
@@ -3393,17 +3416,21 @@ bprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
 // 'y', 'x'. Immediate effect (no need for a call to notcurses_render()).
 // It is an error if 'y', 'x' lies outside the standard plane. Can be
 // called while already visible to move the cursor.
-API int notcurses_cursor_enable(struct notcurses* nc, int y, int x);
+API int notcurses_cursor_enable(struct notcurses* nc, int y, int x)
+  __attribute__ ((nonnull (1)));
 
 // Get the current location of the terminal's cursor, whether visible or not.
-API int notcurses_cursor_yx(struct notcurses* nc, int* y, int* x);
+API int notcurses_cursor_yx(struct notcurses* nc, int* y, int* x)
+  __attribute__ ((nonnull (1)));
 
 // Disable the hardware cursor. It is an error to call this while the
 // cursor is already disabled.
-API int notcurses_cursor_disable(struct notcurses* nc);
+API int notcurses_cursor_disable(struct notcurses* nc)
+  __attribute__ ((nonnull (1)));
 
 // Convert the plane's content to greyscale.
-API void ncplane_greyscale(struct ncplane* n);
+API void ncplane_greyscale(struct ncplane* n)
+  __attribute__ ((nonnull (1)));
 
 //                                 ╭──────────────────────────╮
 //                                 │This is the primary header│
@@ -3455,15 +3482,19 @@ API int ncselector_additem(struct ncselector* n, const struct ncselector_item* i
 API int ncselector_delitem(struct ncselector* n, const char* item);
 
 // Return reference to the selected option, or NULL if there are no items.
-API const char* ncselector_selected(const struct ncselector* n);
+API const char* ncselector_selected(const struct ncselector* n)
+  __attribute__ ((nonnull (1)));
 
 // Return a reference to the ncselector's underlying ncplane.
-API struct ncplane* ncselector_plane(struct ncselector* n);
+API struct ncplane* ncselector_plane(struct ncselector* n)
+  __attribute__ ((nonnull (1)));
 
 // Move up or down in the list. A reference to the newly-selected item is
 // returned, or NULL if there are no items in the list.
-API const char* ncselector_previtem(struct ncselector* n);
-API const char* ncselector_nextitem(struct ncselector* n);
+API const char* ncselector_previtem(struct ncselector* n)
+  __attribute__ ((nonnull (1)));
+API const char* ncselector_nextitem(struct ncselector* n)
+  __attribute__ ((nonnull (1)));
 
 // Offer the input to the ncselector. If it's relevant, this function returns
 // true, and the input ought not be processed further. If it's irrelevant to
@@ -3648,17 +3679,17 @@ API ALLOC struct ncmenu* ncmenu_create(struct ncplane* n, const ncmenu_options*
 API int ncmenu_unroll(struct ncmenu* n, int sectionidx);
 
 // Roll up any unrolled menu section, and hide the menu if using hiding.
-API int ncmenu_rollup(struct ncmenu* n);
+API int ncmenu_rollup(struct ncmenu* n) __attribute__ ((nonnull (1)));
 
 // Unroll the previous/next section (relative to current unrolled). If no
 // section is unrolled, the first section will be unrolled.
-API int ncmenu_nextsection(struct ncmenu* n);
-API int ncmenu_prevsection(struct ncmenu* n);
+API int ncmenu_nextsection(struct ncmenu* n) __attribute__ ((nonnull (1)));
+API int ncmenu_prevsection(struct ncmenu* n) __attribute__ ((nonnull (1)));
 
 // Move to the previous/next item within the currently unrolled section. If no
 // section is unrolled, the first section will be unrolled.
-API int ncmenu_nextitem(struct ncmenu* n);
-API int ncmenu_previtem(struct ncmenu* n);
+API int ncmenu_nextitem(struct ncmenu* n) __attribute__ ((nonnull (1)));
+API int ncmenu_previtem(struct ncmenu* n) __attribute__ ((nonnull (1)));
 
 // Disable or enable a menu item. Returns 0 if the item was found.
 API int ncmenu_item_set_status(struct ncmenu* n, const char* section,
@@ -4104,7 +4135,7 @@ API int ncsubproc_destroy(struct ncsubproc* n);
 // returned. Otherwise, the QR code "version" (size) is returned. The QR code
 // is (version * 4 + 17) columns wide, and ⌈version * 4 + 17⌉ rows tall (the
 // properly-scaled values are written back to '*ymax' and '*xmax').
-API int ncplane_qrcode(struct ncplane* n, int* ymax, int* xmax,
+API int ncplane_qrcode(struct ncplane* n, unsigned* ymax, unsigned* xmax,
                        const void* data, size_t len)
   __attribute__ ((nonnull (1, 4)));
 
@@ -4192,12 +4223,12 @@ API void ncplane_styles_off(struct ncplane* n, unsigned stylebits)
   __attribute__ ((deprecated));
 
 __attribute__ ((deprecated)) API int
-cells_rounded_box(struct ncplane* n, uint32_t styles, uint64_t channels,
+cells_rounded_box(struct ncplane* n, uint16_t styles, uint64_t channels,
                   nccell* ul, nccell* ur, nccell* ll,
                   nccell* lr, nccell* hl, nccell* vl);
 
 __attribute__ ((deprecated)) API int
-cells_double_box(struct ncplane* n, uint32_t styles, uint64_t channels,
+cells_double_box(struct ncplane* n, uint16_t styles, uint64_t channels,
                  nccell* ul, nccell* ur, nccell* ll,
                  nccell* lr, nccell* hl, nccell* vl);
 
@@ -4258,6 +4289,37 @@ API int notcurses_mouse_enable(struct notcurses* n)
 API int notcurses_mouse_disable(struct notcurses* n)
   __attribute__ ((nonnull (1))) __attribute__ ((deprecated));
 
+API int ncplane_highgradient_sized(struct ncplane* n, uint32_t ul, uint32_t ur,
+                                   uint32_t ll, uint32_t lr, int ylen, int xlen)
+  __attribute__ ((deprecated));
+
+__attribute__ ((deprecated)) static inline const char*
+qprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+  return ncmetric(val, decimal, buf, omitdec, 1000, '\0');
+}
+
+// Mibi, kebi, gibibytes sans 'i' suffix. Use IPREFIXSTRLEN + 1.
+__attribute__ ((deprecated)) static inline const char*
+iprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+  return ncmetric(val, decimal, buf, omitdec, 1024, '\0');
+}
+
+// Mibi, kebi, gibibytes. Use BPREFIXSTRLEN + 1 and BPREFIXCOLUMNS.
+__attribute__ ((deprecated)) static inline const char*
+bprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
+  return ncmetric(val, decimal, buf, omitdec, 1024, 'i');
+}
+
+#define PREFIXCOLUMNS 7
+#define IPREFIXCOLUMNS 8
+#define BPREFIXCOLUMNS 9
+#define PREFIXSTRLEN (PREFIXCOLUMNS + 1)  // Does not include a '\0' (xxx.xxU)
+#define IPREFIXSTRLEN (IPREFIXCOLUMNS + 1) //  Does not include a '\0' (xxxx.xxU)
+#define BPREFIXSTRLEN (BPREFIXCOLUMNS + 1) // Does not include a '\0' (xxxx.xxUi), i == prefix
+#define PREFIXFMT(x) NCMETRICFWIDTH((x), PREFIXCOLUMNS), (x)
+#define IPREFIXFMT(x) NCMETRIXFWIDTH((x), IPREFIXCOLUMNS), (x)
+#define BPREFIXFMT(x) NCMETRICFWIDTH((x), BPREFIXCOLUMNS), (x)
+
 #undef API
 #undef ALLOC
 
diff --git a/python/notcurses/context.c b/python/notcurses/context.c
index 7d01c8107c..7aaa9dd0b1 100644
--- a/python/notcurses/context.c
+++ b/python/notcurses/context.c
@@ -239,10 +239,10 @@ Notcurses_linesigs_enable(NotcursesObject *self, PyObject *Py_UNUSED(args))
 static PyObject *
 Notcurses_refresh(NotcursesObject *self, PyObject *Py_UNUSED(args))
 {
-    int rows = 0, collumns = 0;
-    CHECK_NOTCURSES(notcurses_refresh(self->notcurses_ptr, &rows, &collumns));
+    unsigned rows = 0, columns = 0;
+    CHECK_NOTCURSES(notcurses_refresh(self->notcurses_ptr, &rows, &columns));
 
-    return Py_BuildValue("ii", rows, collumns);
+    return Py_BuildValue("II", rows, columns);
 }
 
 static PyObject *
@@ -259,22 +259,22 @@ Notcurses_stdplane(NotcursesObject *self, PyObject *Py_UNUSED(args))
 static PyObject *
 Notcurses_stddim_yx(NotcursesObject *self, PyObject *Py_UNUSED(args))
 {
-    int y = 0, x = 0;
+    unsigned y = 0, x = 0;
     PyObject *new_object CLEANUP_PY_OBJ = NcPlane_Type.tp_alloc((PyTypeObject *)&NcPlane_Type, 0);
     NcPlaneObject *new_plane = (NcPlaneObject *)new_object;
     new_plane->ncplane_ptr = CHECK_NOTCURSES_PTR(notcurses_stddim_yx(self->notcurses_ptr, &y, &x));
 
     Py_INCREF(new_object);
-    return Py_BuildValue("Oii", new_object, y, x);
+    return Py_BuildValue("OII", new_object, y, x);
 }
 
 static PyObject *
 Notcurses_term_dim_yx(NotcursesObject *self, PyObject *Py_UNUSED(args))
 {
-    int rows = 0, collumns = 0;
-    notcurses_term_dim_yx(self->notcurses_ptr, &rows, &collumns);
+    unsigned rows = 0, columns = 0;
+    notcurses_term_dim_yx(self->notcurses_ptr, &rows, &columns);
 
-    return Py_BuildValue("ii", rows, collumns);
+    return Py_BuildValue("II", rows, columns);
 }
 
 static PyObject *
@@ -288,7 +288,7 @@ static PyObject *
 Notcurses_pile_create(NotcursesObject *self, PyObject *args, PyObject *kwds)
 {
     int y = 0, x = 0;
-    int rows = 0, cols = 0;
+    unsigned rows = 0, cols = 0;
     const char *name = NULL;
     // TODO reseize callback
     unsigned long long flags = 0;
@@ -300,7 +300,7 @@ Notcurses_pile_create(NotcursesObject *self, PyObject *args, PyObject *kwds)
                         "flags",
                         "margin_b", "margin_r", NULL};
 
-    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "|iiiisKii", keywords,
+    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "|iiIIsKii", keywords,
                                                   &y, &x,
                                                   &rows, &cols,
                                                   &name,
diff --git a/python/notcurses/plane.c b/python/notcurses/plane.c
index f34ac8ab20..f77f0b45a5 100644
--- a/python/notcurses/plane.c
+++ b/python/notcurses/plane.c
@@ -28,7 +28,7 @@ static PyObject *
 Ncplane_create(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 {
     int y = 0, x = 0;
-    int rows = 0, cols = 0;
+    unsigned rows = 0, cols = 0;
     const char *name = NULL;
     // TODO reseize callback
     unsigned long long flags = 0;
@@ -91,31 +91,31 @@ NcPlane_notcurses(NcPlaneObject *self, PyObject *Py_UNUSED(args))
 static PyObject *
 NcPlane_dim_yx(NcPlaneObject *self, PyObject *Py_UNUSED(args))
 {
-    int y = 0, x = 0;
+    unsigned y = 0, x = 0;
     ncplane_dim_yx(self->ncplane_ptr, &y, &x);
 
-    return Py_BuildValue("ii", y, x);
+    return Py_BuildValue("II", y, x);
 }
 
 static PyObject *
 NcPlane_dim_x(NcPlaneObject *self, PyObject *Py_UNUSED(args))
 {
-    return Py_BuildValue("i", ncplane_dim_x(self->ncplane_ptr));
+    return Py_BuildValue("I", ncplane_dim_x(self->ncplane_ptr));
 }
 
 static PyObject *
 NcPlane_dim_y(NcPlaneObject *self, PyObject *Py_UNUSED(args))
 {
-    return Py_BuildValue("i", ncplane_dim_y(self->ncplane_ptr));
+    return Py_BuildValue("I", ncplane_dim_y(self->ncplane_ptr));
 }
 
 static PyObject *
 NcPlane_pixelgeom(NcPlaneObject *self, PyObject *Py_UNUSED(args))
 {
-    int pxy = 0, pxx = 0, celldimy = 0, celldimx = 0, maxbmapy = 0, maxbmapx = 0;
+    unsigned pxy = 0, pxx = 0, celldimy = 0, celldimx = 0, maxbmapy = 0, maxbmapx = 0;
     ncplane_pixelgeom(self->ncplane_ptr, &pxy, &pxx, &celldimy, &celldimx, &maxbmapy, &maxbmapx);
 
-    return Py_BuildValue("ii ii ii", pxy, pxx, celldimy, celldimx, maxbmapy, maxbmapx);
+    return Py_BuildValue("II II II", pxy, pxx, celldimy, celldimx, maxbmapy, maxbmapx);
 }
 
 static PyObject *
@@ -477,11 +477,12 @@ NcPlane_at_yx_cell(NcPlaneObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
 static PyObject *
 NcPlane_contents(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 {
-    unsigned beg_y = 0, beg_x = 0, len_y = 0, len_x = 0;
+    int beg_y = 0, beg_x = 0;
+    unsigned len_y = 0, len_x = 0;
 
     char *keywords[] = {"begy", "begx", "leny", "lenx", NULL};
 
-    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "II|II", keywords,
+    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "ii|II", keywords,
                                                   &beg_y, &beg_x,
                                                   &len_y, &len_x));
 
@@ -546,11 +547,11 @@ NcPlane_home(NcPlaneObject *self, PyObject *Py_UNUSED(args))
 static PyObject *
 NcPlane_cursor_yx(NcPlaneObject *self, PyObject *Py_UNUSED(args))
 {
-    int y = 0, x = 0;
+    unsigned y = 0, x = 0;
 
     ncplane_cursor_yx(self->ncplane_ptr, &y, &x);
 
-    return Py_BuildValue("ii", y, x);
+    return Py_BuildValue("II", y, x);
 }
 
 static PyObject *
@@ -818,101 +819,47 @@ NcPlane_polyfill_yx(NcPlaneObject *Py_UNUSED(self), PyObject *Py_UNUSED(args), P
 static PyObject *
 NcPlane_gradient(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 {
+    int y = -1, x = -1;
+    unsigned ylen = 0, xlen = 0;
     const char *egc = NULL;
     unsigned long stylemask = 0;
     unsigned long long ul = 0, ur = 0, ll = 0, lr = 0;
-    int ystop = 0, xstop = 0;
 
-    char *keywords[] = {"egc",
+    char *keywords[] = {"y", "x", "ylen", "xlen", "egc",
                         "stylemask",
                         "ul", "ur", "ll", "lr",
-                        "ystop", "xstop",
                         NULL};
-    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "skKKKKii", keywords,
-                                                  &egc,
+    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "siiIIkKKKK", keywords,
+                                                  &y, &x, &ylen, &xlen, &egc,
                                                   &stylemask,
-                                                  &ul, &ur, &ll, &lr,
-                                                  &ystop, &xstop));
+                                                  &ul, &ur, &ll, &lr));
 
     int cells_filled = CHECK_NOTCURSES(
         ncplane_gradient(
-            self->ncplane_ptr, egc,
-            (uint32_t)stylemask,
-            (uint64_t)ul, (uint64_t)ur, (uint64_t)ll, (uint64_t)lr,
-            ystop, xstop));
-
-    return Py_BuildValue("i", cells_filled);
-}
-
-static PyObject *
-NcPlane_highgradient(NcPlaneObject *self, PyObject *args, PyObject *kwds)
-{
-    unsigned long ul = 0, ur = 0, ll = 0, lr = 0;
-    int ystop = 0, xstop = 0;
-
-    char *keywords[] = {"ul", "ur", "ll", "lr",
-                        "ystop", "xstop",
-                        NULL};
-    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "kkkkii", keywords,
-                                                  &ul, &ur, &ll, &lr,
-                                                  &ystop, &xstop));
-
-    int cells_filled = CHECK_NOTCURSES(
-        ncplane_highgradient(
-            self->ncplane_ptr,
-            (uint32_t)ul, (uint32_t)ur, (uint32_t)ll, (uint32_t)lr,
-            ystop, xstop));
-
-    return Py_BuildValue("i", cells_filled);
-}
-
-static PyObject *
-NcPlane_gradient_sized(NcPlaneObject *self, PyObject *args, PyObject *kwds)
-{
-    const char *egc = NULL;
-    unsigned long stylemask = 0;
-    unsigned long long ul = 0, ur = 0, ll = 0, lr = 0;
-    int ylen = 0, xlen = 0;
-
-    char *keywords[] = {"egc",
-                        "stylemask",
-                        "ul", "ur", "ll", "lr",
-                        "ylen", "xlen",
-                        NULL};
-    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "skKKKKii", keywords,
-                                                  &egc,
-                                                  &stylemask,
-                                                  &ul, &ur, &ll, &lr,
-                                                  &ylen, &xlen));
-
-    int cells_filled = CHECK_NOTCURSES(
-        ncplane_gradient_sized(
-            self->ncplane_ptr, egc,
-            (uint32_t)stylemask,
-            (uint64_t)ul, (uint64_t)ur, (uint64_t)ll, (uint64_t)lr,
-            ylen, xlen));
+            self->ncplane_ptr, y, x, ylen, xlen, egc,
+            (uint16_t)stylemask,
+            (uint64_t)ul, (uint64_t)ur, (uint64_t)ll, (uint64_t)lr));
 
     return Py_BuildValue("i", cells_filled);
 }
 
 static PyObject *
-NcPlane_highgradient_sized(NcPlaneObject *self, PyObject *args, PyObject *kwds)
+NcPlane_gradient2x1(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 {
     unsigned long ul = 0, ur = 0, ll = 0, lr = 0;
-    int ylen = 0, xlen = 0;
+    int y = -1, x = -1;
+    unsigned ylen = 0, xlen = 0;
 
-    char *keywords[] = {"ul", "ur", "ll", "lr",
-                        "ylen", "xlen",
+    char *keywords[] = {"y", "x", "ylen", "xlen", "ul", "ur", "ll", "lr",
                         NULL};
-    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "kkkkii", keywords,
-                                                  &ul, &ur, &ll, &lr,
-                                                  &ylen, &xlen));
+    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "iiIIkkkk", keywords,
+                                                  &y, &x, &ylen, &xlen,
+                                                  &ul, &ur, &ll, &lr));
 
     int cells_filled = CHECK_NOTCURSES(
-        ncplane_highgradient_sized(
-            self->ncplane_ptr,
-            (uint32_t)ul, (uint32_t)ur, (uint32_t)ll, (uint32_t)lr,
-            ylen, xlen));
+        ncplane_gradient2x1(
+            self->ncplane_ptr, y, x, ylen, xlen,
+            (uint32_t)ul, (uint32_t)ur, (uint32_t)ll, (uint32_t)lr));
 
     return Py_BuildValue("i", cells_filled);
 }
@@ -920,14 +867,17 @@ NcPlane_highgradient_sized(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 static PyObject *
 NcPlane_format(NcPlaneObject *self, PyObject *args)
 {
-    int ystop = 0, xstop = 0;
+    int y = -1, x = -1;
+    unsigned ylen = 0, xlen = 0;
     unsigned long stylemark = 0;
 
-    GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "iik",
-                                       &ystop, &xstop,
+    GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "iiIIk",
+                                       &y, &x, &ylen, &xlen,
                                        &stylemark));
 
-    int cells_set = CHECK_NOTCURSES(ncplane_format(self->ncplane_ptr, ystop, xstop, (uint32_t)stylemark));
+    int cells_set = CHECK_NOTCURSES(ncplane_format(self->ncplane_ptr,
+                                                   y, x, ylen, xlen,
+                                                   (uint16_t)stylemark));
 
     return Py_BuildValue("i", cells_set);
 }
@@ -935,7 +885,8 @@ NcPlane_format(NcPlaneObject *self, PyObject *args)
 static PyObject *
 NcPlane_stain(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 {
-    int ystop = 0, xstop = 0;
+    int x = -1, y = -1;
+    unsigned ylen = 0, xlen = 0;
     unsigned long long ul = 0, ur = 0, ll = 0, lr = 0;
 
     char *keywords[] = {
@@ -943,14 +894,14 @@ NcPlane_stain(NcPlaneObject *self, PyObject *args, PyObject *kwds)
         "ul", "ur", "ll", "lr",
         NULL};
 
-    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "iiKKKK", keywords,
-                                                  &ystop, &xstop,
+    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "iiIIKKKK", keywords,
+                                                  &y, &x, &ylen, &xlen,
                                                   &ul, &ur, &ll, &lr));
 
     int cells_set = CHECK_NOTCURSES(
         ncplane_stain(
             self->ncplane_ptr,
-            ystop, xstop,
+            y, x, ylen, xlen,
             (uint64_t)ul, (uint64_t)ur, (uint64_t)ll, (uint64_t)lr));
 
     return Py_BuildValue("i", cells_set);
@@ -972,14 +923,15 @@ static PyObject *
 NcPlane_mergedown(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 {
     NcPlaneObject *dst_obj = NULL;
-    unsigned begsrcy = 0, begsrcx = 0, leny = 0, lenx = 0;
-    unsigned dsty = 0, dstx = 0;
+    int begsrcy = 0, begsrcx = 0;
+    unsigned leny = 0, lenx = 0;
+    int dsty = 0, dstx = 0;
 
     char *keywords[] = {"dst",
                         "begsrcy", "begsrcx", "leny", "lenx",
                         "dsty", "dstx",
                         NULL};
-    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "O!IIIIII", keywords,
+    GNU_PY_CHECK_BOOL(PyArg_ParseTupleAndKeywords(args, kwds, "O!iiIIii", keywords,
                                                   &NcPlane_Type, &dst_obj,
                                                   &begsrcy, &begsrcx, &leny, &lenx,
                                                   &dsty, &dstx));
@@ -1337,7 +1289,7 @@ NcPlane_perimeter_rounded(NcPlaneObject *self, PyObject *args, PyObject *kwds)
                                                   &channels,
                                                   &ctlword));
 
-    CHECK_NOTCURSES(ncplane_perimeter_rounded(self->ncplane_ptr, (uint32_t)stylemask, (uint64_t)channels, ctlword));
+    CHECK_NOTCURSES(ncplane_perimeter_rounded(self->ncplane_ptr, (uint16_t)stylemask, (uint64_t)channels, ctlword));
 
     Py_RETURN_NONE;
 }
@@ -1347,7 +1299,7 @@ NcPlane_rounded_box_sized(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 {
     unsigned long styles = 0;
     unsigned long long channels = 0;
-    int ylen = 0, xlen = 0;
+    unsigned ylen = 0, xlen = 0;
     unsigned int ctlword = 0;
 
     char *keywords[] = {"styles",
@@ -1358,14 +1310,14 @@ NcPlane_rounded_box_sized(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 
     GNU_PY_CHECK_BOOL(
         PyArg_ParseTupleAndKeywords(
-            args, kwds, "kKiiI", keywords,
+            args, kwds, "kKIII", keywords,
             &styles, &channels,
             &ylen, &xlen,
             &ctlword));
 
     CHECK_NOTCURSES(ncplane_rounded_box_sized(
         self->ncplane_ptr,
-        (uint32_t)styles,
+        (uint16_t)styles,
         (uint64_t)channels,
         ylen, xlen,
         ctlword));
@@ -1386,7 +1338,7 @@ NcPlane_double_box(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 {
     unsigned long styles = 0;
     unsigned long long channels = 0;
-    int ylen = 0, xlen = 0;
+    unsigned ylen = 0, xlen = 0;
     unsigned int ctlword = 0;
 
     char *keywords[] = {"styles",
@@ -1397,14 +1349,14 @@ NcPlane_double_box(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 
     GNU_PY_CHECK_BOOL(
         PyArg_ParseTupleAndKeywords(
-            args, kwds, "kKiiI", keywords,
+            args, kwds, "kKIII", keywords,
             &styles, &channels,
             &ylen, &xlen,
             &ctlword));
 
     CHECK_NOTCURSES(ncplane_double_box(
         self->ncplane_ptr,
-        (uint32_t)styles,
+        (uint16_t)styles,
         (uint64_t)channels,
         ylen, xlen,
         ctlword));
@@ -1432,7 +1384,7 @@ NcPlane_perimeter_double(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 
     CHECK_NOTCURSES(ncplane_perimeter_double(
         self->ncplane_ptr,
-        (uint32_t)styles,
+        (uint16_t)styles,
         (uint64_t)channels,
         ctlword));
 
@@ -1445,7 +1397,7 @@ NcPlane_double_box_sized(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 
     unsigned long styles = 0;
     unsigned long long channels = 0;
-    int ylen = 0, xlen = 0;
+    unsigned ylen = 0, xlen = 0;
     unsigned int ctlword = 0;
 
     char *keywords[] = {"styles",
@@ -1456,14 +1408,14 @@ NcPlane_double_box_sized(NcPlaneObject *self, PyObject *args, PyObject *kwds)
 
     GNU_PY_CHECK_BOOL(
         PyArg_ParseTupleAndKeywords(
-            args, kwds, "kKiiI", keywords,
+            args, kwds, "kKIII", keywords,
             &styles, &channels,
             &ylen, &xlen,
             &ctlword));
 
     CHECK_NOTCURSES(ncplane_double_box_sized(
         self->ncplane_ptr,
-        (uint32_t)styles,
+        (uint16_t)styles,
         (uint64_t)channels,
         ylen, xlen,
         ctlword));
@@ -1606,11 +1558,11 @@ NcPlane_qrcode(NcPlaneObject *self, PyObject *args)
 
     GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "s#", &data, &len));
 
-    int ymax = 0, xmax = 0;
+    unsigned ymax = 0, xmax = 0;
 
     CHECK_NOTCURSES(ncplane_qrcode(self->ncplane_ptr, &ymax, &xmax, (void *)data, (size_t)len));
 
-    return Py_BuildValue("ii", &ymax, &xmax);
+    return Py_BuildValue("II", &ymax, &xmax);
 }
 
 static PyObject *
@@ -1798,9 +1750,7 @@ static PyMethodDef NcPlane_methods[] = {
     {"polyfill_yx", (void *)NcPlane_polyfill_yx, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Starting at the specified coordinate, if its glyph is different from that of is copied into it, and the original glyph is considered the fill target.")},
 
     {"gradient", (void *)NcPlane_gradient, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Draw a gradient with its upper-left corner at the current cursor position.")},
-    {"highgradient", (void *)NcPlane_highgradient, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Do a high-resolution gradient using upper blocks and synced backgrounds.")},
-    {"gradient_sized", (void *)NcPlane_gradient_sized, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Draw a gradient with its upper-left corner at the current cursor position.")},
-    {"highgradient_sized", (void *)NcPlane_highgradient_sized, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("NcPlane.gradent_sized() meets NcPlane.highgradient().")},
+    {"gradient2x1", (void *)NcPlane_gradient2x1, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("NcPlane.gradent_sized() meets NcPlane.highgradient().")},
 
     {"format", (PyCFunction)NcPlane_format, METH_VARARGS, PyDoc_STR("Set the given style throughout the specified region, keeping content and attributes unchanged. Returns the number of cells set.")},
     {"stain", (void *)NcPlane_stain, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Set the given style throughout the specified region, keeping content and attributes unchanged. Returns the number of cells set.")},
diff --git a/src/demo/animate.c b/src/demo/animate.c
index cdc2c9e80a..126dfcd08d 100644
--- a/src/demo/animate.c
+++ b/src/demo/animate.c
@@ -191,7 +191,7 @@ drawcycles(struct ncplane* std, struct ncprogbar* left, struct ncprogbar* right,
 
 static int
 animate(struct notcurses* nc, struct ncprogbar* left, struct ncprogbar* right){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
   int headx = -1;
   int heady = -1;
@@ -254,10 +254,11 @@ animate(struct notcurses* nc, struct ncprogbar* left, struct ncprogbar* right){
 
 static int
 make_pbars(struct ncplane* column, struct ncprogbar** left, struct ncprogbar** right){
-  int dimy, dimx, coly, colx, colposy, colposx;
+  unsigned dimy, dimx, coly, colx;
   struct notcurses* nc = ncplane_notcurses(column);
   notcurses_stddim_yx(nc, &dimy, &dimx);
   ncplane_dim_yx(column, &coly, &colx);
+  int colposy, colposx;
   ncplane_yx(column, &colposy, &colposx);
   ncplane_options opts = {
     .x = colposx / 4 * -3,
@@ -297,7 +298,7 @@ int animate_demo(struct notcurses* nc){
   if(!notcurses_canutf8(nc)){
     return 0;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   ncplane_erase(n);
   ncplane_home(n);
@@ -306,18 +307,18 @@ int animate_demo(struct notcurses* nc){
   ncchannel_set_rgb8(&tr, 0, 0xff, 0);
   ncchannel_set_rgb8(&bl, 0, 0, 0xff);
   ncchannel_set_rgb8(&br, 0, 0xff, 0xff);
-  if(ncplane_highgradient(n, tl, tr, bl, br, dimy - 1, dimx - 1) < 0){
+  if(ncplane_gradient2x1(n, -1, -1, 0, 0, tl, tr, bl, br) < 0){
     return -1;
   }
   ncplane_set_fg_rgb(n, 0xf0f0a0);
   ncplane_set_bg_rgb(n, 0);
-  int width = 40;
+  unsigned width = 40;
   if(width > dimx - 8){
     if((width = dimx - 8) <= 0){
       return -1;
     }
   }
-  int height = 40;
+  unsigned height = 40;
   if(height >= dimy - 4){
     if((height = dimy - 5) <= 0){
       return -1;
diff --git a/src/demo/boxdemo.c b/src/demo/boxdemo.c
index e3b2b8c584..687d9cad7d 100644
--- a/src/demo/boxdemo.c
+++ b/src/demo/boxdemo.c
@@ -4,7 +4,7 @@
 
 static int
 reload_corners(struct ncplane* n, nccell* ul, nccell* ur, nccell* ll, nccell* lr){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   char* egc;
   if( (egc = ncplane_at_yx(n, 1, dimx - 2, NULL, &ur->channels)) == NULL){
@@ -94,24 +94,25 @@ move_ships(struct notcurses* nc, struct ship* ships, unsigned shipcount){
     if(ships[s].n == NULL){
       continue;
     }
-    int yoff, xoff, ny, nx;
+    int yoff, xoff;
+    unsigned ny, nx;
     ncplane_yx(ships[s].n, &yoff, &xoff);
     ncplane_dim_yx(ships[s].n, &ny, &nx);
-    int dimy = ncplane_dim_y(stdn);
-    int dimx = ncplane_dim_x(stdn);
+    unsigned dimy = ncplane_dim_y(stdn);
+    unsigned dimx = ncplane_dim_x(stdn);
     yoff += ships[s].vely;
     xoff += ships[s].velx;
     if(xoff <= 0){
       xoff = 0;
       ships[s].velx = -ships[s].velx;
-    }else if(xoff >= dimx - nx){
+    }else if((unsigned)xoff >= dimx - nx){
       xoff = dimx - nx - 1;
       ships[s].velx = -ships[s].velx;
     }
     if(yoff <= 1){
       yoff = 2;
       ships[s].vely = -ships[s].vely;
-    }else if(yoff >= dimy - ny){
+    }else if((unsigned)yoff >= dimy - ny){
       yoff = dimy - ny - 1;
       ships[s].vely = -ships[s].vely;
     }
@@ -128,7 +129,7 @@ get_ships(struct notcurses* nc, struct ship* ships, unsigned shipcount){
   if(wmv == NULL){
     return -1;
   }
-  int cdimy, cdimx;
+  unsigned cdimy, cdimx;
   ncplane_pixelgeom(notcurses_stdplane(nc), NULL, NULL, &cdimy, &cdimx, NULL, NULL);
   if(ncvisual_resize(wmv, cdimy * SHIPHEIGHT, cdimx * SHIPWIDTH)){
     ncvisual_destroy(wmv);
@@ -162,7 +163,7 @@ get_ships(struct notcurses* nc, struct ship* ships, unsigned shipcount){
 }
 
 int box_demo(struct notcurses* nc){
-  int ylen, xlen;
+  unsigned ylen, xlen;
   struct ncplane* n = notcurses_stddim_yx(nc, &ylen, &xlen);
   ncplane_erase(n);
   uint64_t transchan = 0;
diff --git a/src/demo/chunli.c b/src/demo/chunli.c
index 51adb34304..411e3bf7a4 100644
--- a/src/demo/chunli.c
+++ b/src/demo/chunli.c
@@ -12,7 +12,7 @@ static int
 chunli_draw(struct notcurses* nc, const char* ext, int count, const nccell* b){
   chunli chuns[CHUNS];
   char file[20];
-  int dimx, dimy;
+  unsigned dimx, dimy;
   ncplane_dim_yx(notcurses_stdplane_const(nc), &dimy, &dimx);
   struct timespec iterdelay;
   timespec_div(&demodelay, 10, &iterdelay);
@@ -31,7 +31,7 @@ chunli_draw(struct notcurses* nc, const char* ext, int count, const nccell* b){
       return -1;
     }
     ncplane_set_base_cell(chuns[i].n, b);
-    int thisx, thisy;
+    unsigned thisx, thisy;
     ncplane_dim_yx(chuns[i].n, &thisy, &thisx);
     if(ncplane_move_yx(chuns[i].n, (dimy - thisy) / 2, (dimx - thisx) / 2)){
       return -1;
@@ -53,7 +53,8 @@ int chunli_demo(struct notcurses* nc){
   }
   struct timespec iterdelay;
   timespec_div(&demodelay, 10, &iterdelay);
-  int ret, dimx, dimy;
+  int ret;
+  unsigned dimx, dimy;
   ncplane_dim_yx(notcurses_stdplane_const(nc), &dimy, &dimx);
   nccell b = CELL_TRIVIAL_INITIALIZER;
   nccell_set_fg_alpha(&b, NCALPHA_TRANSPARENT);
@@ -80,7 +81,7 @@ int chunli_demo(struct notcurses* nc){
       return -1;
     }
     ncplane_set_base_cell(ncp, &b);
-    int thisx, thisy;
+    unsigned thisx, thisy;
     ncplane_dim_yx(ncp, &thisy, &thisx);
     if(ncplane_move_yx(ncp, (dimy - thisy) / 2, (dimx - thisx) / 2)){
       return -1;
diff --git a/src/demo/demo.c b/src/demo/demo.c
index 28d5bd28cf..86e1a4cf7a 100644
--- a/src/demo/demo.c
+++ b/src/demo/demo.c
@@ -21,7 +21,7 @@ static int democount;
 static demoresult* results;
 static char *datadir = NOTCURSES_SHARE;
 
-static const char DEFAULT_DEMO[] = "ixetunchmdbkywgarvlsfjqzo";
+static const char DEFAULT_DEMO[] = "ixetunchmdbkywjgarvlsfqzo";
 
 atomic_bool interrupted = ATOMIC_VAR_INIT(false);
 // checked following demos, whether aborted, failed, or otherwise
@@ -388,6 +388,7 @@ static int
 summary_table(struct notcurses* nc, const char* spec, bool canimage, bool canvideo){
   notcurses_leave_alternate_screen(nc);
   struct ncplane* n = notcurses_stdplane(nc);
+  ncplane_set_bg_default(n);
   ncplane_set_scrolling(n, true);
   bool failed = false;
   uint64_t totalbytes = 0;
@@ -403,20 +404,20 @@ summary_table(struct notcurses* nc, const char* spec, bool canimage, bool canvid
   table_segment(n, "%a", "│");
   table_segment(n, "%w", "│");
   table_segment(n, "TheoFPS", "║\n══╤════════╤════════╪═══════╪═════════╪═══════╪══╪══╪══╪═══════╣\n");
-  char timebuf[PREFIXSTRLEN + 1];
-  char tfpsbuf[PREFIXSTRLEN + 1];
-  char totalbuf[BPREFIXSTRLEN + 1];
+  char timebuf[NCPREFIXSTRLEN + 1];
+  char tfpsbuf[NCPREFIXSTRLEN + 1];
+  char totalbuf[NCBPREFIXSTRLEN + 1];
   uint64_t nsdelta = 0;
   for(size_t i = 0 ; i < strlen(spec) ; ++i){
     nsdelta += results[i].timens;
-    qprefix(results[i].timens, NANOSECS_IN_SEC, timebuf, 0);
-    bprefix(results[i].stats.render_bytes, 1, totalbuf, 0);
+    ncqprefix(results[i].timens, NANOSECS_IN_SEC, timebuf, 0);
+    ncbprefix(results[i].stats.render_bytes, 1, totalbuf, 0);
     uint64_t divisor = results[i].stats.render_ns + results[i].stats.writeout_ns + results[i].stats.raster_ns;
     if(divisor){
-      qprefix((uintmax_t)results[i].stats.writeouts * NANOSECS_IN_SEC * 1000 / divisor,
+      ncqprefix((uintmax_t)results[i].stats.writeouts * NANOSECS_IN_SEC * 1000 / divisor,
               1000, tfpsbuf, 0);
     }else{
-      qprefix(0, NANOSECS_IN_SEC, tfpsbuf, 0);
+      ncqprefix(0, NANOSECS_IN_SEC, tfpsbuf, 0);
     }
     uint32_t rescolor;
     if(results[i].result < 0){
@@ -436,7 +437,7 @@ summary_table(struct notcurses* nc, const char* spec, bool canimage, bool canvid
     ncplane_printf(n, "%8s", demos[results[i].selector - 'a'].name);
     ncplane_set_fg_rgb8(n, 178, 102, 255);
     ncplane_printf(n, "│%*ss│%7" PRIu64 "│%*s│%7.1f│%2" PRId64 "│%2" PRId64 "│%2" PRId64 "│%*s║",
-           PREFIXFMT(timebuf), results[i].stats.renders, BPREFIXFMT(totalbuf),
+           NCPREFIXFMT(timebuf), results[i].stats.renders, NCBPREFIXFMT(totalbuf),
            results[i].timens ?
             results[i].stats.renders / ((double)results[i].timens / NANOSECS_IN_SEC) : 0.0,
            (results[i].timens ?
@@ -445,7 +446,7 @@ summary_table(struct notcurses* nc, const char* spec, bool canimage, bool canvid
             results[i].stats.raster_ns * 100 / results[i].timens : 0),
            (results[i].timens ?
             results[i].stats.writeout_ns * 100 / results[i].timens : 0),
-           PREFIXFMT(tfpsbuf));
+           NCPREFIXFMT(tfpsbuf));
     ncplane_set_fg_rgb(n, rescolor);
     ncplane_printf(n, "%s\n", results[i].result < 0 ? "FAILED" :
                    results[i].result > 0 ? "ABORTED" :
@@ -458,13 +459,13 @@ summary_table(struct notcurses* nc, const char* spec, bool canimage, bool canvid
     totalrenderns += results[i].stats.render_ns;
     totalwriteoutns += results[i].stats.writeout_ns;
   }
-  qprefix(nsdelta, NANOSECS_IN_SEC, timebuf, 0);
-  bprefix(totalbytes, 1, totalbuf, 0);
+  ncqprefix(nsdelta, NANOSECS_IN_SEC, timebuf, 0);
+  ncbprefix(totalbytes, 1, totalbuf, 0);
   table_segment(n, "", "══╧════════╧════════╪═══════╪═════════╪═══════╧══╧══╧══╧═══════╝\n");
   ncplane_putstr(n, "            ");
-  table_printf(n, "│", "%*ss", PREFIXFMT(timebuf));
+  table_printf(n, "│", "%*ss", NCPREFIXFMT(timebuf));
   table_printf(n, "│", "%7lu", totalframes);
-  table_printf(n, "│", "%*s", BPREFIXFMT(totalbuf));
+  table_printf(n, "│", "%*s", NCBPREFIXFMT(totalbuf));
   //table_printf(nc, "│", "%7.1f", nsdelta ? totalframes / ((double)nsdelta / NANOSECS_IN_SEC) : 0);
   ncplane_putchar(n, '\n');
   ncplane_set_fg_rgb8(n, 0xfe, 0x20, 0x76); // PANTONE Strong Red C + 3x0x20
@@ -530,7 +531,7 @@ int main(int argc, char** argv){
   notcurses_mice_enable(nc, NCMICE_BUTTON_EVENT | NCMICE_DRAG_EVENT);
   const bool canimage = notcurses_canopen_images(nc);
   const bool canvideo = notcurses_canopen_videos(nc);
-  int dimx, dimy;
+  unsigned dimx, dimy;
   ncplane_dim_yx(notcurses_stdplane(nc), &dimy, &dimx);
   if(input_dispatcher(nc)){
     goto err;
diff --git a/src/demo/dragon.c b/src/demo/dragon.c
index bcb96c3e10..d4a765b467 100644
--- a/src/demo/dragon.c
+++ b/src/demo/dragon.c
@@ -49,7 +49,7 @@ dragonmayer(struct ncvisual* ncv, const char* str, int iters){
 
 int dragon_demo(struct notcurses* nc){
   done = false;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   --dimy; // don't disturb the menu bar
   // we use a Lindenmayer string rewriting system. the classic dragon curve
diff --git a/src/demo/eagle.c b/src/demo/eagle.c
index 181ed8e031..c96f10db62 100644
--- a/src/demo/eagle.c
+++ b/src/demo/eagle.c
@@ -55,7 +55,7 @@ zoom_map(struct notcurses* nc, const char* map, int* ret){
   int xscale = geom.scalex;
 //fprintf(stderr, "VHEIGHT: %d VWIDTH: %d scale: %d/%d\n", vheight, vwidth, yscale, xscale);
   // we start at the lower left corner of the outzoomed map
-  int placey, placex; // dimensions of true display
+  unsigned placey, placex; // dimensions of true display
   notcurses_term_dim_yx(nc, &placey, &placex);
   float delty = 2 + yscale;
   float deltx = 2 + xscale;
@@ -159,14 +159,15 @@ draw_eagle(struct ncplane* n, const char* sprite){
 static int
 eagles(struct notcurses* nc, struct ncplane* n){
   int ret = 0;
-  int truex, truey; // dimensions of true display
+  unsigned truex, truey; // dimensions of true display
   notcurses_term_dim_yx(nc, &truey, &truex);
   struct timespec flapiter;
   timespec_div(&demodelay, truex / 2, &flapiter);
   const int height = 16;
   const int width = 16;
   struct eagle {
-    int yoff, xoff;
+    int yoff;
+    unsigned xoff;
     struct ncplane* n;
   } e[3];
   for(size_t i = 0 ; i < sizeof(e) / sizeof(*e) ; ++i){
@@ -199,7 +200,7 @@ eagles(struct notcurses* nc, struct ncplane* n){
       e[i].yoff += rand() % (2 + i) - 1;
       if(e[i].yoff < 0){
         e[i].yoff = 0;
-      }else if(e[i].yoff + height >= truey){
+      }else if(e[i].yoff + height >= (int)truey){
         e[i].yoff = truey - height - 1;
       }
       int scale = truex >= 80 ? truex / 80 : 1;
diff --git a/src/demo/fission.c b/src/demo/fission.c
index 15efe11f82..f2109c97e3 100644
--- a/src/demo/fission.c
+++ b/src/demo/fission.c
@@ -6,7 +6,7 @@ drop_bricks(struct notcurses* nc, struct ncplane** arr, int arrcount){
   if(arrcount == 0 || arr == NULL){
     return -1;
   }
-  int stdy, stdx;
+  unsigned stdy, stdx;
   notcurses_term_dim_yx(nc, &stdy, &stdx);
   // an erase+render cycle ought not change the screen, as we duplicated it
   struct timespec iterdelay;
@@ -28,7 +28,7 @@ drop_bricks(struct notcurses* nc, struct ncplane** arr, int arrcount){
       if(rangee < arrcount){
         int y;
         ncplane_yx(arr[ranges], &y, NULL);
-        speeds[rangee - ranges] = y < stdy / 2 ? 1 : -1;
+        speeds[rangee - ranges] = y < (int)stdy / 2 ? 1 : -1;
         ++rangee;
       }
     }
@@ -43,7 +43,7 @@ drop_bricks(struct notcurses* nc, struct ncplane** arr, int arrcount){
         int x, y;
         ncplane_yx(ncp, &y, &x);
         if(felloff){
-          if(y + speeds[i] >= stdy || y + speeds[i] + ncplane_dim_y(ncp) < 0){
+          if(y + speeds[i] >= (int)stdy || y + speeds[i] + (int)ncplane_dim_y(ncp) < 0){
             ncplane_destroy(ncp);
             arr[ranges + i] = NULL;
             if(ranges + i + 1 == rangee){
@@ -104,7 +104,7 @@ shuffle_in(struct ncplane** arr, int count, struct ncplane* n){
 // you played yourself https://genius.com/De-la-soul-fallin-lyrics
 int fission_demo(struct notcurses* nc){
   struct ncplane* npl = NULL;
-  int dimx, dimy;
+  unsigned dimx, dimy;
   struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
   size_t usesize = sizeof(bool) * dimy * dimx;
   bool* usemap = malloc(usesize);
@@ -126,8 +126,8 @@ int fission_demo(struct notcurses* nc){
   //  * newy/newx: actual geometry of current brick
   //  * usey/usex: 
   ncplane_greyscale(stdn);
-  for(int y = 1 ; y < dimy ; ++y){
-    int x = 0;
+  for(unsigned y = 1 ; y < dimy ; ++y){
+    unsigned x = 0;
     while(x < dimx){
       if(usemap[y * dimx + x]){ // skip if we've already been copied
         ++x;
@@ -153,8 +153,8 @@ int fission_demo(struct notcurses* nc){
         goto err;
       }
       // copy the old content into this new ncplane
-      for(int usey = y ; usey < y + newy ; ++usey){
-        for(int usex = x ; usex < x + newx ; ++usex){
+      for(unsigned usey = y ; usey < y + newy ; ++usey){
+        for(unsigned usex = x ; usex < x + newx ; ++usex){
           if(usemap[usey * dimx + usex]){
             newx = usex - x;
             ncplane_resize_simple(n, newy, newx);
diff --git a/src/demo/grid.c b/src/demo/grid.c
index 6972b92fa1..158f670090 100644
--- a/src/demo/grid.c
+++ b/src/demo/grid.c
@@ -115,13 +115,13 @@ gridinv_demo(struct notcurses* nc, struct ncplane *n){
   nccell ul, ll, cl, cr, lc, lr, ur, uc, cc;
   prep_cells2(n, &ul, &uc, &ur, &cl, &cc, &cr, &ll, &lc, &lr);
   for(int i = 0 ; i < 256 ; ++i){
-    int maxx, maxy;
+    unsigned maxx, maxy;
     notcurses_term_dim_yx(nc, &maxy, &maxx);
     int rs = 255 / maxx;
     int gs = 255 / (maxx + maxy);
     int bs = 255 / maxy;
-    int x = 0;
-    int y = 1;
+    unsigned x = 0;
+    unsigned y = 1;
     // top line
     cnccell_set_fg_rgb8(&ul, i / 2, i, i / 2);
     cnccell_set_bg_rgb8(&ul, 255 - rs * x, 255 - gs * (x + y), 255 - bs * y);
@@ -175,7 +175,7 @@ static int
 gridswitch_demo(struct notcurses* nc, struct ncplane *n){
   ncplane_erase(n);
   int ret = 0;
-  int maxx, maxy;
+  unsigned maxx, maxy;
   nccell ul, ll, cl, cr, lc, lr, ur, uc, cc;
   prep_cells(n, &ul, &uc, &ur, &cl, &cc, &cr, &ll, &lc, &lr);
   for(int i = 0 ; i < 256 ; ++i){
@@ -183,8 +183,8 @@ gridswitch_demo(struct notcurses* nc, struct ncplane *n){
     int rs = 256 / maxx;
     int gs = 256 / (maxx + maxy);
     int bs = 256 / maxy;
-    int x = 0;
-    int y = 1;
+    unsigned x = 0;
+    unsigned y = 1;
     int bgr = i;
     int bgg = 0x80;
     int bgb = i;
@@ -246,7 +246,7 @@ gridswitch_demo(struct notcurses* nc, struct ncplane *n){
 
 // red across, blue down, green from UL to LR
 int grid_demo(struct notcurses* nc){
-  int y, x;
+  unsigned y, x;
   struct ncplane* n = notcurses_stdplane(nc);
   ncplane_erase(n);
   nccell ul, uc, ur;
@@ -256,7 +256,7 @@ int grid_demo(struct notcurses* nc){
 
   int ret = 0;
   for(int i = 0 ; i < 256 ; ++i){
-    int maxx, maxy;
+    unsigned maxx, maxy;
     notcurses_term_dim_yx(nc, &maxy, &maxx);
     int rs = 255 / maxx;
     int gs = 255 / (maxx + maxy);
diff --git a/src/demo/highcon.c b/src/demo/highcon.c
index 1684749ec0..d201a63be7 100644
--- a/src/demo/highcon.c
+++ b/src/demo/highcon.c
@@ -63,7 +63,7 @@ generate_next_color(unsigned *total, unsigned *r, unsigned *g, unsigned *b,
 int highcontrast_demo(struct notcurses* nc){
   const int STEP = 16;
   int ret = -1;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   int totcells = (dimy - 1) * dimx;
   if(totcells <= 1){
diff --git a/src/demo/hud.c b/src/demo/hud.c
index 0cfc15ac7a..9044c2cb23 100644
--- a/src/demo/hud.c
+++ b/src/demo/hud.c
@@ -86,7 +86,7 @@ debug_toggle(struct notcurses* nc){
     debug = NULL;
     return;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   notcurses_term_dim_yx(nc, &dimy, &dimx);
   fbuf f;
   if(fbuf_init_small(&f)){
@@ -123,7 +123,7 @@ debug_toggle(struct notcurses* nc){
     return;
   }
   fbuf_free(&f);
-  for(int y = 0 ; y < ncplane_dim_y(n) ; ++y){
+  for(unsigned y = 0 ; y < ncplane_dim_y(n) ; ++y){
     nccell c = CELL_TRIVIAL_INITIALIZER;
     nccell_set_fg_alpha(&c, NCALPHA_TRANSPARENT);
     nccell_set_bg_alpha(&c, NCALPHA_TRANSPARENT);
@@ -144,7 +144,7 @@ about_toggle(struct notcurses* nc){
   }
   const int ABOUT_ROWS = 9;
   const int ABOUT_COLS = 40;
-  int dimy;
+  unsigned dimy;
   notcurses_term_dim_yx(nc, &dimy, NULL);
   ncplane_options nopts = {
     .y = 3,
@@ -392,9 +392,13 @@ hud_print_finished(elem* list){
       if(ncplane_printf_yx(hud, line, 1, "%d", e->frames) < 0){
         return -1;
       }
-      if(ncplane_printf_yx(hud, line, 7, "%"PRIu64".%03"PRIu64"s",
-                           e->totalns / NANOSECS_IN_SEC,
-                           (e->totalns % NANOSECS_IN_SEC) / 1000000) < 0){
+      char buf[NCPREFIXCOLUMNS + 2];
+      ncnmetric(e->totalns, sizeof(buf), NANOSECS_IN_SEC, buf, 0, 1000, '\0');
+      for(int x = 6 ; x < 14 - ncstrwidth(buf) ; ++x){
+        nccell ci = CELL_TRIVIAL_INITIALIZER;
+        ncplane_putc_yx(hud, 1, x, &ci);
+      }
+      if(ncplane_printf_yx(hud, line, 14 - ncstrwidth(buf), "%ss", buf) < 0){
         return -1;
       }
       if(ncplane_putstr_yx(hud, line, 16, e->name) < 0){
@@ -410,7 +414,7 @@ struct ncplane* hud_create(struct notcurses* nc){
   if(hud){
     return NULL;
   }
-  int dimx, dimy;
+  unsigned dimx, dimy;
   notcurses_term_dim_yx(nc, &dimy, &dimx);
   struct ncplane_options nopts = {
     // FPS graph is 6 rows tall; we want one row above it
@@ -608,8 +612,14 @@ int demo_render(struct notcurses* nc){
     if(ncplane_printf_yx(hud, 1, 1, "%d", elems->frames) < 0){
       return -1;
     }
-    if(ncplane_printf_yx(hud, 1, 7, "%"PRIu64".%03"PRIu64"s", ns / NANOSECS_IN_SEC,
-                         (ns % NANOSECS_IN_SEC) / 1000000) < 0){
+    char buf[NCPREFIXCOLUMNS + 2];
+    ncnmetric(ns, sizeof(buf), NANOSECS_IN_SEC, buf, 0, 1000, '\0');
+    for(int x = 6 ; x < 14 - ncstrwidth(buf) ; ++x){
+      nccell ci = CELL_TRIVIAL_INITIALIZER;
+      ncplane_putc_yx(hud, 1, x, &ci);
+    }
+//fprintf(stderr, "[%s] %zu %d\n", buf, strlen(buf), ncstrwidth(buf));
+    if(ncplane_printf_yx(hud, 1, 14 - ncstrwidth(buf), "%ss", buf) < 0){
       return -1;
     }
     if(ncplane_putstr_yx(hud, 1, 16, elems->name) < 0){
@@ -632,7 +642,7 @@ int demo_render(struct notcurses* nc){
 
 int fpsgraph_init(struct notcurses* nc){
   const int PLOTHEIGHT = 6;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
   ncplane_options nopts = {
     .y = NCALIGN_BOTTOM,
diff --git a/src/demo/intro.c b/src/demo/intro.c
index 8877de5b62..d8b2edfcf4 100644
--- a/src/demo/intro.c
+++ b/src/demo/intro.c
@@ -5,7 +5,7 @@ static int centercols;
 static int
 animate(struct notcurses* nc, struct ncplane* ncp, void* curry){
   int* flipmode = curry;
-  int rows, cols;
+  unsigned rows, cols;
   ncplane_dim_yx(ncp, &rows, &cols);
   const bool smallscreen = rows < 26;
   const int row1 = rows - 10 + smallscreen;
@@ -64,7 +64,7 @@ greatscott(struct notcurses* nc, int dimx){
 }
 
 static struct ncplane*
-orcashow(struct notcurses* nc, int dimy, int dimx){
+orcashow(struct notcurses* nc, unsigned dimy, unsigned dimx){
   char* path = find_data("natasha-blur.png");
   if(path == NULL){
     return NULL;
@@ -104,7 +104,8 @@ orcashow(struct notcurses* nc, int dimy, int dimx){
 
 static int
 orcaride(struct notcurses* nc, struct ncplane* on, int iterations){
-  int odimy, odimx, oy, ox, dimx;
+  unsigned odimy, odimx, dimx;
+  int oy, ox;
   ncplane_dim_yx(notcurses_stdplane(nc), NULL, &dimx);
   ncplane_yx(on, &oy, &ox);
   ncplane_dim_yx(on, &odimy, &odimx);
@@ -124,7 +125,7 @@ int intro(struct notcurses* nc){
   if(!notcurses_canutf8(nc)){
     return 0;
   }
-  int rows, cols;
+  unsigned rows, cols;
   struct ncplane* ncp = notcurses_stddim_yx(nc, &rows, &cols);
   uint32_t ccul, ccur, ccll, cclr;
   ccul = ccur = ccll = cclr = 0;
@@ -134,7 +135,7 @@ int intro(struct notcurses* nc){
   ncchannel_set_rgb8(&cclr, 0, 0, 0xff);
   // we use full block rather+fg than space+bg to conflict less with the menu
   ncplane_cursor_move_yx(ncp, 2, 1);
-  if(ncplane_highgradient_sized(ncp, ccul, ccur, ccll, cclr, rows - 3, cols - 2) <= 0){
+  if(ncplane_gradient2x1(ncp, -1, -1, rows - 3, cols - 2, ccul, ccur, ccll, cclr) <= 0){
     return -1;
   }
   nccell c = CELL_TRIVIAL_INITIALIZER;
@@ -168,7 +169,9 @@ int intro(struct notcurses* nc){
   if(ncplane_cursor_move_yx(ncp, 5, (cols - centercols) / 2 + 1)){
     return -1;
   }
-  if(ncplane_gradient(ncp, "Δ", 0, cul, cur, cll, clr, rows - 8, cols / 2 + centercols / 2 - 1) <= 0){
+  if(ncplane_gradient(ncp, -1, -1, rows - 8 - 5,
+                      cols / 2 + centercols / 2 - 1 - ((cols - centercols) / 2 + 1),
+                      "Δ", 0, cul, cur, cll, clr) <= 0){
     return -1;
   }
   nccell_set_fg_rgb(&lr, 0xff0000); nccell_set_bg_rgb(&lr, 0x002000);
diff --git a/src/demo/jungle.c b/src/demo/jungle.c
index 201d8336b4..fbd9c2580f 100644
--- a/src/demo/jungle.c
+++ b/src/demo/jungle.c
@@ -26601,7 +26601,7 @@ int jungle_demo(struct notcurses* nc){
   if(out < ORIGWIDTH * ORIGHEIGHT){ // uh-oh
     return -1;
   }
-  int dimx, dimy;
+  unsigned dimx, dimy;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   // FIXME rewrite all of this using modern ncvisual, sheesh
   dimy *= 2; // use half blocks
@@ -26613,7 +26613,7 @@ int jungle_demo(struct notcurses* nc){
   nccell c = CELL_TRIVIAL_INITIALIZER;
   nccell_load(n, &c, "\xe2\x96\x80"); // upper half block
   for(size_t y = 0 ; y < ORIGHEIGHT ; y += (yiter * 2)){
-    int targy = yoff + y / (yiter * 2);
+    unsigned targy = yoff + y / (yiter * 2);
     if(targy < dimy / 2){
       if(ncplane_cursor_move_yx(n, targy, xoff)){
         return -1;
diff --git a/src/demo/luigi.c b/src/demo/luigi.c
index ec13d26398..7a6bcdb114 100644
--- a/src/demo/luigi.c
+++ b/src/demo/luigi.c
@@ -146,7 +146,7 @@ int luigi_demo(struct notcurses* nc){
   if(!notcurses_canopen_images(nc)){
     return 0;
   }
-  int rows, cols;
+  unsigned rows, cols;
   char* map = find_data("megaman2.bmp");
   struct ncvisual* nv = ncvisual_from_file(map);
   free(map);
@@ -166,7 +166,7 @@ int luigi_demo(struct notcurses* nc){
   const int height = 32;
   int yoff = rows * 4 / 5 - height + 1; // tuned
   struct ncplane* lns[3];
-  int i;
+  unsigned i;
   struct ncplane* lastseen = NULL;
   for(i = 0 ; i < 3 ; ++i){
     struct ncplane_options nopts = {
diff --git a/src/demo/mojibake.c b/src/demo/mojibake.c
index cfef9acaac..94a6cfc9d7 100644
--- a/src/demo/mojibake.c
+++ b/src/demo/mojibake.c
@@ -3687,7 +3687,7 @@ int mojibake_demo(struct notcurses* nc){
   if(!notcurses_canutf8(nc)){
     return 0;
   }
-  int dimy;
+  unsigned dimy;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, NULL);
   ncplane_greyscale(std);
   struct ncplane* title = maketitle(std);
@@ -3714,7 +3714,7 @@ int mojibake_demo(struct notcurses* nc){
     makegroup(title, dimy + 1, face_costume, "face-costume"),
     makegroup(title, dimy + 1, cat_face, "cat-face"),
     makegroup(title, dimy + 1, monkey_face, "monkey-face"),
-    makegroup(title, dimy + 1, emotion, "emotion"),
+    //makegroup(title, dimy + 1, emotion, "emotion"),
     makegroup(title, dimy + 1, hand_fingers_open, "hand-fingers-open"),
     makegroup(title, dimy + 1, hand_fingers_partial, "hand-fingers-partial"),
     makegroup(title, dimy + 1, hand_single_finger, "hand-single-finger"),
@@ -3811,11 +3811,12 @@ int mojibake_demo(struct notcurses* nc){
   do{
     unsigned u = topmost;
     do{
-      int y, x, leny, lenx;
+      int y, x;
       ncplane_yx(planes[u], &y, &x);
-      if(y >= dimy){
+      if(y >= (int)dimy){
         break;
       }
+      unsigned leny, lenx;
       ncplane_dim_yx(planes[u], &leny, &lenx);
       if(y == 2){
         if(leny > 1){
diff --git a/src/demo/normal.c b/src/demo/normal.c
index e2e0450731..1a37a2be45 100644
--- a/src/demo/normal.c
+++ b/src/demo/normal.c
@@ -68,7 +68,7 @@ rotate_visual(struct notcurses* nc, struct ncplane* n, int dy, int dx){
     return -1;
   }
   ncplane_destroy(n);
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
   const int ROTATIONS = 32;
   timespec_div(&demodelay, ROTATIONS / 2, &scaled);
@@ -154,7 +154,7 @@ int normal_demo(struct notcurses* nc){
   if(!notcurses_canutf8(nc)){
     return 0;
   }
-  int dy, dx;
+  unsigned dy, dx;
   int r = -1;
   struct ncplane* nstd = notcurses_stddim_yx(nc, &dy, &dx);
   ncplane_erase(nstd);
@@ -175,13 +175,13 @@ int normal_demo(struct notcurses* nc){
   if(!rgba){
     goto err;
   }
-  for(int off = 0 ; off < dy * dx ; ++off){
+  for(unsigned off = 0 ; off < dy * dx ; ++off){
     rgba[off] = 0xff000000;
   }
-  int y;
+  unsigned y;
   if(dy / geom.scaley % 2){
     y = dy / geom.scaley + 1;
-    for(int x = 0 ; x < dx ; ++x){
+    for(unsigned x = 0 ; x < dx ; ++x){
       if(mcell(offset(rgba, y, x, dx), y, x, dy / geom.scaley, dx)){
         goto err;
       }
@@ -190,7 +190,7 @@ int normal_demo(struct notcurses* nc){
   struct timespec scaled;
   timespec_div(&demodelay, dy, &scaled);
   for(y = 0 ; y <= dy / 2 ; ++y){
-    for(int x = 0 ; x < dx ; ++x){
+    for(unsigned x = 0 ; x < dx ; ++x){
       if(mcell(offset(rgba, dy / 2 - y, x, dx), dy / 2 - y, x, dy, dx)){
         goto err;
       }
@@ -231,7 +231,7 @@ int normal_demo(struct notcurses* nc){
   ncchannels_set_fg_rgb8(&bl, 0xff, 0, 0xff);
   ncchannels_set_fg_rgb8(&br, 0, 0, 0);
   ncplane_dim_yx(n, &dy, &dx);
-  if(ncplane_stain(n, dy - 1, dx - 1, tl, tr, bl, br) < 0){
+  if(ncplane_stain(n, -1, -1, dy - 1, dx - 1, tl, tr, bl, br) < 0){
     goto err;
   }
   DEMO_RENDER(nc);
diff --git a/src/demo/outro.c b/src/demo/outro.c
index 233eba51e8..20dac9f672 100644
--- a/src/demo/outro.c
+++ b/src/demo/outro.c
@@ -3,7 +3,7 @@
 
 static int y;
 static int targy;
-static int xstart;
+static unsigned xstart;
 static struct ncplane* on;
 struct ncvisual_options vopts;
 
@@ -52,13 +52,12 @@ videothread(void* vnc){
   if(ncv == NULL){
     return NULL;
   }
-  int rows, cols;
+  unsigned rows, cols;
   struct ncplane* ncp = notcurses_stddim_yx(nc, &rows, &cols);
   struct ncvisual_options ovopts = {
     .scaling = NCSCALE_STRETCH,
     .n = ncp,
     .y = 1,
-    .flags = NCVISUAL_OPTION_ADDALPHA,
   };
   int three = 3;
   if(ncvisual_blit(nc, ncv, &ovopts) == NULL){
@@ -115,7 +114,7 @@ videothread(void* vnc){
 }
 
 static struct ncplane*
-outro_message(struct notcurses* nc, int* rows, int* cols){
+outro_message(struct notcurses* nc, unsigned* rows, unsigned* cols){
   const char str0[] = " ATL, baby! ATL! ";
   const char str1[] = " throw your hands in the air ";
   const char* str2 = notcurses_canutf8(nc) ? " hack on! —dank❤ " : " hack on! --dank ";
@@ -186,7 +185,7 @@ outro_message(struct notcurses* nc, int* rows, int* cols){
 }
 
 int outro(struct notcurses* nc){
-  int rows, cols;
+  unsigned rows, cols;
   struct ncplane* ncp = notcurses_stddim_yx(nc, &rows, &cols);
   ncplane_erase(ncp);
   struct ncvisual* chncv = NULL;
@@ -208,7 +207,7 @@ int outro(struct notcurses* nc){
     ncplane_set_name(vopts.n, "bnnr");
   }
   xstart = cols;
-  int ystart = rows;
+  unsigned ystart = rows;
   on = outro_message(nc, &ystart, &xstart);
   if(on == NULL){
     return -1;
diff --git a/src/demo/qrcode.c b/src/demo/qrcode.c
index 31fd016573..6d5a17e77a 100644
--- a/src/demo/qrcode.c
+++ b/src/demo/qrcode.c
@@ -6,7 +6,7 @@ int qrcode_demo(struct notcurses* nc){
   }
 #ifdef USE_QRCODEGEN
   char data[128];
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane *stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
   ncplane_erase(stdn);
   struct ncplane* n = ncplane_dup(stdn, NULL);
@@ -21,7 +21,7 @@ int qrcode_demo(struct notcurses* nc){
       done += sizeof(r);
     }
     ncplane_home(n);
-    int y = dimy, x = dimx;
+    unsigned y = dimy, x = dimx;
     ncplane_home(n);
     int qlen = ncplane_qrcode(n, &y, &x, data, len);
     if(qlen > 0){ // FIXME can fail due to being too large for display; distinguish this case
diff --git a/src/demo/reel.c b/src/demo/reel.c
index c496cdd7cb..ac172f6839 100644
--- a/src/demo/reel.c
+++ b/src/demo/reel.c
@@ -192,7 +192,7 @@ ncreel_demo_core(struct notcurses* nc){
   tabletctx* tctxs = NULL;
   bool aborted = false;
   int x = 8, y = 4;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
   struct ncplane_options nopts = {
     .y = y,
diff --git a/src/demo/sliding.c b/src/demo/sliding.c
index e16e331431..a4ff897e23 100644
--- a/src/demo/sliding.c
+++ b/src/demo/sliding.c
@@ -94,7 +94,7 @@ static int
 fill_chunk(struct ncplane* n, int idx){
   const int hidx = idx % CHUNKS_HORZ;
   const int vidx = idx / CHUNKS_HORZ;
-  int maxy, maxx;
+  unsigned maxy, maxx;
   ncplane_dim_yx(n, &maxy, &maxx);
   uint64_t channels = 0;
   int r = 64 + hidx * 10;
@@ -107,7 +107,7 @@ fill_chunk(struct ncplane* n, int idx){
   ncchannel_set_rgb8(&ur, g, b, r);
   ncchannel_set_rgb8(&ll, b, r, g);
   int ret = 0;
-  if(ncplane_highgradient_sized(n, ul, ur, ll, lr, maxy, maxx) <= 0){
+  if(ncplane_gradient2x1(n, -1, -1, 0, 0, ul, ur, ll, lr) <= 0){
     ret = -1;
   }
   ret |= ncplane_double_box(n, 0, channels, maxy - 1, maxx - 1, 0);
@@ -134,7 +134,7 @@ draw_bounding_box(struct ncplane* n, int yoff, int xoff, int chunky, int chunkx)
 // make a bunch of boxes with gradients and use them to play a sliding puzzle.
 int sliding_puzzle_demo(struct notcurses* nc){
   int ret = -1, z;
-  int maxx, maxy;
+  unsigned maxx, maxy;
   struct ncplane* n = notcurses_stddim_yx(nc, &maxy, &maxx);
   int chunky, chunkx;
   // want at least 2x2 for each sliding chunk
diff --git a/src/demo/trans.c b/src/demo/trans.c
index b676e68d08..a3270fff4f 100644
--- a/src/demo/trans.c
+++ b/src/demo/trans.c
@@ -26,7 +26,7 @@ grow_rgb8(uint32_t* rgb){
 
 static struct ncplane*
 legend(struct notcurses* nc, const char* msg){
-  int dimx, dimy;
+  unsigned dimx, dimy;
   notcurses_term_dim_yx(nc, &dimy, &dimx);
   ncplane_options nopts = {
     .rows = 3,
@@ -62,10 +62,10 @@ legend(struct notcurses* nc, const char* msg){
 static int
 slideitslideit(struct notcurses* nc, struct ncplane* n, uint64_t deadline,
                int* vely, int* velx){
-  int dimy, dimx;
   int yoff, xoff;
-  int ny, nx;
+  unsigned dimy, dimx;
   notcurses_term_dim_yx(nc, &dimy, &dimx);
+  unsigned ny, nx;
   ncplane_dim_yx(n, &ny, &nx);
   ncplane_yx(n, &yoff, &xoff);
   struct timespec iterdelay;
@@ -78,14 +78,14 @@ slideitslideit(struct notcurses* nc, struct ncplane* n, uint64_t deadline,
     if(xoff <= 1){
       xoff = 1;
       *velx = -*velx;
-    }else if(xoff >= dimx - nx){
+    }else if((unsigned)xoff >= dimx - nx){
       xoff = dimx - nx - 1;
       *velx = -*velx;
     }
     if(yoff <= 2){
       yoff = 2;
       *vely = -*vely;
-    }else if(yoff >= dimy - ny){
+    }else if((unsigned)yoff >= dimy - ny){
       yoff = dimy - ny - 1;
       *vely = -*vely;
     }
@@ -99,7 +99,7 @@ slideitslideit(struct notcurses* nc, struct ncplane* n, uint64_t deadline,
 // run panels atop the display in an exploration of transparency
 static int
 slidepanel(struct notcurses* nc, struct ncplane* stdn){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   notcurses_term_dim_yx(nc, &dimy, &dimx);
   int ny = dimy / 4;
   int nx = dimx / 3;
@@ -276,13 +276,13 @@ slidepanel(struct notcurses* nc, struct ncplane* stdn){
 // have a great many colors, that they progress reasonably through the space,
 // and that we can write to every coordinate.
 int trans_demo(struct notcurses* nc){
-  int maxx, maxy;
+  unsigned maxx, maxy;
   struct ncplane* n = notcurses_stddim_yx(nc, &maxy, &maxx);
   ncplane_set_fg_rgb8(n, 255, 255, 255);
   uint64_t channels = 0;
   ncchannels_set_fg_rgb8(&channels, 0, 128, 128);
   ncchannels_set_bg_rgb8(&channels, 90, 0, 90);
-  int y = 1, x = 0;
+  unsigned y = 1, x = 0;
   ncplane_cursor_move_yx(n, y, x);
   if(ncplane_rounded_box_sized(n, 0, channels, maxy - 1, maxx, 0)){
     return -1;
diff --git a/src/demo/unicodeblocks.c b/src/demo/unicodeblocks.c
index 841382354a..0f3b70198b 100644
--- a/src/demo/unicodeblocks.c
+++ b/src/demo/unicodeblocks.c
@@ -25,7 +25,7 @@ fade_block(struct notcurses* nc, struct ncplane* nn, const struct timespec* subd
 // negative row will result in vertical pbar on the left side
 static struct ncprogbar*
 pbar_make(struct notcurses* nc, int row){
-  int dimx, dimy;
+  unsigned dimx, dimy;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
   struct ncplane_options nopts = {
     .y = row < 0 ? 4 : row,
@@ -42,8 +42,9 @@ pbar_make(struct notcurses* nc, int row){
   uint64_t channels = 0;
   ncchannels_set_bg_rgb(&channels, 0);
   ncplane_set_base(pbar, "", 0, channels);
-  int posy, posx, pdimy, pdimx;
+  int posy, posx;
   ncplane_yx(pbar, &posy, &posx);
+  unsigned pdimy, pdimx;
   ncplane_dim_yx(pbar, &pdimy, &pdimx);
   ncplane_cursor_move_yx(std, posy - 1, posx - 1);
   channels = 0;
@@ -66,7 +67,7 @@ pbar_make(struct notcurses* nc, int row){
 
 static int
 draw_block(struct ncplane* nn, uint32_t blockstart){
-  int dimx, dimy;
+  unsigned dimx, dimy;
   ncplane_dim_yx(nn, &dimy, &dimx);
   nccell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
   nccell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
@@ -119,7 +120,7 @@ draw_block(struct ncplane* nn, uint32_t blockstart){
 }
 
 int unicodeblocks_demo(struct notcurses* nc){
-  int maxx, maxy;
+  unsigned maxx, maxy;
   struct ncplane* n = notcurses_stddim_yx(nc, &maxy, &maxx);
   // some blocks are good for the printing, some less so. some are only
   // marginally covered by mainstream fonts, some not at all. we explicitly
@@ -207,7 +208,7 @@ int unicodeblocks_demo(struct notcurses* nc){
     return 0;
   }
   ncplane_greyscale(notcurses_stdplane(nc));
-  int pbarrow = 4 + BLOCKSIZE / CHUNKSIZE + 4;
+  unsigned pbarrow = 4 + BLOCKSIZE / CHUNKSIZE + 4;
   if(pbarrow > maxy - 2){
     pbarrow = -1;
   }
diff --git a/src/demo/view.c b/src/demo/view.c
index f4bdf5709a..5bbae627f5 100644
--- a/src/demo/view.c
+++ b/src/demo/view.c
@@ -174,7 +174,7 @@ int view_demo(struct notcurses* nc){
     return 0;
   }
   memset(&marsh, 0, sizeof(marsh));
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* nstd = notcurses_stddim_yx(nc, &dimy, &dimx);
   int ret = view_images(nc, nstd, dimy, dimx);
   if(ret){
diff --git a/src/demo/whiteout.c b/src/demo/whiteout.c
index a2a5c8d481..c52a9e1f18 100644
--- a/src/demo/whiteout.c
+++ b/src/demo/whiteout.c
@@ -14,7 +14,7 @@
 static struct ncplane*
 mathplane(struct notcurses* nc){
   struct ncplane* stdn = notcurses_stdplane(nc);
-  int dimx, dimy;
+  unsigned dimx, dimy;
   notcurses_term_dim_yx(nc, &dimy, &dimx);
   const int HEIGHT = 9;
   const int WIDTH = dimx;
@@ -468,7 +468,8 @@ int witherworm_demo(struct notcurses* nc){
       const int start = starts[i];
       int step = steps[i];
       nccell_init(&c);
-      int y, x, maxy, maxx;
+      unsigned y, x;
+      unsigned maxy, maxx;
       ncplane_dim_yx(n, &maxy, &maxx); // might resize
       int rgb = start;
       int bytes_out = 0;
@@ -508,7 +509,7 @@ int witherworm_demo(struct notcurses* nc){
           }
           int ulen = 0;
           int r;
-          if(wcwidth(wcs) <= maxx - x){
+          if(wcwidth(wcs) <= (int)(maxx - x)){
             if((r = ncplane_putegc(n, &(*s)[idx], &ulen)) <= 0){
               if(ulen < 0){
                 return -1;
diff --git a/src/demo/xray.c b/src/demo/xray.c
index 024901a236..30c0e6db17 100644
--- a/src/demo/xray.c
+++ b/src/demo/xray.c
@@ -75,7 +75,7 @@ struct marsh {
 // make a plane on a new pile suitable for rendering a frame of the video
 static int
 make_plane(struct notcurses* nc, struct ncplane** t){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   notcurses_stddim_yx(nc, &dimy, &dimx);
   // FIXME want a resizecb
   struct ncplane_options opts = {
@@ -167,7 +167,7 @@ int xray_demo(struct notcurses* nc){
   if(!notcurses_canopen_videos(nc)){
     return 0;
   }
-  int dimx, dimy;
+  unsigned dimx, dimy;
   notcurses_term_dim_yx(nc, &dimy, &dimx);
   ncplane_erase(notcurses_stdplane(nc));
   char* path = find_data("notcursesIII.mkv");
diff --git a/src/demo/yield.c b/src/demo/yield.c
index aee04e5a4f..9735ce6b5a 100644
--- a/src/demo/yield.c
+++ b/src/demo/yield.c
@@ -145,7 +145,7 @@ int yield_demo(struct notcurses* nc){
   if(!notcurses_canopen_images(nc)){
     return 0;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
   // in sixel-based implementation, if we redraw each cycle, the underlying
   // material will be redrawn, taking time. erasing won't eliminate the
diff --git a/src/demo/zoo.c b/src/demo/zoo.c
index fd24da8c39..952216b0eb 100644
--- a/src/demo/zoo.c
+++ b/src/demo/zoo.c
@@ -233,7 +233,8 @@ selector_run(struct notcurses* nc, struct ncplane* p, struct ncselector* selecto
     "NCSelector allows a single option to be selected from a list.\n"
     "NCFdplane streams a file descriptor, while NCSubproc spawns a subprocess and streams its output.\n";
   int titers = get_word_count(text);
-  int ret = 0, dimy, dimx;
+  int ret = 0;
+  unsigned dimy, dimx;
   ncplane_dim_yx(notcurses_stdplane(nc), &dimy, &dimx);
   const int centery = (dimy - ncplane_dim_y(p)) / 2;
   int ry, rx, sy, sx;
@@ -307,7 +308,8 @@ mselector_run(struct notcurses* nc, struct ncplane* p, struct ncmultiselector* m
     "Widgets can be controlled with the keyboard and/or mouse. "
     "They are implemented atop ncplanes, and these planes can be manipulated like all others.";
   const int titers = get_word_count(text);
-  int ret = 0, dimy, dimx;
+  int ret = 0;
+  unsigned dimy, dimx;
   ncplane_dim_yx(notcurses_stdplane(nc), &dimy, &dimx);
   const int centery = (dimy - ncplane_dim_y(p)) / 2;
   int ry, rx, sy, sx;
@@ -376,7 +378,7 @@ mselector_run(struct notcurses* nc, struct ncplane* p, struct ncmultiselector* m
 static int
 reader_demo(struct notcurses* nc){
   int ret = -1;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
   const int READER_COLS = 64;
   const int READER_ROWS = 8;
diff --git a/src/fetch/main.c b/src/fetch/main.c
index 1e9be24cf4..0598acc794 100644
--- a/src/fetch/main.c
+++ b/src/fetch/main.c
@@ -365,7 +365,7 @@ drawpalette(struct notcurses* nc){
   if(psize > 256){
     psize = 256;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   if(dimx < 64){
     return -1;
@@ -380,7 +380,7 @@ drawpalette(struct notcurses* nc){
     if(ncplane_cursor_move_yx(n, -1, (dimx - toshow) / 2)){
       return -1;
     }
-    for(int x = (dimx - 64) / 2 ; x < dimx / 2 + 32 ; ++x){
+    for(unsigned x = (dimx - 64) / 2 ; x < dimx / 2 + 32 ; ++x){
       const int truex = x - (dimx - 64) / 2;
       if(y * 64 + truex >= psize){
         break;
@@ -403,8 +403,8 @@ drawpalette(struct notcurses* nc){
 static int
 infoplane_notcurses(struct notcurses* nc, const fetched_info* fi, int planeheight){
   const int planewidth = 72;
-  int dimy;
-  int y;
+  unsigned dimy;
+  unsigned y;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, NULL);
   ncplane_cursor_yx(std, &y, NULL);
   struct ncplane_options nopts = {
@@ -430,16 +430,16 @@ infoplane_notcurses(struct notcurses* nc, const fetched_info* fi, int planeheigh
 #if defined(__linux__)
   struct sysinfo sinfo;
   sysinfo(&sinfo);
-  char totalmet[BPREFIXSTRLEN + 1], usedmet[BPREFIXSTRLEN + 1];
-  bprefix(sinfo.totalram, 1, totalmet, 1);
-  bprefix(sinfo.totalram - sinfo.freeram, 1, usedmet, 1);
+  char totalmet[NCBPREFIXSTRLEN + 1], usedmet[NCBPREFIXSTRLEN + 1];
+  ncbprefix(sinfo.totalram, 1, totalmet, 1);
+  ncbprefix(sinfo.totalram - sinfo.freeram, 1, usedmet, 1);
   ncplane_printf_aligned(infop, 2, NCALIGN_RIGHT, "Processes: %hu ", sinfo.procs);
   ncplane_printf_aligned(infop, 2, NCALIGN_LEFT, " RAM: %sB/%sB", usedmet, totalmet);
 #elif defined(BSD)
   uint64_t ram;
   size_t oldlenp = sizeof(ram);
   if(sysctlbyname("hw.memsize", &ram, &oldlenp, NULL, 0) == 0){
-    char tram[BPREFIXSTRLEN + 1];
+    char tram[NCBPREFIXSTRLEN + 1];
     bprefix(ram, 1, tram, 1);
     ncplane_printf_aligned(infop, 2, NCALIGN_LEFT, " RAM: %sB", tram);
   }
@@ -552,7 +552,7 @@ neologo_present(struct notcurses* nc, const char* nlogo){
       maxlinelen = collen;
     }
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   const int leftpad = (dimx - maxlinelen) / 2;
   for(int i = 0 ; i < linecount ; ++i){
@@ -589,7 +589,7 @@ display_thread(void* vmarshal){
       ncv = ncvisual_from_file(m->dinfo->logofile);
     }
     if(ncv){
-      int y;
+      unsigned y;
       ncplane_cursor_yx(notcurses_stdplane_const(m->nc), &y, NULL);
       bool pixeling = false;
       if(notcurses_check_pixel_support(m->nc) >= 1){
diff --git a/src/info/main.c b/src/info/main.c
index ff87220890..67eeab89c4 100644
--- a/src/info/main.c
+++ b/src/info/main.c
@@ -92,7 +92,7 @@ braille_viz(struct ncplane* n, wchar_t l, const wchar_t* egcs, wchar_t r,
 
 static void
 finish_line(struct ncplane* n){
-  int x;
+  unsigned x;
   ncplane_cursor_yx(n, NULL, &x);
   while(x++ < 80){
     ncplane_putchar(n, ' ');
@@ -147,7 +147,7 @@ emoji_viz(struct ncplane* n){
       }
     }
   }
-  int x;
+  unsigned x;
   ncplane_cursor_yx(n, NULL, &x);
   while(x++ < 80){
     ncplane_putchar(n, ' ');
@@ -312,14 +312,14 @@ unicodedumper(struct ncplane* n, const char* indent){
       ncplane_putchar(n, '\n');
     }
     emoji_viz(n);
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n, &y, &x);
     uint64_t ur = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x1B, 0xd8, 0x8E);
     uint64_t lr = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0xdB, 0x18, 0x8E);
     uint64_t ul = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x19, 0x19, 0x70);
     uint64_t ll = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x19, 0x19, 0x70);
     ncplane_cursor_move_yx(n, y - 15, 0);
-    ncplane_stain(n, y - 1, 79, ul, ur, ll, lr);
+    ncplane_stain(n, -1, -1, 15, 80, ul, ur, ll, lr);
     ncplane_set_styles(n, NCSTYLE_BOLD | NCSTYLE_ITALIC);
     ncplane_cursor_move_yx(n, y - 12, 54);
     wviz(n, L"🯁🯂🯃https://notcurses.com");
@@ -330,7 +330,7 @@ unicodedumper(struct ncplane* n, const char* indent){
 
 static int
 display_logo(struct ncplane* n, const char* path){
-  int cpixy, cpixx;
+  unsigned cpixy, cpixx;
   ncplane_pixelgeom(n, NULL, NULL, &cpixy, &cpixx, NULL, NULL);
   struct ncvisual* ncv = ncvisual_from_file(path);
   if(ncv == NULL){
@@ -340,7 +340,7 @@ display_logo(struct ncplane* n, const char* path){
     ncvisual_destroy(ncv);
     return -1;
   }
-  int y;
+  unsigned y;
   ncplane_cursor_yx(n, &y, NULL);
   struct ncvisual_options vopts = {
     .n = n,
@@ -480,7 +480,7 @@ int main(int argc, const char** argv){
   // so that we know whether we're talking to gpm
   notcurses_mice_enable(nc, NCMICE_ALL_EVENTS);
   const char indent[] = "";
-  int dimx;
+  unsigned dimx;
   struct ncplane* stdn = notcurses_stddim_yx(nc, NULL, &dimx);
   if(dimx < 80){
     ncplane_set_fg_rgb(stdn, 0xff5349);
diff --git a/src/input/input.cpp b/src/input/input.cpp
index c45b14ab0b..1d252ba7cd 100644
--- a/src/input/input.cpp
+++ b/src/input/input.cpp
@@ -26,8 +26,8 @@ using namespace ncpp;
 
 std::mutex mtx;
 uint64_t start;
-static int dimy, dimx;
 std::atomic<bool> done;
+static unsigned dimy, dimx;
 static struct ncuplot* plot;
 
 // return the string version of a special composed key
@@ -185,10 +185,9 @@ char32_t printutf8(char32_t kp){
 // older text, and thus clearly indicate the current output.
 static bool
 dim_rows(const Plane* n){
-  int y, x;
   Cell c;
-  for(y = 0 ; y < dimy ; ++y){
-    for(x = 0 ; x < dimx ; ++x){
+  for(unsigned y = 0 ; y < dimy ; ++y){
+    for(unsigned x = 0 ; x < dimx ; ++x){
       if(n->get_at(y, x, &c) < 0){
         n->release(c);
         return false;
@@ -255,10 +254,10 @@ int input_demo(ncpp::NotCurses* nc) {
   constexpr auto PLOTWIDTH = 56;
   auto n = nc->get_stdplane(&dimy, &dimx);
   // FIXME no ncpp wrapper for Plane::pixelgeom?
-  int celldimx, maxbmapx;
+  unsigned celldimx, maxbmapx;
   ncplane_pixelgeom(*n, nullptr, nullptr, nullptr, &celldimx, nullptr, &maxbmapx);
   struct ncplane_options nopts = {
-    .y = dimy - PLOTHEIGHT - 1,
+    .y = static_cast<int>(dimy) - PLOTHEIGHT - 1,
     .x = NCALIGN_CENTER,
     .rows = PLOTHEIGHT,
     .cols = PLOTWIDTH,
@@ -297,7 +296,7 @@ int input_demo(ncpp::NotCurses* nc) {
     ncuplot_destroy(plot);
     return -1;
   }
-  int y = 0;
+  unsigned y = 0;
   std::deque<wchar_t> cells;
   char32_t r;
   done = false;
@@ -350,9 +349,9 @@ int input_demo(ncpp::NotCurses* nc) {
         n->printf("Unicode: [0x%08x] '%lc'", r, (wchar_t)r);
       }
     }
-    int x;
+    unsigned x;
     n->get_cursor_yx(nullptr, &x);
-    for(int i = x ; i < n->get_dim_x() ; ++i){
+    for(unsigned i = x ; i < n->get_dim_x() ; ++i){
       n->putc(' ');
     }
     if(!dim_rows(n)){
diff --git a/src/lib/blit.c b/src/lib/blit.c
index 208189f55b..e19b790f8c 100644
--- a/src/lib/blit.c
+++ b/src/lib/blit.c
@@ -67,24 +67,18 @@ tria_blit_ascii(ncplane* nc, int linesize, const void* data,
                 int leny, int lenx, const blitterargs* bargs){
 //fprintf(stderr, "ASCII %d X %d @ %d X %d (%p) place: %d X %d\n", leny, lenx, bargs->begy, bargs->begx, data, bargs->u.cell.placey, bargs->u.cell.placex);
   const bool blendcolors = bargs->flags & NCVISUAL_OPTION_BLEND;
-  int dimy, dimx, x, y;
+  unsigned dimy, dimx, x, y;
   int total = 0; // number of cells written
   ncplane_dim_yx(nc, &dimy, &dimx);
   // FIXME not going to necessarily be safe on all architectures hrmmm
   const unsigned char* dat = data;
   int visy = bargs->begy;
   for(y = bargs->u.cell.placey ; visy < (bargs->begy + leny) && y < dimy ; ++y, ++visy){
-    if(y < 0){
-      continue;
-    }
     if(ncplane_cursor_move_yx(nc, y, bargs->u.cell.placex < 0 ? 0 : bargs->u.cell.placex)){
       return -1;
     }
     int visx = bargs->begx;
     for(x = bargs->u.cell.placex ; visx < (bargs->begx + lenx) && x < dimx ; ++x, ++visx){
-      if(x < 0){
-        continue;
-      }
       const unsigned char* rgbbase_up = dat + (linesize * visy) + (visx * 4);
 //fprintf(stderr, "[%04d/%04d] lsize: %d %02x %02x %02x %02x\n", y, x, linesize, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2], rgbbase_up[3]);
       nccell* c = ncplane_cell_ref_yx(nc, y, x);
@@ -122,24 +116,18 @@ tria_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
   const bool blendcolors = bargs->flags & NCVISUAL_OPTION_BLEND;
 //fprintf(stderr, "HALF %d X %d @ %d X %d (%p) place: %d X %d\n", leny, lenx, bargs->begy, bargs->begx, data, bargs->u.cell.placey, bargs->u.cell.placex);
   uint32_t transcolor = bargs->transcolor;
-  int dimy, dimx, x, y;
+  unsigned dimy, dimx, x, y;
   int total = 0; // number of cells written
   ncplane_dim_yx(nc, &dimy, &dimx);
   // FIXME not going to necessarily be safe on all architectures hrmmm
   const unsigned char* dat = data;
   int visy = bargs->begy;
   for(y = bargs->u.cell.placey ; visy < (bargs->begy + leny) && y < dimy ; ++y, visy += 2){
-    if(y < 0){
-      continue;
-    }
     if(ncplane_cursor_move_yx(nc, y, bargs->u.cell.placex < 0 ? 0 : bargs->u.cell.placex)){
       return -1;
     }
     int visx = bargs->begx;
     for(x = bargs->u.cell.placex ; visx < (bargs->begx + lenx) && x < dimx ; ++x, ++visx){
-      if(x < 0){
-        continue;
-      }
       const unsigned char* rgbbase_up = dat + (linesize * visy) + (visx * 4);
       const unsigned char* rgbbase_down = zeroes;
       if(visy < bargs->begy + leny - 1){
@@ -453,7 +441,7 @@ quadrant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
               const blitterargs* bargs){
   const unsigned nointerpolate = bargs->flags & NCVISUAL_OPTION_NOINTERPOLATE;
   const bool blendcolors = bargs->flags & NCVISUAL_OPTION_BLEND;
-  int dimy, dimx, x, y;
+  unsigned dimy, dimx, x, y;
   int total = 0; // number of cells written
   ncplane_dim_yx(nc, &dimy, &dimx);
 //fprintf(stderr, "quadblitter %dx%d -> %d/%d+%d/%d\n", leny, lenx, dimy, dimx, bargs->u.cell.placey, bargs->u.cell.placex);
@@ -461,17 +449,11 @@ quadrant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
   const unsigned char* dat = data;
   int visy = bargs->begy;
   for(y = bargs->u.cell.placey ; visy < (bargs->begy + leny) && y < dimy ; ++y, visy += 2){
-    if(y < 0){
-      continue;
-    }
     if(ncplane_cursor_move_yx(nc, y, bargs->u.cell.placex < 0 ? 0 : bargs->u.cell.placex)){
       return -1;
     }
     int visx = bargs->begx;
     for(x = bargs->u.cell.placex ; visx < (bargs->begx + lenx) && x < dimx ; ++x, visx += 2){
-      if(x < 0){
-        continue;
-      }
       const unsigned char* rgbbase_tl = dat + (linesize * visy) + (visx * 4);
       const unsigned char* rgbbase_tr = zeroes;
       const unsigned char* rgbbase_bl = zeroes;
@@ -674,24 +656,18 @@ sextant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
              const blitterargs* bargs){
   const unsigned nointerpolate = bargs->flags & NCVISUAL_OPTION_NOINTERPOLATE;
   const bool blendcolors = bargs->flags & NCVISUAL_OPTION_BLEND;
-  int dimy, dimx, x, y;
+  unsigned dimy, dimx, x, y;
   int total = 0; // number of cells written
   ncplane_dim_yx(nc, &dimy, &dimx);
 //fprintf(stderr, "sexblitter %dx%d -> %d/%d+%d/%d\n", leny, lenx, dimy, dimx, bargs->u.cell.placey, bargs->u.cell.placex);
   const unsigned char* dat = data;
   int visy = bargs->begy;
   for(y = bargs->u.cell.placey ; visy < (bargs->begy + leny) && y < dimy ; ++y, visy += 3){
-    if(y < 0){
-      continue;
-    }
     if(ncplane_cursor_move_yx(nc, y, bargs->u.cell.placex < 0 ? 0 : bargs->u.cell.placex)){
       return -1;
     }
     int visx = bargs->begx;
     for(x = bargs->u.cell.placex ; visx < (bargs->begx + lenx) && x < dimx ; ++x, visx += 2){
-      if(x < 0){
-        continue;
-      }
       uint32_t rgbas[6] = { 0, 0, 0, 0, 0, 0 };
       memcpy(&rgbas[0], (dat + (linesize * visy) + (visx * 4)), sizeof(*rgbas));
       if(visx < bargs->begx + lenx - 1){
@@ -748,24 +724,18 @@ static inline int
 braille_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
              const blitterargs* bargs){
   const bool blendcolors = bargs->flags & NCVISUAL_OPTION_BLEND;
-  int dimy, dimx, x, y;
+  unsigned dimy, dimx, x, y;
   int total = 0; // number of cells written
   ncplane_dim_yx(nc, &dimy, &dimx);
   // FIXME not going to necessarily be safe on all architectures hrmmm
   const unsigned char* dat = data;
   int visy = bargs->begy;
   for(y = bargs->u.cell.placey ; visy < (bargs->begy + leny) && y < dimy ; ++y, visy += 4){
-    if(y < 0){
-      continue;
-    }
     if(ncplane_cursor_move_yx(nc, y, bargs->u.cell.placex < 0 ? 0 : bargs->u.cell.placex)){
       return -1;
     }
     int visx = bargs->begx;
     for(x = bargs->u.cell.placex ; visx < (bargs->begx + lenx) && x < dimx ; ++x, visx += 2){
-      if(x < 0){
-        continue;
-      }
       const uint32_t* rgbbase_l0 = (const uint32_t*)(dat + (linesize * visy) + (visx * 4));
       const uint32_t* rgbbase_r0 = &zeroes32;
       const uint32_t* rgbbase_l1 = &zeroes32;
diff --git a/src/lib/direct.c b/src/lib/direct.c
index 6e322b8bde..4dd94d13ac 100644
--- a/src/lib/direct.c
+++ b/src/lib/direct.c
@@ -144,8 +144,8 @@ int ncdirect_clear(ncdirect* nc){
   return -1;
 }
 
-int ncdirect_dim_x(ncdirect* nc){
-  int x;
+unsigned ncdirect_dim_x(ncdirect* nc){
+  unsigned x;
   if(nc->tcache.ttyfd >= 0){
     if(update_term_dimensions(NULL, &x, &nc->tcache, 0) == 0){
       return x;
@@ -153,11 +153,11 @@ int ncdirect_dim_x(ncdirect* nc){
   }else{
     return 80; // lol
   }
-  return -1;
+  return 0;
 }
 
-int ncdirect_dim_y(ncdirect* nc){
-  int y;
+unsigned ncdirect_dim_y(ncdirect* nc){
+  unsigned y;
   if(nc->tcache.ttyfd >= 0){
     if(update_term_dimensions(&y, NULL, &nc->tcache, 0) == 0){
       return y;
@@ -165,7 +165,7 @@ int ncdirect_dim_y(ncdirect* nc){
   }else{
     return 24; // lol
   }
-  return -1;
+  return 0;
 }
 
 int ncdirect_cursor_enable(ncdirect* nc){
@@ -185,12 +185,12 @@ int ncdirect_cursor_disable(ncdirect* nc){
 }
 
 static int
-cursor_yx_get(ncdirect* n, const char* u7, int* y, int* x){
+cursor_yx_get(ncdirect* n, const char* u7, unsigned* y, unsigned* x){
   struct inputctx* ictx = n->tcache.ictx;
   if(ncdirect_flush(n)){
     return -1;
   }
-  int fakey, fakex;
+  unsigned fakey, fakex;
   if(y == NULL){
     y = &fakey;
   }
@@ -198,7 +198,7 @@ cursor_yx_get(ncdirect* n, const char* u7, int* y, int* x){
     x = &fakex;
   }
   get_cursor_location(ictx, u7, y, x);
-  loginfo("cursor at y=%d x=%d\n", *y, *x);
+  loginfo("cursor at y=%u x=%u\n", *y, *x);
   return 0;
 }
 
@@ -215,9 +215,11 @@ int ncdirect_cursor_move_yx(ncdirect* n, int y, int x){
     if(hpa){
       return term_emit(tiparm(hpa, x), n->ttyfp, false);
     }else if(n->tcache.ttyfd >= 0 && u7){
-      if(cursor_yx_get(n, u7, &y, NULL)){
+      unsigned yprime;
+      if(cursor_yx_get(n, u7, &yprime, NULL)){
         return -1;
       }
+      y = yprime;
     }else{
       y = 0;
     }
@@ -225,9 +227,11 @@ int ncdirect_cursor_move_yx(ncdirect* n, int y, int x){
     if(!vpa){
       return term_emit(tiparm(vpa, y), n->ttyfp, false);
     }else if(n->tcache.ttyfd >= 0 && u7){
-      if(cursor_yx_get(n, u7, NULL, &x)){
+      unsigned xprime;
+      if(cursor_yx_get(n, u7, NULL, &xprime)){
         return -1;
       }
+      x = xprime;
     }else{
       x = 0;
     }
@@ -362,7 +366,7 @@ detect_cursor_inversion_wrapper(ncdirect* n, const char* u7, int* y, int* x){
 
 // no terminfo capability for this. dangerous--it involves writing controls to
 // the terminal, and then reading a response.
-int ncdirect_cursor_yx(ncdirect* n, int* y, int* x){
+int ncdirect_cursor_yx(ncdirect* n, unsigned* y, unsigned* x){
   // this is only meaningful for real terminals
   if(n->tcache.ttyfd < 0){
     return -1;
@@ -372,7 +376,7 @@ int ncdirect_cursor_yx(ncdirect* n, int* y, int* x){
     fprintf(stderr, "Terminal doesn't support cursor reporting\n");
     return -1;
   }
-  int yval, xval;
+  unsigned yval, xval;
   if(!y){
     y = &yval;
   }
@@ -417,10 +421,10 @@ ncdirect_align(struct ncdirect* n, ncalign_e align, int c){
 
 // y is an out-only param, indicating the location where drawing started
 static int
-ncdirect_dump_sprixel(ncdirect* n, const ncplane* np, int xoff, int* y, fbuf* f){
-  int dimy, dimx;
+ncdirect_dump_sprixel(ncdirect* n, const ncplane* np, int xoff, unsigned* y, fbuf* f){
+  unsigned dimy, dimx;
   ncplane_dim_yx(np, &dimy, &dimx);
-  const int toty = ncdirect_dim_y(n);
+  const unsigned toty = ncdirect_dim_y(n);
   // flush our FILE*, as we're about to use UNIX I/O (since we can't rely on
   // stdio to transfer large amounts at once).
   if(ncdirect_flush(n)){
@@ -431,9 +435,10 @@ ncdirect_dump_sprixel(ncdirect* n, const ncplane* np, int xoff, int* y, fbuf* f)
   }
   if(toty - dimy < *y){
     int scrolls = *y - 1;
-    *y = toty - dimy;
-    if(*y < 0){
+    if(toty <= dimy){
       *y = 0;
+    }else{
+      *y = toty - dimy;
     }
     scrolls -= *y;
     // perform our scrolling outside of the fbuf framework, as we need it
@@ -504,16 +509,16 @@ ncdirect_set_fg_default_f(ncdirect* nc, fbuf* f){
 
 static int
 ncdirect_dump_cellplane(ncdirect* n, const ncplane* np, fbuf* f, int xoff){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(np, &dimy, &dimx);
-  const int toty = ncdirect_dim_y(n);
+  const unsigned toty = ncdirect_dim_y(n);
   // save the existing style and colors
   const bool fgdefault = ncdirect_fg_default_p(n);
   const bool bgdefault = ncdirect_bg_default_p(n);
   const uint32_t fgrgb = ncchannels_fg_rgb(n->channels);
   const uint32_t bgrgb = ncchannels_bg_rgb(n->channels);
-  for(int y = 0 ; y < dimy ; ++y){
-    for(int x = 0 ; x < dimx ; ++x){
+  for(unsigned y = 0 ; y < dimy ; ++y){
+    for(unsigned x = 0 ; x < dimx ; ++x){
       uint16_t stylemask;
       uint64_t channels;
       char* egc = ncplane_at_yx(np, y, x, &stylemask, &channels);
@@ -580,7 +585,7 @@ ncdirect_dump_plane(ncdirect* n, const ncplane* np, int xoff){
     return -1;
   }
   if(np->sprite){
-    int y;
+    unsigned y;
     if(ncdirect_dump_sprixel(n, np, xoff, &y, &f)){
       fbuf_free(&f);
       return -1;
@@ -628,10 +633,6 @@ ncdirect_render_visual(ncdirect* n, ncvisual* ncv,
   if(!vopts){
     vopts = &defvopts;
   }
-  if(vopts->leny < 0 || vopts->lenx < 0){
-    fprintf(stderr, "Invalid render geometry %d/%d\n", vopts->leny, vopts->lenx);
-    return NULL;
-  }
 //fprintf(stderr, "OUR DATA: %p rows/cols: %d/%d outsize: %d/%d %d/%d\n", ncv->data, ncv->pixy, ncv->pixx, dimy, dimx, ymax, xmax);
 //fprintf(stderr, "render %d/%d to scaling: %d\n", ncv->pixy, ncv->pixx, vopts->scaling);
   const struct blitset* bset = rgba_blitter_low(&n->tcache, vopts->scaling,
@@ -640,11 +641,11 @@ ncdirect_render_visual(ncdirect* n, ncvisual* ncv,
   if(!bset){
     return NULL;
   }
-  int ymax = vopts->leny / bset->height;
-  int xmax = vopts->lenx / bset->width;
+  unsigned ymax = vopts->leny / bset->height;
+  unsigned xmax = vopts->lenx / bset->width;
   unsigned dimy = vopts->leny > 0 ? ymax : ncdirect_dim_y(n);
   unsigned dimx = vopts->lenx > 0 ? xmax : ncdirect_dim_x(n);
-  int disprows, dispcols, outy;
+  unsigned disprows, dispcols, outy;
   if(vopts->scaling != NCSCALE_NONE && vopts->scaling != NCSCALE_NONE_HIRES){
     if(bset->geom != NCBLIT_PIXEL){
       dispcols = dimx * encoding_x_scale(&n->tcache, bset);
@@ -964,12 +965,12 @@ char* ncdirect_readline(ncdirect* n, const char* prompt){
   }
   int dimx = ncdirect_dim_x(n);
   // FIXME what if we're reading from redirected input, not a terminal?
-  int y, xstart;
+  unsigned y, xstart;
   if(cursor_yx_get(n, u7, &y, &xstart)){
     return NULL;
   }
   int tline = y;
-  int bline = y;
+  unsigned bline = y;
   wchar_t* str;
   int wspace = BUFSIZ / sizeof(*str);
   if((str = malloc(wspace * sizeof(*str))) == NULL){
@@ -980,7 +981,7 @@ char* ncdirect_readline(ncdirect* n, const char* prompt){
   str[wused++] = L'\0';
   ncinput ni;
   uint32_t id;
-  int oldx = xstart;
+  unsigned oldx = xstart;
   while((id = ncdirect_getc_blocking(n, &ni)) != (uint32_t)-1){
     if(ni.evtype == NCTYPE_RELEASE){
       continue;
@@ -1040,7 +1041,7 @@ char* ncdirect_readline(ncdirect* n, const char* prompt){
         str[wused - 1] = L'\0';
       }
       // FIXME check modifiers
-      int x;
+      unsigned x;
       if(cursor_yx_get(n, u7, &y, &x)){
         break;
       }
@@ -1521,7 +1522,7 @@ int ncdirect_stream(ncdirect* n, const char* filename, ncstreamcb streamer,
   }
   // starting position *after displaying one frame* so as to effect any
   // necessary scrolling.
-  int y = -1, x = -1;
+  unsigned y = 0, x = 0;
   int lastid = -1;
   int thisid = -1;
   do{
@@ -1587,7 +1588,8 @@ ncdirectv* ncdirectf_render(ncdirect* n, ncdirectf* frame, const struct ncvisual
 int ncdirectf_geom(ncdirect* n, ncdirectf* frame,
                    const struct ncvisual_options* vopts, ncvgeom* geom){
   const struct blitset* bset;
-  int disppxy, disppxx, outy, outx, placey, placex;
+  unsigned disppxy, disppxx, outy, outx;
+  int placey, placex;
   return ncvisual_geom_inner(&n->tcache, frame, vopts, geom, &bset,
                              &disppxy, &disppxx, &outy, &outx,
                              &placey, &placex);
diff --git a/src/lib/fade.c b/src/lib/fade.c
index 807178ccdf..9b0e5e83e1 100644
--- a/src/lib/fade.c
+++ b/src/lib/fade.c
@@ -3,8 +3,8 @@
 #include "internal.h"
 
 typedef struct ncfadectx {
-  int rows;                     // number of rows when allocated
-  int cols;                     // number of columns when allocated
+  unsigned rows;                // number of rows when allocated
+  unsigned cols;                // number of columns when allocated
   int maxsteps;                 // maximum number of iterations
   unsigned maxr, maxg, maxb;    // maxima across foreground channels
   unsigned maxbr, maxbg, maxbb; // maxima across background channels
@@ -32,9 +32,9 @@ alloc_ncplane_palette(ncplane* n, ncfadectx* pp, const struct timespec* ts){
   pp->maxbr = pp->maxbg = pp->maxbb = 0;
   unsigned r, g, b, br, bg, bb;
   uint64_t channels;
-  int y, x;
+  unsigned y;
   for(y = 0 ; y < pp->rows ; ++y){
-    for(x = 0 ; x < pp->cols ; ++x){
+    for(unsigned x = 0 ; x < pp->cols ; ++x){
       channels = n->fb[nfbcellidx(n, y, x)].channels;
       pp->channels[y * pp->cols + x] = channels;
       ncchannels_fg_rgb8(channels, &r, &g, &b);
@@ -108,13 +108,13 @@ alloc_ncplane_palette(ncplane* n, ncfadectx* pp, const struct timespec* ts){
 
 int ncplane_fadein_iteration(ncplane* n, ncfadectx* nctx, int iter,
                              fadecb fader, void* curry){
-  int y, x;
   // each time through, we need look each cell back up, due to the
   // possibility of a resize event :/
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
+  unsigned y;
   for(y = 0 ; y < nctx->rows && y < dimy ; ++y){
-    for(x = 0 ; x < nctx->cols && x < dimx; ++x){
+    for(unsigned x = 0 ; x < nctx->cols && x < dimx; ++x){
       unsigned r, g, b;
       ncchannels_fg_rgb8(nctx->channels[nctx->cols * y + x], &r, &g, &b);
       unsigned br, bg, bb;
@@ -175,13 +175,13 @@ int ncplane_fadeout_iteration(ncplane* n, ncfadectx* nctx, int iter,
                               fadecb fader, void* curry){
   unsigned br, bg, bb;
   unsigned r, g, b;
-  int y, x;
   // each time through, we need look each cell back up, due to the
   // possibility of a resize event :/
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
+  unsigned y;
   for(y = 0 ; y < nctx->rows && y < dimy ; ++y){
-    for(x = 0 ; x < nctx->cols && x < dimx; ++x){
+    for(unsigned x = 0 ; x < nctx->cols && x < dimx; ++x){
       nccell* c = &n->fb[dimx * y + x];
       if(!nccell_fg_default_p(c)){
         ncchannels_fg_rgb8(nctx->channels[nctx->cols * y + x], &r, &g, &b);
diff --git a/src/lib/fill.c b/src/lib/fill.c
index c18b99c301..a07a18ec70 100644
--- a/src/lib/fill.c
+++ b/src/lib/fill.c
@@ -1,8 +1,8 @@
 #include "internal.h"
 
 void ncplane_greyscale(ncplane *n){
-  for(int y = 0 ; y < n->leny ; ++y){
-    for(int x = 0 ; x < n->lenx ; ++x){
+  for(unsigned y = 0 ; y < n->leny ; ++y){
+    for(unsigned x = 0 ; x < n->lenx ; ++x){
       nccell* c = &n->fb[nfbcellidx(n, y, x)];
       unsigned r, g, b;
       nccell_fg_rgb8(c, &r, &g, &b);
@@ -20,69 +20,89 @@ void ncplane_greyscale(ncplane *n){
 // success. so a return of 0 means there's no work to be done here, and N means
 // we did some work here, filling everything we could reach. out-of-plane is 0.
 static int
-ncplane_polyfill_recurse(ncplane* n, int y, int x, const nccell* c, const char* filltarg){
-  if(y >= n->leny || x >= n->lenx){
-    return 0; // not fillable
-  }
-  if(y < 0 || x < 0){
-    return 0; // not fillable
-  }
-  nccell* cur = &n->fb[nfbcellidx(n, y, x)];
-  const char* glust = nccell_extended_gcluster(n, cur);
-//fprintf(stderr, "checking %d/%d (%s) for [%s]\n", y, x, glust, filltarg);
-  if(strcmp(glust, filltarg)){
-    return 0;
-  }
-  if(nccell_duplicate(n, cur, c) < 0){
+ncplane_polyfill_inner(ncplane* n, unsigned y, unsigned x, const nccell* c, const char* filltarg){
+  struct topolyfill* stack = NULL;
+  if(create_polyfill_op(y, x, &stack) == NULL){
     return -1;
   }
-  int r, ret = 1;
+  int ret = 0;
+  do{
+    struct topolyfill* s = stack;
+    stack = stack->next;
+    y = s->y;
+    x = s->x;
+    nccell* cur = &n->fb[nfbcellidx(n, y, x)];
+    const char* glust = nccell_extended_gcluster(n, cur);
+//fprintf(stderr, "checking %d/%d (%s) for [%s]\n", y, x, glust, filltarg);
+    if(strcmp(glust, filltarg) == 0){
+      ++ret;
+      if(nccell_duplicate(n, cur, c) < 0){
+        // FIXME need free stack!
+        return -1;
+      }
 //fprintf(stderr, "blooming from %d/%d ret: %d\n", y, x, ret);
-  if((r = ncplane_polyfill_recurse(n, y - 1, x, c, filltarg)) < 0){
-    return -1;
+      if(y){
+        if(create_polyfill_op(y - 1, x, &stack) == NULL){
+          return -1;
+        }
+      }
+      if(y + 1 < n->leny){
+        if(create_polyfill_op(y + 1, x, &stack) == NULL){
+          return -1;
+        }
+      }
+      if(x){
+        if(create_polyfill_op(y, x - 1, &stack) == NULL){
+          return -1;
+        }
+      }
+      if(x + 1 < n->lenx){
+        if(create_polyfill_op(y, x + 1, &stack) == NULL){
+          return -1;
+        }
+      }
+    }
+    free(s);
+  }while(stack);
+  return ret;
+}
+
+// at the initial step only, invalid ystart, xstart is an error, so explicitly check.
+int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){
+  if(ystart < 0){
+    if(ystart != -1){
+      logerror("invalid y: %d\n", ystart);
+      return -1;
+    }
+    ystart = n->y;
   }
-  ret += r;
-  if((r = ncplane_polyfill_recurse(n, y + 1, x, c, filltarg)) < 0){
-    return -1;
+  unsigned y = ystart;
+  if(xstart < 0){
+    if(xstart != -1){
+      logerror("invalid x: %d\n", xstart);
+      return -1;
+    }
+    xstart = n->x;
   }
-  ret += r;
-  if((r = ncplane_polyfill_recurse(n, y, x - 1, c, filltarg)) < 0){
+  unsigned x = xstart;
+  if(y >= n->leny || x >= n->lenx){
+    logerror("invalid start: %u/%u (%u/%u)\n", y, x, n->leny, n->lenx);
     return -1;
   }
-  ret += r;
-  if((r = ncplane_polyfill_recurse(n, y, x + 1, c, filltarg)) < 0){
-    return -1;
+  const nccell* cur = &n->fb[nfbcellidx(n, y, x)];
+  const char* targ = nccell_extended_gcluster(n, cur);
+  const char* fillegc = nccell_extended_gcluster(n, c);
+//fprintf(stderr, "checking %d/%d (%s) for [%s]\n", y, x, targ, fillegc);
+  if(strcmp(fillegc, targ) == 0){
+    return 0;
   }
-  ret += r;
-  return ret;
-}
-
-// at the initial step only, invalid y, x is an error, so explicitly check.
-int ncplane_polyfill_yx(ncplane* n, int y, int x, const nccell* c){
   int ret = -1;
-  if(y < n->leny && x < n->lenx){
-    if(y >= 0 && x >= 0){
-      if(y >= n->leny || x >= n->lenx){
-        return -1; // not fillable
-      }
-      if(y < 0 || x < 0){
-        return -1; // not fillable
-      }
-      const nccell* cur = &n->fb[nfbcellidx(n, y, x)];
-      const char* targ = nccell_extended_gcluster(n, cur);
-      const char* fillegc = nccell_extended_gcluster(n, c);
-//fprintf(stderr, "checking %d/%d (%s) for [%s]\n", y, x, targ, fillegc);
-      if(strcmp(fillegc, targ) == 0){
-        return 0;
-      }
-      // we need an external copy of this, since we'll be writing to it on
-      // the first call into ncplane_polyfill_recurse()
-      char* targcopy = strdup(targ);
-      if(targcopy){
-        ret = ncplane_polyfill_recurse(n, y, x, c, targcopy);
-        free(targcopy);
-      }
-    }
+  // we need an external copy of this, since we'll be writing to it on
+  // the first call into ncplane_polyfill_inner()
+  char* targcopy = strdup(targ);
+  if(targcopy){
+    ret = ncplane_polyfill_inner(n, y, x, c, targcopy);
+    free(targcopy);
   }
   return ret;
 }
@@ -93,16 +113,19 @@ check_gradient_channel_args(uint32_t ul, uint32_t ur, uint32_t bl, uint32_t br){
      ncchannel_default_p(bl) || ncchannel_default_p(br)){
     if(!(ncchannel_default_p(ul) && ncchannel_default_p(ur) &&
          ncchannel_default_p(bl) && ncchannel_default_p(br))){
+      logerror("some (not all) channels were defaults\n");
       return true;
     }
   }
   if(ncchannel_alpha(ul) != ncchannel_alpha(ur) ||
      ncchannel_alpha(ur) != ncchannel_alpha(bl) ||
      ncchannel_alpha(bl) != ncchannel_alpha(br)){
+    logerror("channel alphas didn't match\n");
     return true;
   }
   if(ncchannel_palindex_p(ul) || ncchannel_palindex_p(bl) ||
      ncchannel_palindex_p(br) || ncchannel_palindex_p(ur)){
+    logerror("can't blend palette-indexed color\n");
     return true;
   }
   return false;
@@ -131,7 +154,8 @@ bool check_gradient_args(uint64_t ul, uint64_t ur, uint64_t bl, uint64_t br){
 // we're using double halfblocks, into `c`->channels.
 static inline void
 calc_highgradient(nccell* c, uint32_t ul, uint32_t ur, uint32_t ll,
-                  uint32_t lr, int y, int x, int ylen, int xlen){
+                  uint32_t lr, unsigned y, unsigned x,
+                  unsigned ylen, unsigned xlen){
   if(!ncchannel_default_p(ul)){
     cell_set_fchannel(c, calc_gradient_channel(ul, ur, ll, lr,
                                                y * 2, x, ylen, xlen));
@@ -143,159 +167,116 @@ calc_highgradient(nccell* c, uint32_t ul, uint32_t ur, uint32_t ll,
   }
 }
 
-int ncplane_highgradient(ncplane* n, uint32_t ul, uint32_t ur,
-                         uint32_t ll, uint32_t lr, int ystop, int xstop){
+int ncplane_gradient2x1(ncplane* n, int y, int x, unsigned ylen, unsigned xlen,
+                        uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr){
   if(!notcurses_canutf8(ncplane_notcurses(n))){
-    logerror("Highdef gradients require UTF8\n");
+    logerror("highdef gradients require utf8\n");
     return -1;
   }
   if(check_gradient_channel_args(ul, ur, ll, lr)){
-    logerror("Invalid highdef gradient channels\n");
-    return -1;
-  }
-  int yoff, xoff, ymax, xmax;
-  ncplane_cursor_yx(n, &yoff, &xoff);
-  // must be at least 1x1, with its upper-left corner at the current cursor
-  if(ystop < yoff){
     return -1;
   }
-  if(xstop < xoff){
+  unsigned ystart, xstart;
+  if(check_geometry_args(n, y, x, &ylen, &xlen, &ystart, &xstart)){
     return -1;
   }
-  ncplane_dim_yx(n, &ymax, &xmax);
-  // must be within the ncplane
-  if(xstop >= xmax || ystop >= ymax){
-    return -1;
-  }
-  const int xlen = xstop - xoff + 1;
-  const int ylen = (ystop - yoff + 1) * 2;
   if(xlen == 1){
     if(ul != ur || ll != lr){
+      logerror("horizontal channel variation in single column\n");
       return -1;
     }
   }
   int total = 0;
-  for(int y = yoff ; y <= ystop ; ++y){
-    for(int x = xoff ; x <= xstop ; ++x){
-      nccell* targc = ncplane_cell_ref_yx(n, y, x);
+  for(unsigned yy = ystart ; yy < ystart + ylen ; ++yy){
+    for(unsigned xx = xstart ; xx < xstart + xlen ; ++xx){
+      nccell* targc = ncplane_cell_ref_yx(n, yy, xx);
       targc->channels = 0;
       if(pool_blit_direct(&n->pool, targc, "▀", strlen("▀"), 1) <= 0){
         return -1;
       }
-      calc_highgradient(targc, ul, ur, ll, lr, y - yoff, x - xoff, ylen, xlen);
+      calc_highgradient(targc, ul, ur, ll, lr, yy - ystart, xx - xstart, ylen * 2, xlen);
       ++total;
     }
   }
   return total;
 }
 
+// FIXME remove in abi3
 int ncplane_highgradient_sized(ncplane* n, uint32_t ul, uint32_t ur,
                                uint32_t ll, uint32_t lr, int ylen, int xlen){
   if(ylen < 1 || xlen < 1){
     return -1;
   }
-  int y, x;
   if(!notcurses_canutf8(ncplane_notcurses_const(n))){
     // this works because the uin32_ts we pass in will be promoted to uint64_ts
     // via extension, and the space will employ the background. mwahh!
-    return ncplane_gradient_sized(n, " ", 0, ul, ur, ll, lr, ylen, xlen);
+    return ncplane_gradient(n, -1, -1, ylen, xlen, " ", 0, ul, ur, ll, lr);
   }
-  ncplane_cursor_yx(n, &y, &x);
-  return ncplane_highgradient(n, ul, ur, ll, lr, y + ylen - 1, x + xlen - 1);
+  return ncplane_gradient2x1(n, -1, -1, ylen, xlen, ul, ur, ll, lr);
 }
 
-int ncplane_gradient(ncplane* n, const char* egc, uint32_t stylemask,
-                     uint64_t ul, uint64_t ur, uint64_t bl, uint64_t br,
-                     int ystop, int xstop){
+int ncplane_gradient(ncplane* n, int y, int x, unsigned ylen, unsigned xlen,
+                     const char* egc, uint16_t stylemask,
+                     uint64_t ul, uint64_t ur, uint64_t bl, uint64_t br){
   if(check_gradient_args(ul, ur, bl, br)){
-    logerror("Illegal gradient inputs\n");
-    return -1;
-  }
-  if(egc == NULL){
-    return -1;
-  }
-  int yoff, xoff, ymax, xmax;
-  ncplane_cursor_yx(n, &yoff, &xoff);
-  // must be at least 1x1, with its upper-left corner at the current cursor
-  if(ystop < yoff){
-    logerror("Ystop %d < yoff %d\n", ystop, yoff);
-    return -1;
-  }
-  if(xstop < xoff){
-    logerror("Xstop %d < xoff %d\n", xstop, xoff);
     return -1;
   }
-  ncplane_dim_yx(n, &ymax, &xmax);
-  // must be within the ncplane
-  if(xstop >= xmax || ystop >= ymax){
+  unsigned ystart, xstart;
+  if(check_geometry_args(n, y, x, &ylen, &xlen, &ystart, &xstart)){
     return -1;
   }
-  const int xlen = xstop - xoff + 1;
-  const int ylen = ystop - yoff + 1;
   if(ylen == 1){
     if(xlen == 1){
       if(ul != ur || ur != br || br != bl){
+        logerror("channel variation in 1x1 area\n");
         return -1;
       }
     }else{
       if(ul != bl || ur != br){
+        logerror("vertical channel variation in single row\n");
         return -1;
       }
     }
   }else if(xlen == 1){
     if(ul != ur || bl != br){
+      logerror("horizontal channel variation in single column\n");
       return -1;
     }
   }
   int total = 0;
-  for(int y = yoff ; y <= ystop ; ++y){
-    for(int x = xoff ; x <= xstop ; ++x){
-      nccell* targc = ncplane_cell_ref_yx(n, y, x);
+  for(unsigned yy = ystart ; yy < ystart + ylen ; ++yy){
+    for(unsigned xx = xstart ; xx < xstart + xlen ; ++xx){
+      nccell* targc = ncplane_cell_ref_yx(n, yy, xx);
       targc->channels = 0;
       if(nccell_load(n, targc, egc) < 0){
         return -1;
       }
       targc->stylemask = stylemask;
       calc_gradient_channels(&targc->channels, ul, ur, bl, br,
-                             y - yoff, x - xoff, ylen, xlen);
+                             yy - ystart, xx - xstart, ylen, xlen);
       ++total;
     }
   }
   return total;
 }
 
-int ncplane_stain(ncplane* n, int ystop, int xstop,
+int ncplane_stain(ncplane* n, int y, int x, unsigned ylen, unsigned xlen,
                   uint64_t tl, uint64_t tr, uint64_t bl, uint64_t br){
   // Can't use default or palette-indexed colors in a gradient
   if(check_gradient_args(tl, tr, bl, br)){
-    logerror("Illegal staining inputs\n");
     return -1;
   }
-  int yoff, xoff, ymax, xmax;
-  ncplane_cursor_yx(n, &yoff, &xoff);
-  // must be at least 1x1, with its upper-left corner at the current cursor
-  if(ystop < yoff){
-    logerror("Ystop %d < yoff %d\n", ystop, yoff);
+  unsigned ystart, xstart;
+  if(check_geometry_args(n, y, x, &ylen, &xlen, &ystart, &xstart)){
     return -1;
   }
-  if(xstop < xoff){
-    logerror("Xstop %d < xoff %d\n", xstop, xoff);
-    return -1;
-  }
-  ncplane_dim_yx(n, &ymax, &xmax);
-  // must be within the ncplane
-  if(xstop >= xmax || ystop >= ymax){
-    return -1;
-  }
-  const int xlen = xstop - xoff + 1;
-  const int ylen = ystop - yoff + 1;
   int total = 0;
-  for(int y = yoff ; y <= ystop ; ++y){
-    for(int x = xoff ; x <= xstop ; ++x){
-      nccell* targc = ncplane_cell_ref_yx(n, y, x);
+  for(unsigned yy = ystart ; yy < ystart + ylen ; ++yy){
+    for(unsigned xx = xstart ; xx < xstart + xlen ; ++xx){
+      nccell* targc = ncplane_cell_ref_yx(n, yy, xx);
       if(targc->gcluster){
         calc_gradient_channels(&targc->channels, tl, tr, bl, br,
-                               y - yoff, x - xoff, ylen, xlen);
+                               yy - ystart, xx - xstart, ylen, xlen);
       }
       ++total;
     }
@@ -303,25 +284,16 @@ int ncplane_stain(ncplane* n, int ystop, int xstop,
   return total;
 }
 
-int ncplane_format(ncplane* n, int ystop, int xstop, uint32_t stylemask){
-  int yoff, xoff, ymax, xmax;
-  ncplane_cursor_yx(n, &yoff, &xoff);
-  // must be at least 1x1, with its upper-left corner at the current cursor
-  if(ystop < yoff){
-    return -1;
-  }
-  if(xstop < xoff){
-    return -1;
-  }
-  ncplane_dim_yx(n, &ymax, &xmax);
-  // must be within the ncplane
-  if(xstop >= xmax || ystop >= ymax){
+int ncplane_format(ncplane* n, int y, int x, unsigned ylen,
+                   unsigned xlen, uint16_t stylemask){
+  unsigned ystart, xstart;
+  if(check_geometry_args(n, y, x, &ylen, &xlen, &ystart, &xstart)){
     return -1;
   }
   int total = 0;
-  for(int y = yoff ; y < ystop + 1 ; ++y){
-    for(int x = xoff ; x < xstop + 1 ; ++x){
-      nccell* targc = ncplane_cell_ref_yx(n, y, x);
+  for(unsigned yy = ystart ; yy < ystart + ylen ; ++yy){
+    for(unsigned xx = xstart ; xx < xstart + xlen ; ++xx){
+      nccell* targc = ncplane_cell_ref_yx(n, yy, xx);
       targc->stylemask = stylemask;
       ++total;
     }
@@ -459,12 +431,12 @@ rotate_2x1_ccw(ncplane* src, ncplane* dst, int srcy, int srcx, int dsty, int dst
 // copy 'newp' into 'n' after resizing 'n' to match 'newp'
 static int
 rotate_merge(ncplane* n, ncplane* newp){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(newp, &dimy, &dimx);
   int ret = ncplane_resize(n, 0, 0, 0, 0, 0, 0, dimy, dimx);
   if(ret == 0){
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         const nccell* src = &newp->fb[fbcellidx(y, dimx, x)];
         nccell* targ = &n->fb[fbcellidx(y, dimx, x)];
         if(cell_duplicate_far(&n->pool, targ, newp, src) < 0){
@@ -481,7 +453,7 @@ static ncplane*
 rotate_plane(ncplane* n){
   int absy, absx;
   ncplane_yx(n, &absy, &absx);
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   if(dimx % 2 != 0){
     return NULL;
@@ -505,7 +477,7 @@ int ncplane_rotate_cw(ncplane* n){
   if(newp == NULL){
     return -1;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   int centy, centx;
   ncplane_center_abs(n, &centy, &centx);
@@ -515,9 +487,9 @@ int ncplane_rotate_cw(ncplane* n){
   // the top two leftmost cells. work from the bottom up on the source, so we
   // can copy to the top row from the left to the right.
   int targx, targy = 0;
-  for(int x = 0 ; x < dimx ; x += 2){
+  for(unsigned x = 0 ; x < dimx ; x += 2){
     targx = 0;
-    for(int y = dimy - 1 ; y >= 0 ; --y){
+    for(int y = (int)dimy - 1 ; y >= 0 ; --y){
       if(rotate_2x1_cw(n, newp, y, x, targy, targx)){
         ncplane_destroy(newp);
         return -1;
@@ -536,15 +508,16 @@ int ncplane_rotate_ccw(ncplane* n){
   if(newp == NULL){
     return -1;
   }
-  int dimy, dimx, targdimy, targdimx;
+  unsigned dimy, dimx, targdimy, targdimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   ncplane_dim_yx(newp, &targdimy, &targdimx);
-  int x = dimx - 2, y;
+  int x = (int)dimx - 2;
+  int y;
   // Each row of the target plane is taken from a column of the source plane.
   // As the target row grows (down), the source column shrinks (moves left).
-  for(int targy = 0 ; targy < targdimy ; ++targy){
+  for(unsigned targy = 0 ; targy < targdimy ; ++targy){
     y = 0;
-    for(int targx = 0 ; targx < targdimx ; targx += 2){
+    for(unsigned targx = 0 ; targx < targdimx ; targx += 2){
       if(rotate_2x1_ccw(n, newp, y, x, targy, targx)){
         ncplane_destroy(newp);
         return -1;
@@ -563,17 +536,17 @@ int ncplane_rotate_ccw(ncplane* n){
 #define QR_BASE_SIZE 17
 #define PER_QR_VERSION 4
 
-static inline int
-qrcode_rows(int version){
+static inline unsigned
+qrcode_rows(unsigned version){
   return QR_BASE_SIZE + (version * PER_QR_VERSION);
 }
 
-static inline int
-qrcode_cols(int version){
+static inline unsigned
+qrcode_cols(unsigned version){
   return QR_BASE_SIZE + (version * PER_QR_VERSION);
 }
 
-int ncplane_qrcode(ncplane* n, int* ymax, int* xmax, const void* data, size_t len){
+int ncplane_qrcode(ncplane* n, unsigned* ymax, unsigned* xmax, const void* data, size_t len){
   const ncblitter_e blitfxn = NCBLIT_2x1;
   const int MAX_QR_VERSION = 40; // QR library only supports up to 40
   if(*ymax <= 0 || *xmax <= 0){
@@ -663,7 +636,7 @@ int ncplane_qrcode(ncplane* n, int* ymax, int* xmax, const void* data, size_t le
   return -1;
 }
 #else
-int ncplane_qrcode(ncplane* n, int* ymax, int* xmax, const void* data, size_t len){
+int ncplane_qrcode(ncplane* n, unsigned* ymax, unsigned* xmax, const void* data, size_t len){
   (void)n;
   (void)ymax;
   (void)xmax;
diff --git a/src/lib/in.c b/src/lib/in.c
index bdb7cf0929..25102cc7d2 100644
--- a/src/lib/in.c
+++ b/src/lib/in.c
@@ -2212,7 +2212,7 @@ uint32_t ncdirect_getc(ncdirect* nc, const struct timespec *ts,
   return ncdirect_get(nc, ts, ni);
 }
 
-int get_cursor_location(inputctx* ictx, const char* u7, int* y, int* x){
+int get_cursor_location(inputctx* ictx, const char* u7, unsigned* y, unsigned* x){
   pthread_mutex_lock(&ictx->clock);
   while(ictx->cvalid == 0){
     if(tty_emit(u7, ictx->ti->ttyfd)){
diff --git a/src/lib/in.h b/src/lib/in.h
index 91c3dff3b7..54b0a23aad 100644
--- a/src/lib/in.h
+++ b/src/lib/in.h
@@ -82,7 +82,7 @@ struct initial_responses {
 struct initial_responses* inputlayer_get_responses(struct inputctx* ictx)
   __attribute__ ((nonnull (1)));
 
-int get_cursor_location(struct inputctx* ictx, const char* u7, int* y, int* x)
+int get_cursor_location(struct inputctx* ictx, const char* u7, unsigned* y, unsigned* x)
   __attribute__ ((nonnull (1, 2)));
 
 #ifdef __cplusplus
diff --git a/src/lib/internal.h b/src/lib/internal.h
index 2b7a116078..4b98deb136 100644
--- a/src/lib/internal.h
+++ b/src/lib/internal.h
@@ -74,14 +74,14 @@ struct ncvisual_details;
 typedef struct ncplane {
   nccell* fb;            // "framebuffer" of character cells
   int logrow;            // logical top row, starts at 0, add one for each scroll
-  int x, y;              // current cursor location within this plane
+  unsigned x, y;         // current cursor location within this plane
   // ncplane_yx() etc. use coordinates relative to the plane to which this
   // plane is bound, but absx/absy are always relative to the terminal origin.
   // they must thus be translated by any function which moves a parent plane.
   int absx, absy;        // origin of the plane relative to the pile's origin
                          //  also used as left and top margin on resize by
                          //  ncplane_resize_marginalized()
-  int lenx, leny;        // size of the plane, [0..len{x,y}) is addressable
+  unsigned lenx, leny;   // size of the plane, [0..len{x,y}) is addressable
   egcpool pool;          // attached storage pool for UTF-8 EGCs
   uint64_t channels;     // works the same way as cells
 
@@ -294,7 +294,7 @@ typedef struct ncpile {
   struct notcurses* nc;       // notcurses context
   struct ncpile *prev, *next; // circular list
   size_t crenderlen;          // size of crender vector
-  int dimy, dimx;             // rows and cols at time of render
+  unsigned dimy, dimx;        // rows and cols at time of last render
   int scrolls;                // how many real lines need be scrolled at raster
   sprixel* sprixelcache;      // list of sprixels
 } ncpile;
@@ -317,8 +317,8 @@ typedef struct notcurses {
   ncpile* last_pile;
   egcpool pool;   // egcpool for lastframe
 
-  int lfdimx;     // dimensions of lastframe, unchanged by screen resize
-  int lfdimy;     // lfdimx/lfdimy are 0 until first rasterization
+  unsigned lfdimx; // dimensions of lastframe, unchanged by screen resize
+  unsigned lfdimy; // lfdimx/lfdimy are 0 until first rasterization
 
   int cursory;    // desired cursor placement according to user.
   int cursorx;    // -1 is don't-care, otherwise moved here after each render.
@@ -555,7 +555,7 @@ pool_extended_gcluster(const egcpool* pool, const nccell* c){
 }
 
 static inline nccell*
-ncplane_cell_ref_yx(const ncplane* n, int y, int x){
+ncplane_cell_ref_yx(const ncplane* n, unsigned y, unsigned x){
   return &n->fb[nfbcellidx(n, y, x)];
 }
 
@@ -568,12 +568,12 @@ cell_debug(const egcpool* p, const nccell* c){
 
 static inline void
 plane_debug(const ncplane* n, bool details){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   fprintf(stderr, "p: %p dim: %d/%d poolsize: %d\n", n, dimy, dimx, n->pool.poolsize);
   if(details){
-    for(int y = 0 ; y < 1 ; ++y){
-      for(int x = 0 ; x < 10 ; ++x){
+    for(unsigned y = 0 ; y < 1 ; ++y){
+      for(unsigned x = 0 ; x < 10 ; ++x){
         const nccell* c = &n->fb[fbcellidx(y, dimx, x)];
         fprintf(stderr, "[%03d/%03d] ", y, x);
         cell_debug(&n->pool, c);
@@ -764,7 +764,7 @@ sprite_rebuild(const notcurses* nc, sprixel* s, int ycell, int xcell){
 // happy fact: common reported values for maximum sixel height are 256, 1024,
 // and 4096...not a single goddamn one of which is divisible by six. augh.
 static inline void
-clamp_to_sixelmax(const tinfo* t, int* y, int* x, int* outy, ncscale_e scaling){
+clamp_to_sixelmax(const tinfo* t, unsigned* y, unsigned* x, unsigned* outy, ncscale_e scaling){
   if(t->sixel_maxy && *y > t->sixel_maxy){
     *y = t->sixel_maxy;
   }
@@ -822,9 +822,9 @@ sprixel_state(const sprixel* s, int y, int x){
   int localx = x - (s->n->absx - stdn->absx);
 //fprintf(stderr, "TAM %d at %d/%d (%d/%d, %d/%d)\n", s->n->tam[localy * s->dimx + localx].state, localy, localx, y, x, s->dimy, s->dimx);
   assert(localy >= 0);
-  assert(localy < s->dimy);
+  assert(localy < (int)s->dimy);
   assert(localx >= 0);
-  assert(localx < s->dimx);
+  assert(localx < (int)s->dimx);
   return s->n->tam[localy * s->dimx + localx].state;
 }
 
@@ -869,7 +869,7 @@ int ncplane_resize_internal(ncplane* n, int keepy, int keepx,
                             int yoff, int xoff,
                             unsigned ylen, unsigned xlen);
 
-int update_term_dimensions(int* rows, int* cols, tinfo* tcache, int margin_b);
+int update_term_dimensions(unsigned* rows, unsigned* cols, tinfo* tcache, int margin_b);
 
 ALLOC static inline void*
 memdup(const void* src, size_t len){
@@ -935,7 +935,7 @@ int ncvisual_bounding_box(const struct ncvisual* ncv, int* leny, int* lenx,
 //  steps / 2 is to work around truncate-towards-zero).
 static int
 calc_gradient_component(unsigned tl, unsigned tr, unsigned bl, unsigned br,
-                        int y, int x, int ylen, int xlen){
+                        unsigned y, unsigned x, unsigned ylen, unsigned xlen){
   const int avm = (ylen - 1) - y;
   const int ahm = (xlen - 1) - x;
   if(xlen < 2){
@@ -958,7 +958,7 @@ calc_gradient_component(unsigned tl, unsigned tr, unsigned bl, unsigned br,
 // calculate one of the channels of a gradient at a particular point.
 static inline uint32_t
 calc_gradient_channel(uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr,
-                      int y, int x, int ylen, int xlen){
+                      unsigned y, unsigned x, unsigned ylen, unsigned xlen){
   uint32_t chan = 0;
   ncchannel_set_rgb8_clipped(&chan,
                            calc_gradient_component(ncchannel_r(ul), ncchannel_r(ur),
@@ -978,8 +978,8 @@ calc_gradient_channel(uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr,
 // into `channels'. x and y ought be the location within the gradient.
 static inline void
 calc_gradient_channels(uint64_t* channels, uint64_t ul, uint64_t ur,
-                       uint64_t ll, uint64_t lr, int y, int x,
-                       int ylen, int xlen){
+                       uint64_t ll, uint64_t lr, unsigned y, unsigned x,
+                       unsigned ylen, unsigned xlen){
   if(!ncchannels_fg_default_p(ul)){
     ncchannels_set_fchannel(channels,
                             calc_gradient_channel(ncchannels_fchannel(ul),
@@ -1448,6 +1448,69 @@ int drop_signals(void* nc);
 int block_signals(sigset_t* old_blocked_signals);
 int unblock_signals(const sigset_t* old_blocked_signals);
 
+// takes a signed starting coordinate (where -1 indicates the cursor's
+// position), and an unsigned vector (where 0 indicates "everything
+// remaining", i.e. to the right and below). returns 0 iff everything
+// is valid and on the plane, filling in 'ystart'/'xstart' with the
+// (non-negative) starting coordinates and 'ylen'/'xlen with the
+// (positive) dimensions of the affected area.
+static inline int
+check_geometry_args(const ncplane* n, int y, int x,
+                    unsigned* ylen, unsigned* xlen,
+                    unsigned* ystart, unsigned* xstart){
+  // handle the special -1 case for y/x, and reject other negatives
+  if(y < 0){
+    if(y != -1){
+      logerror("invalid y: %d\n", y);
+      return -1;
+    }
+    y = n->y;
+  }
+  if(x < 0){
+    if(x != -1){
+      logerror("invalid x: %d\n", x);
+      return -1;
+    }
+    x = n->x;
+  }
+  // y and x are both now definitely positive, but might be off-plane.
+  // lock in y and x as ystart and xstart for unsigned comparisons.
+  *ystart = y;
+  *xstart = x;
+  unsigned ymax, xmax;
+  ncplane_dim_yx(n, &ymax, &xmax);
+  if(*ystart >= ymax || *xstart >= xmax){
+    logerror("invalid starting coordinates: %u/%u\n", *ystart, *xstart);
+    return -1;
+  }
+  // handle the special 0 case for ylen/xlen
+  if(*ylen == 0){
+    *ylen = ymax - *ystart;
+  }
+  if(*xlen == 0){
+    *xlen = xmax - *xstart;
+  }
+  // ensure ylen/xlen are on-plane
+  if(*ylen > ymax){
+    logerror("ylen > dimy %u > %u\n", *ylen, ymax);
+    return -1;
+  }
+  if(*xlen > xmax){
+    logerror("xlen > dimx %u > %u\n", *xlen, xmax);
+    return -1;
+  }
+  // ensure x + xlen and y + ylen are on-plane, without overflow
+  if(ymax - *ylen < *ystart){
+    logerror("y + ylen > ymax %u + %u > %u\n", *ystart, *ylen, ymax);
+    return -1;
+  }
+  if(xmax - *xlen < *xstart){
+    logerror("x + xlen > xmax %u + %u > %u\n", *xstart, *xlen, xmax);
+    return -1;
+  }
+  return 0;
+}
+
 void ncvisual_printbanner(fbuf* f);
 
 // alpha comes to us 0--255, but we have only 3 alpha values to map them to
@@ -1548,7 +1611,8 @@ rgba_blit_dispatch(ncplane* nc, const struct blitset* bset,
 int ncvisual_geom_inner(const tinfo* ti, const struct ncvisual* n,
                         const struct ncvisual_options* vopts, ncvgeom* geom,
                         const struct blitset** bset,
-                        int* disppxy, int* disppxx, int* outy, int* outx,
+                        unsigned* disppxy, unsigned* disppxx,
+                        unsigned* outy, unsigned* outx,
                         int* placey, int* placex);
 
 static inline const struct blitset*
@@ -1614,6 +1678,27 @@ resize_bitmap(const uint32_t* bmap, int srows, int scols, size_t sstride,
   return ret;
 }
 
+// a neighbor on which to polyfill. by the time we get to it, it might or
+// might not have been filled in. if so, discard immediately. otherwise,
+// check self, and if valid, push all neighbors.
+struct topolyfill {
+  int y, x;
+  struct topolyfill* next;
+};
+
+static inline struct topolyfill*
+create_polyfill_op(int y, int x, struct topolyfill** stck){
+  // cast for the benefit of c++ callers
+  struct topolyfill* n = (struct topolyfill*)malloc(sizeof(*n));
+  if(n){
+    n->y = y;
+    n->x = x;
+    n->next = *stck;
+    *stck = n;
+  }
+  return n;
+}
+
 // implemented by a multimedia backend (ffmpeg or oiio), and installed
 // prior to calling notcurses_core_init() (by notcurses_init()).
 typedef struct ncvisual_implementation {
diff --git a/src/lib/kitty.c b/src/lib/kitty.c
index 1c53b6c7be..20ce735540 100644
--- a/src/lib/kitty.c
+++ b/src/lib/kitty.c
@@ -718,10 +718,10 @@ destroy_deflator(unsigned animated, z_stream* zctx, int pixy, int pixx){
 static int
 finalize_multiframe_selfref(sprixel* s, fbuf* f){
   int prewiped = 0;
-  for(int y = 0 ; y < s->dimy ; ++y){
-    for(int x = 0 ; x < s->dimx ; ++x){
-      int tyxidx = y * s->dimx + x;
-      int state = s->n->tam[tyxidx].state;
+  for(unsigned y = 0 ; y < s->dimy ; ++y){
+    for(unsigned x = 0 ; x < s->dimx ; ++x){
+      unsigned tyxidx = y * s->dimx + x;
+      unsigned state = s->n->tam[tyxidx].state;
       if(state >= SPRIXCELL_ANNIHILATED){
         if(kitty_blit_wipe_selfref(s, f, y, x)){
           return -1;
@@ -730,7 +730,7 @@ finalize_multiframe_selfref(sprixel* s, fbuf* f){
       }
     }
   }
-  loginfo("transitively wiped %d/%d\n", prewiped, s->dimy * s->dimx);
+  loginfo("transitively wiped %d/%u\n", prewiped, s->dimy * s->dimx);
   return 0;
 }
 
@@ -1126,8 +1126,8 @@ int kitty_remove(int id, fbuf* f){
 // damages cells underneath the graphic which were OPAQUE
 int kitty_scrub(const ncpile* p, sprixel* s){
 //fprintf(stderr, "FROM: %d/%d state: %d s->n: %p\n", s->movedfromy, s->movedfromx, s->invalidated, s->n);
-  for(int yy = s->movedfromy ; yy < s->movedfromy + s->dimy && yy < p->dimy ; ++yy){
-    for(int xx = s->movedfromx ; xx < s->movedfromx + s->dimx && xx < p->dimx ; ++xx){
+  for(unsigned yy = s->movedfromy ; yy < s->movedfromy + s->dimy && yy < p->dimy ; ++yy){
+    for(unsigned xx = s->movedfromx ; xx < s->movedfromx + s->dimx && xx < p->dimx ; ++xx){
       const int ridx = yy * p->dimx + xx;
       assert(0 <= ridx);
       struct crender *r = &p->crender[ridx];
diff --git a/src/lib/layout.c b/src/lib/layout.c
index 8264f8fcbc..05a3920712 100644
--- a/src/lib/layout.c
+++ b/src/lib/layout.c
@@ -47,7 +47,7 @@ puttext_advance_line(ncplane* n){
 //      * C < dimx: ++y, x = 0
 static int
 puttext_line(ncplane* n, ncalign_e align, const char* text, size_t* bytes){
-  int cursx; // current cursor location
+  unsigned cursx; // current cursor location
   ncplane_cursor_yx(n, NULL, &cursx);
   const int dimx = ncplane_dim_x(n);
   const int avail = dimx - cursx - 1;
diff --git a/src/lib/menu.c b/src/lib/menu.c
index d2663d9da4..0f28f68a85 100644
--- a/src/lib/menu.c
+++ b/src/lib/menu.c
@@ -12,7 +12,7 @@ typedef struct ncmenu_int_item {
 
 typedef struct ncmenu_int_section {
   char* name;             // utf-8 c string
-  int itemcount;
+  unsigned itemcount;
   ncmenu_int_item* items; // items, NULL iff itemcount == 0
   ncinput shortcut;       // shortcut, will be underlined if present in name
   int xoff;               // column offset from beginning of menu bar
@@ -62,7 +62,7 @@ mbstr_find_codepoint(const char* s, uint32_t cp, int* col){
 
 static void
 free_menu_section(ncmenu_int_section* ms){
-  for(int i = 0 ; i < ms->itemcount ; ++i){
+  for(unsigned i = 0 ; i < ms->itemcount ; ++i){
     free(ms->items[i].desc);
     free(ms->items[i].shortdesc);
   }
@@ -188,7 +188,7 @@ dup_menu_section(ncmenu_int_section* dst, const struct ncmenu_section* src){
 
 // Duplicates all menu sections in opts, adding their length to '*totalwidth'.
 static int
-dup_menu_sections(ncmenu* ncm, const ncmenu_options* opts, int* totalwidth, int* totalheight){
+dup_menu_sections(ncmenu* ncm, const ncmenu_options* opts, unsigned* totalwidth, unsigned* totalheight){
   if(opts->sectioncount == 0){
     return -1;
   }
@@ -197,9 +197,9 @@ dup_menu_sections(ncmenu* ncm, const ncmenu_options* opts, int* totalwidth, int*
     return -1;
   }
   bool rightaligned = false; // can only right-align once. twice is error.
-  int maxheight = 0;
-  int maxwidth = *totalwidth;
-  int xoff = 2;
+  unsigned maxheight = 0;
+  unsigned maxwidth = *totalwidth;
+  unsigned xoff = 2;
   int i;
   for(i = 0 ; i < opts->sectioncount ; ++i){
     if(opts->sections[i].name){
@@ -294,9 +294,9 @@ section_x(const ncmenu* ncm, int x){
 static int
 write_header(ncmenu* ncm){
   ncplane_set_channels(ncm->ncp, ncm->headerchannels);
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(ncm->ncp, &dimy, &dimx);
-  int xoff = 0; // 2-column margin on left
+  unsigned xoff = 0; // 2-column margin on left
   int ypos = ncm->bottom ? dimy - 1 : 0;
   if(ncplane_cursor_move_yx(ncm->ncp, ypos, 0)){
     return -1;
@@ -385,12 +385,12 @@ ncmenu* ncmenu_create(ncplane* n, const ncmenu_options* opts){
   if(opts->flags >= (NCMENU_OPTION_HIDING << 1u)){
     logwarn("Provided unsupported flags %016" PRIx64 "\n", opts->flags);
   }
-  int totalheight = 1;
-  int totalwidth = 2; // start with two-character margin on the left
+  unsigned totalheight = 1;
+  unsigned totalwidth = 2; // start with two-character margin on the left
   ncmenu* ret = malloc(sizeof(*ret));
   ret->sectioncount = opts->sectioncount;
   ret->sections = NULL;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   if(ret){
     ret->bottom = !!(opts->flags & NCMENU_OPTION_BOTTOM);
@@ -461,13 +461,13 @@ int ncmenu_unroll(ncmenu* n, int sectionidx){
     return -1;
   }
   n->unrolledsection = sectionidx;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n->ncp, &dimy, &dimx);
   const int height = section_height(n, sectionidx);
   const int width = section_width(n, sectionidx);
   int xpos = n->sections[sectionidx].xoff < 0 ?
-    dimx + (n->sections[sectionidx].xoff - 2) : n->sections[sectionidx].xoff;
-  if(xpos + width >= dimx){
+    (int)dimx + (n->sections[sectionidx].xoff - 2) : n->sections[sectionidx].xoff;
+  if(xpos + width >= (int)dimx){
     xpos = dimx - (width + 2);
   }
   int ypos = n->bottom ? dimy - height - 1 : 1;
@@ -478,7 +478,7 @@ int ncmenu_unroll(ncmenu* n, int sectionidx){
     return -1;
   }
   const ncmenu_int_section* sec = &n->sections[sectionidx];
-  for(int i = 0 ; i < sec->itemcount ; ++i){
+  for(unsigned i = 0 ; i < sec->itemcount ; ++i){
     ++ypos;
     if(sec->items[i].desc){
       // FIXME the user ought be able to configure the disabled channel
@@ -487,8 +487,10 @@ int ncmenu_unroll(ncmenu* n, int sectionidx){
       }else{
         ncplane_set_channels(n->ncp, n->disablechannels);
       }
-      if(i == sec->itemselected){
-        ncplane_set_channels(n->ncp, ncchannels_reverse(ncplane_channels(n->ncp)));
+      if(sec->itemselected >= 0){
+        if(i == (unsigned)sec->itemselected){
+          ncplane_set_channels(n->ncp, ncchannels_reverse(ncplane_channels(n->ncp)));
+        }
       }
       ncplane_set_styles(n->ncp, 0);
       int cols = ncplane_putstr_yx(n->ncp, ypos, xpos + 1, sec->items[i].desc);
@@ -585,7 +587,7 @@ int ncmenu_nextitem(ncmenu* n){
   ncmenu_int_section* sec = &n->sections[n->unrolledsection];
   // FIXME probably best to detect cycles
   do{
-    if(++sec->itemselected == sec->itemcount){
+    if((unsigned)++sec->itemselected == sec->itemcount){
       sec->itemselected = 0;
     }
   }while(!sec->items[sec->itemselected].desc || sec->items[sec->itemselected].disabled);
@@ -628,10 +630,10 @@ const char* ncmenu_mouse_selected(const ncmenu* n, const ncinput* click,
   if(click->evtype != NCTYPE_RELEASE){
     return NULL;
   }
-  int y, x, dimy, dimx;
   struct ncplane* nc = n->ncp;
-  y = click->y;
-  x = click->x;
+  int y = click->y;
+  int x = click->x;
+  unsigned dimy, dimx;
   ncplane_dim_yx(nc, &dimy, &dimx);
   if(!ncplane_translate_abs(nc, &y, &x)){
     return NULL;
@@ -645,7 +647,7 @@ const char* ncmenu_mouse_selected(const ncmenu* n, const ncinput* click,
     return NULL;
   }
   const struct ncmenu_int_section* sec = &n->sections[n->unrolledsection];
-  if(y < 2 || y - 2 >= sec->itemcount){
+  if(y < 2 || (unsigned)y - 2 >= sec->itemcount){
     return NULL;
   }
   const int itemidx = y - 2;
@@ -659,14 +661,14 @@ bool ncmenu_offer_input(ncmenu* n, const ncinput* nc){
   // we can't actually select menu items in this function, since we need to
   // invoke an arbitrary function as a result.
   if(nc->id == NCKEY_BUTTON1 && nc->evtype == NCTYPE_RELEASE){
-    int y, x, dimy, dimx;
-    y = nc->y;
-    x = nc->x;
+    int y = nc->y;
+    int x = nc->x;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n->ncp, &dimy, &dimx);
     if(!ncplane_translate_abs(n->ncp, &y, &x)){
       return false;
     }
-    if(y != (n->bottom ? dimy - 1 : 0)){
+    if(y != (n->bottom ? (int)dimy - 1 : 0)){
       return false;
     }
     int i = section_x(n, x);
@@ -726,7 +728,7 @@ int ncmenu_item_set_status(ncmenu* n, const char* section, const char* item,
   for(int si = 0 ; si < n->sectioncount ; ++si){
     struct ncmenu_int_section* sec = &n->sections[si];
     if(strcmp(sec->name, section) == 0){
-      for(int ii = 0 ; ii < sec->itemcount ; ++ii){
+      for(unsigned ii = 0 ; ii < sec->itemcount ; ++ii){
         struct ncmenu_int_item* i = &sec->items[ii];
         if(strcmp(i->desc, item) == 0){
           const bool changed = i->disabled == enabled;
diff --git a/src/lib/metric.c b/src/lib/metric.c
index 38585e7808..aab43de5d6 100644
--- a/src/lib/metric.c
+++ b/src/lib/metric.c
@@ -22,8 +22,9 @@ detect_utf8(void){
   }
 }
 
-const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec,
-                     uintmax_t mult, int uprefix){
+const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal,
+                      char* buf, int omitdec, uintmax_t mult,
+                      int uprefix){
   // FIXME this is global to the process...ick :/
   fesetround(FE_TONEAREST);
   pthread_once(&utf8_detector, detect_utf8);
@@ -70,15 +71,20 @@ const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec,
     // 1,024). That can overflow with large 64-bit values, but we can first
     // divide both sides by mult, and then scale by 100.
     if(omitdec && (val % dv) == 0){
-      sprintfed = sprintf(buf, "%" PRIu64 "%lc", (uint64_t)(val / dv),
+      sprintfed = snprintf(buf, s, "%" PRIu64 "%lc", (uint64_t)(val / dv),
                           (wint_t)prefixes[consumed - 1]);
     }else{
-      sprintfed = sprintf(buf, "%.2f%lc", (double)val / dv,
+      sprintfed = snprintf(buf, s, "%.2f%lc", (double)val / dv,
                           (wint_t)prefixes[consumed - 1]);
     }
+    if(sprintfed < 0){
+      return NULL;
+    }
     if(uprefix){
-      buf[sprintfed] = uprefix;
-      buf[sprintfed + 1] = '\0';
+      if((size_t)sprintfed < s){
+        buf[sprintfed] = uprefix;
+        buf[++sprintfed] = '\0';
+      }
     }
     return buf;
   }
@@ -86,22 +92,32 @@ const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec,
   // val / decimal < dv (or we ran out of prefixes)
   if(omitdec && val % decimal == 0){
     if(consumed){
-      sprintfed = sprintf(buf, "%" PRIu64 "%lc", (uint64_t)(val / decimal),
+      sprintfed = snprintf(buf, s, "%" PRIu64 "%lc", (uint64_t)(val / decimal),
                           (wint_t)subprefixes[consumed - 1]);
     }else{
-      sprintfed = sprintf(buf, "%" PRIu64, (uint64_t)(val / decimal));
+      sprintfed = snprintf(buf, s, "%" PRIu64, (uint64_t)(val / decimal));
     }
   }else{
     if(consumed){
-      sprintfed = sprintf(buf, "%.2f%lc", (double)val / decimal,
+      sprintfed = snprintf(buf, s, "%.2f%lc", (double)val / decimal,
                           (wint_t)subprefixes[consumed - 1]);
     }else{
-      sprintfed = sprintf(buf, "%.2f", (double)val / decimal);
+      sprintfed = snprintf(buf, s, "%.2f", (double)val / decimal);
     }
   }
+  if(sprintfed < 0){
+    return NULL;
+  }
   if(consumed && uprefix){
-    buf[sprintfed] = uprefix;
-    buf[sprintfed + 1] = '\0';
+    if((size_t)sprintfed < s){
+      buf[sprintfed] = uprefix;
+      buf[++sprintfed] = '\0';
+    }
   }
   return buf;
 }
+
+const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec,
+                     uintmax_t mult, int uprefix){
+  return ncnmetric(val, INT_MAX, decimal, buf, omitdec, mult, uprefix);
+}
diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c
index 77ef3a6ce5..77b9302bf6 100644
--- a/src/lib/notcurses.c
+++ b/src/lib/notcurses.c
@@ -184,9 +184,6 @@ cursor_invalid_p(const ncplane* n){
   if(n->y >= n->leny || n->x >= n->lenx){
     return true;
   }
-  if(n->y < 0 || n->x < 0){
-    return true;
-  }
   return false;
 }
 
@@ -195,33 +192,46 @@ char* ncplane_at_cursor(ncplane* n, uint16_t* stylemask, uint64_t* channels){
 }
 
 char* ncplane_at_yx(const ncplane* n, int y, int x, uint16_t* stylemask, uint64_t* channels){
-  if(y < n->leny && x < n->lenx){
-    if(y >= 0 && x >= 0){
-      const nccell* yx = &n->fb[nfbcellidx(n, y, x)];
-      // if we're the right side of a wide glyph, we return the main glyph
-      if(nccell_wide_right_p(yx)){
-        return ncplane_at_yx(n, y, x - 1, stylemask, channels);
-      }
-      char* ret = nccell_extract(n, yx, stylemask, channels);
-      if(ret == NULL){
-        return NULL;
-      }
+  if(y < 0){
+    if(y != -1){
+      logerror("invalid y: %d\n", y);
+      return NULL;
+    }
+    y = n->y;
+  }
+  if(x < 0){
+    if(x != -1){
+      logerror("invalid x: %d\n", x);
+      return NULL;
+    }
+    x = n->x;
+  }
+  if((unsigned)y >= n->leny || (unsigned)x >= n->lenx){
+    logerror("invalid coordinates: %d/%d\n", y, x);
+    return NULL;
+  }
+  const nccell* yx = &n->fb[nfbcellidx(n, y, x)];
+  // if we're the right side of a wide glyph, we return the main glyph
+  if(nccell_wide_right_p(yx)){
+    return ncplane_at_yx(n, y, x - 1, stylemask, channels);
+  }
+  char* ret = nccell_extract(n, yx, stylemask, channels);
+  if(ret == NULL){
+    return NULL;
+  }
 //fprintf(stderr, "GOT [%s]\n", ret);
-      if(strcmp(ret, "") == 0){
-        free(ret);
-        ret = nccell_strdup(n, &n->basecell);
-        if(ret == NULL){
-          return NULL;
-        }
-        if(stylemask){
-          *stylemask = n->basecell.stylemask;
-        }
-      }
-      // FIXME load basecell channels if appropriate
-      return ret;
+  if(strcmp(ret, "") == 0){
+    free(ret);
+    ret = nccell_strdup(n, &n->basecell);
+    if(ret == NULL){
+      return NULL;
+    }
+    if(stylemask){
+      *stylemask = n->basecell.stylemask;
     }
   }
-  return NULL;
+  // FIXME load basecell channels if appropriate
+  return ret;
 }
 
 int ncplane_at_cursor_cell(ncplane* n, nccell* c){
@@ -229,19 +239,33 @@ int ncplane_at_cursor_cell(ncplane* n, nccell* c){
 }
 
 int ncplane_at_yx_cell(ncplane* n, int y, int x, nccell* c){
-  if(y < n->leny && x < n->lenx){
-    if(y >= 0 && x >= 0){
-      nccell* targ = ncplane_cell_ref_yx(n, y, x);
-      if(nccell_duplicate(n, c, targ) == 0){
-        // FIXME take base cell into account where necessary!
-        return strlen(nccell_extended_gcluster(n, targ));
-      }
+  if(y < 0){
+    if(y != -1){
+      logerror("invalid y: %d\n", y);
+      return -1;
+    }
+    y = n->y;
+  }
+  if(x < 0){
+    if(x != -1){
+      logerror("invalid x: %d\n", x);
+      return -1;
     }
+    x = n->x;
+  }
+  if((unsigned)y >= n->leny || (unsigned)x >= n->lenx){
+    logerror("invalid coordinates: %d/%d\n", y, x);
+    return -1;
   }
-  return -1;
+  nccell* targ = ncplane_cell_ref_yx(n, y, x);
+  if(nccell_duplicate(n, c, targ)){
+    return -1;
+  }
+  // FIXME take base cell into account where necessary!
+  return strlen(nccell_extended_gcluster(n, targ));
 }
 
-void ncplane_dim_yx(const ncplane* n, int* rows, int* cols){
+void ncplane_dim_yx(const ncplane* n, unsigned* rows, unsigned* cols){
   if(rows){
     *rows = n->leny;
   }
@@ -252,7 +276,7 @@ void ncplane_dim_yx(const ncplane* n, int* rows, int* cols){
 
 // anyone calling this needs ensure the ncplane's framebuffer is updated
 // to reflect changes in geometry. also called at startup for standard plane.
-int update_term_dimensions(int* rows, int* cols, tinfo* tcache, int margin_b){
+int update_term_dimensions(unsigned* rows, unsigned* cols, tinfo* tcache, int margin_b){
   // if we're not a real tty, we presumably haven't changed geometry, return
   if(tcache->ttyfd < 0){
     if(rows){
@@ -267,7 +291,7 @@ int update_term_dimensions(int* rows, int* cols, tinfo* tcache, int margin_b){
     }
     return 0;
   }
-  int rowsafe, colsafe;
+  unsigned rowsafe, colsafe;
   if(rows == NULL){
     rows = &rowsafe;
   }
@@ -601,41 +625,41 @@ void ncplane_home(ncplane* n){
 }
 
 int ncplane_cursor_move_yx(ncplane* n, int y, int x){
-  if(x >= n->lenx){
-    logerror("Target x %d >= length %d\n", x, n->lenx);
-    return -1;
-  }else if(x < 0){
+  if(x < 0){
     if(x < -1){
       logerror("Negative target x %d\n", x);
       return -1;
     }
+  }else if((unsigned)x >= n->lenx){
+    logerror("target x %d >= width %u\n", x, n->lenx);
+    return -1;
   }else{
     n->x = x;
   }
-  if(y >= n->leny){
-    logerror("Target y %d >= height %d\n", y, n->leny);
-    return -1;
-  }else if(y < 0){
+  if(y < 0){
     if(y < -1){
       logerror("Negative target y %d\n", y);
       return -1;
     }
+  }else if((unsigned)y >= n->leny){
+    logerror("target y %d >= height %u\n", y, n->leny);
+    return -1;
   }else{
     n->y = y;
   }
   if(cursor_invalid_p(n)){
-    logerror("Invalid cursor following move (%d/%d)\n", n->y, n->x);
+    logerror("invalid cursor following move (%d/%d)\n", n->y, n->x);
     return -1;
   }
   return 0;
 }
 
 int ncplane_cursor_move_rel(ncplane* n, int y, int x){
-  if (n->y + y == -1){
-    logerror("Invalid target y -1\n");
+  if((int)n->y + y == -1){
+    logerror("invalid target y -1\n");
     return -1;
-  }else if (n->x + x == -1){
-    logerror("Invalid target x -1\n");
+  }else if((int)n->x + x == -1){
+    logerror("invalid target x -1\n");
     return -1;
   }else return ncplane_cursor_move_yx(n, n->y + y, n->x + x);
 }
@@ -697,34 +721,34 @@ int ncplane_resize_internal(ncplane* n, int keepy, int keepx,
                             int yoff, int xoff,
                             unsigned ylen, unsigned xlen){
   if(keepy < 0 || keepx < 0){ // can't start at negative origin
-    logerror("Can't retain negative offset %dx%d\n", keepy, keepx);
+    logerror("can't retain negative offset %dx%d\n", keepy, keepx);
     return -1;
   }
   if((!keepleny && keeplenx) || (keepleny && !keeplenx)){ // both must be 0
-    logerror("Can't retain null dimension %dx%d\n", keepleny, keeplenx);
+    logerror("can't retain null dimension %dx%d\n", keepleny, keeplenx);
     return -1;
   }
   // can't be smaller than keep length
   if(ylen < keepleny){
-    logerror("Can't map in y dimension: %u < %d\n", ylen, keepleny);
+    logerror("can't map in y dimension: %u < %d\n", ylen, keepleny);
     return -1;
   }
   if(xlen < keeplenx){
-    logerror("Can't map in x dimension: %u < %d\n", xlen, keeplenx);
+    logerror("can't map in x dimension: %u < %d\n", xlen, keeplenx);
     return -1;
   }
   if(ylen <= 0 || xlen <= 0){ // can't resize to trivial or negative size
-    logerror("Can't achieve meaningless size %ux%u\n", ylen, xlen);
+    logerror("can't achieve meaningless size %ux%u\n", ylen, xlen);
     return -1;
   }
-  int rows, cols;
+  unsigned rows, cols;
   ncplane_dim_yx(n, &rows, &cols);
   if(keepleny + keepy > (unsigned)rows){
-    logerror("Can't keep %d@%d rows from %d\n", keepleny, keepy, rows);
+    logerror("can't keep %d@%d rows from %d\n", keepleny, keepy, rows);
     return -1;
   }
   if(keeplenx + keepx > (unsigned)cols){
-    logerror("Can't keep %d@%d cols from %d\n", keeplenx, keepx, cols);
+    logerror("can't keep %d@%d cols from %d\n", keeplenx, keepx, cols);
     return -1;
   }
   loginfo("%dx%d @ %d/%d → %u/%u @ %d/%d (want %ux%u@%d/%d)\n", rows, cols, n->absy, n->absx, ylen, xlen, n->absy + keepy + yoff, n->absx + keepx + xoff, keepleny, keeplenx, keepy, keepx);
@@ -1101,7 +1125,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
       goto err;
     }
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   if(update_term_dimensions(&dimy, &dimx, &ret->tcache, ret->margin_b)){
     goto err;
   }
@@ -1131,10 +1155,13 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
   }
   if(ret->rstate.logendy >= 0){ // if either is set, both are
     if(!ret->suppress_banner && ret->tcache.ttyfd >= 0){
-      if(locate_cursor(&ret->tcache, &ret->rstate.logendy, &ret->rstate.logendx)){
+      unsigned uendy, uendx;
+      if(locate_cursor(&ret->tcache, &uendy, &uendx)){
         free_plane(ret->stdplane);
         goto err;
       }
+      ret->rstate.logendy = uendy;
+      ret->rstate.logendx = uendx;
     }
     if(opts->flags & NCOPTION_PRESERVE_CURSOR){
       ncplane_cursor_move_yx(ret->stdplane, ret->rstate.logendy, ret->rstate.logendx);
@@ -1225,7 +1252,7 @@ int notcurses_stop(notcurses* nc){
     // wrote. move it to the bottom left of the screen, *unless*
     // PRESERVE_CURSOR was used, which is a bit more complex.
     if((nc->flags & NCOPTION_PRESERVE_CURSOR) || !get_escape(&nc->tcache, ESCAPE_SMCUP)){
-      int targy = nc->rstate.logendy;
+      unsigned targy = nc->rstate.logendy;
       fbuf_reset(&nc->rstate.f);
       if(++targy >= nc->lfdimy){
         fbuf_putc(&nc->rstate.f, '\n');
@@ -1335,7 +1362,7 @@ int ncplane_set_base_cell(ncplane* ncp, const nccell* c){
   return nccell_duplicate(ncp, &ncp->basecell, c);
 }
 
-int ncplane_set_base(ncplane* ncp, const char* egc, uint32_t stylemask, uint64_t channels){
+int ncplane_set_base(ncplane* ncp, const char* egc, uint16_t stylemask, uint64_t channels){
   return nccell_prime(ncp, &ncp->basecell, egc, stylemask, channels);
 }
 
@@ -1521,7 +1548,7 @@ int ncplane_move_family_below(ncplane* restrict n, ncplane* restrict bpoint){
   return 0;
 }
 
-void ncplane_cursor_yx(const ncplane* n, int* y, int* x){
+void ncplane_cursor_yx(const ncplane* n, unsigned* y, unsigned* x){
   if(y){
     *y = n->y;
   }
@@ -1547,7 +1574,7 @@ void scroll_down(ncplane* n){
     }
     n->logrow = (n->logrow + 1) % n->leny;
     nccell* row = n->fb + nfbcellidx(n, n->y, 0);
-    for(int clearx = 0 ; clearx < n->lenx ; ++clearx){
+    for(unsigned clearx = 0 ; clearx < n->lenx ; ++clearx){
       nccell_release(n, &row[clearx]);
     }
     memset(row, 0, sizeof(*row) * n->lenx);
@@ -1641,7 +1668,7 @@ ncplane_put(ncplane* n, int y, int x, const char* egc, int cols,
   // line. if scrolling is enabled, move to the next line if so. if x or y are
   // specified, we must always try to print at exactly that location.
   if(x != -1){
-    if(x + cols > n->lenx){
+    if((unsigned)x + cols > n->lenx){
       logerror("Target x %d + %d cols [%.*s] > length %d\n", x, cols, bytes, egc, n->lenx);
       ncplane_cursor_move_yx(n, y, x); // update cursor, though
       return -1;
@@ -1725,7 +1752,7 @@ int ncplane_putegc_yx(ncplane* n, int y, int x, const char* gclust, int* sbytes)
 
 int ncplane_putchar_stained(ncplane* n, char c){
   uint64_t channels = n->channels;
-  uint32_t stylemask = n->stylemask;
+  uint16_t stylemask = n->stylemask;
   const nccell* targ = &n->fb[nfbcellidx(n, n->y, n->x)];
   n->channels = targ->channels;
   n->stylemask = targ->stylemask;
@@ -1737,7 +1764,7 @@ int ncplane_putchar_stained(ncplane* n, char c){
 
 int ncplane_putwegc_stained(ncplane* n, const wchar_t* gclust, int* sbytes){
   uint64_t channels = n->channels;
-  uint32_t stylemask = n->stylemask;
+  uint16_t stylemask = n->stylemask;
   const nccell* targ = &n->fb[nfbcellidx(n, n->y, n->x)];
   n->channels = targ->channels;
   n->stylemask = targ->stylemask;
@@ -1749,7 +1776,7 @@ int ncplane_putwegc_stained(ncplane* n, const wchar_t* gclust, int* sbytes){
 
 int ncplane_putegc_stained(ncplane* n, const char* gclust, int* sbytes){
   uint64_t channels = n->channels;
-  uint32_t stylemask = n->stylemask;
+  uint16_t stylemask = n->stylemask;
   const nccell* targ = &n->fb[nfbcellidx(n, n->y, n->x)];
   n->channels = targ->channels;
   n->stylemask = targ->stylemask;
@@ -1956,7 +1983,7 @@ int ncplane_vline_interp(ncplane* n, const nccell* c, unsigned len,
   int deltbr = (br2 - br1) / ((int)len + 1);
   int deltbg = (bg2 - bg1) / ((int)len + 1);
   int deltbb = (bb2 - bb1) / ((int)len + 1);
-  int ypos, xpos;
+  unsigned ypos, xpos;
   unsigned ret;
   ncplane_cursor_yx(n, &ypos, &xpos);
   nccell dupc = CELL_TRIVIAL_INITIALIZER;
@@ -1994,24 +2021,26 @@ int ncplane_vline_interp(ncplane* n, const nccell* c, unsigned len,
   return ret;
 }
 
+// we must have at least 2x2, or it's an error
 int ncplane_box(ncplane* n, const nccell* ul, const nccell* ur,
                 const nccell* ll, const nccell* lr, const nccell* hl,
                 const nccell* vl, unsigned ystop, unsigned xstop,
                 unsigned ctlword){
-  int yoff, xoff, ymax, xmax;
+  unsigned yoff, xoff;
   ncplane_cursor_yx(n, &yoff, &xoff);
   // must be at least 2x2, with its upper-left corner at the current cursor
-  if(ystop < (unsigned)yoff + 1){
+  if(ystop < yoff + 1){
     logerror("ystop (%u) insufficient for yoff (%d)\n", ystop, yoff);
     return -1;
   }
-  if(xstop < (unsigned)xoff + 1){
+  if(xstop < xoff + 1){
     logerror("xstop (%u) insufficient for xoff (%d)\n", xstop, xoff);
     return -1;
   }
+  unsigned ymax, xmax;
   ncplane_dim_yx(n, &ymax, &xmax);
   // must be within the ncplane
-  if(xstop >= (unsigned)xmax || ystop >= (unsigned)ymax){
+  if(xstop >= xmax || ystop >= ymax){
     logerror("Boundary (%ux%u) beyond plane (%dx%d)\n", ystop, xstop, ymax, xmax);
     return -1;
   }
@@ -2211,7 +2240,7 @@ int ncplane_erase_region(ncplane* n, int ystart, int xstart, int ylen, int xlen)
     logerror("Illegal start of erase (%d, %d)\n", ystart, xstart);
     return -1;
   }
-  if(ystart >= ncplane_dim_y(n) || xstart >= ncplane_dim_x(n)){
+  if(ystart >= (int)ncplane_dim_y(n) || xstart >= (int)ncplane_dim_x(n)){
     logerror("Illegal start of erase (%d, %d)\n", ystart, xstart);
     return -1;
   }
@@ -2225,7 +2254,7 @@ int ncplane_erase_region(ncplane* n, int ystart, int xstart, int ylen, int xlen)
     xstart = 0;
     xlen = ncplane_dim_x(n);
   }
-  if(xlen > ncplane_dim_x(n) || xstart + xlen > ncplane_dim_x(n)){
+  if(xlen > (int)ncplane_dim_x(n) || xstart + xlen > (int)ncplane_dim_x(n)){
     xlen = ncplane_dim_x(n) - xstart;
   }
   if(ylen < 0){
@@ -2238,12 +2267,12 @@ int ncplane_erase_region(ncplane* n, int ystart, int xstart, int ylen, int xlen)
     ystart = 0;
     ylen = ncplane_dim_y(n);
   }
-  if(ylen > ncplane_dim_y(n) || ystart + ylen > ncplane_dim_y(n)){
+  if(ylen > (int)ncplane_dim_y(n) || ystart + ylen > (int)ncplane_dim_y(n)){
     ylen = ncplane_dim_y(n) - ystart;
   }
   // special-case the full plane erasure, as it's powerfully optimized (O(1))
   if(ystart == 0 && xstart == 0 &&
-      ylen == ncplane_dim_y(n) && xlen == ncplane_dim_x(n)){
+      ylen == (int)ncplane_dim_y(n) && xlen == (int)ncplane_dim_x(n)){
     int tmpy = n->y; // preserve cursor location
     int tmpx = n->x;
     ncplane_erase(n);
@@ -2378,7 +2407,8 @@ bool ncplane_translate_abs(const ncplane* n, int* restrict y, int* restrict x){
     if(*y < 0){
       return false;
     }
-    if(*y >= n->leny){
+    unsigned yval = *y;
+    if(yval >= n->leny){
       return false;
     }
   }
@@ -2386,7 +2416,8 @@ bool ncplane_translate_abs(const ncplane* n, int* restrict y, int* restrict x){
     if(*x < 0){
       return false;
     }
-    if(*x >= n->lenx){
+    unsigned xval = *x;
+    if(xval >= n->lenx){
       return false;
     }
   }
@@ -2464,7 +2495,7 @@ int (*ncplane_resizecb(const ncplane* n))(ncplane*){
 int ncplane_resize_marginalized(ncplane* n){
   const ncplane* parent = ncplane_parent_const(n);
   // a marginalized plane cannot be larger than its oppressor plane =]
-  int maxy, maxx;
+  unsigned maxy, maxx;
   if(parent == n){ // root plane, need to use pile size
     ncpile* p = ncplane_pile(n);
     maxy = p->dimy;
@@ -2478,10 +2509,10 @@ int ncplane_resize_marginalized(ncplane* n){
   if((maxx -= (n->margin_r + (n->absx - n->boundto->absx))) < 1){
     maxx = 1;
   }
-  int oldy, oldx;
+  unsigned oldy, oldx;
   ncplane_dim_yx(n, &oldy, &oldx); // current dimensions of 'n'
-  int keepleny = oldy > maxy ? maxy : oldy;
-  int keeplenx = oldx > maxx ? maxx : oldx;
+  unsigned keepleny = oldy > maxy ? maxy : oldy;
+  unsigned keeplenx = oldx > maxx ? maxx : oldx;
   if(ncplane_resize_internal(n, 0, 0, keepleny, keeplenx, 0, 0, maxy, maxx)){
     return -1;
   }
@@ -2493,12 +2524,12 @@ int ncplane_resize_marginalized(ncplane* n){
 
 int ncplane_resize_maximize(ncplane* n){
   const ncpile* pile = ncplane_pile(n); // FIXME should be taken against parent
-  const int rows = pile->dimy;
-  const int cols = pile->dimx;
-  int oldy, oldx;
+  const unsigned rows = pile->dimy;
+  const unsigned cols = pile->dimx;
+  unsigned oldy, oldx;
   ncplane_dim_yx(n, &oldy, &oldx); // current dimensions of 'n'
-  int keepleny = oldy > rows ? rows : oldy;
-  int keeplenx = oldx > cols ? cols : oldx;
+  unsigned keepleny = oldy > rows ? rows : oldy;
+  unsigned keeplenx = oldx > cols ? cols : oldx;
   return ncplane_resize_internal(n, 0, 0, keepleny, keeplenx, 0, 0, rows, cols);
 }
 
@@ -2842,23 +2873,11 @@ is_bg_p(int idx, int py, int px, int width){
 
 static inline uint32_t*
 ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit,
-                         unsigned begy, unsigned begx, unsigned leny,
-                         unsigned lenx, unsigned* pxdimy, unsigned* pxdimx){
+                         int begy, int begx, unsigned leny, unsigned lenx,
+                         unsigned* pxdimy, unsigned* pxdimx){
   const notcurses* ncur = ncplane_notcurses_const(nc);
-  if(begx >= (unsigned)nc->lenx || begy >= (unsigned)nc->leny){
-    logerror("invalid origin (%u,%u)\n", begy, begx);
-    return NULL;
-  }
-  if(lenx == 0){ // -1 means "to the end"; use all space available
-    lenx = nc->lenx - begx;
-  }
-  if(leny == 0){
-    leny = nc->leny - begy;
-  }
-//fprintf(stderr, "sum: %d/%d avail: %d/%d\n", begy + leny, begx + lenx, nc->leny, nc->lenx);
-  if(nc->lenx - begx < lenx || nc->leny - begy < leny){
-    logerror("invalid specs %u + %u > %d or %u + %u > %d\n",
-             begx, lenx, nc->lenx, begy, leny, nc->leny);
+  unsigned ystart, xstart;
+  if(check_geometry_args(nc, begy, begx, &leny, &lenx, &ystart, &xstart)){
     return NULL;
   }
   if(blit == NCBLIT_PIXEL){ // FIXME extend this to support sprixels
@@ -2884,8 +2903,8 @@ ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit,
   uint32_t* ret = malloc(sizeof(*ret) * lenx * bset->width * leny * bset->height);
 //fprintf(stderr, "GEOM: %d/%d %d/%d ret: %p\n", bset->height, bset->width, *pxdimy, *pxdimx, ret);
   if(ret){
-    for(unsigned y = begy, targy = 0 ; y < begy + leny ; ++y, targy += bset->height){
-      for(unsigned x = begx, targx = 0 ; x < begx + lenx ; ++x, targx += bset->width){
+    for(unsigned y = ystart, targy = 0 ; y < ystart + leny ; ++y, targy += bset->height){
+      for(unsigned x = xstart, targx = 0 ; x < xstart + lenx ; ++x, targx += bset->width){
         uint16_t stylemask;
         uint64_t channels;
         char* c = ncplane_at_yx(nc, y, x, &stylemask, &channels);
@@ -2938,7 +2957,7 @@ ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit,
 }
 
 uint32_t* ncplane_as_rgba(const ncplane* nc, ncblitter_e blit,
-                          unsigned begy, unsigned begx, unsigned leny,
+                          int begy, int begx, unsigned leny,
                           unsigned lenx, unsigned* pxdimy, unsigned* pxdimx){
   unsigned px, py;
   if(!pxdimy){
@@ -2951,28 +2970,16 @@ uint32_t* ncplane_as_rgba(const ncplane* nc, ncblitter_e blit,
 }
 
 // return a heap-allocated copy of the contents
-char* ncplane_contents(ncplane* nc, unsigned begy, unsigned begx, unsigned leny, unsigned lenx){
-  if(begx >= (unsigned)nc->lenx || begy >= (unsigned)nc->leny){
-    logerror("beginning coordinates (%u/%u) exceeded area (%d/%d)\n",
-             begy, begx, nc->leny, nc->lenx);
-    return NULL;
-  }
-  if(lenx == 0){ // 0 means "to the end"; use all space available
-    lenx = nc->lenx - begx;
-  }
-  if(leny == 0){
-    leny = nc->leny - begy;
-  }
-  if(nc->lenx - begx < lenx || nc->leny - begy < leny){
-    logerror("ending coordinates (%u/%u) exceeded lengths (%d/%d)\n",
-             begy + leny, begx + lenx, nc->leny, nc->lenx);
+char* ncplane_contents(ncplane* nc, int begy, int begx, unsigned leny, unsigned lenx){
+  unsigned ystart, xstart;
+  if(check_geometry_args(nc, begy, begx, &leny, &lenx, &ystart, &xstart)){
     return NULL;
   }
   size_t retlen = 1;
   char* ret = malloc(retlen);
   if(ret){
-    for(unsigned y = begy, targy = 0 ; y < begy + leny ; ++y, targy += 2){
-      for(unsigned x = begx, targx = 0 ; x < begx + lenx ; ++x, ++targx){
+    for(unsigned y = ystart, targy = 0 ; y < ystart + leny ; ++y, targy += 2){
+      for(unsigned x = xstart, targx = 0 ; x < xstart + lenx ; ++x, ++targx){
         nccell ncl = CELL_TRIVIAL_INITIALIZER;
         // we need ncplane_at_yx_cell() here instead of ncplane_at_yx(),
         // because we should only have one copy of each wide EGC.
@@ -2999,7 +3006,7 @@ char* ncplane_contents(ncplane* nc, unsigned begy, unsigned begx, unsigned leny,
   return ret;
 }
 
-int nccells_double_box(ncplane* n, uint32_t attr, uint64_t channels,
+int nccells_double_box(ncplane* n, uint16_t attr, uint64_t channels,
                        nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   if(notcurses_canutf8(ncplane_notcurses(n))){
     return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXDOUBLE);
@@ -3007,12 +3014,12 @@ int nccells_double_box(ncplane* n, uint32_t attr, uint64_t channels,
   return nccells_ascii_box(n, attr, channels, ul, ur, ll, lr, hl, vl);
 }
 
-int cells_double_box(ncplane* n, uint32_t attr, uint64_t channels,
+int cells_double_box(ncplane* n, uint16_t attr, uint64_t channels,
                      nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   return nccells_double_box(n, attr, channels, ul, ur, ll, lr, hl, vl);
 }
 
-int nccells_rounded_box(ncplane* n, uint32_t attr, uint64_t channels,
+int nccells_rounded_box(ncplane* n, uint16_t attr, uint64_t channels,
                         nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   if(notcurses_canutf8(ncplane_notcurses(n))){
     return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXROUND);
@@ -3020,7 +3027,7 @@ int nccells_rounded_box(ncplane* n, uint32_t attr, uint64_t channels,
   return nccells_ascii_box(n, attr, channels, ul, ur, ll, lr, hl, vl);
 }
 
-int cells_rounded_box(ncplane* n, uint32_t attr, uint64_t channels,
+int cells_rounded_box(ncplane* n, uint16_t attr, uint64_t channels,
                       nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
   return nccells_rounded_box(n, attr, channels, ul, ur, ll, lr, hl, vl);
 }
@@ -3172,9 +3179,9 @@ int ncstrwidth_valid(const char* egcs, int* validbytes, int* validwidth){
   return *validwidth;
 }
 
-void ncplane_pixelgeom(const ncplane* n, int* RESTRICT pxy, int* RESTRICT pxx,
-                       int* RESTRICT celldimy, int* RESTRICT celldimx,
-                       int* RESTRICT maxbmapy, int* RESTRICT maxbmapx){
+void ncplane_pixelgeom(const ncplane* n, unsigned* RESTRICT pxy, unsigned* RESTRICT pxx,
+                       unsigned* RESTRICT celldimy, unsigned* RESTRICT celldimx,
+                       unsigned* RESTRICT maxbmapy, unsigned* RESTRICT maxbmapx){
   notcurses* nc = ncplane_notcurses(n);
   if(celldimy){
     *celldimy = nc->tcache.cellpixy;
diff --git a/src/lib/plot.c b/src/lib/plot.c
index bb1fc44e62..d6b69dee7f 100644
--- a/src/lib/plot.c
+++ b/src/lib/plot.c
@@ -25,13 +25,13 @@ typedef struct ncplot {
      to span the horizontal area. if there are more slots than there are
      columns, we prefer showing more recent slots to less recent. if there are
      fewer slots than there are columns, they prefer the left side. */
-  int rangex;
+  unsigned rangex;
   /* domain minimum and maximum. if detectdomain is true, these are
      progressively enlarged/shrunk to fit the sample set. if not, samples
      outside these bounds are counted, but the displayed range covers only this. */
-  int slotcount;
+  unsigned slotcount;
   int slotstart; /* index of most recently-written slot */
-  bool labelaxisd; /* label dependent axis (consumes PREFIXCOLUMNS columns) */
+  bool labelaxisd; /* label dependent axis (consumes NCPREFIXCOLUMNS columns) */
   bool exponentiali; /* exponential independent axis */
   bool detectdomain; /* is domain detection in effect (stretch the domain)? */
   bool detectonlymax; /* domain detection applies only to max, not min */
@@ -95,9 +95,9 @@ int redraw_pixelplot_##T(nc##X##plot* ncp){ \
   } \
   const int scale = ncplane_notcurses_const(ncp->plot.ncp)->tcache.cellpixx; \
   ncplane_erase(ncp->plot.ncp); \
-  int dimy, dimx; \
+  unsigned dimy, dimx; \
   ncplane_dim_yx(ncp->plot.ncp, &dimy, &dimx); \
-  const int scaleddim = dimx * scale; \
+  const unsigned scaleddim = dimx * scale; \
   /* each transition is worth this much change in value */ \
   const size_t states = ncplane_notcurses_const(ncp->plot.ncp)->tcache.cellpixy; \
   /* FIXME can we not rid ourselves of this meddlesome double? either way, the \
@@ -114,17 +114,17 @@ int redraw_pixelplot_##T(nc##X##plot* ncp){ \
   }else{ \
     interval = ncp->maxy < ncp->miny ? 0 : (ncp->maxy - ncp->miny) / ((double)dimy * states); \
   } \
-  const int startx = ncp->plot.labelaxisd ? PREFIXCOLUMNS : 0; /* plot cols begin here */ \
+  const int startx = ncp->plot.labelaxisd ? NCPREFIXCOLUMNS : 0; /* plot cols begin here */ \
   /* if we want fewer slots than there are available columns, our final column \
      will be other than the plane's final column. most recent x goes here. */ \
-  const int finalx = (ncp->plot.slotcount < scaleddim - 1 - (startx * scale) ? \
-                     startx + (ncp->plot.slotcount / scale) - 1 : dimx - 1); \
+  const unsigned finalx = (ncp->plot.slotcount < scaleddim - 1 - (startx * scale) ? \
+                          startx + (ncp->plot.slotcount / scale) - 1 : dimx - 1); \
   ncplane_set_styles(ncp->plot.ncp, ncp->plot.legendstyle); \
   if(ncp->plot.labelaxisd){ \
     /* show the *top* of each interval range */ \
-    for(int y = 0 ; y < dimy ; ++y){ \
+    for(unsigned y = 0 ; y < dimy ; ++y){ \
       ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[y * states]); \
-      char buf[PREFIXSTRLEN + 1]; \
+      char buf[NCPREFIXSTRLEN + 1]; \
       if(ncp->plot.exponentiali){ \
         if(y == dimy - 1){ /* we cheat on the top row to exactly match maxy */ \
           ncmetric(ncp->maxy * 100, 100, buf, 0, 1000, '\0'); \
@@ -136,18 +136,18 @@ int redraw_pixelplot_##T(nc##X##plot* ncp){ \
       } \
       if(y == dimy - 1 && strlen(ncp->plot.title)){ \
         ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, 0, "%*.*s %s", \
-                          PREFIXSTRLEN, PREFIXSTRLEN, buf, ncp->plot.title); \
+                          NCPREFIXSTRLEN, NCPREFIXSTRLEN, buf, ncp->plot.title); \
       }else{ \
         ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, 0, "%*.*s", \
-                          PREFIXSTRLEN, PREFIXSTRLEN, buf); \
+                          NCPREFIXSTRLEN, NCPREFIXSTRLEN, buf); \
       } \
     } \
   }else if(strlen(ncp->plot.title)){ \
     ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[(dimy - 1) * states]); \
-    ncplane_printf_yx(ncp->plot.ncp, 0, PREFIXCOLUMNS - strlen(ncp->plot.title), "%s", ncp->plot.title); \
+    ncplane_printf_yx(ncp->plot.ncp, 0, NCPREFIXCOLUMNS - strlen(ncp->plot.title), "%s", ncp->plot.title); \
   } \
   ncplane_set_styles(ncp->plot.ncp, NCSTYLE_NONE); \
-  if(finalx < startx){ /* exit on pathologically narrow planes */ \
+  if((int)finalx < startx){ /* exit on pathologically narrow planes */ \
     return 0; \
   } \
   if(!interval){ \
@@ -188,7 +188,7 @@ int redraw_pixelplot_##T(nc##X##plot* ncp){ \
        given cell. */ \
     T intervalbase = ncp->miny; \
     bool done = !ncp->plot.bset->fill; \
-    for(int y = 0 ; y < dimy ; ++y){ \
+    for(unsigned y = 0 ; y < dimy ; ++y){ \
       /* if we've got at least one interval's worth on the number of positions \
         times the number of intervals per position plus the starting offset, \
         we're going to print *something* */ \
@@ -264,10 +264,10 @@ int redraw_plot_##T(nc##X##plot* ncp){ \
     return -1; \
   } \
   ncplane_erase(ncp->plot.ncp); \
-  const int scale = ncp->plot.bset->width; \
-  int dimy, dimx; \
+  const unsigned scale = ncp->plot.bset->width; \
+  unsigned dimy, dimx; \
   ncplane_dim_yx(ncp->plot.ncp, &dimy, &dimx); \
-  const int scaleddim = dimx * scale; \
+  const unsigned scaleddim = dimx * scale; \
   /* each transition is worth this much change in value */ \
   const size_t states = ncp->plot.bset->height + 1; \
   /* FIXME can we not rid ourselves of this meddlesome double? either way, the \
@@ -284,17 +284,17 @@ int redraw_plot_##T(nc##X##plot* ncp){ \
   }else{ \
     interval = ncp->maxy < ncp->miny ? 0 : (ncp->maxy - ncp->miny) / ((double)dimy * states); \
   } \
-  const int startx = ncp->plot.labelaxisd ? PREFIXCOLUMNS : 0; /* plot cols begin here */ \
+  const int startx = ncp->plot.labelaxisd ? NCPREFIXCOLUMNS : 0; /* plot cols begin here */ \
   /* if we want fewer slots than there are available columns, our final column \
      will be other than the plane's final column. most recent x goes here. */ \
-  const int finalx = (ncp->plot.slotcount < scaleddim - 1 - (startx * scale) ? \
-                     startx + (ncp->plot.slotcount / scale) - 1 : dimx - 1); \
+  const unsigned finalx = (ncp->plot.slotcount < scaleddim - 1 - (startx * scale) ? \
+                          startx + (ncp->plot.slotcount / scale) - 1 : dimx - 1); \
   ncplane_set_styles(ncp->plot.ncp, ncp->plot.legendstyle); \
   if(ncp->plot.labelaxisd){ \
     /* show the *top* of each interval range */ \
-    for(int y = 0 ; y < dimy ; ++y){ \
+    for(unsigned y = 0 ; y < dimy ; ++y){ \
       ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[y]); \
-      char buf[PREFIXSTRLEN + 1]; \
+      char buf[NCPREFIXSTRLEN + 1]; \
       if(ncp->plot.exponentiali){ \
         if(y == dimy - 1){ /* we cheat on the top row to exactly match maxy */ \
           ncmetric(ncp->maxy * 100, 100, buf, 0, 1000, '\0'); \
@@ -305,17 +305,17 @@ int redraw_plot_##T(nc##X##plot* ncp){ \
         ncmetric((ncp->maxy - interval * states * (dimy - y - 1)) * 100, 100, buf, 0, 1000, '\0'); \
       } \
       if(y == dimy - 1 && strlen(ncp->plot.title)){ \
-        ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, PREFIXCOLUMNS - strlen(buf), "%s %s", buf, ncp->plot.title); \
+        ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, NCPREFIXCOLUMNS - strlen(buf), "%s %s", buf, ncp->plot.title); \
       }else{ \
-        ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, PREFIXCOLUMNS - strlen(buf), "%s", buf); \
+        ncplane_printf_yx(ncp->plot.ncp, dimy - y - 1, NCPREFIXCOLUMNS - strlen(buf), "%s", buf); \
       } \
     } \
   }else if(strlen(ncp->plot.title)){ \
     ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[dimy - 1]); \
-    ncplane_printf_yx(ncp->plot.ncp, 0, PREFIXCOLUMNS - strlen(ncp->plot.title), "%s", ncp->plot.title); \
+    ncplane_printf_yx(ncp->plot.ncp, 0, NCPREFIXCOLUMNS - strlen(ncp->plot.title), "%s", ncp->plot.title); \
   } \
   ncplane_set_styles(ncp->plot.ncp, NCSTYLE_NONE); \
-  if(finalx < startx){ /* exit on pathologically narrow planes */ \
+  if((int)finalx < startx){ /* exit on pathologically narrow planes */ \
     return 0; \
   } \
   if(!interval){ \
@@ -346,13 +346,13 @@ int redraw_plot_##T(nc##X##plot* ncp){ \
     T intervalbase = ncp->miny; \
     const wchar_t* egc = ncp->plot.bset->plotegcs; \
     bool done = !ncp->plot.bset->fill; \
-    for(int y = 0 ; y < dimy ; ++y){ \
+    for(unsigned y = 0 ; y < dimy ; ++y){ \
       ncplane_set_channels(ncp->plot.ncp, ncp->plot.channels[y]); \
       size_t egcidx = 0, sumidx = 0; \
       /* if we've got at least one interval's worth on the number of positions \
         times the number of intervals per position plus the starting offset, \
         we're going to print *something* */ \
-      for(int i = 0 ; i < scale ; ++i){ \
+      for(unsigned i = 0 ; i < scale ; ++i){ \
         sumidx *= states; \
         if(intervalbase < gvals[i]){ \
           if(ncp->plot.exponentiali){ \
@@ -470,19 +470,19 @@ create_##T(nc##X##plot* ncpp, ncplane* n, const ncplot_options* opts, const T mi
     ncplane_destroy(n); \
     return NULL; \
   } \
-  int sdimy, sdimx; \
+  unsigned sdimy, sdimx; \
   ncplane_dim_yx(n, &sdimy, &sdimx); \
   if(sdimx <= 0){ \
     ncplane_destroy(n); \
     return NULL; \
   } \
-  int dimx = sdimx; \
+  unsigned dimx = sdimx; \
   ncpp->plot.title = strdup(opts->title ? opts->title : ""); \
   ncpp->plot.rangex = opts->rangex; \
   /* if we're sizing the plot based off the plane dimensions, scale it by the \
      plot geometry's width for all calculations */ \
   const unsigned scaleddim = dimx * (bset->geom == NCBLIT_PIXEL ? ncplane_notcurses(n)->tcache.cellpixx : bset->width); \
-  const unsigned scaledprefixlen = PREFIXCOLUMNS * (bset->geom == NCBLIT_PIXEL ? ncplane_notcurses(n)->tcache.cellpixx : bset->width); \
+  const unsigned scaledprefixlen = NCPREFIXCOLUMNS * (bset->geom == NCBLIT_PIXEL ? ncplane_notcurses(n)->tcache.cellpixx : bset->width); \
   if((ncpp->plot.slotcount = ncpp->plot.rangex) == 0){ \
     ncpp->plot.slotcount = scaleddim; \
   } \
diff --git a/src/lib/progbar.c b/src/lib/progbar.c
index e4c7ac2001..6c7a3fdf99 100644
--- a/src/lib/progbar.c
+++ b/src/lib/progbar.c
@@ -48,7 +48,7 @@ static int
 progbar_redraw(ncprogbar* n){
   struct ncplane* ncp = ncprogbar_plane(n);
   // get current dimensions; they might have changed
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(ncp, &dimy, &dimx);
   const bool horizontal = dimx > dimy;
   int range, delt, pos;
@@ -83,11 +83,11 @@ progbar_redraw(ncprogbar* n){
   }
   ncplane_home(ncp);
   if(notcurses_canutf8(ncplane_notcurses(ncp))){
-    if(ncplane_highgradient(ncp, ul, ur, bl, br, dimy - 1, dimx - 1) <= 0){
+    if(ncplane_gradient2x1(ncp, -1, -1, 0, 0, ul, ur, bl, br) <= 0){
       return -1;
     }
   }else{
-    if(ncplane_gradient(ncp, " ", 0, ul, ur, bl, br, dimy - 1, dimx - 1) <= 0){
+    if(ncplane_gradient(ncp, -1, -1, 0, 0, " ", 0, ul, ur, bl, br) <= 0){
       return -1;
     }
   }
@@ -117,7 +117,7 @@ progbar_redraw(ncprogbar* n){
   const int egcidx = (int)(chunk / (eachcell / 8));
   const char* egc = egcs + egcidx * 5;
   if(horizontal){
-    for(int freepos = 0 ; freepos < dimy ; ++freepos){
+    for(unsigned freepos = 0 ; freepos < dimy ; ++freepos){
       if(notcurses_canutf8(ncplane_notcurses(ncp))){
         nccell* c = ncplane_cell_ref_yx(ncp, freepos, pos);
         if(pool_blit_direct(&ncp->pool, c, egc, strlen(egc), 1) <= 0){
@@ -131,7 +131,7 @@ progbar_redraw(ncprogbar* n){
       }
     }
   }else{
-    for(int freepos = 0 ; freepos < dimx ; ++freepos){
+    for(unsigned freepos = 0 ; freepos < dimx ; ++freepos){
       if(notcurses_canutf8(ncplane_notcurses(ncp))){
         nccell* c = ncplane_cell_ref_yx(ncp, pos, freepos);
         if(pool_blit_direct(&ncp->pool, c, egc, strlen(egc), 1) <= 0){
@@ -149,13 +149,13 @@ progbar_redraw(ncprogbar* n){
   pos += delt;
   while(pos >= 0 && pos < range){
     if(horizontal){
-      for(int freepos = 0 ; freepos < dimy ; ++freepos){
+      for(unsigned freepos = 0 ; freepos < dimy ; ++freepos){
         nccell* c = ncplane_cell_ref_yx(ncp, freepos, pos);
         nccell_release(ncp, c);
         nccell_init(c);
       }
     }else{
-      for(int freepos = 0 ; freepos < dimx ; ++freepos){
+      for(unsigned freepos = 0 ; freepos < dimx ; ++freepos){
         nccell* c = ncplane_cell_ref_yx(ncp, pos, freepos);
         nccell_release(ncp, c);
         nccell_init(c);
diff --git a/src/lib/reader.c b/src/lib/reader.c
index cda56647f7..a06a76d53e 100644
--- a/src/lib/reader.c
+++ b/src/lib/reader.c
@@ -61,10 +61,10 @@ ncreader_redraw(ncreader* n){
   assert(n->xproject >= 0);
   assert(n->textarea->lenx >= n->ncp->lenx);
   assert(n->textarea->leny >= n->ncp->leny);
-  for(int y = 0 ; y < n->ncp->leny ; ++y){
-    const int texty = y;
-    for(int x = 0 ; x < n->ncp->lenx ; ++x){
-      const int textx = x + n->xproject;
+  for(unsigned y = 0 ; y < n->ncp->leny ; ++y){
+    const unsigned texty = y;
+    for(unsigned x = 0 ; x < n->ncp->lenx ; ++x){
+      const unsigned textx = x + n->xproject;
       const nccell* src = &n->textarea->fb[nfbcellidx(n->textarea, texty, textx)];
       nccell* dst = &n->ncp->fb[nfbcellidx(n->ncp, y, x)];
 //fprintf(stderr, "projecting %d/%d [%s] to %d/%d [%s]\n", texty, textx, cell_extended_gcluster(n->textarea, src), y, x, cell_extended_gcluster(n->ncp, dst));
@@ -121,9 +121,9 @@ int ncreader_move_left(ncreader* n){
 // row. if on the right side of the viewarea, but not the right side of the
 // textarea, pans right. returns 0 if a move was made.
 int ncreader_move_right(ncreader* n){
-  int viewx = n->ncp->x;
-  int textx = n->textarea->x;
-  int y = n->ncp->y;
+  unsigned textx = n->textarea->x;
+  unsigned y = n->ncp->y;
+  unsigned viewx = n->ncp->x;
 //fprintf(stderr, "moving right: tcurs: %dx%d vcurs: %dx%d xproj: %d\n", y, textx, y, viewx, n->xproject);
   if(textx >= n->textarea->lenx - 1){
     // are we on the last column of the textarea? if so, we must also be on
@@ -171,7 +171,7 @@ int ncreader_move_up(ncreader* n){
 // try to move down. does not move past the bottom of the textarea.
 // returns 0 if a move was made.
 int ncreader_move_down(ncreader* n){
-  int y = n->ncp->y;
+  unsigned y = n->ncp->y;
   if(y >= n->textarea->leny - 1){
     // are we on the last row of the textarea? if so, we can't move.
     return -1;
diff --git a/src/lib/reel.c b/src/lib/reel.c
index f036067ea9..a4ab71cdde 100644
--- a/src/lib/reel.c
+++ b/src/lib/reel.c
@@ -114,8 +114,7 @@ typedef enum {
 
 static int
 draw_borders(ncplane* n, unsigned mask, uint64_t channel, direction_e direction){
-  int lenx, leny;
-  int ret = 0;
+  unsigned lenx, leny;
   ncplane_dim_yx(n, &leny, &lenx);
   int maxx = lenx - 1;
   int maxy = leny - 1;
@@ -142,6 +141,7 @@ draw_borders(ncplane* n, unsigned mask, uint64_t channel, direction_e direction)
   // we're left following the previous stanza, end based on maxhorizy.
   const bool candrawbottom = y <= maxy || direction == DIRECTION_UP || (mask & NCBOXMASK_TOP);
   const int maxhorizy = maxy - (candrawbottom && !(mask & NCBOXMASK_BOTTOM));
+  int ret = 0;
   while(y <= maxhorizy){
     if(!(mask & NCBOXMASK_LEFT)){
       ret |= ncplane_cursor_move_yx(n, y, 0);
@@ -186,7 +186,10 @@ tablet_geom(const ncreel* nr, nctablet* t, int* begx, int* begy,
 //fprintf(stderr, "jigsawing %p with %d/%d dir %d\n", t, frontiertop, frontierbottom, direction);
   *begy = 0;
   *begx = 0;
-  ncplane_dim_yx(nr->p, leny, lenx);
+  unsigned uleny, ulenx;
+  ncplane_dim_yx(nr->p, &uleny, &ulenx);
+  *leny = uleny;
+  *lenx = ulenx;
   if(frontiertop < 0){
     if(direction == DIRECTION_UP){
       return -1;
@@ -412,7 +415,7 @@ trim_reel_overhang(ncreel* r, nctablet* top, nctablet* bottom){
   }
 //fprintf(stderr, "trimming: top %p bottom %p\n", top->p, bottom->p);
   ncplane_yx(top->p, &y, NULL);
-  int ylen, xlen;
+  unsigned ylen, xlen;
   ncplane_dim_yx(top->p, &ylen, &xlen);
   const int miny = !(r->ropts.bordermask & NCBOXMASK_TOP);
   int boty = y + ylen - 1;
@@ -501,14 +504,15 @@ tighten_reel_down(ncreel* r, int ybot){
     if(cur->p == NULL){
       break;
     }
-    int cury, curx, ylen;
+    int cury, curx;
+    unsigned ylen;
     ncplane_yx(cur->p, &cury, &curx);
     ncplane_dim_yx(cur->p, &ylen, NULL);
-    if(cury <= ybot - ylen - 1){
+    if(cury <= ybot - (int)ylen - 1){
       break;
     }
 //fprintf(stderr, "tightening %p down to %d from %d\n", cur, ybot - ylen, cury);
-    cury = ybot - ylen;
+    cury = ybot - (int)ylen;
     ncplane_move_yx(cur->p, cury, curx);
     ybot = cury - 1;
     if((cur = cur->prev) == r->tablets){
@@ -559,7 +563,7 @@ tighten_reel(ncreel* r){
         return -1;
       }
     }
-    int ylen;
+    unsigned ylen;
     ncplane_dim_yx(cur->p, &ylen, NULL);
     expected += ylen + 1;
 //fprintf(stderr, "bottom (%p) gets %p\n", bottom, cur);
@@ -572,14 +576,15 @@ tighten_reel(ncreel* r){
   cur = r->tablets;
   if(cur){
     const ncplane* n = cur->p;
-    int yoff, ylen, rylen;
+    int yoff;
+    unsigned ylen, rylen;
     ncplane_dim_yx(r->p, &rylen, NULL);
     ncplane_yx(n, &yoff, NULL);
     ncplane_dim_yx(n, &ylen, NULL);
     const int ybot = rylen - 1 + !!(r->ropts.bordermask & NCBOXMASK_BOTTOM);
     // FIXME want to tighten down whenever we're at the bottom, and the reel
     // is full, not just in this case (this can leave a gap of more than 1 row)
-    if(yoff + ylen + 1 >= ybot){
+    if(yoff + (int)ylen + 1 >= ybot){
       if(tighten_reel_down(r, ybot)){
         return -1;
       }
diff --git a/src/lib/render.c b/src/lib/render.c
index 51c62f29cf..0fd160d04f 100644
--- a/src/lib/render.c
+++ b/src/lib/render.c
@@ -9,7 +9,7 @@
 // two. new areas are initialized to empty, just like a new plane. lost areas
 // have their egcpool entries purged.
 static nccell*
-restripe_lastframe(notcurses* nc, int rows, int cols){
+restripe_lastframe(notcurses* nc, unsigned rows, unsigned cols){
   assert(rows);
   assert(cols);
   const size_t size = sizeof(*nc->lastframe) * (rows * cols);
@@ -21,7 +21,7 @@ restripe_lastframe(notcurses* nc, int rows, int cols){
   size_t maxlinecopy = sizeof(nccell) * copycols;
   size_t minlineset = sizeof(nccell) * cols - maxlinecopy;
   unsigned zorch = nc->lfdimx > cols ? nc->lfdimx - cols : 0;
-  for(int y = 0 ; y < rows ; ++y){
+  for(unsigned y = 0 ; y < rows ; ++y){
     if(y < nc->lfdimy){
       if(maxlinecopy){
         memcpy(&tmp[cols * y], &nc->lastframe[nc->lfdimx * y], maxlinecopy);
@@ -40,8 +40,8 @@ restripe_lastframe(notcurses* nc, int rows, int cols){
     }
   }
   // excise any egcpool entries from below the new plane area
-  for(int y = rows ; y < nc->lfdimy ; ++y){
-    for(int x = 0 ; x < nc->lfdimx ; ++x){
+  for(unsigned y = rows ; y < nc->lfdimy ; ++y){
+    for(unsigned x = 0 ; x < nc->lfdimx ; ++x){
       pool_release(&nc->pool, &nc->lastframe[fbcellidx(y, nc->lfdimx, x)]);
     }
   }
@@ -57,9 +57,9 @@ restripe_lastframe(notcurses* nc, int rows, int cols){
 // at the same origin. Initiates a resize cascade for the pile containing |pp|.
 // The current terminal geometry, changed or not, is written to |rows|/|cols|.
 static int
-notcurses_resize_internal(ncplane* pp, int* restrict rows, int* restrict cols){
+notcurses_resize_internal(ncplane* pp, unsigned* restrict rows, unsigned* restrict cols){
   notcurses* n = ncplane_notcurses(pp);
-  int r, c;
+  unsigned r, c;
   if(rows == NULL){
     rows = &r;
   }
@@ -67,8 +67,8 @@ notcurses_resize_internal(ncplane* pp, int* restrict rows, int* restrict cols){
     cols = &c;
   }
   ncpile* pile = ncplane_pile(pp);
-  int oldrows = pile->dimy;
-  int oldcols = pile->dimx;
+  unsigned oldrows = pile->dimy;
+  unsigned oldcols = pile->dimx;
   *rows = oldrows;
   *cols = oldcols;
   if(update_term_dimensions(rows, cols, &n->tcache, n->margin_b)){
@@ -111,7 +111,7 @@ notcurses_resize_internal(ncplane* pp, int* restrict rows, int* restrict cols){
 
 // Check for a window resize on the standard pile.
 static int
-notcurses_resize(notcurses* n, int* restrict rows, int* restrict cols){
+notcurses_resize(notcurses* n, unsigned* restrict rows, unsigned* restrict cols){
   pthread_mutex_lock(&n->pilelock);
   int ret = notcurses_resize_internal(notcurses_stdplane(n), rows, cols);
   pthread_mutex_unlock(&n->pilelock);
@@ -239,13 +239,14 @@ __attribute__ ((nonnull (1, 2, 7)))
 static void
 paint(ncplane* p, struct crender* rvec, int dstleny, int dstlenx,
       int dstabsy, int dstabsx, sprixel** sprixelstack){
-  int y, x, dimy, dimx, offy, offx;
+  unsigned y, x, dimy, dimx;
+  int offy, offx;
   ncplane_dim_yx(p, &dimy, &dimx);
   offy = p->absy - dstabsy;
   offx = p->absx - dstabsx;
 //fprintf(stderr, "PLANE %p %d %d %d %d %d %d %p\n", p, dimy, dimx, offy, offx, dstleny, dstlenx, p->sprite);
   // skip content above or to the left of the physical screen
-  int starty, startx;
+  unsigned starty, startx;
   if(offy < 0){
     starty = -offy;
   }else{
@@ -526,21 +527,43 @@ postpaint(const tinfo* ti, nccell* lastframe, int dimy, int dimx,
 // merging one plane down onto another is basically just performing a render
 // using only these two planes, with the result written to the lower plane.
 int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst,
-                      unsigned begsrcy, unsigned begsrcx,
-                      unsigned leny, unsigned lenx,
-                      unsigned dsty, unsigned dstx){
+                      int begsrcy, int begsrcx, unsigned leny, unsigned lenx,
+                      int dsty, int dstx){
 //fprintf(stderr, "Merging down %d/%d @ %d/%d to %d/%d\n", leny, lenx, begsrcy, begsrcx, dsty, dstx);
-  if(dsty >= (unsigned)dst->leny || dstx >= (unsigned)dst->lenx){
+  if(dsty < 0){
+    if(dsty != -1){
+      logerror("invalid dsty %d\n", dsty);
+      return -1;
+    }
+    dsty = dst->y;
+  }
+  if(dstx < 0){
+    if(dstx != -1){
+      logerror("invalid dstx %d\n", dstx);
+      return -1;
+    }
+    dstx = dst->x;
+  }
+  if((unsigned)dsty >= dst->leny || (unsigned)dstx >= dst->lenx){
     logerror("dest origin %u/%u ≥ dest dimensions %d/%d\n",
              dsty, dstx, dst->leny, dst->lenx);
     return -1;
   }
-  if(dst->leny - leny < dsty || dst->lenx - lenx < dstx){
-    logerror("dest len %u/%u ≥ dest dimensions %d/%d\n",
-             leny, lenx, dst->leny, dst->lenx);
-    return -1;
+  if(begsrcy < 0){
+    if(begsrcy != -1){
+      logerror("invalid begsrcy %d\n", begsrcy);
+      return -1;
+    }
+    begsrcy = src->y;
+  }
+  if(begsrcx < 0){
+    if(begsrcx != -1){
+      logerror("invalid begsrcx %d\n", begsrcx);
+      return -1;
+    }
+    begsrcx = src->x;
   }
-  if(begsrcy >= (unsigned)src->leny || begsrcx >= (unsigned)src->lenx){
+  if((unsigned)begsrcy >= src->leny || (unsigned)begsrcx >= src->lenx){
     logerror("source origin %u/%u ≥ source dimensions %d/%d\n",
              begsrcy, begsrcx, src->leny, src->lenx);
     return -1;
@@ -557,7 +580,12 @@ int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst,
       return -1;
     }
   }
-  if(src->leny - leny < begsrcy || src->lenx - lenx < begsrcx){
+  if(dst->leny - leny < (unsigned)dsty || dst->lenx - lenx < (unsigned)dstx){
+    logerror("dest len %u/%u ≥ dest dimensions %d/%d\n",
+             leny, lenx, dst->leny, dst->lenx);
+    return -1;
+  }
+  if(src->leny - leny < (unsigned)begsrcy || src->lenx - lenx < (unsigned)begsrcx){
     logerror("source len %u/%u ≥ source dimensions %d/%d\n",
              leny, lenx, src->leny, src->lenx);
     return -1;
@@ -931,14 +959,14 @@ clean_sprixels(notcurses* nc, ncpile* p, fbuf* f, int scrolls){
 
 // scroll the lastframe data |rows| up, to reflect scrolling reality
 static void
-scroll_lastframe(notcurses* nc, int rows){
+scroll_lastframe(notcurses* nc, unsigned rows){
   // the top |rows| rows need be released (though not more than the actual
   // number of rows!)
   if(rows > nc->lfdimy){
     rows = nc->lfdimy;
   }
-  for(int targy = 0 ; targy < rows ; ++targy){
-    for(int targx = 0 ; targx < nc->lfdimx ; ++targx){
+  for(unsigned targy = 0 ; targy < rows ; ++targy){
+    for(unsigned targx = 0 ; targx < nc->lfdimx ; ++targx){
       const size_t damageidx = targy * nc->lfdimx + targx;
       nccell* c = &nc->lastframe[damageidx];
       pool_release(&nc->pool, c);
@@ -947,7 +975,7 @@ scroll_lastframe(notcurses* nc, int rows){
   // now for all rows subsequent, up through lfdimy - rows, move them back.
   // if we scrolled all rows, we will not move anything (and we just
   // released everything).
-  for(int targy = 0 ; targy < nc->lfdimy - rows ; ++targy){
+  for(unsigned targy = 0 ; targy < nc->lfdimy - rows ; ++targy){
     const size_t dstidx = targy * nc->lfdimx;
     nccell* dst = &nc->lastframe[dstidx];
     const size_t srcidx = dstidx + rows * nc->lfdimx;
@@ -955,7 +983,7 @@ scroll_lastframe(notcurses* nc, int rows){
     memcpy(dst, src, sizeof(*dst) * nc->lfdimx);
   }
   // now for the last |rows| rows, initialize them to 0.
-  int targy = nc->lfdimy - rows;
+  unsigned targy = nc->lfdimy - rows;
   while(targy < nc->lfdimy){
     const size_t dstidx = targy * nc->lfdimx;
     nccell* dst = &nc->lastframe[dstidx];
@@ -1093,9 +1121,9 @@ rasterize_core(notcurses* nc, const ncpile* p, fbuf* f, unsigned phase){
   struct crender* rvec = p->crender;
   // we only need to emit a coordinate if it was damaged. the damagemap is a
   // bit per coordinate, one per struct crender.
-  for(int y = nc->margin_t; y < p->dimy + nc->margin_t ; ++y){
+  for(unsigned y = nc->margin_t; y < p->dimy + nc->margin_t ; ++y){
     const int innery = y - nc->margin_t;
-    for(int x = nc->margin_l ; x < p->dimx + nc->margin_l ; ++x){
+    for(unsigned x = nc->margin_l ; x < p->dimx + nc->margin_l ; ++x){
       const int innerx = x - nc->margin_l;
       const size_t damageidx = innery * nc->lfdimx + innerx;
       unsigned r, g, b, br, bg, bb;
@@ -1361,7 +1389,7 @@ int clear_and_home(notcurses* nc, tinfo* ti, fbuf* f){
 }
 
 // FIXME need to work with the most recently-rendered pile, no?
-int notcurses_refresh(notcurses* nc, int* restrict dimy, int* restrict dimx){
+int notcurses_refresh(notcurses* nc, unsigned* restrict dimy, unsigned* restrict dimx){
   if(notcurses_resize(nc, dimy, dimx)){
     return -1;
   }
@@ -1406,15 +1434,15 @@ int ncpile_render_to_file(ncplane* n, FILE* fp){
   if(fbuf_init(&f)){
     return -1;
   }
-  const int count = (nc->lfdimx > p->dimx ? nc->lfdimx : p->dimx) *
-                    (nc->lfdimy > p->dimy ? nc->lfdimy : p->dimy);
+  const unsigned count = (nc->lfdimx > p->dimx ? nc->lfdimx : p->dimx) *
+                         (nc->lfdimy > p->dimy ? nc->lfdimy : p->dimy);
   p->crender = malloc(count * sizeof(*p->crender));
   if(p->crender == NULL){
     fbuf_free(&f);
     return -1;
   }
   init_rvec(p->crender, count);
-  for(int i = 0 ; i < count ; ++i){
+  for(unsigned i = 0 ; i < count ; ++i){
     p->crender[i].s.damaged = 1;
   }
   int ret = raster_and_write(nc, p, &f);
@@ -1575,27 +1603,31 @@ pool_egc_copy(const egcpool* e, const nccell* c){
   return strdup(egcpool_extended_gcluster(e, c));
 }
 
-char* notcurses_at_yx(notcurses* nc, int yoff, int xoff, uint16_t* stylemask, uint64_t* channels){
-  char* egc = NULL;
-  if(nc->lastframe){
-    if(yoff >= 0 && yoff < nc->lfdimy){
-      if(xoff >= 0 || xoff < nc->lfdimx){
-        const nccell* srccell = &nc->lastframe[yoff * nc->lfdimx + xoff];
-        if(nccell_wide_right_p(srccell)){
-          return notcurses_at_yx(nc, yoff, xoff - 1, stylemask, channels);
-        }
-        if(stylemask){
-          *stylemask = srccell->stylemask;
-        }
-        if(channels){
-          *channels = srccell->channels;
-        }
-//fprintf(stderr, "COPYING: %d from %p\n", srccell->gcluster, &nc->pool);
-        egc = pool_egc_copy(&nc->pool, srccell);
-      }
-    }
+char* notcurses_at_yx(notcurses* nc, unsigned yoff, unsigned xoff, uint16_t* stylemask, uint64_t* channels){
+  if(nc->lastframe == NULL){
+    logerror("haven't yet rendered\n");
+    return NULL;
   }
-  return egc;
+  if(yoff >= nc->lfdimy){
+    logerror("invalid coordinates: %u/%u\n", yoff, xoff);
+    return NULL;
+  }
+  if(xoff >= nc->lfdimx){
+    logerror("invalid coordinates: %u/%u\n", yoff, xoff);
+    return NULL;
+  }
+  const nccell* srccell = &nc->lastframe[yoff * nc->lfdimx + xoff];
+  if(nccell_wide_right_p(srccell)){
+    return notcurses_at_yx(nc, yoff, xoff - 1, stylemask, channels);
+  }
+  if(stylemask){
+    *stylemask = srccell->stylemask;
+  }
+  if(channels){
+    *channels = srccell->channels;
+  }
+//fprintf(stderr, "COPYING: %d from %p\n", srccell->gcluster, &nc->pool);
+  return pool_egc_copy(&nc->pool, srccell);
 }
 
 int ncdirect_set_bg_rgb_f(ncdirect* nc, unsigned rgb, fbuf* f){
diff --git a/src/lib/selector.c b/src/lib/selector.c
index d3992f8941..b529752282 100644
--- a/src/lib/selector.c
+++ b/src/lib/selector.c
@@ -19,16 +19,16 @@ typedef struct ncselector {
   unsigned selected;             // index of selection
   unsigned startdisp;            // index of first option displayed
   unsigned maxdisplay;           // max number of items to display, 0 -> no limit
-  int longop;                    // columns occupied by longest option
-  int longdesc;                  // columns occupied by longest description
+  unsigned longop;               // columns occupied by longest option
+  unsigned longdesc;             // columns occupied by longest description
   struct ncselector_int* items;  // list of items and descriptions, heap-copied
   unsigned itemcount;            // number of pairs in 'items'
   char* title;                   // can be NULL, in which case there's no riser
-  int titlecols;                 // columns occupied by title
+  unsigned titlecols;            // columns occupied by title
   char* secondary;               // can be NULL
-  int secondarycols;             // columns occupied by secondary
+  unsigned secondarycols;        // columns occupied by secondary
   char* footer;                  // can be NULL
-  int footercols;                // columns occupied by footer
+  unsigned footercols;           // columns occupied by footer
   uint64_t opchannels;           // option channels
   uint64_t descchannels;         // description channels
   uint64_t titlechannels;        // title channels
@@ -42,15 +42,15 @@ typedef struct ncmultiselector {
   unsigned current;               // index of highlighted item
   unsigned startdisp;             // index of first option displayed
   unsigned maxdisplay;            // max number of items to display, 0 -> no limit
-  int longitem;                   // columns occupied by longest item
+  unsigned longitem;              // columns occupied by longest item
   struct ncmselector_int* items;  // items, descriptions, and statuses, heap-copied
   unsigned itemcount;             // number of pairs in 'items'
   char* title;                    // can be NULL, in which case there's no riser
-  int titlecols;                  // columns occupied by title
+  unsigned titlecols;             // columns occupied by title
   char* secondary;                // can be NULL
-  int secondarycols;              // columns occupied by secondary
+  unsigned secondarycols;         // columns occupied by secondary
   char* footer;                   // can be NULL
-  int footercols;                 // columns occupied by footer
+  unsigned footercols;            // columns occupied by footer
   uint64_t opchannels;            // option channels
   uint64_t descchannels;          // description channels
   uint64_t titlechannels;         // title channels
@@ -62,7 +62,7 @@ typedef struct ncmultiselector {
 // ideal body width given the ncselector's items and secondary/footer
 static int
 ncselector_body_width(const ncselector* n){
-  int cols = 0;
+  unsigned cols = 0;
   // the body is the maximum of
   //  * longop + longdesc + 5
   //  * secondary + 2
@@ -94,21 +94,25 @@ ncselector_draw(ncselector* n){
     size_t riserwidth = n->titlecols + 4;
     int offx = ncplane_halign(n->ncp, NCALIGN_RIGHT, riserwidth);
     ncplane_cursor_move_yx(n->ncp, 0, 0);
-    ncplane_hline(n->ncp, &transchar, offx);
+    if(offx){
+      ncplane_hline(n->ncp, &transchar, offx);
+    }
     ncplane_cursor_move_yx(n->ncp, 0, offx);
     ncplane_rounded_box_sized(n->ncp, 0, n->boxchannels, 3, riserwidth, 0);
     n->ncp->channels = n->titlechannels;
     ncplane_printf_yx(n->ncp, 1, offx + 1, " %s ", n->title);
     yoff += 2;
     ncplane_cursor_move_yx(n->ncp, 1, 0);
-    ncplane_hline(n->ncp, &transchar, offx);
+    if(offx){
+      ncplane_hline(n->ncp, &transchar, offx);
+    }
   }
-  int bodywidth = ncselector_body_width(n);
-  int dimy, dimx;
+  unsigned bodywidth = ncselector_body_width(n);
+  unsigned dimy, dimx;
   ncplane_dim_yx(n->ncp, &dimy, &dimx);
   int xoff = ncplane_halign(n->ncp, NCALIGN_RIGHT, bodywidth);
   if(xoff){
-    for(int y = yoff + 1 ; y < dimy ; ++y){
+    for(unsigned y = yoff + 1 ; y < dimy ; ++y){
       ncplane_cursor_move_yx(n->ncp, y, 0);
       ncplane_hline(n->ncp, &transchar, xoff);
     }
@@ -158,7 +162,7 @@ ncselector_draw(ncselector* n){
   // Top line of body (background and possibly up arrow)
   ++yoff;
   ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
-  for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
+  for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
     nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
     ncplane_putc(n->ncp, &transc);
   }
@@ -177,12 +181,12 @@ ncselector_draw(ncselector* n){
   n->uarrowy = yoff;
   unsigned printidx = n->startdisp;
   unsigned printed = 0;
-  for(yoff += 1 ; yoff < dimy - 2 ; ++yoff){
+  for(yoff += 1 ; yoff < (int)dimy - 2 ; ++yoff){
     if(n->maxdisplay && printed == n->maxdisplay){
       break;
     }
     ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
-    for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
+    for(int i = xoff + 1 ; i < (int)dimx - 1 ; ++i){
       nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
       ncplane_putc(n->ncp, &transc);
     }
@@ -203,7 +207,7 @@ ncselector_draw(ncselector* n){
   }
   // Bottom line of body (background and possibly down arrow)
   ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
-  for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
+  for(int i = xoff + 1 ; i < (int)dimx - 1 ; ++i){
     nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
     ncplane_putc(n->ncp, &transc);
   }
@@ -221,10 +225,10 @@ ncselector_draw(ncselector* n){
 
 // calculate the necessary dimensions based off properties of the selector
 static void
-ncselector_dim_yx(const ncselector* n, int* ncdimy, int* ncdimx){
-  int rows = 0, cols = 0; // desired dimensions
-  int dimy, dimx; // dimensions of containing screen
+ncselector_dim_yx(const ncselector* n, unsigned* ncdimy, unsigned* ncdimx){
+  unsigned rows = 0, cols = 0; // desired dimensions
   const ncplane* parent = ncplane_parent(n->ncp);
+  unsigned dimy, dimx; // dimensions of containing plane
   ncplane_dim_yx(parent, &dimy, &dimx);
   if(n->title){ // header adds two rows for riser
     rows += 2;
@@ -301,13 +305,21 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
   }
   for(ns->itemcount = 0 ; ns->itemcount < itemcount ; ++ns->itemcount){
     const struct ncselector_item* src = &opts->items[ns->itemcount];
-    int cols = ncstrwidth(src->option);
+    int unsafe = ncstrwidth(src->option);
+    if(unsafe < 0){
+      goto freeitems;
+    }
+    unsigned cols = unsafe;
     ns->items[ns->itemcount].opcolumns = cols;
     if(cols > ns->longop){
       ns->longop = cols;
     }
     const char *desc = src->desc ? src->desc : "";
-    cols = ncstrwidth(desc);
+    unsafe = ncstrwidth(desc);
+    if(unsafe < 0){
+      goto freeitems;
+    }
+    cols = unsafe;
     ns->items[ns->itemcount].desccolumns = cols;
     if(cols > ns->longdesc){
       ns->longdesc = cols;
@@ -320,7 +332,7 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
       goto freeitems;
     }
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ns->ncp = n;
   ncselector_dim_yx(ns, &dimy, &dimx);
   if(ncplane_resize_simple(n, dimy, dimx)){
@@ -343,7 +355,7 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
 }
 
 int ncselector_additem(ncselector* n, const struct ncselector_item* item){
-  int origdimy, origdimx;
+  unsigned origdimy, origdimx;
   ncselector_dim_yx(n, &origdimy, &origdimx);
   size_t newsize = sizeof(*n->items) * (n->itemcount + 1);
   struct ncselector_int* items = realloc(n->items, newsize);
@@ -354,7 +366,11 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
   n->items[n->itemcount].option = strdup(item->option);
   const char *desc = item->desc ? item->desc : "";
   n->items[n->itemcount].desc = strdup(desc);
-  int cols = ncstrwidth(item->option);
+  int usafecols = ncstrwidth(item->option);
+  if(usafecols < 0){
+    return -1;
+  }
+  unsigned cols = usafecols;
   n->items[n->itemcount].opcolumns = cols;
   if(cols > n->longop){
     n->longop = cols;
@@ -365,7 +381,7 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
     n->longdesc = cols;
   }
   ++n->itemcount;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncselector_dim_yx(n, &dimy, &dimx);
   if(origdimx < dimx || origdimy < dimy){ // resize if too small
     ncplane_resize_simple(n->ncp, dimy, dimx);
@@ -374,7 +390,7 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
 }
 
 int ncselector_delitem(ncselector* n, const char* item){
-  int origdimy, origdimx;
+  unsigned origdimy, origdimx;
   ncselector_dim_yx(n, &origdimy, &origdimx);
   bool found = false;
   int maxop = 0, maxdesc = 0;
@@ -406,7 +422,7 @@ int ncselector_delitem(ncselector* n, const char* item){
   if(found){
     n->longop = maxop;
     n->longdesc = maxdesc;
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncselector_dim_yx(n, &dimy, &dimx);
     if(origdimx > dimx || origdimy > dimy){ // resize if too big
       ncplane_resize_simple(n->ncp, dimy, dimx);
@@ -556,9 +572,9 @@ ncplane* ncmultiselector_plane(ncmultiselector* n){
 }
 
 // ideal body width given the ncselector's items and secondary/footer
-static int
+static unsigned
 ncmultiselector_body_width(const ncmultiselector* n){
-  int cols = 0;
+  unsigned cols = 0;
   // the body is the maximum of
   //  * longop + longdesc + 5
   //  * secondary + 2
@@ -585,25 +601,29 @@ ncmultiselector_draw(ncmultiselector* n){
   // if we have a title, we'll draw a riser. the riser is two rows tall, and
   // exactly four columns longer than the title, and aligned to the right. we
   // draw a rounded box. the body will blow part or all of the bottom away.
-  int yoff = 0;
+  unsigned yoff = 0;
   if(n->title){
     size_t riserwidth = n->titlecols + 4;
     int offx = ncplane_halign(n->ncp, NCALIGN_RIGHT, riserwidth);
     ncplane_cursor_move_yx(n->ncp, 0, 0);
-    ncplane_hline(n->ncp, &transchar, offx);
+    if(offx){
+      ncplane_hline(n->ncp, &transchar, offx);
+    }
     ncplane_rounded_box_sized(n->ncp, 0, n->boxchannels, 3, riserwidth, 0);
     n->ncp->channels = n->titlechannels;
     ncplane_printf_yx(n->ncp, 1, offx + 1, " %s ", n->title);
     yoff += 2;
     ncplane_cursor_move_yx(n->ncp, 1, 0);
-    ncplane_hline(n->ncp, &transchar, offx);
+    if(offx){
+      ncplane_hline(n->ncp, &transchar, offx);
+    }
   }
-  int bodywidth = ncmultiselector_body_width(n);
-  int dimy, dimx;
+  unsigned bodywidth = ncmultiselector_body_width(n);
+  unsigned dimy, dimx;
   ncplane_dim_yx(n->ncp, &dimy, &dimx);
   int xoff = ncplane_halign(n->ncp, NCALIGN_RIGHT, bodywidth);
   if(xoff){
-    for(int y = yoff + 1 ; y < dimy ; ++y){
+    for(unsigned y = yoff + 1 ; y < dimy ; ++y){
       ncplane_cursor_move_yx(n->ncp, y, 0);
       ncplane_hline(n->ncp, &transchar, xoff);
     }
@@ -641,7 +661,7 @@ ncmultiselector_draw(ncmultiselector* n){
   // Top line of body (background and possibly up arrow)
   ++yoff;
   ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
-  for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
+  for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
     nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
     ncplane_putc(n->ncp, &transc);
   }
@@ -662,7 +682,7 @@ ncmultiselector_draw(ncmultiselector* n){
       break;
     }
     ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
-    for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
+    for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
       nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
       ncplane_putc(n->ncp, &transc);
     }
@@ -692,7 +712,7 @@ ncmultiselector_draw(ncmultiselector* n){
   }
   // Bottom line of body (background and possibly down arrow)
   ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
-  for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
+  for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
     nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
     ncplane_putc(n->ncp, &transc);
   }
@@ -816,9 +836,9 @@ bool ncmultiselector_offer_input(ncmultiselector* n, const ncinput* nc){
 // calculate the necessary dimensions based off properties of the selector and
 // the containing plane
 static int
-ncmultiselector_dim_yx(const ncmultiselector* n, int* ncdimy, int* ncdimx){
-  int rows = 0, cols = 0; // desired dimensions
-  int dimy, dimx; // dimensions of containing screen
+ncmultiselector_dim_yx(const ncmultiselector* n, unsigned* ncdimy, unsigned* ncdimx){
+  unsigned rows = 0, cols = 0; // desired dimensions
+  unsigned dimy, dimx; // dimensions of containing screen
   ncplane_dim_yx(ncplane_parent(n->ncp), &dimy, &dimx);
   if(n->title){ // header adds two rows for riser
     rows += 2;
@@ -891,11 +911,19 @@ ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_option
   }
   for(ns->itemcount = 0 ; ns->itemcount < itemcount ; ++ns->itemcount){
     const struct ncmselector_item* src = &opts->items[ns->itemcount];
-    int cols = ncstrwidth(src->option);
+    int unsafe = ncstrwidth(src->option);
+    if(unsafe < 0){
+      goto freeitems;
+    }
+    unsigned cols = unsafe;
     if(cols > ns->longitem){
       ns->longitem = cols;
     }
-    int cols2 = ncstrwidth(src->desc);
+    unsafe = ncstrwidth(src->desc);
+    if(unsafe < 0){
+      goto freeitems;
+    }
+    unsigned cols2 = unsafe;
     if(cols + cols2 > ns->longitem){
       ns->longitem = cols + cols2;
     }
@@ -908,7 +936,7 @@ ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_option
       goto freeitems;
     }
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ns->ncp = n;
   if(ncmultiselector_dim_yx(ns, &dimy, &dimx)){
     goto freeitems;
diff --git a/src/lib/sixel.c b/src/lib/sixel.c
index 90b815e9fe..f7de3c308b 100644
--- a/src/lib/sixel.c
+++ b/src/lib/sixel.c
@@ -277,9 +277,9 @@ scrub_color_table(sprixel* s){
   if(s->n && s->n->tam){
     // we use the sprixel cell geometry rather than the plane's because this
     // is called during our initial blit, before we've resized the plane.
-    for(int y = 0 ; y < s->dimy ; ++y){
-      for(int x = 0 ; x < s->dimx ; ++x){
-        int txyidx = y * s->dimx + x;
+    for(unsigned y = 0 ; y < s->dimy ; ++y){
+      for(unsigned x = 0 ; x < s->dimx ; ++x){
+        unsigned txyidx = y * s->dimx + x;
         sprixcell_e state = s->n->tam[txyidx].state;
         if(state == SPRIXCELL_ANNIHILATED || state == SPRIXCELL_ANNIHILATED_TRANS){
 //fprintf(stderr, "POSTEXRACT WIPE %d/%d\n", y, x);
@@ -382,14 +382,14 @@ void sixel_refresh(const ncpile* p, sprixel* s){
   }
   int absy, absx;
   ncplane_abs_yx(s->n, &absy, &absx);
-  for(int y = 0 ; y < s->dimy ; ++y){
-    const int yy = absy + y;
-    for(int x = 0 ; x < s->dimx ; ++x){
-      int idx = y * s->dimx + x;
+  for(unsigned y = 0 ; y < s->dimy ; ++y){
+    const unsigned yy = absy + y;
+    for(unsigned x = 0 ; x < s->dimx ; ++x){
+      unsigned idx = y * s->dimx + x;
       if(s->needs_refresh[idx]){
-        const int xx = absx + x;
+        const unsigned xx = absx + x;
         if(xx < p->dimx && yy < p->dimy){
-          int ridx = yy * p->dimx + xx;
+          unsigned ridx = yy * p->dimx + xx;
           struct crender *r = &p->crender[ridx];
           r->s.damaged = 1;
         }
@@ -962,8 +962,8 @@ int sixel_scrub(const ncpile* p, sprixel* s){
   loginfo("%d state %d at %d/%d (%d/%d)\n", s->id, s->invalidated, s->movedfromy, s->movedfromx, s->dimy, s->dimx);
   int starty = s->movedfromy;
   int startx = s->movedfromx;
-  for(int yy = starty ; yy < starty + s->dimy && yy < p->dimy ; ++yy){
-    for(int xx = startx ; xx < startx + s->dimx && xx < p->dimx ; ++xx){
+  for(int yy = starty ; yy < starty + (int)s->dimy && yy < (int)p->dimy ; ++yy){
+    for(int xx = startx ; xx < startx + (int)s->dimx && xx < (int)p->dimx ; ++xx){
       int ridx = yy * p->dimx + xx;
       struct crender *r = &p->crender[ridx];
       if(!s->n){
@@ -972,11 +972,11 @@ int sixel_scrub(const ncpile* p, sprixel* s){
         continue;
       }
       sprixel* trues = r->sprixel ? r->sprixel : s;
-      if(yy >= trues->n->leny || yy - trues->n->absy < 0){
+      if(yy >= (int)trues->n->leny || yy - trues->n->absy < 0){
         r->s.damaged = 1;
         continue;
       }
-      if(xx >= trues->n->lenx || xx - trues->n->absx < 0){
+      if(xx >= (int)trues->n->lenx || xx - trues->n->absx < 0){
         r->s.damaged = 1;
         continue;
       }
@@ -1014,11 +1014,11 @@ int sixel_draw(const tinfo* ti, const ncpile* p, sprixel* s, fbuf* f,
       return -1;
     }
     if(s->invalidated == SPRIXEL_MOVED){
-      for(int yy = s->movedfromy ; yy < s->movedfromy + s->dimy && yy < p->dimy ; ++yy){
+      for(int yy = s->movedfromy ; yy < s->movedfromy + (int)s->dimy && yy < (int)p->dimy ; ++yy){
         if(yy < 0){
           continue;
         }
-        for(int xx = s->movedfromx ; xx < s->movedfromx + s->dimx && xx < p->dimx ; ++xx){
+        for(int xx = s->movedfromx ; xx < s->movedfromx + (int)s->dimx && xx < (int)p->dimx ; ++xx){
           if(xx < 0){
             continue;
           }
diff --git a/src/lib/sprite.c b/src/lib/sprite.c
index d3f5c890ee..93f67c6bfb 100644
--- a/src/lib/sprite.c
+++ b/src/lib/sprite.c
@@ -11,16 +11,16 @@ void sprixel_debug(const sprixel* s, FILE* out){
           s->invalidated);
   if(s->n){
     int idx = 0;
-    for(int y = 0 ; y < s->dimy ; ++y){
-      for(int x = 0 ; x < s->dimx ; ++x){
+    for(unsigned y = 0 ; y < s->dimy ; ++y){
+      for(unsigned x = 0 ; x < s->dimx ; ++x){
         fprintf(out, "%d", s->n->tam[idx].state);
         ++idx;
       }
       fprintf(out, "\n");
     }
     idx = 0;
-    for(int y = 0 ; y < s->dimy ; ++y){
-      for(int x = 0 ; x < s->dimx ; ++x){
+    for(unsigned y = 0 ; y < s->dimy ; ++y){
+      for(unsigned x = 0 ; x < s->dimx ; ++x){
         if(s->n->tam[idx].state == SPRIXCELL_ANNIHILATED){
           if(s->n->tam[idx].auxvector){
             fprintf(out, "%03d] %p\n", idx, s->n->tam[idx].auxvector);
@@ -153,7 +153,7 @@ sprixel* sprixel_alloc(const tinfo* ti, ncplane* n, int dimy, int dimx){
 // |pixy| and |pixx| are the output pixel geometry (i.e. |pixy| must be a
 // multiple of 6 for sixel). output coverage ought already have been loaded.
 // takes ownership of 's' on success. frees any existing glyph.
-int sprixel_load(sprixel* spx, fbuf* f, int pixy, int pixx,
+int sprixel_load(sprixel* spx, fbuf* f, unsigned pixy, unsigned pixx,
                  int parse_start, sprixel_e state){
   assert(spx->n);
   if(spx->cellpxy > 0){ // don't explode on ncdirect case
diff --git a/src/lib/sprite.h b/src/lib/sprite.h
index 7373fe4e6b..342f64db25 100644
--- a/src/lib/sprite.h
+++ b/src/lib/sprite.h
@@ -141,7 +141,7 @@ typedef struct sprixel {
   sprixel_e invalidated;// sprixel invalidation state
   struct sprixel* next;
   struct sprixel* prev;
-  int dimy, dimx;       // cell geometry
+  unsigned dimy, dimx;  // cell geometry
   int pixy, pixx;       // pixel geometry (might be smaller than cell geo)
   int cellpxy, cellpxx; // cell-pixel geometry at time of creation
   // each tacache entry is one of 0 (standard opaque cell), 1 (cell with
@@ -214,8 +214,8 @@ void fbcon_scroll(const struct ncpile* p, tinfo* ti, int rows);
 void sixel_refresh(const struct ncpile* p, sprixel* s);
 
 // takes ownership of s on success.
-int sprixel_load(sprixel* spx, fbuf* f, int pixy, int pixx, int parse_start,
-                 sprixel_e state);
+int sprixel_load(sprixel* spx, fbuf* f, unsigned pixy, unsigned pixx,
+                 int parse_start, sprixel_e state);
 
 #ifdef __cplusplus
 }
diff --git a/src/lib/stats.c b/src/lib/stats.c
index 559d41fa0b..eb8511a174 100644
--- a/src/lib/stats.c
+++ b/src/lib/stats.c
@@ -166,44 +166,44 @@ void summarize_stats(notcurses* nc){
     clreol = "";
   }
   const ncstats *stats = &nc->stashed_stats;
-  char totalbuf[BPREFIXSTRLEN + 1];
-  char minbuf[BPREFIXSTRLEN + 1];
-  char maxbuf[BPREFIXSTRLEN + 1];
-  char avgbuf[BPREFIXSTRLEN + 1];
+  char totalbuf[NCBPREFIXSTRLEN + 1];
+  char minbuf[NCBPREFIXSTRLEN + 1];
+  char maxbuf[NCBPREFIXSTRLEN + 1];
+  char avgbuf[NCBPREFIXSTRLEN + 1];
   if(stats->renders){
-    qprefix(stats->render_ns, NANOSECS_IN_SEC, totalbuf, 0);
-    qprefix(stats->render_min_ns, NANOSECS_IN_SEC, minbuf, 0);
-    qprefix(stats->render_max_ns, NANOSECS_IN_SEC, maxbuf, 0);
-    qprefix(stats->render_ns / stats->renders, NANOSECS_IN_SEC, avgbuf, 0);
+    ncqprefix(stats->render_ns, NANOSECS_IN_SEC, totalbuf, 0);
+    ncqprefix(stats->render_min_ns, NANOSECS_IN_SEC, minbuf, 0);
+    ncqprefix(stats->render_max_ns, NANOSECS_IN_SEC, maxbuf, 0);
+    ncqprefix(stats->render_ns / stats->renders, NANOSECS_IN_SEC, avgbuf, 0);
     fprintf(stderr, "%s%"PRIu64" render%s, %ss (%ss min, %ss avg, %ss max)" NL,
             clreol, stats->renders, stats->renders == 1 ? "" : "s",
             totalbuf, minbuf, avgbuf, maxbuf);
   }
   if(stats->writeouts || stats->failed_writeouts){
-    qprefix(stats->raster_ns, NANOSECS_IN_SEC, totalbuf, 0);
-    qprefix(stats->raster_min_ns, NANOSECS_IN_SEC, minbuf, 0);
-    qprefix(stats->raster_max_ns, NANOSECS_IN_SEC, maxbuf, 0);
-    qprefix(stats->raster_ns / (stats->writeouts + stats->failed_writeouts),
+    ncqprefix(stats->raster_ns, NANOSECS_IN_SEC, totalbuf, 0);
+    ncqprefix(stats->raster_min_ns, NANOSECS_IN_SEC, minbuf, 0);
+    ncqprefix(stats->raster_max_ns, NANOSECS_IN_SEC, maxbuf, 0);
+    ncqprefix(stats->raster_ns / (stats->writeouts + stats->failed_writeouts),
             NANOSECS_IN_SEC, avgbuf, 0);
     fprintf(stderr, "%s%"PRIu64" raster%s, %ss (%ss min, %ss avg, %ss max)" NL,
             clreol, stats->writeouts, stats->writeouts == 1 ? "" : "s",
             totalbuf, minbuf, avgbuf, maxbuf);
-    qprefix(stats->writeout_ns, NANOSECS_IN_SEC, totalbuf, 0);
-    qprefix(stats->writeout_ns ? stats->writeout_min_ns : 0,
+    ncqprefix(stats->writeout_ns, NANOSECS_IN_SEC, totalbuf, 0);
+    ncqprefix(stats->writeout_ns ? stats->writeout_min_ns : 0,
             NANOSECS_IN_SEC, minbuf, 0);
-    qprefix(stats->writeout_max_ns, NANOSECS_IN_SEC, maxbuf, 0);
-    qprefix(stats->writeouts ? stats->writeout_ns / stats->writeouts : 0,
+    ncqprefix(stats->writeout_max_ns, NANOSECS_IN_SEC, maxbuf, 0);
+    ncqprefix(stats->writeouts ? stats->writeout_ns / stats->writeouts : 0,
             NANOSECS_IN_SEC, avgbuf, 0);
     fprintf(stderr, "%s%"PRIu64" write%s, %ss (%ss min, %ss avg, %ss max)" NL,
             clreol, stats->writeouts, stats->writeouts == 1 ? "" : "s",
             totalbuf, minbuf, avgbuf, maxbuf);
   }
   if(stats->renders || stats->input_events){
-    bprefix(stats->render_bytes, 1, totalbuf, 1),
-    bprefix(stats->render_bytes ? stats->render_min_bytes : 0,
+    ncbprefix(stats->render_bytes, 1, totalbuf, 1),
+    ncbprefix(stats->render_bytes ? stats->render_min_bytes : 0,
             1, minbuf, 1),
-    bprefix(stats->renders ? stats->render_bytes / stats->renders : 0, 1, avgbuf, 1);
-    bprefix(stats->render_max_bytes, 1, maxbuf, 1),
+    ncbprefix(stats->renders ? stats->render_bytes / stats->renders : 0, 1, avgbuf, 1);
+    ncbprefix(stats->render_max_bytes, 1, maxbuf, 1),
     fprintf(stderr, "%s%sB (%sB min, %sB avg, %sB max) %"PRIu64" input%s Ghpa: %"PRIu64 NL,
             clreol, totalbuf, minbuf, avgbuf, maxbuf,
             stats->input_events,
@@ -234,7 +234,7 @@ void summarize_stats(notcurses* nc){
           (stats->fgelisions * 100.0) / (stats->fgemissions + stats->fgelisions),
           (stats->bgemissions + stats->bgelisions) == 0 ? 0 :
           (stats->bgelisions * 100.0) / (stats->bgemissions + stats->bgelisions));
-  bprefix(stats->sprixelbytes, 1, totalbuf, 1);
+  ncbprefix(stats->sprixelbytes, 1, totalbuf, 1);
   fprintf(stderr, "%sBitmap emits:elides: %"PRIu64":%"PRIu64" (%.2f%%) %sB (%.2f%%) SuM: %"PRIu64" (%.2f%%)" NL,
           clreol, stats->sprixelemissions, stats->sprixelelisions,
           (stats->sprixelemissions + stats->sprixelelisions) == 0 ? 0 :
diff --git a/src/lib/tabbed.c b/src/lib/tabbed.c
index 8dcd5886c4..0910aba995 100644
--- a/src/lib/tabbed.c
+++ b/src/lib/tabbed.c
@@ -22,8 +22,8 @@ typedef struct nctabbed {
 
 void nctabbed_redraw(nctabbed* nt){
   nctab* t;
-  int drawn_cols = 0;
-  int rows, cols;
+  unsigned drawn_cols = 0;
+  unsigned rows, cols;
   if(nt->tabcount == 0){
     // no tabs = nothing to draw
     ncplane_erase(nt->hp);
@@ -148,7 +148,7 @@ nctab* nctab_prev(nctab* t){
 nctabbed* nctabbed_create(ncplane* n, const nctabbed_options* topts){
   nctabbed_options zeroed = {};
   ncplane_options nopts = {};
-  int nrows, ncols;
+  unsigned nrows, ncols;
   nctabbed* nt;
   if(!topts){
     topts = &zeroed;
diff --git a/src/lib/termdesc.c b/src/lib/termdesc.c
index c7c1b8a032..e26474bd89 100644
--- a/src/lib/termdesc.c
+++ b/src/lib/termdesc.c
@@ -1144,7 +1144,7 @@ char* termdesc_longterm(const tinfo* ti){
 // send a u7 request, and wait until we have a cursor report. if input's ttyfd
 // is valid, we can just camp there. otherwise, we need dance with potential
 // user input looking at infd.
-int locate_cursor(tinfo* ti, int* cursor_y, int* cursor_x){
+int locate_cursor(tinfo* ti, unsigned* cursor_y, unsigned* cursor_x){
 #ifdef __MINGW64__
   if(ti->outhandle){
     CONSOLE_SCREEN_BUFFER_INFO conbuf;
diff --git a/src/lib/termdesc.h b/src/lib/termdesc.h
index 72b6fed344..13f3849cb9 100644
--- a/src/lib/termdesc.h
+++ b/src/lib/termdesc.h
@@ -112,7 +112,7 @@ typedef struct tinfo {
   // be acquired on all terminals with pixel support.
   unsigned cellpixy;               // cell pixel height, might be 0
   unsigned cellpixx;               // cell pixel width, might be 0
-  int dimy, dimx;                  // most recent cell geometry
+  unsigned dimy, dimx;             // most recent cell geometry
 
   unsigned supported_styles; // bitmask over NCSTYLE_* driven via sgr/ncv
 
@@ -155,16 +155,16 @@ typedef struct tinfo {
   // on TERM heuristics. otherwise, we attempt to detect sixel support, and
   // query the details of the implementation.
   int color_registers; // sixel color registers (post pixel_query_done)
-  int sixel_maxx;      // maximum theoretical sixel width
+  unsigned sixel_maxx; // maximum theoretical sixel width
   // in sixel, we can't render to the bottom row, lest we force a one-line
   // scroll. we thus clamp sixel_maxy_pristine to the minimum of
   // sixel_maxy_pristine (the reported sixel_maxy), and the number of rows
   // less one times the cell height. sixel_maxy is thus recomputed whenever
   // we get a resize event. it is only defined if we have sixel_maxy_pristine,
   // so kitty graphics (which don't force a scroll) never deal with this.
-  int sixel_maxy;            // maximum working sixel height
-  int sixel_maxy_pristine;   // maximum theoretical sixel height, as queried
-  int sprixel_scale_height;  // sprixel must be a multiple of this many rows
+  unsigned sixel_maxy;          // maximum working sixel height
+  unsigned sixel_maxy_pristine; // maximum theoretical sixel height, as queried
+  unsigned sprixel_scale_height;// sprixel must be a multiple of this many rows
   const char* termname;      // terminal name from environment variables/init
   char* termversion;         // terminal version (freeform) from query responses
   queried_terminals_e qterm; // detected terminal class
@@ -242,7 +242,7 @@ void free_terminfo_cache(tinfo* ti);
 // return a heap-allocated copy of termname + termversion
 char* termdesc_longterm(const tinfo* ti);
 
-int locate_cursor(tinfo* ti, int* cursor_y, int* cursor_x);
+int locate_cursor(tinfo* ti, unsigned* cursor_y, unsigned* cursor_x);
 
 // tlen -- size of escape table. tused -- used bytes in same.
 // returns -1 if the starting location is >= 65535. otherwise,
diff --git a/src/lib/tree.c b/src/lib/tree.c
index 8565300d60..6e09f9990d 100644
--- a/src/lib/tree.c
+++ b/src/lib/tree.c
@@ -261,7 +261,7 @@ void* nctree_next(nctree* n){
   if(tmp != n->curitem){
     n->curitem = tmp;
     n->activerow += rows;
-    if(n->activerow >= ncplane_dim_y(n->items.ncp)){
+    if(n->activerow >= (int)ncplane_dim_y(n->items.ncp)){
       n->activerow = ncplane_dim_y(n->items.ncp) - 1;
     }
   }
@@ -315,7 +315,7 @@ draw_tree_item(nctree* n, nctree_int_item* nii, const unsigned* path,
   }else{
     // FIXME possibly enlarge nii->ncp?
   }
-  if(ncplane_y(nii->ncp) <= *frontiert || *frontierb >= ncplane_dim_y(n->items.ncp)){
+  if(ncplane_y(nii->ncp) <= *frontiert || *frontierb >= (int)ncplane_dim_y(n->items.ncp)){
     ncplane_move_yx(nii->ncp, *frontiert, ncplane_x(nii->ncp));
   }else{
     ncplane_move_yx(nii->ncp, *frontierb, ncplane_x(nii->ncp));
@@ -329,7 +329,7 @@ draw_tree_item(nctree* n, nctree_int_item* nii, const unsigned* path,
   if(ncplane_y(nii->ncp) <= *frontiert){
     *frontiert = ncplane_y(nii->ncp) - 1;
   }
-  if(ncplane_y(nii->ncp) + ncplane_dim_y(nii->ncp) > *frontierb){
+  if(ncplane_y(nii->ncp) + (int)ncplane_dim_y(nii->ncp) > *frontierb){
     *frontierb = ncplane_y(nii->ncp) + ncplane_dim_y(nii->ncp);
   }
   return 0;
@@ -408,7 +408,7 @@ nctree_inner_redraw(nctree* n, unsigned* tmppath){
   nii = n->curitem;
   // draw items below the current one FIXME
   memcpy(tmppath, n->currentpath, sizeof(*tmppath) * (n->maxdepth + 1));
-  while(frontierb < ncplane_dim_y(n->items.ncp)){
+  while(frontierb < (int)ncplane_dim_y(n->items.ncp)){
     if((tmpnii = nctree_next_internal(n, tmppath)) == nii){
       break;
     }
diff --git a/src/lib/visual-details.h b/src/lib/visual-details.h
index 219b0c0301..e9347e39ab 100644
--- a/src/lib/visual-details.h
+++ b/src/lib/visual-details.h
@@ -22,9 +22,9 @@ struct ncvisual_details;
 typedef struct ncvisual {
   struct ncvisual_details* details;// implementation-specific details
   uint32_t* data; // (scaled) RGBA image data, rowstride bytes per row
-  int pixx, pixy; // pixel geometry, *not* cell geometry
+  unsigned pixx, pixy; // pixel geometry, *not* cell geometry
   // lines are sometimes padded. this many true bytes per row in data.
-  int rowstride;
+  unsigned rowstride;
   bool owndata; // we own data iff owndata == true
 } ncvisual;
 
@@ -42,7 +42,7 @@ ncvisual_set_data(ncvisual* ncv, void* data, bool owned){
 
 // shrink one dimension to retrieve the original aspect ratio
 static inline void
-scale_visual(const ncvisual* ncv, int* disprows, int* dispcols){
+scale_visual(const ncvisual* ncv, unsigned* disprows, unsigned* dispcols){
   float xratio = (float)(*dispcols) / ncv->pixx;
   if(xratio * ncv->pixy > *disprows){
     xratio = (float)(*disprows) / ncv->pixy;
diff --git a/src/lib/visual.c b/src/lib/visual.c
index 1bfaffe6ce..28f2544fe4 100644
--- a/src/lib/visual.c
+++ b/src/lib/visual.c
@@ -121,7 +121,8 @@ ncvisual* ncvisual_create(void){
 }
 
 static inline void
-ncvisual_origin(const struct ncvisual_options* vopts, int* restrict begy, int* restrict begx){
+ncvisual_origin(const struct ncvisual_options* vopts, unsigned* restrict begy,
+                unsigned* restrict begx){
   *begy = vopts ? vopts->begy : 0;
   *begx = vopts ? vopts->begx : 0;
 }
@@ -133,7 +134,8 @@ int ncvisual_blitter_geom(const notcurses* nc, const ncvisual* n,
                           ncblitter_e* blitter){
   ncvgeom geom;
   const struct blitset* bset;
-  int disppxy, disppxx, outy, outx, placey, placex;
+  unsigned disppxy, disppxx, outy, outx;
+  int placey, placex;
   if(ncvisual_geom_inner(&nc->tcache, n, vopts, &geom, &bset,
                          &disppxy, &disppxx, &outy, &outx,
                          &placey, &placex)){
@@ -168,8 +170,8 @@ int ncvisual_blitter_geom(const notcurses* nc, const ncvisual* n,
 // accounts for sixels being a multiple of six pixels tall.
 static void
 shape_sprixel_plane(const tinfo* ti, ncplane* parent, const ncvisual* ncv,
-                    ncscale_e scaling, int* disppixy, int* disppixx,
-                    uint64_t flags, int* outy, int* outx,
+                    ncscale_e scaling, unsigned* disppixy, unsigned* disppixx,
+                    uint64_t flags, unsigned* outy, unsigned* outx,
                     int* placey, int* placex, int pxoffy, int pxoffx){
   if(scaling != NCSCALE_NONE && scaling != NCSCALE_NONE_HIRES){
     // disppixy/disppix are treated initially as cells
@@ -219,8 +221,8 @@ shape_sprixel_plane(const tinfo* ti, ncplane* parent, const ncvisual* ncv,
 int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
                         const struct ncvisual_options* vopts, ncvgeom* geom,
                         const struct blitset** bset,
-                        int* disppixy, int* disppixx,
-                        int* outy, int* outx,
+                        unsigned* disppixy, unsigned* disppixx,
+                        unsigned* outy, unsigned* outx,
                         int* placey, int* placex){
   if(ti == NULL && n == NULL){
     logerror("got NULL for both sources\n");
@@ -286,17 +288,13 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
   geom->leny = vopts->leny;
   *placey = vopts->y;
   *placex = vopts->x;
-  logdebug("vis %dx%d+%dx%d %p\n", geom->begy, geom->begx, geom->leny, geom->lenx, n->data);
-  if(geom->begy < 0 || geom->begx < 0){
-    logerror("invalid geometry for visual %d %d %d %d\n", geom->begy, geom->begx, geom->leny, geom->lenx);
-    return -1;
-  }
+  logdebug("vis %ux%u+%ux%u %p\n", geom->begy, geom->begx, geom->leny, geom->lenx, n->data);
   if(n->data == NULL){
     logerror("no data in visual\n");
     return -1;
   }
   if(geom->begx >= n->pixx || geom->begy >= n->pixy){
-    logerror("visual too large %d > %d or %d > %d\n", geom->begy, n->pixy, geom->begx, n->pixx);
+    logerror("visual too large %u > %d or %u > %d\n", geom->begy, n->pixy, geom->begx, n->pixx);
     return -1;
   }
   if(geom->lenx == 0){ // 0 means "to the end"; use all available source material
@@ -340,13 +338,13 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
       }
       if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){
         // FIXME clamp to sprixel limits
-        int rows = ((geom->leny + ti->cellpixy - 1) / ti->cellpixy) + !!vopts->pxoffy;
+        unsigned rows = ((geom->leny + ti->cellpixy - 1) / ti->cellpixy) + !!vopts->pxoffy;
         if(rows > ncplane_dim_y(vopts->n)){
           logerror("sprixel too tall %d for plane %d\n", geom->leny + vopts->pxoffy,
                    ncplane_dim_y(vopts->n) * ti->cellpixy);
           return -1;
         }
-        int cols = ((geom->lenx + ti->cellpixx - 1) / ti->cellpixx) + !!vopts->pxoffx;
+        unsigned cols = ((geom->lenx + ti->cellpixx - 1) / ti->cellpixx) + !!vopts->pxoffx;
         if(cols > ncplane_dim_x(vopts->n)){
           logerror("sprixel too wide %d for plane %d\n", geom->lenx + vopts->pxoffx,
                    ncplane_dim_x(vopts->n) * ti->cellpixx);
@@ -405,7 +403,7 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
       logerror("pixel offsets cannot be used with cell blitting\n");
       return -1;
     }
-    int dispcols, disprows;
+    unsigned dispcols, disprows;
     if(vopts->n == NULL || (vopts->flags & NCVISUAL_OPTION_CHILDPLANE)){ // create plane
 //fprintf(stderr, "CPATH1, create beg %dx%d len %dx%d\n", geom->begy, geom->begx, geom->leny, geom->lenx);
       if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){
@@ -463,7 +461,8 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
 int ncvisual_geom(const notcurses* nc, const ncvisual* n,
                   const struct ncvisual_options* vopts, ncvgeom* geom){
   const struct blitset* bset;
-  int disppxy, disppxx, outy, outx, placey, placex;
+  unsigned disppxy, disppxx, outy, outx;
+  int placey, placex;
   return ncvisual_geom_inner(nc ? &nc->tcache : NULL, n, vopts, geom, &bset,
                              &disppxy, &disppxx, &outy, &outx, &placey, &placex);
 }
@@ -543,7 +542,9 @@ void* bgra_to_rgba(const void* data, int rows, int* rowstride, int cols, int alp
 // pixels. Returns the area of the box (0 if there are no pixels).
 int ncvisual_bounding_box(const ncvisual* ncv, int* leny, int* lenx,
                           int* offy, int* offx){
-  int trow, lcol = -1, rcol = INT_MAX; // FIXME shouldn't need lcol init
+  unsigned lcol = 0;
+  unsigned rcol = UINT_MAX;
+  unsigned trow;
   // first, find the topmost row with a real pixel. if there is no such row,
   // there are no such pixels. if we find one, we needn't look in this region
   // for other extrema, so long as we keep the leftmost and rightmost through
@@ -551,13 +552,12 @@ int ncvisual_bounding_box(const ncvisual* ncv, int* leny, int* lenx,
   // and rightmost pixel of whichever row has the topmost valid pixel. unlike
   // the topmost, they'll need be further verified.
   for(trow = 0 ; trow < ncv->pixy ; ++trow){
-    int x;
-    for(x = 0 ; x < ncv->pixx ; ++x){
+    for(unsigned x = 0 ; x < ncv->pixx ; ++x){
       uint32_t rgba = ncv->data[trow * ncv->rowstride / 4 + x];
       if(rgba){
         lcol = x; // leftmost pixel of topmost row
         // now find rightmost pixel of topmost row
-        int xr;
+        unsigned xr;
         for(xr = ncv->pixx - 1 ; xr > x ; --xr){
           rgba = ncv->data[trow * ncv->rowstride / 4 + xr];
           if(rgba){ // rightmost pixel of topmost row
@@ -578,20 +578,19 @@ int ncvisual_bounding_box(const ncvisual* ncv, int* leny, int* lenx,
     *offy = 0;
     *offx = 0;
   }else{
-    assert(lcol >= 0);
     assert(rcol < ncv->pixx);
     // we now know topmost row, and left/rightmost through said row. now we must
     // find the bottommost row, checking left/rightmost throughout.
-    int brow;
+    unsigned brow;
     for(brow = ncv->pixy - 1 ; brow > trow ; --brow){
-      int x;
+      unsigned x;
       for(x = 0 ; x < ncv->pixx ; ++x){
         uint32_t rgba = ncv->data[brow * ncv->rowstride / 4 + x];
         if(rgba){
           if(x < lcol){
             lcol = x;
           }
-          int xr;
+          unsigned xr;
           for(xr = ncv->pixx - 1 ; xr > x && xr > rcol ; --xr){
             rgba = ncv->data[brow * ncv->rowstride / 4 + xr];
             if(rgba){ // rightmost pixel of bottommost row
@@ -610,15 +609,15 @@ int ncvisual_bounding_box(const ncvisual* ncv, int* leny, int* lenx,
     }
     // we now know topmost and bottommost row, and left/rightmost within those
     // two sections. now check the rest for left and rightmost.
-    for(int y = trow + 1 ; y < brow ; ++y){
-      for(int x = 0 ; x < lcol ; ++x){
+    for(unsigned y = trow + 1 ; y < brow ; ++y){
+      for(unsigned x = 0 ; x < lcol ; ++x){
         uint32_t rgba = ncv->data[y * ncv->rowstride / 4 + x];
         if(rgba){
           lcol = x;
           break;
         }
       }
-      for(int x = ncv->pixx - 1 ; x > rcol ; --x){
+      for(unsigned x = ncv->pixx - 1 ; x > rcol ; --x){
         uint32_t rgba = ncv->data[y * ncv->rowstride / 4 + x];
         if(rgba){
           rcol = x;
@@ -746,14 +745,16 @@ int ncvisual_rotate(ncvisual* ncv, double rads){
   }
   memset(data, 0, bbarea * 4);
 //fprintf(stderr, "bbarea: %d bby: %d bbx: %d centy: %d centx: %d bbcenty: %d bbcentx: %d\n", bbarea, bby, bbx, centy, centx, bbcenty, bbcentx);
-  for(int y = 0 ; y < ncv->pixy ; ++y){
-      for(int x = 0 ; x < ncv->pixx ; ++x){
+  for(unsigned y = 0 ; y < ncv->pixy ; ++y){
+      for(unsigned x = 0 ; x < ncv->pixx ; ++x){
       int targx = x, targy = y;
       rotate_point(&targy, &targx, stheta, ctheta, centy, centx);
-      const int deconvx = targx - bboffx;
-      const int deconvy = targy - bboffy;
-      if(deconvy >= 0 && deconvx >= 0 && deconvy < bby && deconvx < bbx){
-        data[deconvy * bbx + deconvx] = ncv->data[y * (ncv->rowstride / 4) + x];
+      if(targx > bboffx && targy > bboffy){
+        const int deconvx = targx - bboffx;
+        const int deconvy = targy - bboffy;
+        if(deconvy < bby && deconvx < bbx){
+          data[deconvy * bbx + deconvx] = ncv->data[y * (ncv->rowstride / 4) + x];
+        }
       }
 //fprintf(stderr, "CW: %d/%d (%08x) -> %d/%d (stride: %d)\n", y, x, ncv->data[y * (ncv->rowstride / 4) + x], targy, targx, ncv->rowstride);
 //fprintf(stderr, "wrote %08x to %d (%d)\n", data[targy * ncv->pixy + targx], targy * ncv->pixy + targx, (targy * ncv->pixy + targx) * 4);
@@ -1113,7 +1114,8 @@ ncplane* ncvisual_blit(notcurses* nc, ncvisual* ncv, const struct ncvisual_optio
           vopts->leny, vopts->lenx, vopts->begy, vopts->begx, vopts->n);
   ncvgeom geom;
   const struct blitset* bset;
-  int disppxy, disppxx, outy, outx, placey, placex;
+  unsigned disppxy, disppxx, outy, outx;
+  int placey, placex;
   if(ncvisual_geom_inner(&nc->tcache, ncv, vopts, &geom, &bset,
                          &disppxy, &disppxx, &outy, &outx,
                          &placey, &placex)){
@@ -1191,7 +1193,7 @@ ncplane* ncvisual_render(notcurses* nc, ncvisual* ncv, const struct ncvisual_opt
 }
 
 ncvisual* ncvisual_from_plane(const ncplane* n, ncblitter_e blit,
-                              unsigned begy, unsigned begx,
+                              int begy, int begx,
                               unsigned leny, unsigned lenx){
   unsigned py, px;
   uint32_t* rgba = ncplane_as_rgba(n, blit, begy, begx, leny, lenx, &py, &px);
@@ -1199,7 +1201,7 @@ ncvisual* ncvisual_from_plane(const ncplane* n, ncblitter_e blit,
   if(rgba == NULL){
     return NULL;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n, &dimy, &dimx);
   ncvisual* ncv = ncvisual_from_rgba(rgba, py, px * 4, px);
   free(rgba);
@@ -1241,53 +1243,37 @@ int ncvisual_simple_streamer(ncvisual* ncv, struct ncvisual_options* vopts,
   return ret;
 }
 
-int ncvisual_set_yx(const struct ncvisual* n, int y, int x, uint32_t pixel){
-  if(y >= n->pixy || y < 0){
+int ncvisual_set_yx(const struct ncvisual* n, unsigned y, unsigned x, uint32_t pixel){
+  if(y >= n->pixy){
+    logerror("invalid coordinates %u/%u\n", y, x);
     return -1;
   }
-  if(x >= n->pixx || x < 0){
+  if(x >= n->pixx){
+    logerror("invalid coordinates %u/%u\n", y, x);
     return -1;
   }
   n->data[y * (n->rowstride / 4) + x] = pixel;
   return 0;
 }
 
-int ncvisual_at_yx(const ncvisual* n, int y, int x, uint32_t* pixel){
-  if(y >= n->pixy || y < 0){
+int ncvisual_at_yx(const ncvisual* n, unsigned y, unsigned x, uint32_t* pixel){
+  if(y >= n->pixy){
+    logerror("invalid coordinates %u/%u\n", y, x);
     return -1;
   }
-  if(x >= n->pixx || x < 0){
+  if(x >= n->pixx){
+    logerror("invalid coordinates %u/%u\n", y, x);
     return -1;
   }
   *pixel = n->data[y * (n->rowstride / 4) + x];
   return 0;
 }
 
-// a neighbor on which to polyfill. by the time we get to it, it might or
-// might not have been filled in. if so, discard immediately. otherwise,
-// check self, and if valid, push all neighbors.
-struct topolyfill {
-  int y, x;
-  struct topolyfill* next;
-};
-
-static inline struct topolyfill*
-create_polyfill_op(int y, int x, struct topolyfill** stack){
-  struct topolyfill* n = malloc(sizeof(*n));
-  if(n){
-    n->y = y;
-    n->x = x;
-    n->next = *stack;
-    *stack = n;
-  }
-  return n;
-}
-
 // originally i wrote this recursively, at which point it promptly began
 // exploding once i multithreaded the [yield] demo. hence the clumsy stack
 // and hand-rolled iteration. alas, poor yorick!
 static int
-ncvisual_polyfill_core(ncvisual* n, int y, int x, uint32_t rgba, uint32_t match){
+ncvisual_polyfill_core(ncvisual* n, unsigned y, unsigned x, uint32_t rgba, uint32_t match){
   struct topolyfill* stack = malloc(sizeof(*stack));
   if(stack == NULL){
     return -1;
@@ -1308,6 +1294,7 @@ ncvisual_polyfill_core(ncvisual* n, int y, int x, uint32_t rgba, uint32_t match)
       *pixel = rgba;
       if(y){
         if(create_polyfill_op(y - 1, x, &stack) == NULL){
+          // FIXME need free stack!
           return -1;
         }
       }
@@ -1332,11 +1319,13 @@ ncvisual_polyfill_core(ncvisual* n, int y, int x, uint32_t rgba, uint32_t match)
   return ret;
 }
 
-int ncvisual_polyfill_yx(ncvisual* n, int y, int x, uint32_t rgba){
-  if(y >= n->pixy || y < 0){
+int ncvisual_polyfill_yx(ncvisual* n, unsigned y, unsigned x, uint32_t rgba){
+  if(y >= n->pixy){
+    logerror("invalid coordinates %u/%u\n", y, x);
     return -1;
   }
-  if(x >= n->pixx || x < 0){
+  if(x >= n->pixx){
+    logerror("invalid coordinates %u/%u\n", y, x);
     return -1;
   }
   uint32_t* pixel = &n->data[y * (n->rowstride / 4) + x];
diff --git a/src/media/ffmpeg.c b/src/media/ffmpeg.c
index b9b42d7f77..2fc5696727 100644
--- a/src/media/ffmpeg.c
+++ b/src/media/ffmpeg.c
@@ -141,7 +141,7 @@ subtitle_plane_from_text(ncplane* parent, const char* text){
   uint64_t channels = 0;
   ncchannels_set_fg_alpha(&channels, NCALPHA_HIGHCONTRAST);
   ncchannels_set_fg_rgb8(&channels, 0x88, 0x88, 0x88);
-  ncplane_stain(n, -1, -1, channels, channels, channels, channels);
+  ncplane_stain(n, -1, -1, 0, 0, channels, channels, channels, channels);
   ncchannels_set_fg_default(&channels);
   ncplane_puttext(n, 0, NCALIGN_LEFT, text, NULL);
   ncchannels_set_bg_alpha(&channels, NCALPHA_TRANSPARENT);
diff --git a/src/player/play.cpp b/src/player/play.cpp
index 247449032e..3734413e27 100644
--- a/src/player/play.cpp
+++ b/src/player/play.cpp
@@ -88,7 +88,7 @@ auto perframe(struct ncvisual* ncv, struct ncvisual_options* vopts,
   if(!nc.render()){
     return -1;
   }
-  int dimx, dimy, oldx, oldy;
+  unsigned dimx, dimy, oldx, oldy;
   nc.get_term_dim(&dimy, &dimx);
   ncplane_dim_yx(vopts->n, &oldy, &oldx);
   uint64_t absnow = timespec_to_ns(abstime);
@@ -346,7 +346,7 @@ int direct_mode_player(int argc, char** argv, ncscale_e scalemode,
     if(dm.streamfile(argv[i], perframe_direct, &vopts, NULL)){
       failed = true;
     }
-    int y, x;
+    unsigned y, x;
     dm.get_cursor_yx(&y, &x);
     if(x){
       std::cout << std::endl;
@@ -361,7 +361,7 @@ int rendered_mode_player_inner(NotCurses& nc, int argc, char** argv,
                                bool quiet, bool loop,
                                double timescale, double displaytime,
                                bool noninterp, uint32_t transcolor){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   std::unique_ptr<Plane> stdn(nc.get_stdplane(&dimy, &dimx));
   uint64_t transchan = 0;
   ncchannels_set_fg_alpha(&transchan, NCALPHA_TRANSPARENT);
diff --git a/src/poc/bitmapstates.c b/src/poc/bitmapstates.c
index ae6aaf638b..624e20bf8d 100644
--- a/src/poc/bitmapstates.c
+++ b/src/poc/bitmapstates.c
@@ -11,9 +11,9 @@ emit(struct ncplane* n, const char* str){
 // draw a bitmap of 6x6 cells with a cell left out
 static int
 wipebitmap(struct notcurses* nc){
-  int cellpxy, cellpxx;
+  unsigned cellpxy, cellpxx;
   ncplane_pixelgeom(notcurses_stdplane(nc), NULL, NULL,
-                     &cellpxy, &cellpxx, NULL, NULL);
+                    &cellpxy, &cellpxx, NULL, NULL);
   int pixy = cellpxy * 6;
   int pixx = cellpxx * 6;
   uint32_t* pixels = malloc(sizeof(*pixels) * pixx * pixy);
@@ -79,7 +79,7 @@ wipebitmap(struct notcurses* nc){
   sleep(2);
 
   ncplane_erase(notcurses_stdplane(nc));
-  for(int i = cellpxy ; i < 5 * cellpxy ; ++i){
+  for(unsigned i = cellpxy ; i < 5 * cellpxy ; ++i){
     memset(pixels + (i * 6 * cellpxx + cellpxx), 0, cellpxx * 4 * sizeof(*pixels));
   }
   struct ncvisual* ncve = ncvisual_from_rgba(pixels, 6 * cellpxy, 6 * cellpxx * 4, 6 * cellpxx);
diff --git a/src/poc/cjkscroll.c b/src/poc/cjkscroll.c
index a93351727d..8cdbe81d09 100644
--- a/src/poc/cjkscroll.c
+++ b/src/poc/cjkscroll.c
@@ -14,7 +14,7 @@ int main(void){
   if(nc == NULL){
     return EXIT_FAILURE;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   wchar_t wc = 0x4e00;
   ncplane_set_scrolling(n, true);
diff --git a/src/poc/cursor.c b/src/poc/cursor.c
index efb93b4a74..8ba1ff24fc 100644
--- a/src/poc/cursor.c
+++ b/src/poc/cursor.c
@@ -35,13 +35,13 @@ int main(void){
   if(n == NULL){
     return EXIT_FAILURE;
   }
-  int y, x;
+  unsigned y, x;
   if(ncdirect_cursor_yx(n, &y, &x)){
     goto err;
   }
-  int dimx = ncdirect_dim_x(n);
-  int dimy = ncdirect_dim_y(n);
-  printf("Cursor: column %d/%d row %d/%d\n", x, dimx, y, dimy);
+  unsigned dimx = ncdirect_dim_x(n);
+  unsigned dimy = ncdirect_dim_y(n);
+  printf("Cursor: column %u/%u row %u/%u\n", x, dimx, y, dimy);
   ncdirect_stop(n);
   return EXIT_SUCCESS;
 
diff --git a/src/poc/direct.c b/src/poc/direct.c
index 1c0d3de4bb..059747ec88 100644
--- a/src/poc/direct.c
+++ b/src/poc/direct.c
@@ -36,14 +36,14 @@ int main(void){
   ret |= ncdirect_cursor_right(n, dimx / 2);
   ret |= ncdirect_cursor_up(n, dimy / 2);
   printf(" erperperp! \n");
-  int y = -420, x = -420;
+  unsigned y, x;
   // FIXME try a push/pop
   if(ncdirect_cursor_yx(n, &y, &x) == 0){
     printf("\n\tRead cursor position: y: %d x: %d\n", y, x);
     y += 2; // we just went down two lines
     while(y > 3){
       ret = -1;
-      int newy;
+      unsigned newy;
       if(ncdirect_cursor_yx(n, &newy, NULL)){
         break;
       }
diff --git a/src/poc/dirlines.c b/src/poc/dirlines.c
index b18f09a0ae..a2beb97f9c 100644
--- a/src/poc/dirlines.c
+++ b/src/poc/dirlines.c
@@ -8,8 +8,7 @@ int main(void){
   }
   uint64_t flags = NCDIRECT_OPTION_DRAIN_INPUT;
   struct ncdirect* n = ncdirect_core_init(NULL, stdout, flags);
-  putchar('\n');
-  for(int i = 0 ; i < 15 ; ++i){
+  for(int i = 1 ; i < 15 ; ++i){
     uint64_t c1 = 0, c2 = 0;
     ncchannels_set_fg_rgb8(&c1, 0x0, 0x10 * i, 0xff);
     ncchannels_set_fg_rgb8(&c2, 0x10 * i, 0x0, 0x0);
@@ -21,7 +20,7 @@ int main(void){
     ncdirect_set_bg_default(n);
     putchar('\n');
   }
-  for(int i = 0 ; i < 15 ; ++i){
+  for(int i = 1 ; i < 15 ; ++i){
     uint64_t c1 = 0, c2 = 0;
     ncchannels_set_fg_rgb8(&c1, 0x0, 0x10 * i, 0xff);
     ncchannels_set_fg_rgb8(&c2, 0x10 * i, 0x0, 0x0);
diff --git a/src/poc/fbconscroll.c b/src/poc/fbconscroll.c
index 47cb543c3a..1fe6d38be9 100644
--- a/src/poc/fbconscroll.c
+++ b/src/poc/fbconscroll.c
@@ -25,7 +25,7 @@ int main(int argc, char** argv){
   if(nc == NULL){
     return EXIT_FAILURE;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   ncplane_set_scrolling(n, true);
   for(int i = 0 ; i < rows ; ++i){
diff --git a/src/poc/gradients.c b/src/poc/gradients.c
index 017d6d565c..e4b6ff1b84 100644
--- a/src/poc/gradients.c
+++ b/src/poc/gradients.c
@@ -6,13 +6,13 @@
 // gradient of 'A's changing color and background changing in reverse
 static int
 gradientA(struct notcurses* nc){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
   uint64_t ul = NCCHANNELS_INITIALIZER(0, 0, 0, 0xff, 0xff, 0xff);
   uint64_t ur = NCCHANNELS_INITIALIZER(0, 0xff, 0xff, 0xff, 0, 0);
   uint64_t ll = NCCHANNELS_INITIALIZER(0xff, 0, 0, 0, 0xff, 0xff);
   uint64_t lr = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0, 0, 0);
-  if(ncplane_gradient(stdn, "A", NCSTYLE_NONE, ul, ur, ll, lr, dimy - 1, dimx - 1) <= 0){
+  if(ncplane_gradient(stdn, 0, 0, 0, 0, "A", NCSTYLE_NONE, ul, ur, ll, lr) <= 0){
     return -1;
   }
   if(notcurses_render(nc)){
@@ -24,20 +24,20 @@ gradientA(struct notcurses* nc){
 
 static int
 gradStriations(struct notcurses* nc){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
   uint64_t ul = NCCHANNELS_INITIALIZER(0, 0, 0, 0xff, 0xff, 0xff);
   uint64_t ur = NCCHANNELS_INITIALIZER(0, 0xff, 0xff, 0xff, 0, 0);
   uint64_t ll = NCCHANNELS_INITIALIZER(0xff, 0, 0, 0, 0xff, 0xff);
   uint64_t lr = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0, 0, 0);
-  if(ncplane_gradient(stdn, "▄", NCSTYLE_NONE, ul, ur, ll, lr, dimy - 1, dimx - 1) <= 0){
+  if(ncplane_gradient(stdn, 0, 0, 0, 0, "▄", NCSTYLE_NONE, ul, ur, ll, lr) <= 0){
     return -1;
   }
   if(notcurses_render(nc)){
     return -1;
   }
   sleep(1);
-  if(ncplane_gradient(stdn, "▀", NCSTYLE_NONE, ul, ur, ll, lr, dimy - 1, dimx - 1) <= 0){
+  if(ncplane_gradient(stdn, 0, 0, 0, 0, "▀", NCSTYLE_NONE, ul, ur, ll, lr) <= 0){
     return -1;
   }
   if(notcurses_render(nc)){
@@ -49,13 +49,13 @@ gradStriations(struct notcurses* nc){
 
 static int
 gradHigh(struct notcurses* nc){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
   uint64_t ul = NCCHANNEL_INITIALIZER(0, 0, 0);
   uint64_t ur = NCCHANNEL_INITIALIZER(0, 0xff, 0xff);
   uint64_t ll = NCCHANNEL_INITIALIZER(0xff, 0, 0);
   uint64_t lr = NCCHANNEL_INITIALIZER(0xff, 0xff, 0xff);
-  if(ncplane_highgradient(stdn, ul, ur, ll, lr, dimy - 1, dimx - 1) <= 0){
+  if(ncplane_gradient2x1(stdn, 0, 0, 0, 0, ul, ur, ll, lr) <= 0){
     return -1;
   }
   if(notcurses_render(nc)){
diff --git a/src/poc/grid.c b/src/poc/grid.c
index 587ac349aa..fa0f283e43 100644
--- a/src/poc/grid.c
+++ b/src/poc/grid.c
@@ -2,8 +2,8 @@
 
 struct ncvisual*
 draw_grid(struct ncplane* stdn){
-  int maxby, maxbx;
-  int cellpxy, cellpxx;
+  unsigned maxby, maxbx;
+  unsigned cellpxy, cellpxx;
   ncplane_pixelgeom(stdn, NULL, NULL, &cellpxy, &cellpxx, &maxby, &maxbx);
   if(cellpxy <= 1 || cellpxx <= 1){
     fprintf(stderr, "cell-pixel geometry: %d %d\n", cellpxy, cellpxx);
@@ -15,20 +15,20 @@ draw_grid(struct ncplane* stdn){
   }
   // we want an inlay on each cell, so if they're 10 wide, we want pixels
   // at 0, 9, 10, 19, 20, 29, etc.
-  for(int y = 0 ; y < maxby ; ++y){
+  for(unsigned y = 0 ; y < maxby ; ++y){
     uint32_t* row = rgba + y * maxbx;
-    for(int x = 0 ; x < maxbx ; ++x){
+    for(unsigned x = 0 ; x < maxbx ; ++x){
       uint32_t* px = row + x;
       ncpixel_set_a(px, 255);
       ncpixel_set_r(px, 0x39);
       ncpixel_set_g(px, 0xff);
       ncpixel_set_b(px, 0xa0);
     }
-    for(int yi = 0 ; yi < cellpxy - 2 ; ++yi){
+    for(unsigned yi = 0 ; yi < cellpxy - 2 ; ++yi){
       ++y;
       if(y < maxby){
         row = rgba + y * maxbx;
-        for(int x = 0 ; x < maxbx ; ++x){
+        for(unsigned x = 0 ; x < maxbx ; ++x){
           uint32_t* px = row + x;
           ncpixel_set_a(px, 255);
           ncpixel_set_r(px, 0x39);
@@ -47,12 +47,12 @@ draw_grid(struct ncplane* stdn){
     ++y;
     row = rgba + y * maxbx;
     if(y < maxby){
-      for(int x = 0 ; x < maxbx ; ++x){
-	uint32_t* px = row + x;
-	ncpixel_set_a(px, 255);
-	ncpixel_set_r(px, 0x39);
-	ncpixel_set_g(px, 0xff);
-	ncpixel_set_b(px, 0xa0);
+      for(unsigned x = 0 ; x < maxbx ; ++x){
+        uint32_t* px = row + x;
+        ncpixel_set_a(px, 255);
+        ncpixel_set_r(px, 0x39);
+        ncpixel_set_g(px, 0xff);
+        ncpixel_set_b(px, 0xa0);
       }
     }
   }
@@ -74,7 +74,7 @@ int main(void){
   if(nc == NULL){
     return EXIT_FAILURE;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
   struct ncvisual* ncv = draw_grid(stdn);
   if(ncv == NULL){
diff --git a/src/poc/interp.c b/src/poc/interp.c
index fa99eb1eac..ca10fc06a9 100644
--- a/src/poc/interp.c
+++ b/src/poc/interp.c
@@ -104,7 +104,7 @@ int main(void){
     return EXIT_FAILURE;
   }
   struct ncplane* stdn = notcurses_stdplane(nc);
-  int cellpixy, cellpixx;
+  unsigned cellpixy, cellpixx;
   ncplane_pixelgeom(stdn, NULL, NULL, &cellpixy, &cellpixx, NULL, NULL);
   if(interp(nc, cellpixy, cellpixx)){
     goto err;
diff --git a/src/poc/menu.c b/src/poc/menu.c
index 342b53c4be..24ca2218c6 100644
--- a/src/poc/menu.c
+++ b/src/poc/menu.c
@@ -102,7 +102,7 @@ int main(void){
   ncchannels_set_bg_rgb(&mopts.headerchannels, 0x440000);
   ncchannels_set_fg_rgb(&mopts.sectionchannels, 0xb0d700);
   ncchannels_set_bg_rgb(&mopts.sectionchannels, 0x002000);
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   struct ncmenu* top = ncmenu_create(n, &mopts);
   if(top == NULL){
diff --git a/src/poc/ncwidth.c b/src/poc/ncwidth.c
index 3a7147cf4f..fa665d3630 100644
--- a/src/poc/ncwidth.c
+++ b/src/poc/ncwidth.c
@@ -74,13 +74,14 @@ int main(int argc, char **argv){
       totalb += conv;
       add_wchar(&wbuf, &bufsize, &used, w);
     }
-    int y, x, newy, newx;
     putchar('\n');
+    unsigned y, x;
     ncdirect_cursor_yx(n, &y, &x);
     printf("%s", *argv);
     fflush(stdout);
+    unsigned newy, newx;
     ncdirect_cursor_yx(n, &newy, &newx);
-    int realcols = (newx - x) + ncdirect_dim_x(n) * (newy - y);
+    unsigned realcols = (newx - x) + ncdirect_dim_x(n) * (newy - y);
     printf("\n iterated wcwidth: %d total bytes: %llu wcswidth: %d true width: %d\n\n",
            totalcols, (unsigned long long)totalb, wcswidth(wbuf, used), realcols);
     ncdirect_cursor_yx(n, &y, &x);
@@ -123,14 +124,14 @@ int main(int argc, char **argv){
     }
     ncdirect_set_fg_default(n);
     ncdirect_set_bg_default(n);
-    for(int z = 0 ; z < realcols && z < ncdirect_dim_x(n) ; ++z){
+    for(unsigned z = 0 ; z < realcols && z < ncdirect_dim_x(n) ; ++z){
       putchar('0' + z % 10);
     }
     if(realcols < ncdirect_dim_x(n)){
       putchar('\n');
     }
     if(realcols > 20){
-      for(int z = 0 ; z < realcols && z < ncdirect_dim_x(n) ; ++z){
+      for(unsigned z = 0 ; z < realcols && z < ncdirect_dim_x(n) ; ++z){
         if(z % 10){
           putchar(' ');
         }else{
diff --git a/src/poc/pixel.c b/src/poc/pixel.c
index 7a66e869ce..1b01a585b8 100644
--- a/src/poc/pixel.c
+++ b/src/poc/pixel.c
@@ -8,10 +8,10 @@ handle(struct notcurses* nc, const char *fn){
   if(ncv == NULL){
     return -1;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
-  for(int y = 0 ; y < dimy ; y += 15){
-    for(int x = 0 ; x < dimx ; x += 15){
+  for(unsigned y = 0 ; y < dimy ; y += 15){
+    for(unsigned x = 0 ; x < dimx ; x += 15){
       uint64_t channels = NCCHANNELS_INITIALIZER(rand() % 256, rand() % 256, 100, rand() % 256, 100, 140);
       ncplane_set_base(stdn, "a", 0, channels);
       struct ncvisual_options vopts = {
diff --git a/src/poc/procroller.c b/src/poc/procroller.c
index 54b3d76d07..39b545c415 100644
--- a/src/poc/procroller.c
+++ b/src/poc/procroller.c
@@ -43,9 +43,9 @@ int main(int argc, char** argv){
   }
   setlocale(LC_ALL, "");
   notcurses_options opts = {
-    .flags = NCOPTION_INHIBIT_SETLOCALE
-              | NCOPTION_SUPPRESS_BANNERS
-              | NCOPTION_DRAIN_INPUT,
+    .flags = NCOPTION_NO_ALTERNATE_SCREEN
+              | NCOPTION_INHIBIT_SETLOCALE
+              | NCOPTION_SUPPRESS_BANNERS,
   };
   struct notcurses* nc = notcurses_core_init(&opts, NULL);
   if(nc == NULL){
@@ -73,7 +73,10 @@ int main(int argc, char** argv){
   ncplane_set_fg_rgb(std, 0x00bcaa);
   ncplane_printf_aligned(std, -1, NCALIGN_CENTER, "press any key to continue (%s)", *argv);
   notcurses_render(nc);
-  notcurses_get(nc, NULL, NULL);
+  ncinput ni;
+  do{
+    notcurses_getc_blocking(nc, &ni);
+  }while(ni.evtype == NCTYPE_RELEASE);
   if(notcurses_stop(nc)){
     return EXIT_FAILURE;
   }
diff --git a/src/poc/progbar.c b/src/poc/progbar.c
index 34a5bca35d..05ba68d2f0 100644
--- a/src/poc/progbar.c
+++ b/src/poc/progbar.c
@@ -31,7 +31,7 @@ pbar_fill(struct notcurses* nc, struct ncprogbar* pbar){
 
 static struct ncprogbar*
 hbar_make(struct notcurses* nc, uint64_t flags){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
   struct ncplane_options nopts = {
     .y = 1,
@@ -45,8 +45,9 @@ hbar_make(struct notcurses* nc, uint64_t flags){
   if(pbar == NULL){
     return NULL;
   }
-  int posy, posx, pdimy, pdimx;
+  int posy, posx;
   ncplane_yx(pbar, &posy, &posx);
+  unsigned pdimy, pdimx;
   ncplane_dim_yx(pbar, &pdimy, &pdimx);
   ncplane_cursor_move_yx(std, posy - 1, posx - 1);
   uint64_t channels = 0;
@@ -71,7 +72,7 @@ hbar_make(struct notcurses* nc, uint64_t flags){
 
 static struct ncprogbar*
 pbar_make(struct notcurses* nc, uint64_t flags){
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
   struct ncplane_options nopts = {
     .y = dimy / 2,
@@ -85,8 +86,9 @@ pbar_make(struct notcurses* nc, uint64_t flags){
   if(pbar == NULL){
     return NULL;
   }
-  int posy, posx, pdimy, pdimx;
+  int posy, posx;
   ncplane_yx(pbar, &posy, &posx);
+  unsigned pdimy, pdimx;
   ncplane_dim_yx(pbar, &pdimy, &pdimx);
   ncplane_cursor_move_yx(std, posy - 1, posx - 1);
   uint64_t channels = 0;
diff --git a/src/poc/qrcode.c b/src/poc/qrcode.c
index c6114e01a7..5ed5167608 100644
--- a/src/poc/qrcode.c
+++ b/src/poc/qrcode.c
@@ -4,7 +4,7 @@
 
 static int
 render_qrcode(struct ncplane* n, int dimy, int dimx, const char* text){
-  int y = dimy, x = dimx;
+  unsigned y = dimy, x = dimx;
   ncplane_home(n);
   int ver = ncplane_qrcode(n, &y, &x, text, strlen(text));
   if(ver < 0){
@@ -30,7 +30,7 @@ int main(int argc, const char** argv){
              | NCOPTION_DRAIN_INPUT,
   };
   struct notcurses* nc = notcurses_init(&opts, NULL);
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
   while(*++argv){
     if(render_qrcode(std, dimy, dimx, *argv)){
diff --git a/src/poc/rgb.c b/src/poc/rgb.c
index 84a936a328..afd2bccd4f 100644
--- a/src/poc/rgb.c
+++ b/src/poc/rgb.c
@@ -17,7 +17,7 @@ int main(void){
   if(nc == NULL){
     return EXIT_FAILURE;
   }
-  int y, x, dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stdplane(nc);
   ncplane_dim_yx(n, &dimy, &dimx);
   int r , g, b;
@@ -25,8 +25,8 @@ int main(void){
   g = 0x80;
   b = 0;
   ncplane_set_bg_rgb8(n, 0x40, 0x20, 0x40);
-  for(y = 0 ; y < dimy ; ++y){
-    for(x = 0 ; x < dimx ; ++x){
+  for(unsigned y = 0 ; y < dimy ; ++y){
+    for(unsigned x = 0 ; x < dimx ; ++x){
       if(ncplane_set_fg_rgb8(n, r, g, b)){
         goto err;
       }
diff --git a/src/poc/rotate.c b/src/poc/rotate.c
index 1ca5d65378..72efb39d11 100644
--- a/src/poc/rotate.c
+++ b/src/poc/rotate.c
@@ -29,7 +29,7 @@ int main(int argc, char** argv){
   if((nc = notcurses_init(&opts, NULL)) == NULL){
     return EXIT_FAILURE;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = ncplane_dup(notcurses_stddim_yx(nc, &dimy, &dimx), NULL);
   if(!n){
     notcurses_stop(nc);
diff --git a/src/poc/rtl.c b/src/poc/rtl.c
index 3f09d9a88d..21b919dbe3 100644
--- a/src/poc/rtl.c
+++ b/src/poc/rtl.c
@@ -10,7 +10,7 @@ int main(void){
   if(!nc){
     return EXIT_FAILURE;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   ncplane_printf_yx(n, dimy / 2 - 2, 0, "ࡢ‎ࡣ‎ࡤ‎ࡥ‎ࡦ‎ࡧ‎ࡨ‎ࡩ‎ࡪ‎ࢠ‎ࢡ‎ࢢ‎ࢣ‎ࢤ‎ࢥ‎ࢦ‎ࢧ‎ࢨ‎ࢩ‎ࢪ‎ࢫ‎ࢬ‎ࢭ‎ࢮ‎ࢯ‎ࢰ‎ࢱ‎ࢲ‎ࢳ‎ࢴ‎ࢶ‎ࢷ‎ࢸ‎ࢹ‎ࢺ‎ࢻ‎ࢼ‎ࢽ‎࣢ः");
   ncplane_printf_yx(n, dimy / 2 - 1, 0, "࠲‎࠳‎࠴‎࠵‎࠶‎࠷‎࠸‎࠹‎࠺‎࠻‎࠼‎࠽‎࠾‎ࡀ‎ࡁ‎ࡂ‎ࡃ‎ࡄ‎ࡅ‎ࡆ‎ࡇ‎ࡈ‎ࡉ‎ࡊ‎ࡋ‎ࡌ‎ࡍ‎ࡎ‎ࡏ‎ࡐ‎ࡑ‎ࡒ‎ࡓ‎ࡔ‎ࡕ‎ࡖ‎ࡗ‎ࡘ‎࡞‎ࡡ");
@@ -28,8 +28,8 @@ int main(void){
   }
   const char* brew = "םבעברஸீரோகிரிﻧﺎﻠﻘﺻﺮﻴﻧﻖﺻﺭﺎoshitﻠﺷﻮﻗﺎﻠﺴﻛﺮﻳﺓ";
   const char *b = brew;
-  for(int y = dimy / 2 + 2 ; y < dimy ; ++y){
-    for(int x = 0 ; x < dimx ; ++x){
+  for(unsigned y = dimy / 2 + 2 ; y < dimy ; ++y){
+    for(unsigned x = 0 ; x < dimx ; ++x){
       int bytes;
       if(ncplane_putegc_yx(n, y, x, b, &bytes) <= 0){
         break;
diff --git a/src/poc/scroll.c b/src/poc/scroll.c
index f803206f15..135fe2e04c 100644
--- a/src/poc/scroll.c
+++ b/src/poc/scroll.c
@@ -14,7 +14,7 @@ int main(void){
   if(nc == NULL){
     return EXIT_FAILURE;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   char c = 'A';
   ncplane_set_scrolling(n, true);
diff --git a/src/poc/sgr-full.c b/src/poc/sgr-full.c
index 44845b15c4..5ff0903a47 100644
--- a/src/poc/sgr-full.c
+++ b/src/poc/sgr-full.c
@@ -13,7 +13,7 @@ int main(void){
   if(nc == NULL){
     return EXIT_FAILURE;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
   ncplane_set_scrolling(n, true);
   // FIXME do full permutations?
diff --git a/src/poc/statepixel.c b/src/poc/statepixel.c
index 9d71efdf8f..35150e2927 100644
--- a/src/poc/statepixel.c
+++ b/src/poc/statepixel.c
@@ -7,7 +7,7 @@
 static int
 across_row(struct notcurses* nc, int y, struct ncplane* n, struct ncplane* t,
            const struct timespec* ds){
-  for(int x = 0 ; x < ncplane_dim_x(n) ; ++x){
+  for(unsigned x = 0 ; x < ncplane_dim_x(n) ; ++x){
     if(ncplane_move_yx(t, y, x)){
       return -1;
     }
@@ -21,7 +21,7 @@ across_row(struct notcurses* nc, int y, struct ncplane* n, struct ncplane* t,
 
 static int
 across_bmap(struct notcurses* nc, struct ncplane* n, struct ncplane* t, const struct timespec* ds){
-  for(int y = 0 ; y < ncplane_dim_y(n) - 1 ; ++y){
+  for(unsigned y = 0 ; y < ncplane_dim_y(n) - 1 ; ++y){
     if(across_row(nc, y, n, t, ds)){
       return -1;
     }
diff --git a/src/poc/tabbed.c b/src/poc/tabbed.c
index 45b0fddfb9..caddb17be5 100644
--- a/src/poc/tabbed.c
+++ b/src/poc/tabbed.c
@@ -63,7 +63,7 @@ int main(int argc, char** argv){
   if(!nc){
     return EXIT_FAILURE;
   }
-  int rows, cols;
+  unsigned rows, cols;
   struct ncplane* stdp = notcurses_stddim_yx(nc, &rows, &cols);
   struct ncplane_options popts = {
     .y = 3,
diff --git a/src/poc/tree.c b/src/poc/tree.c
index ee41365738..a12f031eb9 100644
--- a/src/poc/tree.c
+++ b/src/poc/tree.c
@@ -413,8 +413,7 @@ ncdup_paint(struct ncplane* n){
   uint32_t tr = NCCHANNEL_INITIALIZER(0x88, 0x88, 0x88);
   uint32_t bl = NCCHANNEL_INITIALIZER(0x88, 0x88, 0x88);
   uint32_t br = NCCHANNEL_INITIALIZER(0xff, 0xff, 0xff);
-  return ncplane_highgradient_sized(n, tl, tr, bl, br,
-                                    ncplane_dim_y(n), ncplane_dim_x(n));
+  return ncplane_gradient2x1(n, -1, -1, 0, 0, tl, tr, bl, br);
 }
 
 static int
diff --git a/src/pocpp/reader.cpp b/src/pocpp/reader.cpp
index 6aa04346f8..0798872349 100644
--- a/src/pocpp/reader.cpp
+++ b/src/pocpp/reader.cpp
@@ -31,7 +31,7 @@ auto main(int argc, const char** argv) -> int {
   notcurses_options ncopts{};
   ncopts.flags = NCOPTION_INHIBIT_SETLOCALE;
   NotCurses nc(ncopts);
-  int dimy, dimx;
+  unsigned dimy, dimx;
   auto n = std::make_unique<Plane *>(nc.get_stdplane(&dimy, &dimx));
   nc.get_term_dim(&dimy, &dimx);
   ncreader_options opts{};
@@ -55,12 +55,12 @@ auto main(int argc, const char** argv) -> int {
     return EXIT_FAILURE;
   }
   ncinput ni;
-  int tgeomy, tgeomx, vgeomy, vgeomx;
+  unsigned tgeomy, tgeomx, vgeomy, vgeomx;
   struct ncplane* ncp = ncreader_plane(nr);
   struct ncplane* tplane = ncplane_above(ncp);
   ncplane_dim_yx(tplane, &tgeomy, &tgeomx);
   ncplane_dim_yx(ncp, &vgeomy, &vgeomx);
-  (*n)->printf(0, 0, "Scroll: %c Cursor: 000/000 Viewgeom: %03d/%03d Textgeom: %03d/%03d",
+  (*n)->printf(0, 0, "Scroll: %c Cursor: 000/000 Viewgeom: %03u/%03u Textgeom: %03u/%03u",
                horscroll ? '+' : '-', vgeomy, vgeomx, tgeomy, tgeomx);
   nc.render();
   while(nc.get(true, &ni) != (char32_t)-1){
@@ -72,11 +72,11 @@ auto main(int argc, const char** argv) -> int {
     }else if((ni.ctrl && ni.id == 'D') || ni.id == NCKEY_ENTER){
       break;
     }else if(ncreader_offer_input(nr, &ni)){
-      int ncpy, ncpx;
+      unsigned ncpy, ncpx;
       ncplane_cursor_yx(ncp, &ncpy, &ncpx);
       ncplane_dim_yx(tplane, &tgeomy, &tgeomx);
       ncplane_dim_yx(ncp, &vgeomy, &vgeomx);
-      (*n)->printf(0, 0, "Scroll: %c Cursor: %03d/%03d Viewgeom: %03d/%03d Textgeom: %03d/%03d",
+      (*n)->printf(0, 0, "Scroll: %c Cursor: %03u/%03u Viewgeom: %03u/%03u Textgeom: %03u/%03u",
                    horscroll ? '+' : '-', ncpy, ncpx, vgeomy, vgeomx, tgeomy, tgeomx);
       nc.render();
     }
diff --git a/src/pocpp/reel.cpp b/src/pocpp/reel.cpp
index 1d2b04e295..3c41e0580e 100644
--- a/src/pocpp/reel.cpp
+++ b/src/pocpp/reel.cpp
@@ -16,7 +16,7 @@ class TabletCtx {
       lines(rand() % 5 + 3),
       rgb(rand() % 0x1000000),
       idx(++class_idx) {}
-    int getLines() const {
+    unsigned getLines() const {
       return lines;
     }
     void addLine() {
@@ -51,7 +51,7 @@ int tabletfxn(struct nctablet* _t, bool cliptop __attribute__ ((unused))){
   p->release(c);
   p->set_bg_rgb(0xffffff);
   p->set_fg_rgb(0x000000);
-  int ret = tctx->getLines();
+  unsigned ret = tctx->getLines();
   if(ret > p->get_dim_y()){
     ret = p->get_dim_y();
   }
@@ -189,7 +189,7 @@ int runreels(struct notcurses* nc, struct ncreel* nr){
 static int
 resize_reel(struct ncplane* n){
   const struct ncplane* p = ncplane_parent_const(n);
-  int py, px;
+  unsigned py, px;
   ncplane_dim_yx(p, &py, &px);
   if(ncplane_resize(n, 0, 0, 0, 0, 0, 0, py - 1, px) < 0){
     return -1;
@@ -210,7 +210,7 @@ int main(int argc, char** argv){
   if(nc == nullptr){
     return EXIT_FAILURE;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   auto nstd = notcurses_stddim_yx(nc, &dimy, &dimx);
   struct ncplane* n;
   if(ncplane_putstr_aligned(nstd, 0, NCALIGN_CENTER, "(a)dd (d)el (+/-) change lines (q)uit") <= 0){
diff --git a/src/pocpp/resize.cpp b/src/pocpp/resize.cpp
index 4ee8520ae9..40480f0620 100644
--- a/src/pocpp/resize.cpp
+++ b/src/pocpp/resize.cpp
@@ -23,7 +23,7 @@ int main(int argc, char** argv){
   }
   struct ncvisual_options vopts{};
   bool failed = false;
-  int dimy, dimx;
+  unsigned dimy, dimx;
   int top = 0;
   int bot;
   auto ncv = ncvisual_from_file(file);
@@ -53,7 +53,7 @@ int main(int argc, char** argv){
     if(notcurses_render(nc)){
       goto err;
     }
-    if(top > bot){
+    if(top >= bot){
       break;
     }
     // one from bottom
diff --git a/src/pocpp/rgbbg.cpp b/src/pocpp/rgbbg.cpp
index 99c20a308c..c74b2d109a 100644
--- a/src/pocpp/rgbbg.cpp
+++ b/src/pocpp/rgbbg.cpp
@@ -14,7 +14,7 @@ auto main() -> int {
   if(nc == nullptr){
     return EXIT_FAILURE;
   }
-  int y, x, dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n = notcurses_stdplane(nc);
   ncplane_dim_yx(n, &dimy, &dimx);
   int r , g, b;
@@ -22,11 +22,11 @@ auto main() -> int {
   g = 0x80;
   b = 0;
   ncplane_set_fg_rgb8(n, 0x40, 0x20, 0x40);
-  for(y = 0 ; y < dimy ; ++y){
+  for(unsigned y = 0 ; y < dimy ; ++y){
     if(ncplane_cursor_move_yx(n, y, 0)){
       goto err;
     }
-    for(x = 0 ; x < dimx ; ++x){
+    for(unsigned x = 0 ; x < dimx ; ++x){
       if(ncplane_set_bg_rgb8(n, r, g, b)){
         goto err;
       }
diff --git a/src/tetris/background.h b/src/tetris/background.h
index 650fd2bbd2..978aa3df54 100644
--- a/src/tetris/background.h
+++ b/src/tetris/background.h
@@ -14,7 +14,7 @@ void DrawBoard() { // draw all fixed components of the game
   }catch(...){
     stdplane_->printf(1, 1, "couldn't load %s", BackgroundFile.c_str());
   }
-  int y, x;
+  unsigned y, x;
   stdplane_->get_dim(&y, &x);
   board_top_y_ = y - (BOARD_HEIGHT + 2);
   board_ = std::make_unique<ncpp::Plane>(BOARD_HEIGHT, BOARD_WIDTH * 2,
diff --git a/src/tetris/lock.h b/src/tetris/lock.h
index 38766c4f7d..3cad98c180 100644
--- a/src/tetris/lock.h
+++ b/src/tetris/lock.h
@@ -1,6 +1,6 @@
 bool LockPiece(){ // returns true if game has ended by reaching level 16
   curpiece_->mergedown_simple(*board_);
-  int bdimy, bdimx;
+  unsigned bdimy, bdimx;
   board_->get_dim(&bdimy, &bdimx);
   int cleared; // how many contiguous lines were cleared
   do{
@@ -16,7 +16,7 @@ bool LockPiece(){ // returns true if game has ended by reaching level 16
     }
     if(cleared){ // topmost verified clear is y + 1, bottommost is y + cleared
       for(int dy = y ; dy >= 0 ; --dy){
-        for(int x = 1 ; x < bdimx - 1 ; ++x){
+        for(unsigned x = 1 ; x < bdimx - 1 ; ++x){
           ncpp::Cell c;
           board_->get_at(dy, x, &c);
           board_->putc(dy + cleared, x, &c);
diff --git a/src/tetris/newpiece.h b/src/tetris/newpiece.h
index 5040a273ce..932bdd1b8d 100644
--- a/src/tetris/newpiece.h
+++ b/src/tetris/newpiece.h
@@ -13,7 +13,7 @@ std::unique_ptr<ncpp::Plane> NewPiece() {
   const int tidx = rand() % 7;
   const struct tetrimino* t = &tetriminos[tidx];
   const size_t cols = strlen(t->texture);
-  int y, x;
+  unsigned y, x;
   stdplane_->get_dim(&y, &x);
   const int xoff = x / 2 - BOARD_WIDTH + 2 * (rand() % (BOARD_WIDTH / 2));
   std::unique_ptr<ncpp::Plane> n = std::make_unique<ncpp::Plane>(2, cols, board_top_y_ - 1, xoff, nullptr);
diff --git a/src/tetris/stain.h b/src/tetris/stain.h
index 436a6e33b8..c47af8ad30 100644
--- a/src/tetris/stain.h
+++ b/src/tetris/stain.h
@@ -14,5 +14,5 @@ void StainBoard(int dimy, int dimx){
   uint64_t tr = NCCHANNELS_INITIALIZER(c2, green, c1, c2, green, c1);
   uint64_t bl = NCCHANNELS_INITIALIZER(c2, green, c1, c2, green, c1);
   uint64_t br = NCCHANNELS_INITIALIZER(c1, green, c2, c1, green, c2);
-  board_->stain(dimy - 2, dimx - 2, tl, tr, bl, br);
+  board_->stain(0, 1, dimy - 1, dimx - 2, tl, tr, bl, br);
 }
diff --git a/src/tetris/stuck.h b/src/tetris/stuck.h
index d17f188790..4763bd438f 100644
--- a/src/tetris/stuck.h
+++ b/src/tetris/stuck.h
@@ -1,5 +1,5 @@
 bool InvalidMove() { // a bit wasteful, but pieces are tiny
-  int dy, dx;
+  unsigned dy, dx;
   curpiece_->get_dim(&dy, &dx);
   while(dy--){
     int x = dx;
@@ -12,7 +12,8 @@ bool InvalidMove() { // a bit wasteful, but pieces are tiny
       curpiece_->release(c);
       int transy = dy, transx = x; // need game area coordinates via translation
       curpiece_->translate(*board_, &transy, &transx);
-      if(transy < 0 || transy >= board_->get_dim_y() || transx < 0 || transx >= board_->get_dim_x()){
+      if(transy < 0 || (unsigned)transy >= board_->get_dim_y()
+          || transx < 0 || (unsigned)transx >= board_->get_dim_x()){
         return true;
       }
       board_->get_at(transy, transx, &b);


Test patch:
diff --git a/src/tests/Ncpp.cpp b/src/tests/Ncpp.cpp
index 1f39355961..361dfde0fd 100644
--- a/src/tests/Ncpp.cpp
+++ b/src/tests/Ncpp.cpp
@@ -42,7 +42,7 @@ TEST_CASE("Ncpp"
     NotCurses nc{ nopts };
     auto std1 = nc.get_stdplane();
     CHECK(nullptr != std1);
-    int y, x;
+    unsigned y, x;
     auto std2 = nc.get_stdplane(&y, &x);
     CHECK(nullptr != std2);
     CHECK(0 < x);
diff --git a/src/tests/bitmap.cpp b/src/tests/bitmap.cpp
index 497ac3d0d1..43514b5771 100644
--- a/src/tests/bitmap.cpp
+++ b/src/tests/bitmap.cpp
@@ -52,7 +52,7 @@ TEST_CASE("Bitmaps") {
     vopts.n = nn;
     vopts.blitter = NCBLIT_PIXEL;
     vopts.flags = NCVISUAL_OPTION_NODEGRADE;
-    int maxy, maxx;
+    unsigned maxy, maxx;
     ncplane_pixelgeom(n_, nullptr, nullptr, nullptr, nullptr, &maxy, &maxx);
     CHECK(0 == ncvisual_resize(ncv, maxy, maxx));
     auto n = ncvisual_blit(nc_, ncv, &vopts);
@@ -539,7 +539,7 @@ TEST_CASE("Bitmaps") {
     CHECK(s->dimy == dimy);
     CHECK(s->dimx == dimx);
     const auto tam = n->tam;
-    for(int i = 0 ; i < s->dimy * s->dimx ; ++i){
+    for(unsigned i = 0 ; i < s->dimy * s->dimx ; ++i){
       int py = (i / dimx) * nc_->tcache.cellpixy;
       int px = (i % dimx) * nc_->tcache.cellpixx;
       // cells with a transparent pixel ought be SPRIXCELL_MIXED;
@@ -595,10 +595,10 @@ TEST_CASE("Bitmaps") {
     CHECK(newn);
     ncplane_move_bottom(newn);
     CHECK(0 == notcurses_render(nc_));
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         CHECK(1 == ncplane_putchar_yx(n_, y, x, 'x'));
         // FIXME generates too much output, OOMing ctest
         // CHECK(0 == notcurses_render(nc_));
@@ -624,7 +624,7 @@ TEST_CASE("Bitmaps") {
     vopts.flags = NCVISUAL_OPTION_NODEGRADE | NCVISUAL_OPTION_CHILDPLANE;
     auto n = ncvisual_blit(nc_, ncv, &vopts);
     REQUIRE(nullptr != n);
-    for(int i = 0 ; i <= ncplane_dim_x(n_) ; ++i){
+    for(unsigned i = 0 ; i <= ncplane_dim_x(n_) ; ++i){
       CHECK(0 == ncplane_move_yx(n, 0, i));
       CHECK(0 == notcurses_render(nc_));
     }
@@ -646,7 +646,7 @@ TEST_CASE("Bitmaps") {
     vopts.x = ncplane_dim_x(n_) - 3;
     auto n = ncvisual_blit(nc_, ncv, &vopts);
     REQUIRE(nullptr != n);
-    for(int i = ncplane_dim_x(n_) - 3 ; i >= 0 ; --i){
+    for(int i = static_cast<int>(ncplane_dim_x(n_)) - 3 ; i >= 0 ; --i){
       CHECK(0 == ncplane_move_yx(n, 0, i));
       CHECK(0 == notcurses_render(nc_));
     }
@@ -667,7 +667,7 @@ TEST_CASE("Bitmaps") {
     vopts.flags = NCVISUAL_OPTION_NODEGRADE | NCVISUAL_OPTION_CHILDPLANE;
     auto n = ncvisual_blit(nc_, ncv, &vopts);
     REQUIRE(nullptr != n);
-    for(int i = 0 ; i <= ncplane_dim_y(n_) ; ++i){
+    for(unsigned i = 0 ; i <= ncplane_dim_y(n_) ; ++i){
       CHECK(0 == ncplane_move_yx(n, i, 0));
       CHECK(0 == notcurses_render(nc_));
     }
@@ -689,7 +689,7 @@ TEST_CASE("Bitmaps") {
     vopts.flags = NCVISUAL_OPTION_NODEGRADE | NCVISUAL_OPTION_CHILDPLANE;
     auto n = ncvisual_blit(nc_, ncv, &vopts);
     REQUIRE(nullptr != n);
-    for(int i = ncplane_dim_y(n_) - 3 ; i >= 0 ; --i){
+    for(int i = static_cast<int>(ncplane_dim_y(n_)) - 3 ; i >= 0 ; --i){
       CHECK(0 == ncplane_move_yx(n, i, 0));
       CHECK(0 == notcurses_render(nc_));
     }
diff --git a/src/tests/cell.cpp b/src/tests/cell.cpp
index 7c1ee906d5..77248c200a 100644
--- a/src/tests/cell.cpp
+++ b/src/tests/cell.cpp
@@ -71,7 +71,7 @@ TEST_CASE("Cell") {
 
   SUBCASE("SetItalic") {
     nccell c = CELL_TRIVIAL_INITIALIZER;
-    int dimy, dimx;
+    unsigned dimy, dimx;
     notcurses_term_dim_yx(nc_, &dimy, &dimx);
     nccell_set_styles(&c, NCSTYLE_ITALIC);
     CHECK(1 == nccell_load(n_, &c, "i"));
@@ -84,7 +84,7 @@ TEST_CASE("Cell") {
 
   SUBCASE("SetBold") {
     nccell c = CELL_TRIVIAL_INITIALIZER;
-    int dimy, dimx;
+    unsigned dimy, dimx;
     notcurses_term_dim_yx(nc_, &dimy, &dimx);
     nccell_set_styles(&c, NCSTYLE_BOLD);
     CHECK(1 == nccell_load(n_, &c, "b"));
@@ -97,7 +97,7 @@ TEST_CASE("Cell") {
 
   SUBCASE("SetUnderline") {
     nccell c = CELL_TRIVIAL_INITIALIZER;
-    int dimy, dimx;
+    unsigned dimy, dimx;
     notcurses_term_dim_yx(nc_, &dimy, &dimx);
     nccell_set_styles(&c, NCSTYLE_UNDERLINE);
     CHECK(1 == nccell_load(n_, &c, "u"));
diff --git a/src/tests/direct.cpp b/src/tests/direct.cpp
index e611037f66..a364ac1b53 100644
--- a/src/tests/direct.cpp
+++ b/src/tests/direct.cpp
@@ -139,14 +139,12 @@ TEST_CASE("Direct") {
       CHECK(nullptr != ncdv);
       CHECK(0 == ncdirect_raster_frame(nc_, ncdv, NCALIGN_LEFT));
       ncdirectf_free(dirf);
-      int y, x;
-      int dimy = ncdirect_dim_y(nc_);
-      int dimx = ncdirect_dim_x(nc_);
+      unsigned y, x;
       // FIXME fails if u6 is reversed (on e.g. kmscon)
       CHECK(0 == ncdirect_cursor_yx(nc_, &y, &x));
-      CHECK(0 <= y);
+      auto dimy = ncdirect_dim_y(nc_);
+      auto dimx = ncdirect_dim_x(nc_);
       CHECK(dimy > y);
-      CHECK(0 <= x);
       CHECK(dimx > x);
     }
   }
@@ -163,13 +161,11 @@ TEST_CASE("Direct") {
         CHECK(nullptr != ncdv);
         CHECK(0 == ncdirect_raster_frame(nc_, ncdv, NCALIGN_LEFT));
         ncdirectf_free(dirf);
-        int y, x;
-        int dimy = ncdirect_dim_y(nc_);
-        int dimx = ncdirect_dim_x(nc_);
+        unsigned y, x;
         CHECK(0 == ncdirect_cursor_yx(nc_, &y, &x));
-        CHECK(0 <= y);
+        auto dimy = ncdirect_dim_y(nc_);
+        auto dimx = ncdirect_dim_x(nc_);
         CHECK(dimy > y);
-        CHECK(0 <= x);
         CHECK(dimx > x);
       }
     }
diff --git a/src/tests/erase.cpp b/src/tests/erase.cpp
index 86e7260127..121065bb87 100644
--- a/src/tests/erase.cpp
+++ b/src/tests/erase.cpp
@@ -7,7 +7,7 @@ TEST_CASE("Erase") {
   if(!nc_){
     return;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
   REQUIRE(n_);
 
@@ -21,8 +21,8 @@ TEST_CASE("Erase") {
   // clear all columns to the left of cursor, inclusive
   SUBCASE("EraseColumnsLeft") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, 0, -INT_MAX));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(x <= dimx / 2){
@@ -38,8 +38,8 @@ TEST_CASE("Erase") {
   // clear all columns to the right of cursor, inclusive
   SUBCASE("EraseColumnsRight") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, 0, INT_MAX));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(x >= dimx / 2){
@@ -55,8 +55,8 @@ TEST_CASE("Erase") {
   // clear all rows above cursor, inclusive
   SUBCASE("EraseRowsAbove") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, -INT_MAX, 0));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(y <= dimy / 2){
@@ -72,8 +72,8 @@ TEST_CASE("Erase") {
   // clear all rows below cursor, inclusive
   SUBCASE("EraseRowsBelow") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, INT_MAX, 0));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(y >= dimy / 2){
@@ -89,8 +89,8 @@ TEST_CASE("Erase") {
   // current cursor to the end of the line
   SUBCASE("EraseToEOL") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, 1, INT_MAX));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(y == dimy / 2 && x >= dimx / 2){
@@ -106,8 +106,8 @@ TEST_CASE("Erase") {
   // current cursor to the start of the line
   SUBCASE("EraseToSOL") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, 1, -INT_MAX));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(y == dimy / 2 && x <= dimx / 2){
@@ -123,8 +123,8 @@ TEST_CASE("Erase") {
   // current cursor to the end of the line using -1 len
   SUBCASE("EraseToEOLNeg") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, -1, INT_MAX));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(y == dimy / 2 && x >= dimx / 2){
@@ -140,8 +140,8 @@ TEST_CASE("Erase") {
   // current cursor to the start of the line using -1 len
   SUBCASE("EraseToSOLNeg") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, -1, -INT_MAX));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(y == dimy / 2 && x <= dimx / 2){
@@ -157,8 +157,8 @@ TEST_CASE("Erase") {
   // current cursor only
   SUBCASE("EraseCurrentCursor") {
     CHECK(0 == ncplane_erase_region(n_, -1, -1, 1, 1));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         char* c = ncplane_at_yx(n_, y, x, nullptr, nullptr);
         REQUIRE(nullptr != c);
         if(y == dimy / 2 && x == dimx / 2){
diff --git a/src/tests/fade.cpp b/src/tests/fade.cpp
index f46f58dd71..8c3c86975c 100644
--- a/src/tests/fade.cpp
+++ b/src/tests/fade.cpp
@@ -38,14 +38,14 @@ TEST_CASE("Fade") {
     return;
   }
   REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
-  int dimy, dimx;
+  unsigned dimy, dimx;
   ncplane_dim_yx(n_, &dimy, &dimx);
   nccell c = CELL_CHAR_INITIALIZER('*');
   nccell_set_fg_rgb8(&c, 0xff, 0xff, 0xff);
   unsigned rgb = 0xffffffu;
   CHECK(!ncplane_set_scrolling(n_, true));
-  for(int y = 0 ; y < dimy ; ++y){
-    for(int x = 0 ; x < dimx ; ++x){
+  for(unsigned y = 0 ; y < dimy ; ++y){
+    for(unsigned x = 0 ; x < dimx ; ++x){
       rgb -= 32;
       if(rgb < 32){
         rgb = 0xffffffu;
diff --git a/src/tests/fbuf.cpp b/src/tests/fbuf.cpp
index 510897e7de..06dc827550 100644
--- a/src/tests/fbuf.cpp
+++ b/src/tests/fbuf.cpp
@@ -6,7 +6,7 @@ TEST_CASE("Fbuf") {
   if(!nc_){
     return;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
   REQUIRE(n_);
   REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
diff --git a/src/tests/fills.cpp b/src/tests/fills.cpp
index 7217f682be..2f0b73bbb0 100644
--- a/src/tests/fills.cpp
+++ b/src/tests/fills.cpp
@@ -16,7 +16,7 @@ TEST_CASE("Fills") {
 
   // can't polyfill with a null glyph
   SUBCASE("PolyfillNullGlyph") {
-    int dimx, dimy;
+    unsigned dimx, dimy;
     ncplane_dim_yx(n_, &dimy, &dimx);
     nccell c = CELL_TRIVIAL_INITIALIZER;
     CHECK(0 > ncplane_polyfill_yx(n_, dimy, dimx, &c));
@@ -24,13 +24,13 @@ TEST_CASE("Fills") {
 
   // trying to polyfill an invalid cell ought be an error
   SUBCASE("PolyfillOffplane") {
-    int dimx, dimy;
+    unsigned dimx, dimy;
     ncplane_dim_yx(n_, &dimy, &dimx);
     nccell c = CELL_CHAR_INITIALIZER('+');
     CHECK(0 > ncplane_polyfill_yx(n_, dimy, 0, &c));
     CHECK(0 > ncplane_polyfill_yx(n_, 0, dimx, &c));
-    CHECK(0 > ncplane_polyfill_yx(n_, 0, -1, &c));
-    CHECK(0 > ncplane_polyfill_yx(n_, -1, 0, &c));
+    CHECK(0 > ncplane_polyfill_yx(n_, 0, -2, &c));
+    CHECK(0 > ncplane_polyfill_yx(n_, -2, 0, &c));
   }
 
   SUBCASE("PolyfillOnGlyph") {
@@ -116,16 +116,16 @@ TEST_CASE("Fills") {
     uint64_t c = 0;
     ncchannels_set_fg_rgb(&c, 0x40f040);
     ncchannels_set_bg_rgb(&c, 0x40f040);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
-    REQUIRE(0 < ncplane_gradient_sized(n_, "M", 0, c, c, c, c, dimy, dimx));
+    REQUIRE(0 < ncplane_gradient(n_, -1, -1, dimy, dimx, "M", 0, c, c, c, c));
     nccell cl = CELL_TRIVIAL_INITIALIZER;
     uint64_t channels = 0;
     ncchannels_set_fg_rgb(&channels, 0x40f040);
     ncchannels_set_bg_rgb(&channels, 0x40f040);
     // check all squares 
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         REQUIRE(0 <= ncplane_at_yx_cell(n_, y, x, &cl));
         CHECK(htole('M') == cl.gcluster);
         CHECK(0 == cl.stylemask);
@@ -146,9 +146,9 @@ TEST_CASE("Fills") {
     ncchannels_set_bg_rgb(&ur, 0x40f040);
     ncchannels_set_fg_rgb(&lr, 0xf040f0);
     ncchannels_set_bg_rgb(&lr, 0xf040f0);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
-    REQUIRE(0 < ncplane_gradient_sized(n_, "V", 0, ul, ur, ll, lr, dimy, dimx));
+    REQUIRE(0 < ncplane_gradient(n_, 0, 0, dimy, dimx, "V", 0, ul, ur, ll, lr));
     nccell c = CELL_TRIVIAL_INITIALIZER;
     uint64_t channels = 0;
     ncchannels_set_fg_rgb(&channels, 0x40f040);
@@ -157,9 +157,9 @@ TEST_CASE("Fills") {
     // the components ought be going in the correct direction.
     uint64_t lastyrgb, lastxrgb;
     lastyrgb = -1;
-    for(int y = 0 ; y < dimy ; ++y){
+    for(unsigned y = 0 ; y < dimy ; ++y){
       lastxrgb = -1;
-      for(int x = 0 ; x < dimx ; ++x){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         REQUIRE(0 <= ncplane_at_yx_cell(n_, y, x, &c));
         CHECK(htole('V') == c.gcluster);
         CHECK(0 == c.stylemask);
@@ -197,9 +197,9 @@ TEST_CASE("Fills") {
     ncchannels_set_bg_rgb(&ll, 0x40f040);
     ncchannels_set_fg_rgb(&lr, 0xf040f0);
     ncchannels_set_bg_rgb(&lr, 0xf040f0);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
-    REQUIRE(0 < ncplane_gradient_sized(n_, "H", 0, ul, ur, ll, lr, dimy, dimx));
+    REQUIRE(0 < ncplane_gradient(n_, 0, 0, dimy, dimx, "H", 0, ul, ur, ll, lr));
     // check corners FIXME
     CHECK(0 == notcurses_render(nc_));
   }
@@ -215,9 +215,9 @@ TEST_CASE("Fills") {
     ncchannels_set_bg_rgb(&ur, 0xf040f0);
     ncchannels_set_fg_rgb(&lr, 0xffffff);
     ncchannels_set_bg_rgb(&lr, 0x000000);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
-    REQUIRE(0 < ncplane_gradient_sized(n_, "X", 0, ul, ur, ll, lr, dimy, dimx));
+    REQUIRE(0 < ncplane_gradient(n_, 0, 0, dimy, dimx, "X", 0, ul, ur, ll, lr));
     // check corners FIXME
     CHECK(0 == notcurses_render(nc_));
   }
@@ -233,14 +233,14 @@ TEST_CASE("Fills") {
     ncchannels_set_bg_rgb(&ll, 0xff0000);
     ncchannels_set_fg_rgb(&ur, 0xff00ff);
     ncchannels_set_bg_rgb(&ur, 0x00ff00);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
-    REQUIRE(0 < ncplane_gradient_sized(n_, "S", 0, ul, ur, ll, lr, dimy, dimx));
+    REQUIRE(0 < ncplane_gradient(n_, 0, 0, dimy, dimx, "S", 0, ul, ur, ll, lr));
     // check corners FIXME
     CHECK(0 == notcurses_render(nc_));
   }
 
-  SUBCASE("Ncplane_Format") {
+  SUBCASE("Format") {
     int sbytes;
     CHECK(0 == ncplane_set_fg_rgb(n_, 0x444444));
     CHECK(1 == ncplane_putegc(n_, "A", &sbytes));
@@ -251,32 +251,31 @@ TEST_CASE("Fills") {
     CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
     nccell c = CELL_TRIVIAL_INITIALIZER;
     nccell_on_styles(&c, NCSTYLE_BOLD);
-    CHECK(0 < ncplane_format(n_, 0, 0, c.stylemask));
+    CHECK(0 < ncplane_format(n_, 0, 0, 0, 0, c.stylemask));
     nccell d = CELL_TRIVIAL_INITIALIZER;
     CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
     CHECK(d.stylemask == c.stylemask);
     CHECK(0x444444 == nccell_fg_rgb(&d));
   }
 
-  SUBCASE("Ncplane_Stain") {
+  SUBCASE("Stain") {
     int sbytes;
     CHECK(0 == ncplane_set_fg_rgb(n_, 0x444444));
-    for(int y = 0 ; y < 8 ; ++y){
-      for(int x = 0 ; x < 8 ; ++x){
+    for(unsigned y = 0 ; y < 8 ; ++y){
+      for(unsigned x = 0 ; x < 8 ; ++x){
         CHECK(1 == ncplane_putegc_yx(n_, y, x, "A", &sbytes));
       }
     }
     CHECK(0 == notcurses_render(nc_));
     // EGC/color should change, but nothing else
-    CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
     uint64_t channels = 0;
     ncchannels_set_fg_rgb8(&channels, 0x88, 0x99, 0x77);
     ncchannels_set_bg_rgb(&channels, 0);
-    REQUIRE(0 < ncplane_stain(n_, 7, 7, channels, channels, channels, channels));
+    REQUIRE(0 < ncplane_stain(n_, 0, 0, 7, 7, channels, channels, channels, channels));
     CHECK(0 == notcurses_render(nc_));
     nccell d = CELL_TRIVIAL_INITIALIZER;
-    for(int y = 0 ; y < 8 ; ++y){
-      for(int x = 0 ; x < 8 ; ++x){
+    for(unsigned y = 0 ; y < 7 ; ++y){
+      for(unsigned x = 0 ; x < 7 ; ++x){
         CHECK(1 == ncplane_at_yx_cell(n_, y, x, &d));
         CHECK(channels == d.channels);
         REQUIRE(cell_simple_p(&d));
@@ -291,11 +290,10 @@ TEST_CASE("Fills") {
     CHECK(0 == ncplane_set_fg_rgb(n_, 0x444444));
     CHECK(1 == ncplane_putegc_yx(n_, 0, 0, "A", &sbytes));
     CHECK(0 == notcurses_render(nc_));
-    CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
     uint64_t channels = 0;
     ncchannels_set_fg_rgb8(&channels, 0x88, 0x99, 0x77);
     ncchannels_set_bg_rgb(&channels, 0);
-    REQUIRE(0 < ncplane_gradient(n_, "A", 0, channels, channels, channels, channels, 0, 0));
+    REQUIRE(0 < ncplane_gradient(n_, 0, 0, 0, 0, "A", 0, channels, channels, channels, channels));
     CHECK(0 == notcurses_render(nc_));
     nccell d = CELL_TRIVIAL_INITIALIZER;
     CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
@@ -316,23 +314,22 @@ TEST_CASE("Fills") {
     ncchannels_set_fg_rgb8(&chan2, 0x77, 0x99, 0x88);
     ncchannels_set_bg_rgb(&chan1, 0);
     ncchannels_set_bg_rgb(&chan2, 0);
-    REQUIRE(0 < ncplane_gradient(n_, "A", 0, chan1, chan2, chan1, chan2, 0, 3));
+    CHECK(0 < ncplane_gradient(n_, 0, 0, 0, 3, "A", 0, chan1, chan2, chan1, chan2));
     CHECK(0 == notcurses_render(nc_));
     nccell d = CELL_TRIVIAL_INITIALIZER;
     CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
     CHECK(chan1 == d.channels);
-    REQUIRE(cell_simple_p(&d));
+    CHECK(cell_simple_p(&d));
     CHECK(htole('A') == d.gcluster);
-    CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
-    REQUIRE(0 < ncplane_gradient(n_, "A", 0, chan2, chan1, chan2, chan1, 0, 3));
+    CHECK(0 < ncplane_gradient(n_, 0, 0, 0, 3, "A", 0, chan2, chan1, chan2, chan1));
     CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
-    REQUIRE(cell_simple_p(&d));
+    CHECK(cell_simple_p(&d));
     CHECK(htole('A') == d.gcluster);
     CHECK(chan2 == d.channels);
   }
 
   // Unlike a typical gradient, a high gradient ought be able to do a vertical
-  // change in a single row.
+  // change in a single row (though not a single column).
   SUBCASE("HighGradient2Colors1Row") {
     uint32_t ul, ur, ll, lr;
     ul = ur = ll = lr = 0;
@@ -340,9 +337,8 @@ TEST_CASE("Fills") {
     ncchannel_set(&lr, 0x000000);
     ncchannel_set(&ll, 0x00ffff);
     ncchannel_set(&ur, 0xff00ff);
-    int dimy, dimx;
-    ncplane_dim_yx(n_, &dimy, &dimx);
-    REQUIRE(0 < ncplane_highgradient_sized(n_, ul, ur, ll, lr, dimy, dimx));
+    CHECK(0 > ncplane_gradient2x1(n_, 0, 0, 1, 1, ul, ur, ll, lr));
+    CHECK(0 < ncplane_gradient2x1(n_, 0, 0, 1, 2, ul, ur, ll, lr));
     CHECK(0 == notcurses_render(nc_));
   }
 
@@ -353,9 +349,7 @@ TEST_CASE("Fills") {
     ncchannel_set(&lr, 0x000000);
     ncchannel_set(&ll, 0x00ffff);
     ncchannel_set(&ur, 0xff00ff);
-    int dimy, dimx;
-    ncplane_dim_yx(n_, &dimy, &dimx);
-    REQUIRE(0 < ncplane_highgradient_sized(n_, ul, ur, ll, lr, dimy, dimx));
+    CHECK(0 < ncplane_gradient2x1(n_, 0, 0, 0, 0, ul, ur, ll, lr));
     CHECK(0 == notcurses_render(nc_));
   }
 
@@ -499,8 +493,8 @@ TEST_CASE("Fills") {
     CHECK(0 < ncplane_polyfill_yx(p2, 0, 0, &c2));
     CHECK(0 == ncplane_mergedown_simple(p2, p1));
     CHECK(0 == notcurses_render(nc_));
-    for(int y = 0 ; y < DIMY ; ++y){
-      for(int x = 0 ; x < DIMX ; ++x){
+    for(unsigned y = 0 ; y < DIMY ; ++y){
+      for(unsigned x = 0 ; x < DIMX ; ++x){
         CHECK(0 < ncplane_at_yx_cell(p1, y, x, &c1));
         if(y < 1 || y > 5 || x < 1 || x > 5){
           auto cstr = nccell_strdup(p1, &c1);
@@ -539,7 +533,7 @@ TEST_CASE("Fills") {
     ncchannels_set_fg_rgb(&ur, 0xff0000);
     ncchannels_set_fg_rgb(&bl, 0x00ff00);
     ncchannels_set_fg_rgb(&br, 0x0000ff);
-    ncplane_highgradient_sized(p1, ul, ur, bl, br, DIMY, DIMX);
+    ncplane_gradient2x1(p1, 0, 0, DIMY, DIMX, ul, ur, bl, br);
     CHECK(0 == notcurses_render(nc_));
     struct ncplane_options n2opts = {
       .y = 3,
@@ -554,11 +548,11 @@ TEST_CASE("Fills") {
     };
     auto p2 = ncplane_create(n_, &n2opts);
     REQUIRE(p2);
-    ncplane_highgradient_sized(p2, br, bl, ur, ul, DIMY / 2, DIMX / 2);
+    ncplane_gradient2x1(p2, 0, 0, DIMY / 2, DIMX / 2, br, bl, ur, ul);
     CHECK(0 == ncplane_mergedown_simple(p2, p1));
     CHECK(0 == notcurses_render(nc_));
-    for(int y = 0 ; y < DIMY ; ++y){
-      for(int x = 0 ; x < DIMX ; ++x){
+    for(unsigned y = 0 ; y < DIMY ; ++y){
+      for(unsigned x = 0 ; x < DIMX ; ++x){
         nccell c1 = CELL_TRIVIAL_INITIALIZER;
         CHECK(0 < ncplane_at_yx_cell(p1, y, x, &c1));
         if(y < 1 || y > 5 || x < 1 || x > 5){
@@ -581,9 +575,11 @@ TEST_CASE("Fills") {
 #ifdef USE_QRCODEGEN
   SUBCASE("QRCodes") {
     const char* qr = "a very simple qr code";
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
-    CHECK(0 < ncplane_qrcode(n_, &dimy, &dimx, qr, strlen(qr)));
+    unsigned sdimy = dimy;
+    unsigned sdimx = dimx;
+    CHECK(0 < ncplane_qrcode(n_, &sdimy, &sdimx, qr, strlen(qr)));
     CHECK(0 == notcurses_render(nc_));
   }
 #endif
diff --git a/src/tests/geom.cpp b/src/tests/geom.cpp
index b35b3f3609..1ee9f83ec2 100644
--- a/src/tests/geom.cpp
+++ b/src/tests/geom.cpp
@@ -10,7 +10,7 @@ TEST_CASE("Geometry") {
 
   SUBCASE("Center") {
     const struct test {
-      int leny, lenx;       // geometries
+      unsigned leny, lenx;  // geometries
       int centy, centx;     // pre-calculated centers
     } tests[] = {
       { 1, 1, 0, 0, },
@@ -52,7 +52,7 @@ TEST_CASE("Geometry") {
 
   SUBCASE("CenterAbs") {
     const struct test {
-      int leny, lenx;       // geometries
+      unsigned leny, lenx;  // geometries
       int absy, absx;       // location of the origin
       int centy, centx;     // pre-calculated centers
     } tests[] = {
diff --git a/src/tests/main.cpp b/src/tests/main.cpp
index 8203481eef..cb6a1f3304 100644
--- a/src/tests/main.cpp
+++ b/src/tests/main.cpp
@@ -145,9 +145,9 @@ auto lang_and_term() -> void {
     std::cerr << "Couldn't create notcurses testing framework" << std::endl;
     exit(EXIT_FAILURE);
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   notcurses_stddim_yx(nc, &dimy, &dimx);
-  std::cout << "Detected geometry: " << dimx << 'x' << dimy << std::endl;
+  std::cout << "Detected cell geometry: " << dimx << 'x' << dimy << std::endl;
   notcurses_stop(nc);
   if(dimx < 50 || dimy < 24){ // minimum assumed geometry
     std::cerr << "Terminal was too small for tests (minimum 50x24)" << std::endl;
diff --git a/src/tests/media.cpp b/src/tests/media.cpp
index 6c4e5af798..8352522d0a 100644
--- a/src/tests/media.cpp
+++ b/src/tests/media.cpp
@@ -52,7 +52,7 @@ TEST_CASE("Media") {
   }
 
   SUBCASE("LoadImageCreatePlane") {
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncp_, &dimy, &dimx);
     auto ncv = ncvisual_from_file(find_data("changes.jpg").get());
     REQUIRE(ncv);
@@ -72,7 +72,7 @@ TEST_CASE("Media") {
   }
 
   SUBCASE("LoadImage") {
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncp_, &dimy, &dimx);
     auto ncv = ncvisual_from_file(find_data("changes.jpg").get());
     REQUIRE(ncv);
@@ -88,7 +88,7 @@ TEST_CASE("Media") {
   }
 
   SUBCASE("InflateImage") {
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncp_, &dimy, &dimx);
     auto ncv = ncvisual_from_file(find_data("changes.jpg").get());
     REQUIRE(ncv);
@@ -112,7 +112,7 @@ TEST_CASE("Media") {
   }
 
   SUBCASE("PlaneDuplicate") {
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncp_, &dimy, &dimx);
     auto ncv = ncvisual_from_file(find_data("changes.jpg").get());
     REQUIRE(ncv);
@@ -124,7 +124,7 @@ TEST_CASE("Media") {
     REQUIRE(nullptr != needle);
     struct ncplane* newn = ncplane_dup(ncp_, needle);
     free(needle);
-    int ndimx, ndimy;
+    unsigned ndimx, ndimy;
     REQUIRE(nullptr != newn);
     ncvisual_destroy(ncv);
     ncplane_erase(ncp_);
@@ -137,7 +137,7 @@ TEST_CASE("Media") {
 
   SUBCASE("LoadVideoASCIIScale") {
     if(notcurses_canopen_videos(nc_)){
-      int dimy, dimx;
+      unsigned dimy, dimx;
       ncplane_dim_yx(ncp_, &dimy, &dimx);
       auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
       REQUIRE(ncv);
@@ -161,7 +161,7 @@ TEST_CASE("Media") {
 
   SUBCASE("LoadVideoHalfScale") {
     if(notcurses_canopen_videos(nc_)){
-      int dimy, dimx;
+      unsigned dimy, dimx;
       ncplane_dim_yx(ncp_, &dimy, &dimx);
       auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
       REQUIRE(ncv);
@@ -185,7 +185,7 @@ TEST_CASE("Media") {
   // quadblitter is default for NCSCALE_SCALE_HIRES
   SUBCASE("LoadVideoQuadScale") {
     if(notcurses_canopen_videos(nc_)){
-      int dimy, dimx;
+      unsigned dimy, dimx;
       ncplane_dim_yx(ncp_, &dimy, &dimx);
       auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
       REQUIRE(ncv);
@@ -208,7 +208,7 @@ TEST_CASE("Media") {
 
   SUBCASE("LoadVideoSexScale") {
     if(notcurses_canopen_videos(nc_)){
-      int dimy, dimx;
+      unsigned dimy, dimx;
       ncplane_dim_yx(ncp_, &dimy, &dimx);
       auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
       REQUIRE(ncv);
@@ -231,7 +231,7 @@ TEST_CASE("Media") {
 
   SUBCASE("LoadVideoBrailleScale") {
     if(notcurses_canopen_videos(nc_)){
-      int dimy, dimx;
+      unsigned dimy, dimx;
       ncplane_dim_yx(ncp_, &dimy, &dimx);
       auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
       REQUIRE(ncv);
@@ -256,7 +256,7 @@ TEST_CASE("Media") {
   SUBCASE("LoadVideoPixelStretchOnePlane") {
     if(notcurses_check_pixel_support(nc_) > 0){
       if(notcurses_canopen_videos(nc_)){
-        int dimy, dimx;
+        unsigned dimy, dimx;
         ncplane_dim_yx(ncp_, &dimy, &dimx);
         auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
         REQUIRE(ncv);
@@ -282,10 +282,10 @@ TEST_CASE("Media") {
   }
 
   // do a pixel video with a different plane for each frame
-  SUBCASE("LoadVideoPixelScaleDifferentPlanes") {
+  SUBCASE("LoadVideoPixelStretchDifferentPlanes") {
     if(notcurses_check_pixel_support(nc_) > 0){
       if(notcurses_canopen_videos(nc_)){
-        int dimy, dimx;
+        unsigned dimy, dimx;
         ncplane_dim_yx(ncp_, &dimy, &dimx);
         auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
         REQUIRE(ncv);
@@ -296,10 +296,12 @@ TEST_CASE("Media") {
           }
           CHECK(0 == ret);
           struct ncvisual_options opts{};
-          opts.scaling = NCSCALE_SCALE;
+          opts.scaling = NCSCALE_STRETCH;
           opts.blitter = NCBLIT_PIXEL;
-          REQUIRE(ncvisual_blit(nc_, ncv, &opts));
+          auto n = ncvisual_blit(nc_, ncv, &opts);
+          REQUIRE(nullptr != n);
           CHECK(0 == notcurses_render(nc_));
+          CHECK(0 == ncplane_destroy(n));
         }
         ncvisual_destroy(ncv);
       }
@@ -308,7 +310,7 @@ TEST_CASE("Media") {
 
   SUBCASE("LoopVideo") {
     if(notcurses_canopen_videos(nc_)){
-      int dimy, dimx;
+      unsigned dimy, dimx;
       ncplane_dim_yx(ncp_, &dimy, &dimx);
       auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
       REQUIRE(ncv);
@@ -335,7 +337,7 @@ TEST_CASE("Media") {
 
   SUBCASE("LoadVideoCreatePlane") {
     if(notcurses_canopen_videos(nc_)){
-      int dimy, dimx;
+      unsigned dimy, dimx;
       ncplane_dim_yx(ncp_, &dimy, &dimx);
       auto ncv = ncvisual_from_file(find_data("notcursesIII.mkv").get());
       REQUIRE(ncv);
diff --git a/src/tests/metric.cpp b/src/tests/metric.cpp
index 2164769b53..954555e858 100644
--- a/src/tests/metric.cpp
+++ b/src/tests/metric.cpp
@@ -26,7 +26,7 @@ TEST_CASE("Metric") {
   REQUIRE(0 ==  fesetround(FE_TONEAREST));
 
   SUBCASE("CornerInts") {
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     impericize_ncmetric(0, 1, buf, 0, 1000, '\0');
     CHECK(!strcmp("0.00", buf));
     impericize_ncmetric(0, 1, buf, 0, 1024, 'i');
@@ -74,7 +74,7 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("Maxints") {
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     // FIXME these will change based on the size of intmax_t and uintmax_t
     impericize_ncmetric(INTMAX_MAX - 1, 1, buf, 0, 1000, '\0');
     CHECK(!strcmp("9.22E", buf));
@@ -87,7 +87,7 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("Maxints1024") {
-    char buf[PREFIXSTRLEN + 1], gold[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1], gold[NCPREFIXSTRLEN + 1];
     // FIXME these will change based on the size of intmax_t and uintmax_t
     REQUIRE(ncmetric(((double)(INTMAX_MAX - 1ull)), 1, buf, 0, 1024, 'i'));
     sprintf(gold, "%.2fEi", ((double)(INTMAX_MAX - 1ull)) / (1ull << 60));
@@ -110,8 +110,8 @@ TEST_CASE("Metric") {
   const char suffixes[] = "\0KMGTPE";
 
   SUBCASE("PowersOfTen") {
-    char gold[PREFIXSTRLEN + 1];
-    char buf[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t goldval = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -133,8 +133,8 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("PowersOfTenNoDec") {
-    char gold[PREFIXSTRLEN + 1];
-    char buf[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t goldval = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -156,8 +156,8 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("PowersOfTwo") {
-    char gold[BPREFIXSTRLEN + 1];
-    char buf[BPREFIXSTRLEN + 1];
+    char gold[NCBPREFIXSTRLEN + 1];
+    char buf[NCBPREFIXSTRLEN + 1];
     uintmax_t goldval = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -179,8 +179,8 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("PowersOfTwoNoDec") {
-    char gold[BPREFIXSTRLEN + 1];
-    char buf[BPREFIXSTRLEN + 1];
+    char gold[NCBPREFIXSTRLEN + 1];
+    char buf[NCBPREFIXSTRLEN + 1];
     uintmax_t goldval = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -202,8 +202,8 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("PowersOfTwoAsTens") {
-    char gold[PREFIXSTRLEN + 1];
-    char buf[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t vfloor = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -225,8 +225,8 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("PowersOfTenAsTwos") {
-    char gold[BPREFIXSTRLEN + 1];
-    char buf[BPREFIXSTRLEN + 1];
+    char gold[NCBPREFIXSTRLEN + 1];
+    char buf[NCBPREFIXSTRLEN + 1];
     uintmax_t vfloor = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -248,8 +248,8 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("PowersOfTenMinusOne") {
-    char gold[PREFIXSTRLEN + 1];
-    char buf[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t vfloor = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -271,8 +271,8 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("PowersOfTenPlusOne") {
-    char gold[PREFIXSTRLEN + 1];
-    char buf[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t vfloor = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -294,8 +294,8 @@ TEST_CASE("Metric") {
   }
 
   SUBCASE("PowersOfTenMinusOneAsTwos") {
-    char gold[BPREFIXSTRLEN + 1];
-    char buf[BPREFIXSTRLEN + 1];
+    char gold[NCBPREFIXSTRLEN + 1];
+    char buf[NCBPREFIXSTRLEN + 1];
     uintmax_t vfloor = 1;
     uintmax_t val = 1;
     size_t i = 0;
@@ -323,67 +323,67 @@ TEST_CASE("Metric") {
   // nanoseconds, but want output in seconds.
   // This requires 'decimal' = GIG.
   SUBCASE("ScaledGigSupra") {
-    char gold[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
     snprintf(gold, sizeof(gold), "%.2f", 9.029); // 9.02
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t val = 9027854993;
     uintmax_t decimal = GIG;
-    REQUIRE(qprefix(val, decimal, buf, 0));
+    REQUIRE(ncqprefix(val, decimal, buf, 0));
     CHECK(!strcmp(buf, gold));
   }
 
   SUBCASE("ScaledGigUnity") {
-    char gold[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
     snprintf(gold, sizeof(gold), "%.2f", 1.0); // 1.00
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t decimal = GIG;
     uintmax_t val = decimal;
-    REQUIRE(qprefix(val, decimal, buf, 0));
+    REQUIRE(ncqprefix(val, decimal, buf, 0));
     CHECK(!strcmp(buf, gold));
   }
 
   SUBCASE("ScaledGigJustAbove") {
-    char gold[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
     snprintf(gold, sizeof(gold), "%.2f", 1.0); // 1.00
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t val = 1000000001;
     uintmax_t decimal = GIG;
-    REQUIRE(qprefix(val, decimal, buf, 0));
+    REQUIRE(ncqprefix(val, decimal, buf, 0));
     CHECK(!strcmp(buf, gold));
   }
 
   SUBCASE("ScaledGigJustBelow") {
-    char gold[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
     snprintf(gold, sizeof(gold), "%.2fm", 999.999); //999.99
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t val = 999999999;
     uintmax_t decimal = GIG;
-    REQUIRE(qprefix(val, decimal, buf, 0));
+    REQUIRE(ncqprefix(val, decimal, buf, 0));
     CHECK(!strcmp(buf, gold));
   }
 
   SUBCASE("ScaledGigSub") {
-    char gold[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
     snprintf(gold, sizeof(gold), "%.2fm", 27.85); // 27.85
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t val = 27854993;
     uintmax_t decimal = GIG;
-    REQUIRE(qprefix(val, decimal, buf, 0));
+    REQUIRE(ncqprefix(val, decimal, buf, 0));
     CHECK(!strcmp(buf, gold));
   }
 
   SUBCASE("ScaledGigSubSub") {
-    char gold[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
     snprintf(gold, sizeof(gold), "%.2fm", 7.85); // 7.85
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t val = 7854993;
     uintmax_t decimal = GIG;
-    REQUIRE(qprefix(val, decimal, buf, 0));
+    REQUIRE(ncqprefix(val, decimal, buf, 0));
     CHECK(!strcmp(buf, gold));
   }
 
   SUBCASE("SmallCorners") {
-    char buf[PREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     impericize_ncmetric(1, 1000, buf, 0, 1000, '\0');
     CHECK(!strcmp("1.00m", buf));
     impericize_ncmetric(1, 1024, buf, 0, 1024, 'i');
@@ -431,13 +431,13 @@ TEST_CASE("Metric") {
     }else{
       smallsuffixes = L"yzafpnum";
     }
-    char gold[PREFIXSTRLEN + 1];
-    char buf[PREFIXSTRLEN + 1];
+    char gold[NCPREFIXSTRLEN + 1];
+    char buf[NCPREFIXSTRLEN + 1];
     uintmax_t goldval = 1;
     uintmax_t val = 1;
     size_t i = 0;
     do{
-      REQUIRE(qprefix(val, 1000000000000000ull, buf, '\0'));
+      REQUIRE(ncqprefix(val, 1000000000000000ull, buf, '\0'));
       const int sidx = i / 3 + 3;
       snprintf(gold, sizeof(gold), "%ju%s00%lc", goldval, decisep, smallsuffixes[sidx]);
       CHECK(!strcmp(gold, buf));
@@ -456,7 +456,7 @@ TEST_CASE("Metric") {
 
   // inspired by #929
   SUBCASE("BigMult") {
-    char qbuf[IPREFIXSTRLEN + 1];
+    char qbuf[NCIPREFIXSTRLEN + 1];
     CHECK(nullptr != impericize_ncmetric(1115614, 1000, qbuf, 0, 1000, '\0'));
     CHECK(0 == strcmp("1.11K", qbuf));
     CHECK(nullptr != impericize_ncmetric(372688, 1024, qbuf, 0, 1024, '\0'));
diff --git a/src/tests/notcurses.cpp b/src/tests/notcurses.cpp
index d1c857ea19..671b6e5926 100644
--- a/src/tests/notcurses.cpp
+++ b/src/tests/notcurses.cpp
@@ -17,7 +17,7 @@ TEST_CASE("NotcursesBase") {
   }
 
   SUBCASE("TermDimensions") {
-    int x, y;
+    unsigned x, y;
     notcurses_term_dim_yx(nc_, &y, &x);
     auto stry = getenv("LINES");
     if(stry){
@@ -32,9 +32,9 @@ TEST_CASE("NotcursesBase") {
   }
 
   SUBCASE("RefreshSameSize") {
-    int x, y;
+    unsigned x, y;
     notcurses_term_dim_yx(nc_, &y, &x);
-    int newx, newy;
+    unsigned newx, newy;
     CHECK(0 == notcurses_refresh(nc_, &newy, &newx));
     CHECK(newx == x);
     CHECK(newy == y);
@@ -56,17 +56,17 @@ TEST_CASE("NotcursesBase") {
 
   // create planes partitioning the entirety of the screen, one at each coordinate
   SUBCASE("TileScreenWithPlanes") {
-    int maxx, maxy;
+    unsigned maxx, maxy;
     notcurses_term_dim_yx(nc_, &maxy, &maxx);
     auto total = maxx * maxy;
     auto planes = new struct ncplane*[total];
     int* planesecrets = new int[total];
-    for(int y = 0 ; y < maxy ; ++y){
-      for(int x = 0 ; x < maxx ; ++x){
+    for(unsigned y = 0 ; y < maxy ; ++y){
+      for(unsigned x = 0 ; x < maxx ; ++x){
         const auto idx = y * maxx + x;
         struct ncplane_options nopts = {
-          .y = y,
-          .x = x,
+          .y = static_cast<int>(y),
+          .x = static_cast<int>(x),
           .rows = 1,
           .cols = 1,
           .userptr = &planesecrets[idx],
@@ -80,8 +80,8 @@ TEST_CASE("NotcursesBase") {
       }
     }
     REQUIRE(0 == notcurses_render(nc_));
-    for(int y = 0 ; y < maxy ; ++y){
-      for(int x = 0 ; x < maxx ; ++x){
+    for(unsigned y = 0 ; y < maxy ; ++y){
+      for(unsigned x = 0 ; x < maxx ; ++x){
         const auto idx = y * maxx + x;
         auto userptr = ncplane_userptr(planes[idx]);
         REQUIRE(userptr);
diff --git a/src/tests/piles.cpp b/src/tests/piles.cpp
index c38bde6af5..3bb771eba8 100644
--- a/src/tests/piles.cpp
+++ b/src/tests/piles.cpp
@@ -5,7 +5,7 @@ TEST_CASE("Piles") {
   if(!nc_){
     return;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
   REQUIRE(nullptr != n_);
 
diff --git a/src/tests/plane.cpp b/src/tests/plane.cpp
index 474f2054d3..5a918d848f 100644
--- a/src/tests/plane.cpp
+++ b/src/tests/plane.cpp
@@ -2,7 +2,7 @@
 #include "main.h"
 
 void BoxPermutationsRounded(struct notcurses* nc, struct ncplane* n, unsigned edges) {
-  int dimx, dimy;
+  unsigned dimx, dimy;
   ncplane_dim_yx(n, &dimy, &dimx);
   REQUIRE(2 < dimy);
   REQUIRE(47 < dimx);
@@ -30,7 +30,7 @@ TEST_CASE("Plane") {
 
   // Starting position ought be 0, 0 (the origin)
   SUBCASE("StdPlanePosition") {
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == x);
     CHECK(0 == y);
@@ -38,9 +38,9 @@ TEST_CASE("Plane") {
 
   // Dimensions of the standard plane ought be the same as those of the context
   SUBCASE("StdPlaneDimensions") {
-    int cols, rows;
+    unsigned cols, rows;
     notcurses_term_dim_yx(nc_, &rows, &cols);
-    int ncols, nrows;
+    unsigned ncols, nrows;
     ncplane_dim_yx(n_, &nrows, &ncols);
     CHECK(rows == nrows);
     CHECK(cols == ncols);
@@ -48,10 +48,10 @@ TEST_CASE("Plane") {
 
   // Verify that we can move to all four coordinates of the standard plane
   SUBCASE("MoveStdPlaneDimensions") {
-    int cols, rows;
+    unsigned cols, rows;
     notcurses_term_dim_yx(nc_, &rows, &cols);
     CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(y == 0);
     CHECK(x == 0);
@@ -71,7 +71,7 @@ TEST_CASE("Plane") {
 
   // Verify that we can move to all four coordinates of the standard plane
   SUBCASE("MoveBeyondPlaneFails") {
-    int cols, rows;
+    unsigned cols, rows;
     notcurses_term_dim_yx(nc_, &rows, &cols);
     CHECK(0 > ncplane_cursor_move_yx(n_, -2, 0));
     CHECK(0 > ncplane_cursor_move_yx(n_, -2, -2));
@@ -108,7 +108,7 @@ TEST_CASE("Plane") {
     nccell c = CELL_CHAR_INITIALIZER('a');
     CHECK(0 < ncplane_putc_yx(n_, 0, 0, &c));
     CHECK(0 == strcmp("a", ncplane_at_yx(n_, 0, 0, nullptr, nullptr)));
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(1 == x);
@@ -128,7 +128,7 @@ TEST_CASE("Plane") {
     nccell c{};
     CHECK(strlen(cchar) == nccell_load(n_, &c, cchar));
     CHECK(0 < ncplane_putc(n_, &c));
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(1 == x);
@@ -140,7 +140,7 @@ TEST_CASE("Plane") {
     const wchar_t* w = L"✔";
     int sbytes = 0;
     CHECK(0 < ncplane_putwegc(n_, w, &sbytes));
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(1 == x);
@@ -157,7 +157,7 @@ TEST_CASE("Plane") {
       int wrote = ncplane_putstr(n_, *s);
       CHECK(ncstrwidth(*s) == wrote);
     }
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(2 == y);
     CHECK(10 <= x);
@@ -174,7 +174,7 @@ TEST_CASE("Plane") {
       int wrote = ncplane_putwstr(n_, *s);
       CHECK(0 < wrote);
     }
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(2 == y);
     CHECK(10 <= x);
@@ -190,7 +190,7 @@ TEST_CASE("Plane") {
     CHECK(!ncplane_set_scrolling(n_, true));
     int wrote = ncplane_putwstr(n_, e);
     CHECK(0 < wrote);
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK_LE(0, y);
     CHECK(1 <= x); // FIXME tighten in on this
@@ -198,16 +198,16 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("HorizontalLines") {
-    int x, y;
+    unsigned x, y;
     ncplane_dim_yx(n_, &y, &x);
     REQUIRE(0 < y);
     REQUIRE(0 < x);
     nccell c{};
     nccell_load(n_, &c, "-");
-    for(int yidx = 0 ; yidx < y ; ++yidx){
+    for(unsigned yidx = 0 ; yidx < y ; ++yidx){
       CHECK(0 == ncplane_cursor_move_yx(n_, yidx, 1));
       CHECK(x - 2 == ncplane_hline(n_, &c, x - 2));
-      int posx, posy;
+      unsigned posx, posy;
       ncplane_cursor_yx(n_, &posy, &posx);
       CHECK(yidx == posy);
       CHECK(x - 1 == posx);
@@ -217,16 +217,16 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("VerticalLines") {
-    int x, y;
+    unsigned x, y;
     ncplane_dim_yx(n_, &y, &x);
     REQUIRE(0 < y);
     REQUIRE(0 < x);
     nccell c{};
     nccell_load(n_, &c, "|");
-    for(int xidx = 1 ; xidx < x - 1 ; ++xidx){
+    for(unsigned xidx = 1 ; xidx < x - 1 ; ++xidx){
       CHECK(0 == ncplane_cursor_move_yx(n_, 1, xidx));
       CHECK(y - 2 == ncplane_vline(n_, &c, y - 2));
-      int posx, posy;
+      unsigned posx, posy;
       ncplane_cursor_yx(n_, &posy, &posx);
       CHECK(y - 2 == posy);
       CHECK(xidx == posx - 1);
@@ -237,7 +237,7 @@ TEST_CASE("Plane") {
 
   // reject attempts to draw boxes beyond the boundaries of the ncplane
   SUBCASE("BadlyPlacedBoxen") {
-    int x, y;
+    unsigned x, y;
     ncplane_dim_yx(n_, &y, &x);
     REQUIRE(2 < y);
     REQUIRE(2 < x);
@@ -274,7 +274,7 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("BoxPermutationsDouble") {
-    int dimx, dimy;
+    unsigned dimx, dimy;
     ncplane_dim_yx(n_, &dimy, &dimx);
     REQUIRE(2 < dimx);
     REQUIRE(47 < dimx);
@@ -289,7 +289,7 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("PerimeterRoundedBox") {
-    int x, y;
+    unsigned x, y;
     ncplane_dim_yx(n_, &y, &x);
     REQUIRE(2 < y);
     REQUIRE(2 < x);
@@ -299,7 +299,7 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("PerimeterRoundedBoxSized") {
-    int x, y;
+    unsigned x, y;
     ncplane_dim_yx(n_, &y, &x);
     REQUIRE(2 < y);
     REQUIRE(2 < x);
@@ -309,7 +309,7 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("PerimeterDoubleBox") {
-    int x, y;
+    unsigned x, y;
     ncplane_dim_yx(n_, &y, &x);
     REQUIRE(2 < y);
     REQUIRE(2 < x);
@@ -319,7 +319,7 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("PerimeterDoubleBoxSized") {
-    int x, y;
+    unsigned x, y;
     ncplane_dim_yx(n_, &y, &x);
     REQUIRE(2 < y);
     REQUIRE(2 < x);
@@ -401,7 +401,7 @@ TEST_CASE("Plane") {
   // for the standard plane, and that we can change it.
   SUBCASE("UserPtr") {
     CHECK(nullptr == ncplane_userptr(n_));
-    int x, y;
+    unsigned x, y;
     void* sentinel = &x;
     notcurses_term_dim_yx(nc_, &y, &x);
     struct ncplane_options nopts = {
@@ -427,7 +427,7 @@ TEST_CASE("Plane") {
   // create a new plane, the same size as the terminal, and verify that it
   // occupies the same dimensions as the standard plane.
   SUBCASE("NewPlaneSameSize") {
-    int x, y;
+    unsigned x, y;
     notcurses_term_dim_yx(nc_, &y, &x);
     struct ncplane_options nopts = {
       .y = 0,
@@ -439,11 +439,11 @@ TEST_CASE("Plane") {
     };
     struct ncplane* ncp = ncplane_create(n_, &nopts);
     REQUIRE(ncp);
-    int px, py;
+    unsigned px, py;
     ncplane_dim_yx(ncp, &py, &px);
     CHECK(y == py);
     CHECK(x == px);
-    int sx, sy;
+    unsigned sx, sy;
     ncplane_dim_yx(n_, &sy, &sx);
     CHECK(sy == py);
     CHECK(sx == px);
@@ -453,7 +453,7 @@ TEST_CASE("Plane") {
   // create a new plane, the same size as the terminal, and verify that it
   // occupies the same dimensions as the standard plane, but on another pile.
   SUBCASE("NewPileSameSize") {
-    int x, y;
+    unsigned x, y;
     notcurses_term_dim_yx(nc_, &y, &x);
     struct ncplane_options nopts = {
       .y = 0,
@@ -465,11 +465,11 @@ TEST_CASE("Plane") {
     };
     struct ncplane* ncp = ncpile_create(nc_, &nopts);
     REQUIRE(ncp);
-    int px, py;
+    unsigned px, py;
     ncplane_dim_yx(ncp, &py, &px);
     CHECK(y == py);
     CHECK(x == px);
-    int sx, sy;
+    unsigned sx, sy;
     ncplane_dim_yx(n_, &sy, &sx);
     CHECK(sy == py);
     CHECK(sx == px);
@@ -484,7 +484,7 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("ShrinkPlane") {
-    int maxx, maxy;
+    unsigned maxx, maxy;
     int x = 0, y = 0;
     notcurses_term_dim_yx(nc_, &maxy, &maxx);
     struct ncplane_options nopts = {
@@ -528,9 +528,9 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("GrowPlane") {
-    int maxx = 2, maxy = 2;
+    unsigned maxx = 2, maxy = 2;
     int x = 0, y = 0;
-    int dimy, dimx;
+    unsigned dimy, dimx;
     notcurses_term_dim_yx(nc_, &dimy, &dimx);
     x = dimx / 2 - 1;
     y = dimy / 2 - 1;
@@ -552,7 +552,7 @@ TEST_CASE("Plane") {
       REQUIRE(0 == ncplane_resize(newp, 1, 1, maxy - 3, maxx - 3, 1, 1, maxy, maxx));
       // FIXME check dims, pos
     }
-    while(y < dimy){
+    while(y < static_cast<int>(dimy)){
       ++maxy;
       if(y){
         ++y;
@@ -560,7 +560,7 @@ TEST_CASE("Plane") {
       REQUIRE(0 == ncplane_resize(newp, 1, 0, maxy - 2, maxx, 1, 0, maxy, maxx));
       // FIXME check dims, pos
     }
-    while(x < dimx){
+    while(x < static_cast<int>(dimx)){
       ++maxx;
       if(x){
         ++x;
@@ -588,11 +588,11 @@ TEST_CASE("Plane") {
     CHECK(0 == testcell.stylemask);
     CHECK(0 == testcell.channels);
     nccell_release(n_, &testcell);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
     REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - strlen(STR2)));
     REQUIRE(0 < ncplane_putstr(n_, STR2));
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n_, &y, &x);
     REQUIRE(1 == y);
     REQUIRE(dimx == x);
@@ -626,11 +626,11 @@ TEST_CASE("Plane") {
     CHECK(0 == testcell.stylemask);
     CHECK(0 == testcell.channels);
     nccell_release(n_, &testcell);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
     REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - mbstowcs(nullptr, STR2, 0)));
     REQUIRE(0 < ncplane_putstr(n_, STR2));
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n_, &y, &x);
     REQUIRE(1 == y);
     REQUIRE(dimx == x);
@@ -657,7 +657,7 @@ TEST_CASE("Plane") {
     const char STR3[] = "da chronic lives";
     ncplane_set_styles(n_, NCSTYLE_BOLD);
     REQUIRE(0 < ncplane_putstr_yx(n_, 0, 0, STR1));
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == ncplane_cursor_move_yx(n_, y + 1, x - strlen(STR2)));
     ncplane_on_styles(n_, NCSTYLE_ITALIC);
@@ -667,7 +667,7 @@ TEST_CASE("Plane") {
     REQUIRE(0 < ncplane_putstr(n_, STR3));
     ncplane_off_styles(n_, NCSTYLE_ITALIC);
     CHECK(0 == notcurses_render(nc_));
-    int newx;
+    unsigned newx;
     ncplane_cursor_yx(n_, &y, &newx);
     CHECK(newx == x);
     nccell testcell = CELL_TRIVIAL_INITIALIZER;
@@ -684,7 +684,7 @@ TEST_CASE("Plane") {
 
   SUBCASE("BoxGradients") {
     const auto sidesz = 5;
-    int dimx, dimy;
+    unsigned dimx, dimy;
     ncplane_dim_yx(n_, &dimy, &dimx);
     REQUIRE(20 < dimy);
     REQUIRE(40 < dimx);
@@ -722,7 +722,7 @@ TEST_CASE("Plane") {
 
   SUBCASE("BoxSideColors") {
     const auto sidesz = 5;
-    int dimx, dimy;
+    unsigned dimx, dimy;
     ncplane_dim_yx(n_, &dimy, &dimx);
     REQUIRE(20 < dimy);
     REQUIRE(40 < dimx);
@@ -778,14 +778,14 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("NewPlaneOnRight") {
-    int ncols, nrows;
+    unsigned ncols, nrows;
     ncplane_dim_yx(n_, &nrows, &ncols);
     nccell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
     int y, x;
     ncplane_yx(n_, &y, &x);
     struct ncplane_options nopts = {
       .y = y,
-      .x = ncols - 3,
+      .x = static_cast<int>(ncols) - 3,
       .rows = 2,
       .cols = 2,
       .userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
@@ -801,7 +801,7 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("MoveToLowerRight") {
-    int ncols, nrows;
+    unsigned ncols, nrows;
     ncplane_dim_yx(n_, &nrows, &ncols);
     nccell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
     int y, x;
@@ -859,7 +859,7 @@ TEST_CASE("Plane") {
   }
 
   SUBCASE("MouseEvent") {
-    int dimy, dimx;
+    unsigned dimy, dimx;
     notcurses_stddim_yx(nc_, &dimy, &dimx);
     struct ncplane_options nopts = {
       .y = 1,
@@ -1084,17 +1084,17 @@ TEST_CASE("Plane") {
     REQUIRE(nullptr != n);
     CHECK(false == ncplane_set_scrolling(n, true));
     uint64_t channels = NCCHANNELS_INITIALIZER(0, 0xff, 0, 0xff, 0, 0xff);
-    int y, x;
+    unsigned y, x;
     CHECK(1 == ncplane_set_base(n, " ", 0, channels));
     CHECK(0 == notcurses_render(nc_));
-    for(int i = 0 ; i < ncplane_dim_y(n) ; ++i){
+    for(unsigned i = 0 ; i < ncplane_dim_y(n) ; ++i){
       ncplane_cursor_yx(n, &y, &x);
       CHECK(i == y);
       CHECK(0 == x);
       CHECK(0 < ncplane_putstr(n, "here's a line\n"));
       CHECK(0 == notcurses_render(nc_));
     }
-    for(int i = 0 ; i < ncplane_dim_y(n) ; ++i){
+    for(unsigned i = 0 ; i < ncplane_dim_y(n) ; ++i){
       ncplane_cursor_yx(n, &y, &x);
       CHECK(ncplane_dim_y(n) - 1 == y);
       CHECK(0 == x);
diff --git a/src/tests/reader.cpp b/src/tests/reader.cpp
index 6bb6bdfa8c..fd83873e04 100644
--- a/src/tests/reader.cpp
+++ b/src/tests/reader.cpp
@@ -7,7 +7,7 @@ TEST_CASE("Readers") {
   if(!nc_){
     return;
   }
-  int dimx, dimy;
+  unsigned dimx, dimy;
   struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
   REQUIRE(n_);
   REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
diff --git a/src/tests/reel.cpp b/src/tests/reel.cpp
index f8ef44d251..df88f25311 100644
--- a/src/tests/reel.cpp
+++ b/src/tests/reel.cpp
@@ -22,7 +22,7 @@ auto ncreel_validate(const ncreel* n) -> bool {
       }else if(y == cury){
         return false;
       }
-      int ylen, xlen;
+      unsigned ylen, xlen;
       ncplane_dim_yx(np, &ylen, &xlen);
       cury = y + ylen - 1;
     }
@@ -32,11 +32,12 @@ auto ncreel_validate(const ncreel* n) -> bool {
   do{
     const ncplane* np = t->p;
     if(np){
-      int y, x, ylen, xlen;
+      int y, x;
+      unsigned ylen, xlen;
       ncplane_yx(np, &y, &x);
       ncplane_dim_yx(np, &ylen, &xlen);
 //fprintf(stderr, "backwards: %p (%p) @ %d\n", t, np, y);
-      if(y + ylen - 1 > cury - 1){
+      if(y + static_cast<int>(ylen) - 1 > cury - 1){
         if(wentaround){
           return false;
         }
@@ -69,9 +70,9 @@ int check_allborders(nctablet* t, bool drawfromtop) {
   (void)drawfromtop;
   auto ncp = nctablet_plane(t);
   REQUIRE(ncp);
-  int rows, cols;
+  unsigned rows, cols;
   ncplane_dim_yx(ncp, &rows, &cols);
-  int srows, scols;
+  unsigned srows, scols;
   ncplane_dim_yx(notcurses_stdplane(ncplane_notcurses(ncp)), &srows, &scols);
   CHECK(srows >= rows + 3);
   CHECK(scols == cols + 4);
@@ -82,9 +83,9 @@ int check_noborders(nctablet* t, bool drawfromtop) {
   (void)drawfromtop;
   auto ncp = nctablet_plane(t);
   REQUIRE(ncp);
-  int rows, cols;
+  unsigned rows, cols;
   ncplane_dim_yx(ncp, &rows, &cols);
-  int srows, scols;
+  unsigned srows, scols;
   ncplane_dim_yx(notcurses_stdplane(ncplane_notcurses(ncp)), &srows, &scols);
   CHECK(srows == rows);
   CHECK(scols == cols);
@@ -95,9 +96,9 @@ int check_notborders(nctablet* t, bool drawfromtop) {
   (void)drawfromtop;
   auto ncp = nctablet_plane(t);
   REQUIRE(ncp);
-  int rows, cols;
+  unsigned rows, cols;
   ncplane_dim_yx(ncp, &rows, &cols);
-  int srows, scols;
+  unsigned srows, scols;
   ncplane_dim_yx(notcurses_stdplane(ncplane_notcurses(ncp)), &srows, &scols);
   CHECK(srows == rows + 2); // we get maximum possible size to try out
   CHECK(scols == cols + 2);
@@ -108,9 +109,9 @@ int check_norborders(nctablet* t, bool drawfromtop) {
   (void)drawfromtop;
   auto ncp = nctablet_plane(t);
   REQUIRE(ncp);
-  int rows, cols;
+  unsigned rows, cols;
   ncplane_dim_yx(ncp, &rows, &cols);
-  int srows, scols;
+  unsigned srows, scols;
   ncplane_dim_yx(notcurses_stdplane(ncplane_notcurses(ncp)), &srows, &scols);
   CHECK(srows >= rows + 1);
   CHECK(scols == cols + 2);
@@ -286,7 +287,7 @@ TEST_CASE("Reels") {
 
   SUBCASE("TransparentBackground") {
     ncreel_options r{};
-    int dimy, dimx;
+    unsigned dimy, dimx;
     notcurses_term_dim_yx(nc_, &dimy, &dimx);
     uint64_t channels = 0;
     ncchannels_set_bg_alpha(&channels, NCALPHA_TRANSPARENT);
diff --git a/src/tests/resize.cpp b/src/tests/resize.cpp
index d8ed50c615..75d3b9a158 100644
--- a/src/tests/resize.cpp
+++ b/src/tests/resize.cpp
@@ -5,7 +5,7 @@ TEST_CASE("Resize") {
   if(!nc_){
     return;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
   REQUIRE(n_);
   uint64_t ul, ur, ll, lr;
@@ -21,8 +21,8 @@ TEST_CASE("Resize") {
 
   // start at full size, and shrink to a nothing
   SUBCASE("ResizeShrink") {
-    int y = dimy;
-    int x = dimx;
+    unsigned y = dimy;
+    unsigned x = dimx;
     struct ncplane_options nopts = {
       .y = 0,
       .x = 0,
@@ -33,7 +33,7 @@ TEST_CASE("Resize") {
     };
     struct ncplane* testn = ncplane_create(n_, &nopts);
     REQUIRE(nullptr != testn);
-    REQUIRE(0 < ncplane_gradient_sized(testn, "V", 0, ul, ur, ll, lr, y, x));
+    REQUIRE(0 < ncplane_gradient(testn, -1, -1, y, x, "V", 0, ul, ur, ll, lr));
     CHECK(0 == notcurses_render(nc_));
     while(y > 1 || x > 1){
       y = y > 1 ? y - 1 : y;
@@ -46,8 +46,8 @@ TEST_CASE("Resize") {
 
   // start at 1x1, and enlarge to fill the screen
   SUBCASE("ResizeEnlarge") {
-    int y = 2;
-    int x = 2;
+    unsigned y = 2;
+    unsigned x = 2;
     struct ncplane_options nopts = {
       .y = 0,
       .x = 0,
@@ -58,13 +58,13 @@ TEST_CASE("Resize") {
     };
     struct ncplane* testn = ncplane_create(n_, &nopts);
     REQUIRE(nullptr != testn);
-    REQUIRE(0 < ncplane_gradient_sized(testn, "V", 0, ul, ur, ll, lr, y, x));
+    REQUIRE(0 < ncplane_gradient(testn, -1, -1, y, x, "V", 0, ul, ur, ll, lr));
     CHECK(0 == notcurses_render(nc_));
     while(y < dimy || x < dimx){
       y = y < dimy ? y + 1 : y;
       x = x < dimx ? x + 1 : x;
       CHECK(0 == ncplane_resize(testn, 0, 0, 0, 0, 0, 0, y, x));
-      REQUIRE(0 < ncplane_gradient_sized(testn, "V", 0, ul, ur, ll, lr, y, x));
+      REQUIRE(0 < ncplane_gradient(testn, -1, -1, y, x, "V", 0, ul, ur, ll, lr));
       CHECK(0 == notcurses_render(nc_));
     }
     CHECK(0 == ncplane_destroy(testn));
diff --git a/src/tests/rotate.cpp b/src/tests/rotate.cpp
index 0d7abc11cd..952791d9ae 100644
--- a/src/tests/rotate.cpp
+++ b/src/tests/rotate.cpp
@@ -35,8 +35,10 @@ TEST_CASE("Rotate") {
     CHECK(0 == notcurses_stop(nc_));
     return;
   }
-  int dimy, dimx;
-  struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
+  unsigned udimy, udimx;
+  struct ncplane* n_ = notcurses_stddim_yx(nc_, &udimy, &udimx);
+  int dimy = udimy;
+  int dimx = udimx;
   REQUIRE(n_);
 
   uint64_t ul, ur, ll, lr;
@@ -98,7 +100,7 @@ TEST_CASE("Rotate") {
       .margin_b = 0, .margin_r = 0,
     };
     struct ncplane* testn = ncplane_create(n_, &nopts);
-    REQUIRE(0 < ncplane_gradient_sized(testn, " ", 0, ul, ur, ll, lr, 8, 16));
+    REQUIRE(0 < ncplane_gradient(testn, -1, -1, 8, 16, " ", 0, ul, ur, ll, lr));
     RotateCW(nc_, testn);
     CHECK(0 == ncplane_destroy(testn));
   }
@@ -117,7 +119,7 @@ TEST_CASE("Rotate") {
       .margin_b = 0, .margin_r = 0,
     };
     struct ncplane* testn = ncplane_create(n_, &nopts);
-    REQUIRE(0 < ncplane_gradient_sized(testn, " ", 0, ul, ur, ll, lr, 8, 32));
+    REQUIRE(0 < ncplane_gradient(testn, -1, -1, 8, 32, " ", 0, ul, ur, ll, lr));
     RotateCW(nc_, testn);
     CHECK(0 == ncplane_destroy(testn));
   }
@@ -136,7 +138,7 @@ TEST_CASE("Rotate") {
       .margin_b = 0, .margin_r = 0,
     };
     struct ncplane* testn = ncplane_create(n_, &nopts);
-    REQUIRE(0 < ncplane_gradient_sized(testn, " ", 0, ul, ur, ll, lr, 8, 16));
+    REQUIRE(0 < ncplane_gradient(testn, -1, -1, 8, 16, " ", 0, ul, ur, ll, lr));
     RotateCCW(nc_, testn);
     CHECK(0 == ncplane_destroy(testn));
   }
@@ -155,7 +157,7 @@ TEST_CASE("Rotate") {
       .margin_b = 0, .margin_r = 0,
     };
     struct ncplane* testn = ncplane_create(n_, &nopts);
-    REQUIRE(0 < ncplane_gradient_sized(testn, " ", 0, ul, ur, ll, lr, 8, 32));
+    REQUIRE(0 < ncplane_gradient(testn, -1, -1, 8, 32, " ", 0, ul, ur, ll, lr));
     RotateCCW(nc_, testn);
     CHECK(0 == ncplane_destroy(testn));
   }
diff --git a/src/tests/scrolling.cpp b/src/tests/scrolling.cpp
index 92073707a3..d50912daf1 100644
--- a/src/tests/scrolling.cpp
+++ b/src/tests/scrolling.cpp
@@ -32,7 +32,7 @@ TEST_CASE("Scrolling") {
     CHECK(!ncplane_set_scrolling(n, false));
     // try to write 40 EGCs; it ought fail after 20
     CHECK(-20 == ncplane_putstr(n, "0123456789012345678901234567890123456789"));
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n, &y, &x);
     CHECK(0 == y);
     CHECK(20 == x);
@@ -81,7 +81,7 @@ TEST_CASE("Scrolling") {
     struct ncplane* n = ncplane_create(n_, &nopts);
     REQUIRE(n);
     CHECK(20 == ncplane_putstr(n, "01234567890123456789"));
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n, &y, &x);
     CHECK(0 == y);
     CHECK(20 == x);
@@ -119,7 +119,7 @@ TEST_CASE("Scrolling") {
         CHECK(0 > ret);
       }
     }
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n, &y, &x);
     CHECK(0 == y);
     CHECK(20 == x);
@@ -177,7 +177,7 @@ TEST_CASE("Scrolling") {
     CHECK(!ncplane_set_scrolling(n, true));
     CHECK(40 == ncplane_putstr(n, out)); // fill up the plane w/ numbers
     CHECK(0 == notcurses_render(nc_));
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n, &y, &x);
     CHECK(1 == y);
     CHECK(20 == x);
@@ -273,7 +273,7 @@ TEST_CASE("Scrolling") {
     CHECK(0 < ncplane_polyfill_yx(np, 0, 0, &c));
     CHECK(0 == ncplane_cursor_move_yx(n_, ncplane_dim_y(n_) - 1, 0));
     CHECK(0 == notcurses_render(nc_));
-    for(int i = 0 ; i < ncplane_dim_y(np) + starty ; ++i){
+    for(unsigned i = 0 ; i < ncplane_dim_y(np) + starty ; ++i){
       CHECK(starty - i == ncplane_y(np));
       CHECK(0 == ncplane_putchar(n_, '\n'));
       CHECK(0 == notcurses_render(nc_));
@@ -301,7 +301,7 @@ TEST_CASE("Scrolling") {
     CHECK(0 < ncplane_polyfill_yx(np, 0, 0, &c));
     CHECK(0 == ncplane_cursor_move_yx(n_, ncplane_dim_y(n_) - 1, 0));
     CHECK(0 == notcurses_render(nc_));
-    for(int i = 0 ; i < ncplane_dim_y(np) + starty ; ++i){
+    for(unsigned i = 0 ; i < ncplane_dim_y(np) + starty ; ++i){
       CHECK(starty == ncplane_y(np));
       CHECK(0 == ncplane_putchar(n_, '\n'));
       CHECK(0 == notcurses_render(nc_));
diff --git a/src/tests/selector.cpp b/src/tests/selector.cpp
index 03448ff43d..8c27990d75 100644
--- a/src/tests/selector.cpp
+++ b/src/tests/selector.cpp
@@ -28,7 +28,7 @@ TEST_CASE("Selectors") {
     CHECK(nullptr == ncselector_selected(ncs));
     struct ncplane* ncsp = ncselector_plane(ncs);
     REQUIRE(nullptr != ncsp);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncsp, &dimy, &dimx);
     CHECK(4 == dimy);
     CHECK(5 == dimx);
@@ -53,7 +53,7 @@ TEST_CASE("Selectors") {
     CHECK(0 == notcurses_render(nc_));
     struct ncplane* ncsp = ncselector_plane(ncs);
     REQUIRE(nullptr != ncsp);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncsp, &dimy, &dimx);
     CHECK(6 == dimy);
     CHECK(strlen(opts.title) + 4 == dimx);
@@ -79,7 +79,7 @@ TEST_CASE("Selectors") {
     CHECK(0 == notcurses_render(nc_));
     struct ncplane* ncsp = ncselector_plane(ncs);
     REQUIRE(nullptr != ncsp);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncsp, &dimy, &dimx);
     CHECK(4 == dimy);
     CHECK(strlen(opts.secondary) + 2 == dimx);
@@ -105,7 +105,7 @@ TEST_CASE("Selectors") {
     CHECK(0 == notcurses_render(nc_));
     struct ncplane* ncsp = ncselector_plane(ncs);
     REQUIRE(nullptr != ncsp);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncsp, &dimy, &dimx);
     CHECK(4 == dimy);
     CHECK(strlen(opts.footer) + 2 == dimx);
@@ -136,7 +136,7 @@ TEST_CASE("Selectors") {
     CHECK(0 == notcurses_render(nc_));
     struct ncplane* ncsp = ncselector_plane(ncs);
     REQUIRE(nullptr != ncsp);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncsp, &dimy, &dimx);
     CHECK(7 == dimy);
     CHECK(15 < dimx);
@@ -259,7 +259,7 @@ TEST_CASE("Selectors") {
     CHECK(0 == strcmp(sel, items[0].option));
     struct ncplane* ncsp = ncselector_plane(ncs);
     REQUIRE(nullptr != ncsp);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncsp, &dimy, &dimx);
     CHECK(5 == dimy);
     ncselector_destroy(ncs, nullptr);
@@ -310,7 +310,7 @@ TEST_CASE("Selectors") {
     CHECK(0 == strcmp(sel, items[0].option));
     struct ncplane* ncsp = ncselector_plane(ncs);
     REQUIRE(nullptr != ncsp);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncsp, &dimy, &dimx);
     CHECK(6 == dimy);
     ncselector_destroy(ncs, nullptr);
diff --git a/src/tests/sixel.cpp b/src/tests/sixel.cpp
index 129e84b2a1..e267779cda 100644
--- a/src/tests/sixel.cpp
+++ b/src/tests/sixel.cpp
@@ -196,7 +196,7 @@ TEST_CASE("Sixels") {
 //print_bmap(rgbold, newn->sprite->pixy, newn->sprite->pixx);
     CHECK(0 == notcurses_render(nc_));
     struct ncplane_options nopts = {
-      .y = ncplane_dim_y(newn) * 3 / 4,
+      .y = (int)ncplane_dim_y(newn) * 3 / 4,
       .x = 0,
       .rows = ncplane_dim_y(newn) / 4,
       .cols = ncplane_dim_x(newn) / 2,
diff --git a/src/tests/stacking.cpp b/src/tests/stacking.cpp
index be3b6947cb..7f8bc73fa7 100644
--- a/src/tests/stacking.cpp
+++ b/src/tests/stacking.cpp
@@ -22,7 +22,7 @@ TEST_CASE("Stacking") {
     CHECK(0 == notcurses_stop(nc_));
     return;
   }
-  int dimy, dimx;
+  unsigned dimy, dimx;
   struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
   REQUIRE(nullptr != n_);
 
@@ -63,7 +63,6 @@ TEST_CASE("Stacking") {
     uint64_t channels;
     auto egc = notcurses_at_yx(nc_, 0, 0, nullptr, &channels);
     REQUIRE(nullptr != egc);
-notcurses_debug(nc_, stderr);
     // ought yield space with white background FIXME currently just yields
     // a lower half block
     CHECK(0 == strcmp("\u2584", egc));
diff --git a/src/tests/visual.cpp b/src/tests/visual.cpp
index 2722e9e1df..39e48914b1 100644
--- a/src/tests/visual.cpp
+++ b/src/tests/visual.cpp
@@ -148,9 +148,9 @@ TEST_CASE("Visual") {
     vopts.scaling = NCSCALE_SCALE;
     CHECK(0 == ncvisual_geom(nc_, ncv, &vopts, &g));
     ncvisual_destroy(ncv);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
-    int mindim = dimy < dimx ? dimy : dimx;
+    unsigned mindim = dimy < dimx ? dimy : dimx;
     CHECK(10 == g.pixy);
     CHECK(10 == g.pixx);
     CHECK(1 == g.scaley);
@@ -174,7 +174,7 @@ TEST_CASE("Visual") {
     vopts.scaling = NCSCALE_STRETCH;
     CHECK(0 == ncvisual_geom(nc_, ncv, &vopts, &g));
     ncvisual_destroy(ncv);
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(n_, &dimy, &dimx);
     CHECK(10 == g.pixy);
     CHECK(10 == g.pixx);
@@ -310,7 +310,7 @@ TEST_CASE("Visual") {
   // everywhere within that plane
   SUBCASE("Stretch") {
     std::vector<uint32_t> v(1, htole(0xff1c28ff));
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncp_, &dimy, &dimx);
     auto ncv = ncvisual_from_rgba(v.data(), 1, sizeof(decltype(v)::value_type), 1);
     REQUIRE(nullptr != ncv);
@@ -325,8 +325,8 @@ TEST_CASE("Visual") {
     CHECK(dimy == ncplane_dim_y(n));
     CHECK(dimx == ncplane_dim_x(n));
     ncvisual_destroy(ncv);
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         uint16_t stylemask;
         uint64_t channels;
         auto c = ncplane_at_yx(n, y, x, &stylemask, &channels);
@@ -403,7 +403,7 @@ TEST_CASE("Visual") {
     }
     REQUIRE(newn);
     auto enewn = ncvisual_blit(nc_, ncv, &vopts);
-    int newy, newx;
+    unsigned newy, newx;
     ncplane_dim_yx(enewn, &newy, &newx);
     CHECK(6 == newy);
     CHECK(6 == newx);
@@ -414,7 +414,7 @@ TEST_CASE("Visual") {
   }
 
   SUBCASE("LoadRGBAFromMemory") {
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncp_, &dimy, &dimx);
     // alpha, then b, g, r
     std::vector<uint32_t> rgba(dimx * dimy * 2, htole(0xff88bbccull));
@@ -425,8 +425,8 @@ TEST_CASE("Visual") {
     opts.n = ncp_;
     CHECK(ncp_ == ncvisual_blit(nc_, ncv, &opts));
     CHECK(0 == notcurses_render(nc_));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         uint16_t stylemask;
         uint64_t channels;
         auto c = ncplane_at_yx(ncp_, y, x, &stylemask, &channels);
@@ -441,7 +441,7 @@ TEST_CASE("Visual") {
   }
 
   SUBCASE("LoadBGRAFromMemory") {
-    int dimy, dimx;
+    unsigned dimy, dimx;
     ncplane_dim_yx(ncp_, &dimy, &dimx);
     // A should be at the highest memory address, which would be the most
     // significant byte on little-endian. then r, g, b.
@@ -453,8 +453,8 @@ TEST_CASE("Visual") {
     opts.n = ncp_;
     CHECK(nullptr != ncvisual_blit(nc_, ncv, &opts));
     CHECK(0 == notcurses_render(nc_));
-    for(int y = 0 ; y < dimy ; ++y){
-      for(int x = 0 ; x < dimx ; ++x){
+    for(unsigned y = 0 ; y < dimy ; ++y){
+      for(unsigned x = 0 ; x < dimx ; ++x){
         uint16_t stylemask;
         uint64_t channels;
         auto c = ncplane_at_yx(ncp_, y, x, &stylemask, &channels);
@@ -647,7 +647,7 @@ TEST_CASE("Visual") {
       };
       auto ncvp = ncvisual_blit(nc_, ncv, &vopts);
       REQUIRE(nullptr != ncvp);
-      int dimy, dimx;
+      unsigned dimy, dimx;
       ncplane_dim_yx(ncvp, &dimy, &dimx);
       CHECK(1 == dimy);
       CHECK(1 == dimx);
@@ -692,7 +692,7 @@ TEST_CASE("Visual") {
         };
         auto ncvp = ncvisual_blit(nc_, ncv, &vopts);
         REQUIRE(nullptr != ncvp);
-        int dimy, dimx;
+        unsigned dimy, dimx;
         ncplane_dim_yx(ncvp, &dimy, &dimx);
         CHECK(1 == dimy);
         CHECK(1 == dimx);
@@ -740,7 +740,7 @@ TEST_CASE("Visual") {
         };
         auto ncvp = ncvisual_blit(nc_, ncv, &vopts);
         REQUIRE(nullptr != ncvp);
-        int dimy, dimx;
+        unsigned dimy, dimx;
         ncplane_dim_yx(ncvp, &dimy, &dimx);
         CHECK(1 == dimy);
         CHECK(1 == dimx);
@@ -793,7 +793,7 @@ TEST_CASE("Visual") {
         };
         auto ncvp = ncvisual_blit(nc_, ncv, &vopts);
         REQUIRE(nullptr != ncvp);
-        int dimy, dimx;
+        unsigned dimy, dimx;
         ncplane_dim_yx(ncvp, &dimy, &dimx);
         CHECK(1 == dimy);
         CHECK(1 == dimx);
@@ -845,7 +845,7 @@ TEST_CASE("Visual") {
         };
         auto ncvp = ncvisual_blit(nc_, ncv, &vopts);
         REQUIRE(nullptr != ncvp);
-        int dimy, dimx;
+        unsigned dimy, dimx;
         ncplane_dim_yx(ncvp, &dimy, &dimx);
         CHECK(1 == dimy);
         CHECK(1 == dimx);
diff --git a/src/tests/wide.cpp b/src/tests/wide.cpp
index a8a9e15cd5..77c5c8f937 100644
--- a/src/tests/wide.cpp
+++ b/src/tests/wide.cpp
@@ -21,7 +21,7 @@ TEST_CASE("Wide") {
     const char* w = "\u5168";
     int sbytes = 0;
     CHECK(0 < ncplane_putegc(n_, w, &sbytes));
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(2 == x);
@@ -32,10 +32,10 @@ TEST_CASE("Wide") {
   SUBCASE("RejectWideAsian") {
     const char* w = "\u5168";
     int sbytes = 0;
-    int dimx;
+    unsigned dimx;
     ncplane_dim_yx(n_, nullptr, &dimx);
     CHECK(0 < ncplane_putegc_yx(n_, 0, dimx - 3, w, &sbytes));
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(dimx - 1 == x);
@@ -52,12 +52,12 @@ TEST_CASE("Wide") {
   SUBCASE("RejectWideAsianPlaced") {
     const char* w = "\u5168";
     int sbytes = 0;
-    int dimx;
+    unsigned dimx;
     ncplane_dim_yx(n_, nullptr, &dimx);
     // now it ought be rejected
     CHECK(0 > ncplane_putegc_yx(n_, 0, dimx - 1, w, &sbytes));
     // cursor ought remain where it was
-    int y, x;
+    unsigned y, x;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(dimx - 1 == x);
@@ -116,7 +116,7 @@ TEST_CASE("Wide") {
     int sbytes = 0;
     CHECK(0 < ncplane_putegc_yx(n_, 0, 1, wbashed, &sbytes));
     CHECK(0 < ncplane_putchar_yx(n_, 1, 1, bashed));
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(1 == y);
     CHECK(2 == x);
@@ -148,7 +148,7 @@ TEST_CASE("Wide") {
     CHECK(0 < cols1);
     int cols2 = ncplane_putegc_yx(n_, 0, 1, w, &sbytes);
     CHECK(0 < cols2);
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(1 + cols2 == x);
@@ -175,7 +175,7 @@ TEST_CASE("Wide") {
     CHECK(0 < ncplane_putegc_yx(n_, 0, 2, wbashedr, &sbytes));
     CHECK(1 == ncplane_putchar_yx(n_, 0, 1, *cc));
     CHECK(1 == ncplane_putchar_yx(n_, 0, 2, *cc));
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(3 == x);
@@ -205,7 +205,7 @@ TEST_CASE("Wide") {
     CHECK(0 < ncplane_putegc_yx(n_, 0, 0, wsafel, &sbytes));
     CHECK(0 < ncplane_putegc_yx(n_, 0, 3, wsafer, &sbytes));
     CHECK(1 == ncplane_putchar_yx(n_, 0, 2, *cc));
-    int x, y;
+    unsigned x, y;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(3 == x);
@@ -237,7 +237,7 @@ TEST_CASE("Wide") {
     };
     struct ncplane* ncp = ncplane_create(n_, &nopts);
     REQUIRE(ncp);
-    int dimx, dimy;
+    unsigned dimx, dimy;
     ncplane_dim_yx(n_, &dimy, &dimx);
     CHECK(0 == ncplane_rounded_box_sized(ncp, 0, 0, 3, 4, 0));
     CHECK(ncstrwidth(SCORPION) == ncplane_putegc_yx(ncp, 1, 1, SCORPION, nullptr));
@@ -301,11 +301,12 @@ TEST_CASE("Wide") {
     char* egc;
 
     // print two wide glyphs on the standard plane
-    int y, x;
-    ncplane_yx(n_, &y, &x);
-    CHECK(0 == y);
-    CHECK(0 == x);
+    int py, px;
+    ncplane_yx(n_, &py, &px);
+    CHECK(0 == py);
+    CHECK(0 == px);
     CHECK(2 == ncplane_putstr(n_, "\xe5\x85\xa8")); // \u5168 (全)
+    unsigned y, x;
     ncplane_cursor_yx(n_, &y, &x);
     CHECK(0 == y);
     CHECK(2 == x);