text:
Draw the Easter Bunny
This happy individual is known in folklore as the Easter Bunny.

Colours
It is created using 4 colours:

Light pink
Dark pink
White
Black

(I'm happy for these colours to be approximated in your answer. It does not need to be this precise shade)
Shapes
It is constructed of these shapes:

Two tall ellipses in light pink (outer ears). They have the same height and width.
Two tall ellipses in dark pink (inner ears). They are smaller than the outer ears and one is drawn on top of each of the outer ears. They are the same height and width.
One large circle in light pink (head). It intersects with the bottom third of both outer ears (but no higher).
Two circles in white (outer eyes). They are drawn on the head. Their diameter is less than the width of the outer ears. They have the same horizontal position as the outer ears.
Two circles in black (inner eyes). They have a smaller diameter than the outer eyes. One is drawn on each of the outer eyes.
One vertical line in black (upper mouth). It is drawn on the head and is lower than the bottom of the outer eyes. It is roughly equidistant from each eye.
Two arcs in black (lower mouth). They are drawn on the head and arc downwards from a horizontal line. Both intersect with the bottom of the upper mouth, but one goes right and the other goes left.

The Rules

Use any language and tools you like.
Output can be an image, html, svg, or other markup.
It's code golf, so aim to do it in the smallest number of bytes.
Please include a screenshot of the result.
Please feel free to approximate the colours defined.

Happy Easter!

What size image would you like?

@Neil size doesn’t matter, Neil. As long as it meets the requirements for shape and colour.

I've got a desmos answer in the works. Is having no white in the eyes acceptable?

@BenjaminUrquhart not really. That considerably simplifies the process. You could make it a grey, if that helps.

Eh, I'll figure it out. Maybe a bloodshot bunny.

@BenjaminUrquhart works for me

I guess Magenta or Red aren't allowed instead of the dark pink? ;) Would save a couple of bytes. if not, what is the RGB color of your dark pink, then I'll just use that in my answer.

@KevinCruijssen I'm happy with some different colours here. Incidentally I used (255, 200 200) and (255, 127, 127), if that's of interest to you.

T-SQL, 445 439 bytes
DECLARE @ GEOMETRY='MULTIPOINT((3 3),(7 3))',
@l GEOMETRY='CIRCULARSTRING(3 6,3.3 9,3 12,2.7 9,3 6)',@r GEOMETRY
SET @=@.STBuffer(.6)SET @r=@l.STUnion('CIRCULARSTRING(7 6,7.3 9,7 12,6.7 9,7 6)')
SELECT*FROM(VALUES(@),(@),(@),(@r.STBuffer(.3)),(@),(@),(@),(@),(@),(@),(@),(@),(@),
(@),(@),('CIRCULARSTRING(7 0,6 -1,5 0,5 1,5 1,5 0,5 0,4 -1,3 0)'),
(GEOMETRY::Point(5,1,0).STBuffer(5).STUnion(@r.STBuffer(1.3)).STDifference(@.STBuffer(.4)))
)a(g)

This site could use more T-SQL-based drawings!
Run on SQL 2017, but uses SQL geo-spatial storage features added back in SQL 2008. Line breaks are for readability only.
Output:

So, this was a pain to do in T-SQL, since spatial objects aren't exactly designed for drawing (no "ellipse" object, for example). Even more, getting the colors even close to right required a bit of trial and error.
Basically I'm constructing the following geometric objects:

The eyes (@), which are points expanded into disks using STBuffer(.6) (the set of all points within 0.6 of those starting points)
The ears (@r), which are generated as pointy curves, but are "puffed out" using STBuffer into either the inner or outer ears
The face, which is a disk plus the ears minus the eyes. I have to construct this and display it as a single object, or SQL would display it in different colors.
The mouth, which is a curve created using CIRCULARSTRING

To get the colors right, I have to SELECT these in the proper order. SSMS has a built-in sequence of colors for objects displayed in the spatial results pane, so the dark pink inner ears had to come 4th, and the light pink face had to come 16th. This required putting in a whole bunch of extra copies of the eyes, which is ok since we want them as close to black as possible (colors are somewhat transparent, so stacking them makes them darker).
Help and inspiration from the following resources:

Drawing in color in SQL
Botticelli’s Birth of Venus using T-SQL
SQL Server Christmas card

EDIT: Moved the bunny down by 4 units, which changes some coordinates to a single digit, saving 6 bytes. No change in displayed output.

Building a rabbit with geometry objects, brilliant! xD

Red, 375 340 329 bytes
Red[needs 'View]f: 'fill-pen p: 'pen e: 'ellipse c: 'circle
t:[5x5 0 180]view[base 200x200 #FFF draw
compose[(p)pink(f)pink(c)100x100 30(e)75x25
20x60(e)105x25 20x60(p)#E28(f)#E28(e)79x35 12x35(e)109x35
12x35(p)#FFF(f)#FFF(c)88x92 8(c)112x92 8(p)#000(f)#000(c)88x92
5(c)112x92 5 line 100x108 100x115 arc 95x115(t)arc 105x115(t)]]

Python, 368 bytes
Using matplotlib.
from matplotlib import pyplot as l,patches as p,transforms as t;z=0,;[l.gca().add_patch(p.Wedge(z*2,R,s,360,width=w,color=(r,o,o),transform=t.Affine2D.from_values(X,0,0,9,350+x*n,y*9)))for R,s,w,r,o,X,x,y in zip([11,7,15,4,2,2,99],z*5+(180,359),[None]*5+[.2,.4],(1,)*4+z*3,(.8,.6,.8,1)+z*3,[4,4]+[9]*5,[7,7,0,6,6,2,98.8],[51,51,30,35,35,24,26])for n in[-9,9]];l.show()

Result:

Ungolfed:
from matplotlib import pyplot, patches, transforms
z = 0, # store zero as a tuple for later repetition
for radius, startAngle, width, red, other, xStretch, x, y in \
    zip([11 ,7  ,15 ,4  ,2  ,2  ,99   ],  # radius
        z * 5 +             (180,359  ),  # start angle
        [None] * 5 +        [.2 ,.4   ],  # wedge width (None = full)
        (1,) * 4        +z * 3         ,  # red channel
        (.8 ,.6 ,.8 ,1) +z * 3         ,  # other color channels
        [4]*2 + [9]*5                  ,  # x stretch factor
        [ 7 ,7  ,0  ,6  ,6  ,2  ,98.8 ],  # x
        [51 ,51 ,30 ,35 ,35 ,24 ,26   ]): # y
#        |   |   |   |   |   |   |
#        |   |   |   |   |   |   "straight" line for upper mouth
#        |   |   |   |   |   |   approximated by large radius arc
#        |   |   |   |   |   |
#        |   |   |   |   |   Arc for lower mouth
#        |   |   |   |   |
#        |   |   |   |   Inner eye circle
#        |   |   |   |
#        |   |   |   Outer eye circle
#        |   |   |
#        |   |   Circle for head
#        |   |
#        |   Inner ear ellipse
#        |
#        Outer ear ellipse

    for n in [-9, 9]:        # draw left and right side mirrored
        pyplot.gca().add_patch( patches.Wedge(
            z*2,       # center = (0, 0), actual location set by the transform below
            radius,
            startAngle,
            360,       # end angle
            width = width,
            color = (red, other, other), # only red channel varies from the others
            transform = transforms.Affine2D.from_values( # affine transform matrix
                xStretch,    # x stretch factor
                0, 0,        # unused cross-axis coefficients for skew/rotation
                9,           # y stretch factor
                x * n + 350, # x value reflected by n, centered at 350
                y * 9 )))    # y value

pyplot.show()

Ruby with Shoes, 240 characters
Shoes.app{['fcc',[0,40,60],[5,0,20,50],[35,0,20,50],'f99',[t=10,t,t,h=30],[40,t,t,h],'fff',[t,55,15],[35,55,15],'000',[14,58,7],[38,58,7]].map{|v|stroke fill v rescue oval *v}
nofill
line h,75,h,80
arc 25,80,t,t,0,3.14
arc 35,80,t,t,0,3.14}

Sample output:

HTML, 280 278 bytes

a{color:#FFC8C8;}b{color:#FF7F7F;font-size:6px;margin-left:-10px;}m,n,j,d{display:block;}m{margin:-15px -3px;font-size:40px;}n{margin:-35px 5px;color:#FFF;font-size:15px;}j{margin:-14px 1px;color:#000;font-size:10px;}
⬮⬮⬮⬮<m>⬤<n>● ●<j>●   ●<d>   w

Here is a screenshot:

Citations

Oval characters: https://unicode.org/charts/PDF/U2B00.pdf
Invisible character: https://stackoverflow.com/a/17979246/7668911

JavaScript + P5.js, 291 276 273 bytes
A lot of small changes this time around.. that don't change the byte size at all.
setup=_=>{createCanvas(u=400,u);(e=ellipse,f=fill)`#fcc`;e(u/=2,u,x=150,x);e(x+=10,z=99,50,z);e(w=240,z,50,z);f`#f77`;e(x,z,y=30,80);e(w,z,y,80);f``;e(w,v=180,y,y);e(x,v,y,y);f(0);e(w,v,y=9,y);e(x,v,y,y);noFill(line(u,225,u,250));arc(195,...a=[245,y,y,0,PI]);arc(205,...a)}

Try it online!
Explanation:
setup = _ => {
    createCanvas(u=400, u);                 // Create basic canvas.
    (e = ellipse, f = fill)`#fcc`;          // Light pink
    e(u /= 2, u, 150, 150);                 // These first few lines end up defining short-hand names for functions.
    e(x += 10, z = 99, 50, z);              // Throughout the code, you will see
    e(w = 240, z, 50, z);                   // lots of variable definitions.
    f`#f77`;                                // Dark pink
    e(x, z, y = 30, 80);                    // Another variable declaration
    e(w, z, y, 80);
    f``;                                    // Empty fill argument = white, apparently? (Eyes start here)
    e(w, v = 180, y, y);                    // I'll just stop commenting on declarations now
    e(x, v, y, y);
    f(0);                                   // fill(x) = fill(x, x, x)
    e(w, v, y = 9, y);
    e(x, v, y, y);
    noFill(line(u, 225, u, 250));           // Last part of bunny starts here.
                                            // Get rid of fill so the bunny doesn't look bad
    arc(195, ...a= [245, y, y, 0, PI]);
    arc(205, ...a)                          // arc() creates something similar to a semi-circle.
}

You can use #fcc and #f77 for the colors.

Well... I haven't found any new bytes since then. Safe to say I've optimized this too much?

Javascript, 381 326 bytes
Thanks Arnold and Epicness.

(d=document).body.appendChild(a=d.createElement`canvas`);b=a.getContext`2d`;'A707|A7,/|Z707|Z7,/|MZAA|CR--|UR--|CR**|UR**|Id**|Nd**|La(+'.split`|`.map(x=>x.split``.map(c=>c.charCodeAt()-40)).map((x,i)=>b[b.beginPath(b.fillStyle='#'+'fccf77fff000'.substr('030306699'[i],3)),b.ellipse(...x,0,0,3*-~(i<9)),i>8?'stroke':'fill']())

389 bytes

Recently submited an edit for -6.

If you are willing to change your answer HTML+JavaScript you can make the HTML part <canvas id=A> and the first part of the JS b=A.getContext... - I used this in my Flag of Iceland some time ago. This post just saved that that answer 2 bytes :) https://codegolf.stackexchange.com/a/176852/8340

As a bonus you can embed a "stack snippet" :) https://stackoverflow.blog/2014/09/16/introducing-runnable-javascript-css-and-html-code-snippets/

You can save 3 more bytes with (D=document).body.appendChild(a=D.createElement\canvas`)`.

Processing, 388 343 319 chars/bytes
Not very elegant, but here it is. Saved bytes by making the image smaller.
int b=50,c=60,g=70;
noStroke();
//Face
fill(#FFCCCC);
ellipse(b,g,c,c);
//Outer ears
ellipse(40,25,15,b);
ellipse(c,25,15,b);
//Inner ears
fill(#FF9999);
ellipse(40,25,7,30);
ellipse(c,25,7,30);
//Outer eyes
fill(-1);
ellipse(40,g,10,10);
ellipse(c,g,10,10);
//Inner eyes
fill(0);
ellipse(40,g,5,5);
ellipse(c,g,5,5);
//Mouth
stroke(0);
line(b,80,b,85);
noFill();
arc(53,85,5,5,0,PI);
arc(48,85,5,5,0,PI);

I saved a few bytes here and there: 332 bytes

279 bytes

If strokes are allowed, 258 bytes

@Zylviij Used some of the ideas you had and got it down to 343 chars. I don't think you can assign functions to variables in Processing.

I haven't ever personally used or downloaded processing, but I did test my scripts here and they worked without producing errors in the image or console

@Zylviij Huh. I don't usually post Processing answers here, so I don't know the meta. I was not able to run your code in the Processing IDE that you can download from the website.

PostScript, 688 484 468 439 359 bytes
Golfed version:
<</F{closepath fill}/C{0 360 arc}/c{curveto}/s{setrgbcolor}/M{moveto}/h{7 15 M 7 25 1 25 1 15 c 1 5 7 5 7 15 c F 1 .5 .5 s 6 15 M 6 22 2 22 2 15 c 2 8 6 8 6 15 c F 1 1 1 s 4 3 2 C F 0 0 0 s 4 3 1 C F 0 -3 M 0 -5 lineto stroke 1 -5 1 180 0 arc stroke}>>begin 80 60 translate 5 5 scale .2 setlinewidth 1 .7 .7 s 0 0 10 C F gsave h grestore -1 1 scale h showpage

Ungolfed version:
% define some short-named procedures for later use
<<
  /F {closepath fill}
  /C {0 360 arc}
  /c {curveto}
  /s {setrgbcolor}
  /M {moveto}
  /h {                           % procedure for drawing one half
    7 15 M 7 25 1 25 1 15 c      % ellipse for outer ear
           1  5 7  5 7 15 c F
    1 .5 .5 s                    % dark pink
    6 15 M 6 22 2 22 2 15 c      % ellipse for inner ear
           2  8 6  8 6 15 c F
    1 1 1 s                      % white
    4 3 2 C F                    % circle for outer eye
    0 0 0 s                      % black
    4 3 1 C F                    % circle for inner eye
    0 -3 M 0 -5 lineto stroke    % line for upper mouth
    1 -5 1 180 0 arc stroke      % arc for lower mouth
  }
>> begin

80 60 translate                  % over-all shift
5 5 scale                        % over-all scale
.2 setlinewidth
1 .7 .7 s                        % light pink
0 0 10 C F                       % large circle for head
gsave h grestore                 % right half
-1 1 scale h                     % left half
showpage

Result:

Lua + LÖVE/Love2D, 328 bytes
l=love g=l.graphics c=g.setColor e=g.ellipse a=g.arc f="fill" k="line" o="open"function l.draw()c(1,.7,.7)e(f,50,82,40,40)e(f,30,28,10,25)e(f,70,28,10,25)c(1,.4,.4)e(f,30,28,5,18)e(f,70,28,5,18)c(1,1,1)e(f,35,73,8,8)e(f,65,73,8,8)c(0,0,0)g[k](49,90,49,99)a(k,o,45,96,5,.5,2.7)a(k,o,53,96,5,.5,2.7)e(f,35,73,4,4)e(f,65,73,4,4)end

Try it online!

SVG (HTML5), 415 bytes

<svg width=48 height=80><g fill=#fdd><circle cx=24 cy=52 r=24 /><ellipse cx=12 cy=16 rx=8 ry=16 /><ellipse cx=36 cy=16 rx=8 ry=16 /></g><g fill=#f99><ellipse cx=12 cy=16 rx=4 ry=12 /><ellipse cx=36 cy=16 rx=4 ry=12 /></g><g fill=#fff><circle cx=16 cy=44 r=6 /><circle cx=32 cy=44 r=6 /></g><circle cx=16 cy=44 r=3 /><circle cx=32 cy=44 r=3 /><path stroke=#000 fill=none d=M18,60a3,3,180,0,0,6,0v-6v6a3,3,180,0,0,6,0

Keeping the height below 100 to help save precious bytes, but still the longest...

Java, 508 472 bytes
import java.awt.*;v->new Frame(){Graphics2D G;Color C;void d(int...d){G.fillOval(d[0],d[1],d[2],d[3]);}{add(new Panel(){public void paint(Graphics g){G=(Graphics2D)g;G.setPaint(C.PINK);d(0,65,99,99);d(22,0,24,75);d(58,0,24,75);G.setPaint(C.MAGENTA);d(27,5,14,65);d(63,5,14,65);G.setPaint(C.WHITE);d(24,85,20,20);d(60,85,20,20);G.setPaint(C.BLACK);d(30,91,8,8);d(66,91,8,8);G.drawArc(41,124,9,11,0,-180);G.drawArc(50,124,9,11,0,-180);G.drawLine(50,119,50,130);}});show();}}

This is the resulting bunny:

Explanation:
import java.awt.*;              // Required imports for almost everything
v->                             // Method with empty unused parameter and no return-type
  new Frame(){                  //  Create a new Frame
    Graphics2D G;               //   Graphics2D-object on class-level
    Color C;                    //   Color variable to save bytes with static calls
    void d(int...d){            //   Create an inner method with integer-varargs as parameter
      G.fillOval(               //    Draw a circle/oval, filled with the current color:
        d[0],d[1],              //     With the first two integers as starting x,y position
        d[2],                   //     Third as width
        d[3]));}                //     And fourth as height
    {                           //   Then open an initializer-block inside the Frame-class
     add(new Panel(){           //    And add a Panel to the Frame we can draw on
       public void paint(Graphics g){
                                //     Override the Panel's paint-method
         G=(Graphics2D)g;       //      Set the Graphics2D-object with the parameter
         G.setPaint(C.PINK);    //      Set the color to pink (255,175,175)
         d(0,65,99,99);         //      Draw the head circle
         d(22,0,24,75);         //      Draw the left ear
         d(58,0,24,75);         //      Draw the right ear
         G.setPaint(C.MAGENTA); //      Change the color to magenta (255,0,255)
         d(27,5,14,65);         //      Draw the inner part of the left ear
         d(63,5,14,65);         //      Draw the inner part of the right ear
         G.setPaint(C.WHITE);   //      Change the color to white (255,255,255)
         d(24,85,20,20);        //      Draw the left eye
         d(60,85,20,20);        //      Draw the right eye
         G.setPaint(C.BLACK);   //      Change the color to black (0,0,0)
         d(30,91,8,8);          //      Draw the left pupil
         d(66,91,8,8);          //      Draw the right pupil
         G.drawArc(41,124,9,11,0,-180);
                                //      Draw the left mouth elipse
         G.drawArc(50,124,9,11,0,-180);
                                //      Draw the right mouth elipse
         G.drawLine(50,119,50,130);}});
                                //      Draw the line of the mouth
    show();}}                   //    And finally show the Frame on the screen

Racket – 597 bytes
#!racket/gui
(require pict)(show-pict(let*([c cc-superimpose][f filled-ellipse][h hc-append][v vc-append][r rotate][p"pink"][E(c(f 85 140 #:color p)(f 50 90 #:color"maroon"))][I(c(f 60 60 #:color"white")(f 30 30 #:color"brown"))][M(dc(λ(D X Y)(define-syntax-rule(S a ...)(send D a ...))(let([P(S get-pen)][B(S get-brush)])(S set-brush(new brush%[style 'transparent]))(S set-pen(new pen%[width 5]))(S draw-arc(+ 1 X)Y 48 48(- pi)0)(S set-brush B)(S set-pen P)))50 50)])(v -40(h 20(r E .2)(r E -.2))(c(f 220 220 #:color p)(v 20(h 40 I I)(v -25(filled-rectangle 8 30 #:color"darkbrown")(h M M)))))))

Here's the TIO link. Note that TIO can not display the pict, hence why it shows an error. Feel free to use the link as a means to verify byte count and/or copy code into a local file.

Screenshot from DrRacket

Yeah, I'm using Light Theme at 12am xD
Explanation of the code
This explanation uses the ungolfed version of the program, but I will explain what I did to golf it up along the way.
On line one, we set the language to racket/gui. This us to create GUIs and use some pieces of Racket's canvas API (we use the brush% and pen% classes to make new styles for them). Right underneath the language statement, we import the pict package. This package sort of works like JavaScript's Canvas API.
#lang racket/gui
(require pict)

(show-pict ...)

We then start the program by calling show-pict which renders a picture to the screen.
While Racket has already made picts for fishes and files, it doesn't have a pict for an easter bunny. So let's make one! To make the eyes and the ears, we can use filled ellipses. In pict, they are defined simply as filled-ellipse. The function receives the following input:
(filled-ellipse width height #:color [fill-color])

Now we want to center an ellipse inside of another (the outer one for the outer ear/eyeball and the inner ellipse for the inner ear/pupil). To that, we simply use the function cc-superimpose (standing for "align center x, align center y, on top of another pict").
(let ([ear (cc-superimpose (filled-ellipse 85 140 #:color "pink")
                           (filled-ellipse 50 90 #:color "maroon"))]  ;; Inner ear
      [eye (cc-superimpose (filled-ellipse 60 60 #:color "white")
                           (filled-ellipse 30 30 #:color "brown"))])  ;; Eye pupil
  ...))

Now comes a trickier part: the mouth. I say it is tricky because it involves using the canvas context API to draw arcs. pict provides a neat little function called dc which allows use to access the drawing context for the canvas. It accepts three arguments: a function that draws the pict using the context, width and height. The function that it receives must also receive three arguments, but this time, they are: the drawing context and the current x and y positions for the pen and brush.
(dc (lambda (dc dx dy)
      ...) width height)

To tell the context to draw something or to configure the pen and brush, we use the send function to call the one of the object's methods. In our case, we set the brush to 'transparent.
(send dc set-brush (new brush% [style 'transparent]))

Now that the basic functionality is mostly explained, let's create the mouth once and for all.
(let ([ear (cc-superimpose (filled-ellipse 85 140 #:color "pink")
                           (filled-ellipse 50 90 #:color "maroon"))]  ;; Inner ear
      [eye (cc-superimpose (filled-ellipse 60 60 #:color "white")
                           (filled-ellipse 30 30 #:color "brown"))]  ;; Eye pupil
      [mouth (dc (λ (dc dx dy)
                   ;; Save old pen/brush state
                   (define old-pen (send dc get-pen))
                   (define old-brush (send dc get-brush))
                   ;; Set new styles for pen/brush
                   (send dc set-brush (new brush% [style 'transparent]))
                   (send dc set-pen (new pen% [width 5]))
                   ;; Draw an arc of width/height 48 at (dx+1,dy) counter-clockwise
                   (send dc draw-arc (+ 1 dx) dy 48 48 (- pi) 0)
                   ;; Reset to default pen/brush for `dc` function
                   (send dc set-brush old-brush)
                   (send dc set-pen old-pen)) 50 50)])
  ...))

One thing to note is (+ 1 dx). I had a rendering issue where the arc would be one pixel to the left of the nose, and this seemed to fix it. I think it might be caused from putting the arcs side-by-side using hc-append.
Let's add these facial features to the actual face.
(let ([ear (cc-superimpose (filled-ellipse 85 140 #:color "pink")
                           (filled-ellipse 50 90 #:color "maroon"))]  ;; Inner ear
      [eye (cc-superimpose (filled-ellipse 60 60 #:color "white")
                           (filled-ellipse 30 30 #:color "brown"))]  ;; Eye pupil
      [mouth (dc (λ (dc dx dy)
                    ;; Save old pen/brush state
                    (define old-pen (send dc get-pen))
                    (define old-brush (send dc get-brush))
                    ;; Set new styles for pen/brush
                    (send dc set-brush (new brush% [style 'transparent]))
                    (send dc set-pen (new pen% [width 5]))
                    ;; Draw an arc of width/height 48 at (dx+1,dy) counter-clockwise
                    (send dc draw-arc (+ 1 dx) dy 48 48 (- pi) 0)
                    ;; Reset to default pen/brush for `dc` function
                    (send dc set-brush old-brush)
                    (send dc set-pen old-pen))
                  50 50)])
  ;; Ears + Face
  (vc-append -40
             ;; Ears
             (hc-append 20
                        (rotate ear .2)
                        (rotate ear -.2))
             ;; Face
             (cc-superimpose (filled-ellipse 220 220 #:color "pink")
                             (vc-append 20
                                        ;; Eyes
                                        (hc-append 40 eye eye)
                                        (vc-append -25
                                                   ;; Nose
                                                   (filled-rectangle 8 30 #:color "darkbrown")
                                                   ;; Mouth
                                                   (hc-append mouth mouth))))))

The vc-append appends picts vertically, and hc-append appends picts horizontally. Both functions receive an optional spacing parameter as it's first argument. So the arcs for the mouth have no space between them, but the eyes have 40 pixels between them. To fit the nose and the mouth snuggly together, I used -25 as the spacing.
Putting the program together is as simple as placing the let block inside of show-pict.
A cleaner more declarative way
#lang racket/gui
(require pict)

(define ear (cc-superimpose (filled-ellipse 85 140 #:color "pink")
                            (filled-ellipse 50 90 #:color "maroon")))

(define ears (hc-append 20 (rotate ear .2) (rotate ear -.2)))

(define eye (cc-superimpose (filled-ellipse 60 60 #:color "white")
                            (filled-ellipse 30 30 #:color "brown")))

(define eyes (hc-append 40 eye eye))

(define nose (filled-rectangle 8 30 #:color "darkbrown"))

(define mouth (dc (λ(dc dx dy)
                    (define old-pen (send dc get-pen))
                    (define old-brush (send dc get-brush))
                    (send dc set-brush (new brush% [style 'transparent]))
                    (send dc set-pen (new pen% [width 5]))
                    (send dc draw-arc (+ 1 dx) dy 48 48 (- pi) 0)
                    (send dc set-brush old-brush)
                    (send dc set-pen old-pen))
                  50 50))

(define nose+mouth (vc-append -25 nose (hc-append mouth mouth)))

(define eyes+nose+mouth (vc-append 20 eyes nose+mouth))

(define face (cc-superimpose (filled-ellipse 220 220 #:color "pink")
                             eyes+nose+mouth))

(define easter-bunny (vc-append -40 ears face))
(show-pict easter-bunny)

How I golfed the code
While the let statement is cool, its brother let* is cooler. A normal let statement doesn't allow other variables inside of its binding block to see each other. but this isn't the case with let*:
;; Normal let - Can't use `f` in let binding
(let ([f filled-ellipse]
      [red-circle (filled-ellipse 50 50 #:color "red")])
  (cc-superimpose (f 50 50 #:color "yellow") red-circle))

;; Cooler let*
(let ([f filled-ellipse]
      [red-circle (f 50 50 #:color "red")])
  (cc-superimpose (f 50 50 #:color "yellow") red-circle))

Because I use cc-superimpose, vc-append, hc-append, etc. a lot, I used let* so that I could bind them to shorter names:
(let* ([c cc-superimpose]
       [f filled-ellipse]
       [h hc-append]
       [v vc-append]
       [r rotate]
       [p "pink"])
  ...)

I then proceeded to rename all variables to shorter names, ear becomes E, eye becomes I, etc. After that was done, I started to ponder what I could do with the dreaded mouth sends. I ended up creating a macro :)
(let* (...
       [M (dc (λ (D X Y)
                 ;; This macro will replace (S get-pen) with (send D get-pen)
                 (define-syntax-rule (S a ...)
                   (send D a ...))
                 (let ([P (S get-pen)] [B (S get-brush)])
                   (S set-brush (new brush% [style 'transparent]))
                   (S set-pen (new pen% [width 5]))
                   (S draw-arc (+ 1 X) Y 48 48 (- pi) 0)
                   (S set-brush B)
                   (S set-pen P)))
                50 50)])
  ...)

Once that was done, I deleted all unnecessary spaces.
The golfed code and the code I used in the explanation are basically identical. If you don't want to open a new window, simply remove the call to show-pict. Pict only displays well in DrRacket. If you try to print a pict to a console like CMD or terminal, you'd see #<pict> which is Racket's way of telling you "Yes the statement returned something, but I can only tell you what type of object it returned.
Conclusion
It's 2am now as I write this conclusion, hope everyone enjoyed this little tutorial-ish explanation!
Have an amazing week!

Scala, with Java AWT(Abstract Window Toolkit). 714 bytes
Port of @Kevin Cruijssen's Java answer in Scala.

Golfed Scala code.
import java.awt._;import java.awt.event._;object M extends App{new Frame{def d(g:Graphics2D,x:Int,y:Int,w:Int,h:Int)=g.fillOval(x,y,w,h);add(new Panel{override def paint(g:Graphics){val g2=g.asInstanceOf[Graphics2D];g2.setPaint(Color.PINK);d(g2,0,65,99,99);d(g2,22,0,24,75);d(g2,58,0,24,75);g2.setPaint(Color.MAGENTA);d(g2,27,5,14,65);d(g2,63,5,14,65);g2.setPaint(Color.WHITE);d(g2,24,85,20,20);d(g2,60,85,20,20);g2.setPaint(Color.BLACK);d(g2,30,91,8,8);d(g2,66,91,8,8);g2.drawArc(41,124,9,11,0,-180);g2.drawArc(50,124,9,11,0,-180);g2.drawLine(50,119,50,130);}});setSize(new Dimension(200,200));setVisible(true);addWindowListener(new WindowAdapter{override def windowClosing(e:WindowEvent):Unit=System.exit(0);})}}

This is the resulting bunny.

Ungolfed Scala code.
import java.awt._
import java.awt.event._

object ScalaMain extends App {
  new Frame {
    def d(g: Graphics2D, x: Int, y: Int, w: Int, h: Int): Unit = g.fillOval(x, y, w, h)

    add(new Panel {
      override def paint(g: Graphics): Unit = {
        val g2d = g.asInstanceOf[Graphics2D]
        g2d.setPaint(Color.PINK)
        d(g2d, 0, 65, 99, 99)
        d(g2d, 22, 0, 24, 75)
        d(g2d, 58, 0, 24, 75)
        g2d.setPaint(Color.MAGENTA)
        d(g2d, 27, 5, 14, 65)
        d(g2d, 63, 5, 14, 65)
        g2d.setPaint(Color.WHITE)
        d(g2d, 24, 85, 20, 20)
        d(g2d, 60, 85, 20, 20)
        g2d.setPaint(Color.BLACK)
        d(g2d, 30, 91, 8, 8)
        d(g2d, 66, 91, 8, 8)
        g2d.drawArc(41, 124, 9, 11, 0, -180)
        g2d.drawArc(50, 124, 9, 11, 0, -180)
        g2d.drawLine(50, 119, 50, 130)
      }
    })
    setSize(new Dimension(200, 200))
    setVisible(true)
    addWindowListener(new WindowAdapter {
      override def windowClosing(e: WindowEvent): Unit = System.exit(0)
    })
  }
}


text:
Marquee sign letters
Each day you put up a new word on a marquee sign with movable letters, buying just the letters you need to write it. You re-use letters you've bought for earlier words whenever possible. Given the words you want to write each day in order, output the letters you buy each day.

Example
Input:  ['ONE', 'TWO', 'THREE', 'SEVENTEEN']
Output: ['ENO', 'TW', 'EHR', 'EENSV']

Day 1: You start with no letters, so to write ONE, you buy all its
  letters E, N, O.
Day 2: The next day, you want to put up TWO
  (taking down the ONE). You already have an O from ONE, so you
  buy an additional TW.
Day 3: At this point, you have ENOWT. To write
  THREE, you need EHR. Note that you need to buy a second E in
  addition to the one you have.
Day 4: To write SEVENTEEN, you need 4
  E's total of which you already have two (not three!), so you buy two more.
  You also have the T and one of the N's, so you buy the remaining letters:
  EENSV.
We've output letters sorted alphabetically in this example, but you may
  output them in any order.

Input: A non-empty list of non-empty strings of letters A-Z. You may use lowercase if you prefer. Lists of characters are fine for strings.
Output: Output or print the additional letters you need to buy each day. The letters for a day may be output in any order, but the days must come in the right order.
The letters from each day should be separated from other days so you can tell where a day ends. A trailing and/or leading separator is fine, both within a day or between days. Note that a day may have no letters bought, which should be reflected in the output (a space or empty line is OK, even for the last day).
Test cases
['ONE', 'TWO', 'THREE', 'SEVENTEEN']
['ENO', 'TW', 'EHR', 'EENSV']

['ONE', 'TWO', 'ONE', 'THREE']
['ENO', 'TW', '', 'EHR']

['ABC', 'AABC', 'ABBC', 'ABCC', 'AABBCC']
['ABC', 'A', 'B', 'C', '']

['SHORT', 'LOONG', 'LOOOONG', 'LOOOOOOONG', 'SHORT', 'LOOONG']
['HORST', 'GLNO', 'OO', 'OOO', '', '']

Here are all the inputs and outputs as separate lists:
[['ONE', 'TWO', 'THREE', 'SEVENTEEN'], ['ONE', 'TWO', 'ONE', 'THREE'], ['ABC', 'AABC', 'ABBC', 'ABCC', 'AABBCC'], ['SHORT', 'LOONG', 'LOOOONG', 'LOOOOOOONG', 'SHORT', 'LOOONG']]
[['ENO', 'TW', 'EHR', 'EENSV'], ['ENO', 'TW', '', 'EHR'], ['ABC', 'A', 'B', 'C', ''], ['HORST', 'GLNO', 'OO', 'OOO', '', '']]

And as space-separated strings (the trailing spaces in the outputs matter):
ONE TWO THREE SEVENTEEN
ONE TWO ONE THREE
ABC AABC ABBC ABCC AABBCC
SHORT LOONG LOOOONG LOOOOOOONG SHORT LOOONG

ENO TW EHR EENSV
ENO TW  EHR
ABC A B C
HORST GLNO OO OOO

Leaderboards

var QUESTION_ID=183544,OVERRIDE_USER=20260;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="
"+e.body.replace(OVERRIDE_REG,"")+"
")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
 <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">

Leaderboard

	Author	Language	Size

Winners by Language

Language	User	Score

{{PLACE}}	{{NAME}}	{{LANGUAGE}}	{{SIZE}}	Link

{{LANGUAGE}}	{{NAME}}	{{SIZE}}	Link

A wild leaderboard script has appeared in the userscript age :o

Can we output as an an array of characters that need to be bought rather than a string of all the characters? e.g.: [['E', 'N', 'O'], ...]

Is the output SHORTLONGOOOOO valid for the last output? AKA using no delimiters?

@Downgoat Yes, lists are chars are fine to output.

@MagicOctopusUrn No, you need delimiters, otherwise you can't tell what letters are for what day.

Can the input be a space-delimited string?  Your last code block implies(?) that it can be.

@Tau Yes, space separated is fine.

Haskell, 54 49 bytes
import Data.List
g x=zipWith(\\)x$scanl(++)""$g x

Try it online!
We build the output list by calculating pairwise the list difference (\\) of the input list and the cumulative append of the output list (starting with "").
input list:                ONE       TWO       THREE        SEVENTEEN
cumulative append:         ""   +->  ONE  +->  ONETW   +->  ONETWHRE
list difference (output):  ONE -+    TW  -+    HRE    -+    SVEEN

With both Data.List and Data.Function in scope (e.g. by using the lambdabot environment), this can be shortened to 30 bytes:
fix.(.scanl(++)"").zipWith(\\)

Edit: -5 bytes thanks to @Sriotchilism O'Zaic.

Why not this?

Python 2, 72 68 bytes
-4 bytes thanks to Jonathan Allan.
p=''
for r in input():
 for x in p:r=r.replace(x,'',1)
 print r;p+=r

Try it online!
Commented
l=input()       # the list of words to write
p=''            # p contains all letters we own
for r in l:     # for each word ...
  for x in p:   # for each letter we own ...
    r=r.replace(x,'',1)   # remove one occurence from the current word
  print r       # print the remaining word
  p+=r          # add the remaining chars to p

for r in input(): saves 4 bytes.

Jelly, 7 bytes
,œ-@Kɗ/

Try it online!
Output:  -separated string.

Perl 6, 44 40 bytes
-4 bytes thanks to Matthew Jensen
{$!=@;.map:{kxxv $!=.comb∖($⊎=$!):}}

Try it online!
Outputs as a list of lists of characters.
Explanation
{                                  } # Anonymous codeblock
 $!=@;                               # Initialise $! to an empty list
      .map:{                      }  # Map each item in the input to
                    .comb            # The string split to characters
                                     # In a Bag
                         ∖           # Set minus
                          ($⊎=$!)    # The accumulated Bag of results
                 $!=                 # And save the result for the next item
            kxxv                 : # Then decompose the Bag into a list

A reason for the downvote would be appreciated

Not the downvoter, but I'm gonna say this output format strays too far. Something like Bag(E(2), N, S, V) would need to actually show two E's to be OK.

What, really? That's just the default print formatting. The return result is an unordered list that contains those characters (and can contain multiple of the same character). I'll update the output formatting to better reflect this, but the downvote seems ridiculous.

Downvoter, could you please explain, is this about I/O or something else? About the bag format, I don't know Perl, is this common for I/O in Perl golfs? Looking at the docs (cached because site is down), they seem to me to be more like dicts with counts, akin to Python's collections.Counter which I didn't intend to allow as output. Can one easily iterate over bag elts with multiplicity, cast to a list/array, display with multiplicity, etc?

Downvote was a mistake, was meant to be up.

@xnor I've changed the output to a list of list of characters at the expense of 6 bytes

I don't know how Perl works, but I was playing around and removing .Bag seems not to change the function.

@MatthewJensen You are correct, since the ∖ operator with a Bag on one side converts the other side to a Bag as well. Thanks!

JavaScript (Node.js), 59 bytes
a=>a.map(h=>([...t].map(c=>h=h.replace(c,'')),t+=h,h),t='')

Try it online!
Quite straightforward solution. For each word h, remove letters we already have.
Here is an explained version of that code:

f = list => {
  // the string that accumulates all the letters already bought
  let accu = '';
  // for every word in the list
  return list.map( word => {
    // for every letter already bought
    [...accu]
      // remove the letter from the word
      .map(char => {
        return word = word.replace(char,'')
      });
    // add not bought letters to accumulator
    accu += word;
    // the reduced word (without already bought letters) should be added to result map
    // this represents the letters to buy today
    return word
  }, accu)
}

console.log(f(['ONE', 'TWO', 'THREE', 'SEVENTEEN']))
console.log(f(['ONE', 'TWO', 'ONE', 'THREE']))
console.log(f(['ABC', 'AABC', 'ABBC', 'ABCC', 'AABBCC']))
console.log(f(['SHORT', 'LOONG', 'LOOOONG', 'LOOOOOOONG', 'SHORT', 'LOOONG']))

You can save 1 byte by borrowing the only worthwhile trick from my otherwise overcomplicated solution.

Haskell, 44 bytes
import Data.List
foldl1(\a x->a++',':(x\\a))

Try it online!
Output is a string like ONE,TW,HRE,SVEEN with commas between days.

What a nice use of the output format to avoid needing to fold the \\. And an unexpected foldl1 base case too.

J, 29 bytes
-29 bytes thanks to FrownyFrog!
(],a.<@#~0>.-&(1#.a.=/;))/@|.

Try it online!
Original Post
J, 58 bytes
[:}.@>[:(],<@(/:~@({.@>@-.&(((e.<@#[){:)\));))&.>/<@a:,~|.

Try it online!
Thanks to ngn for help improving the "subtract letters while respecting repetition part".
Not a great fit for J, but an illuminating exercise.
Let's begin by constructing a helper verb wo ("without") that removes all
chacters in one string from another, while respecting repetitions.
wo=.{.@>@-.&(((e. <@# [) {:)\)

There is a fun idea here: We make each repeated instance of a character unique,
by repeating it the required number of times.  Thus if our original
string is ABBA it becomes:
┌─┬─┬──┬──┐
│A│B│BB│AA│
└─┴─┴──┴──┘

A third A would become AAA and so on.  This is accomplished by the phrase
((e. <@# [) {:)\, which takes each prefix \, looks at the final element
{: of it, and constructs a mask of all elements in that prefix that match
e. that final element, and then filters and boxes just those elements <@#.
With our inputs both "unique-ified" we can now safely use normal set minus -.
while still respecting repetition.
We then open each result and take only the first element to "undo" our repetitions: {.@>
Plugging this helper verb in, our overall solution (which simply inlines it) becomes:
[: }.@> [: (] , <@(/:~@wo ;))&.>/ <@a: ,~ |.

Essentially, all we do here is setup our problem as a single reduction.  We
start be reversing the input |. and appending to it ,~ an ace a:, or empty box,
which will be the initial value of our final result, like so:
┌─────────┬─────┬───┬───┬──┐
│SEVENTEEN│THREE│TWO│ONE│┌┐│
│         │     │   │   ││││
│         │     │   │   │└┘│
└─────────┴─────┴───┴───┴──┘

We stick the following verb between each element to effect the reduction:
(] , <@(/:~@wo ;))/

This says: take the right input ] (ie, our result) and append to it ,  the
left input (this is ONE on the first iteration, TWO on the 2nd, etc)
without wo the raze of ; the right input (ie, without any previous letters
so far used), but before appending sort it /:~ and box it again <@.
At the end of all this we'll have the result we want, a list of boxes, but all inside
one big additional box, and still with the empty box at the front.  Thus we open
to remove the outer box and kill the first element: }.@>.

[:}.@>|.(],a.<@#~0>.-&(1#.a.=/;))&.>/@,<@a:

A simple (],a.<@#~0>.-&(1#.a.=/;))/@|. also works unless I'm missing an edge case.

As far as I can tell, sorting is nowhere in the requirements.

Updated and now that I've had time to absorb it, just wanted to say again: That's damn nice J!

JavaScript (ES6),  66  65 bytes
a=>a.map(b=s=>[...s].filter(c=>x==(x=x.replace(c))?b+=c:0,x=b+0))

Try it online!
Commented
\$b\$ is a string holding all available letters (and also some invalid characters, but this is irrelevant to the algorithm). For each new word, we create a copy of \$b\$ in \$x\$. Each letter \$c\$ of a word is either used by removing it from \$x\$ or bought by appending it to \$b\$. Only bought letters are returned.
a =>                      // a[] = input
  a.map(b =               // initialize b to the callback function of this map()
                          // it will be coerced to a string that does not contain
                          // any letter in uppercase
    s =>                  // for each entry s in a[]:
    [...s].filter(c =>    //   for each character c in s:
      x == (              //     check whether x is changed when
        x = x.replace(c)  //     c is replaced with 'undefined'
      ) ?                 //     if so:
        b += c            //       append c to b and keep c
      :                   //     else:
        0,                //       discard c
      x = b + 0           //     coerce b to a string and save it in x
    )                     //   end of filter()
  )                       // end of map()

C++ (gcc), 177 170 bytes
-5 bytes thanks to @anatolyg's tip, -2 bytes to small things I noticed.
#import<random>
#define v std::vector<std::string>
v a(v p){std::vector<int>o(91),b;int j=-1;for(auto i:p){b=o;p[++j]="";for(int c:i)--b[c]<0?p[j]+=c,++o[c]:0;}return p;}

Explanation
#import<random> adds both <string> and <vector> for half the bytes.
First creates a 91-element vector of 0s (only indices 65-90 are used to store letter occurences), and another vector of the same type but not set to a value. Iterates through each element of the input (the days): gets the currently owned letters, gets the letters that are needed for the day, overrides the input at the index with the needed amount and updates the owned letters. Returns the overridden input.
Try it online!

You can do #define v std::vector<std::string and remove using namespace std to reduce byte count by 6 bytes.

R, 119 112 106 103 bytes
-7 bytes from aliasing the two longer function names and now taking user input from scan()
-6 bytes to only call strsplit() once at the beginning
-3 bytes to get rid of the aliasing again and assign two variables in one call
(Also edited the byte count which was erroneously low earlier)
a=scan(,'');b=a=strsplit(a,'');for(i in 2:length(a))b[[i]]=vecsets::vsetdiff(a[[i]],unlist(b[1:i-1]));b

This is my very first PPCG submission of any kind! So I have no idea what I'm doing both in terms of golfing and in terms of posting etiquette. The output is a list of vectors which may or may not meet the terms of the challenge. :-P
As for the code itself, it takes user input via scan() and compares each new day's letters to the cumulatively owned letters, as in other solutions. If there are shorter alternatives to unlist and strsplit for converting strings into vectors of individual characters that would be cool to know. I also used the vsetdiff function in Carl Withoft's vecsets package to get the set difference of the letters needed for the next day and the current letters owned.

Welcome! You can (and should if possible) post a link to https://tio.run/#r; if you open it, you'll notice it automatically pre-create the post with the bytes count header, the code etc ;)

Unfortunately vecsets is not included in TIO :(

@digEmAll thanks for the tip. Is it considered bad form to use functions from packages? I thought about hard coding the vsetdiff but it would have wasted too many bytes.

no, it's perfectly fine. I'm a little reluctant myself in using external packages, but it's just me... I prefer to approach the challenges in base R code ;)

103 in base R

Your version in 99 bytes

80 if we print the values instead of storing

@digEmAll these are great! nice to see what's possible. :-D Didn't realize you could nest scan() but I guess it's obvious

The 80 bytes version in 73 bytes thanks to some obvious improvements I missed :D

PowerShell, 71 bytes
$args|%{$w=$_;$p|% t*y|%{$w=$w-replace"^(.*?)$_(.*)",'$1$2'};$w;$p+=$w}

Try it online!
Takes input words $args and iterates over them. Each iteration we set the current word $w, then loop over our $pool of already-purchased letters. Each inner loop, we perform a regex -replace on our current $word, so that we're replacing just the first instance of the letter from our $pool. Once we've gone through all letters in the pool, we output what's remaining $w (i.e., what we need to purchase), and then tack those letters onto our pool $p+=$w for the next word.

Python 2, 102 100 bytes
from collections import*
c=Counter
l=c()
for x in map(c,input()):y=x-l;l+=y;print list(y.elements())

Try it online!
-2 bytes, thanks to Embodiment of Ignorance

100 bytes

@EmbodimentofIgnorance Thanks :)

Japt, 15 14 bytes
£Q®X=rZPPÃQ±XX

Try it
£Q®X=rZPPÃQ±XX     :Implicit input of array
£                  :Map each X
 Q®                :  Map each Z in Q (initially a quotation mark)
   X=              :    Reassign to X
     rZ            :    Replace Z with
       P           :    The empty string
        P          :    With the default global flag disabled
         Ã         :  End map
          Q±X      :  Append X to Q
             X     :  Return X

@Downvoter, please have the decency to leave a comment.

C# (Visual C# Interactive Compiler), 123 bytes
a=>{var b="";for(dynamic i=0,e,f;i{
  // b: cumulative letters
  var b="";
  for(
    // i: loop index of string
    // e: copy of cumulative letters for manipulation
    // f: characters missing from current string
    dynamic i=0,e,f;
    // iterate over each string in a
    i<a.Count;
    // add missing letters of the day to
    // cumulative missing letters and
    // update array for output
    b+=a[i++]=f
  )
    // iterate current string with character c
    foreach(var c in
      // tuplized variable assignment
      // e=b.ToList()
      //   set e to a copy of the cumulative letters
      // f=""
      //   initially there are no letters needed for the day
      ((e,f)=
      (b.ToList(),"")).f+a[i]
    )
      // conditionally add c to missing letters for the day
      f+=e.Remove(c)?"":c;
}

05AB1E, 11 bytes
-6 thanks to Kevin Cruijssen
ćsvDysSõ.;»

Try it online!

Your 15-byter works, but I would replace the trailing J with ». Also, you can save 4 bytes by replacing vyð.;}ðK with Sõ.; 11 bytes.

Ahhhh... I needed S to make it vectorize.

Red, 75 bytes
func[b][a: copy""foreach w b[foreach c a[replace w c""]print w append a w]]

Try it online!

Excel VBA, 127 bytes
Function z(w)
z=""
For Each x In w.Cells
v=x.value
For y=1To Len(z)
v=Replace(v,Mid(z,y,1),"",1,1)
Next
z=z&v
Next
End Function

Takes input in the form of an excel range.

C (gcc), 118 bytes
m(a,r,q,u)char**a,*r,*q,*u;{for(;*a;a++,memcpy(r,q,255))for(memcpy(q,r,255),u=*a;*u;u++)*u=r[*u]-->0?32:(q[*u]++,*u);}

Try it online!
As a little bonus it takes the stock in r at the start as an array. Outputs the input null-terminated null-terminated-string list a with all pre-owned letters replaced with spaces.

106 bytes

Swift 4.2/Xcode 10.2, 244 242 239 238 bytes
a.reduce(([Character:Int](),[String]())){c,l in let b=l.reduce(into:[Character:Int]()){$0[$1,default:0]+=1}.map{($0,max(0,$1-(c.0[$0] ?? 0)))};return(c.0.merging(b){$0+$1},c.1+[b.map{String(Array(repeating:$0.0,count:$0.1))}.joined()])}.1

Try it online!
The letters are not arranged in alphabetical order, it is not forbidden by the rules.

K (ngn/k), 36 33 bytes
*+(){(a;x,a:&0|-/#''='(y;x@:1))}\

Try it online!

Scala, 68 bytes
(c:Seq[String])=>c./:(Seq(""))((a,n)=>a:+n.diff(a./:("")(_+_))).tail

Try it online!
/: is short-hand for foldLeft operator,
a is aggregation, ultimately returns the result we want,
n is next element
Un-golfed
def NewLettersPerDay(c: Seq[String]): Seq[String] = {
    c.foldLeft(Seq(""))((agg, next) => {
      val existingLetters = agg.reduce(_+_)
      val newDayLetters = next.diff(existingLetters)
      agg :+ newDayLetters
    }).tail
}

PHP, 87 bytes
for(;$w=$argv[++$i];print' ')for($b=$a;$l=$w[$$i++];)$b[$l]?$b[$l]--:++$a[$l]&&print$l;

Try it online!

C# (Visual C# Interactive Compiler), 112 bytes
a=>{var b="";for(int i=0;;b+=a[i++])foreach(var z in b)if(a[i].Contains(z))a[i]=a[i].Remove(a[i].IndexOf(z),1);}

Try it online!

Hmm... This throws an exception?

@dana I'm pretty sure functions that don't return anything are allowed to exit with exceptions

Interesting... I suppose it's not the strangest rule.

Perl 5 -p, 28 bytes
for$i(@h){s/$i//}push@h,/./g

Try it online!

Ruby, 52 bytes
->l{r="";l.map{|x|r.chars{|c|x[c]&&x[c]=''};r+=x;x}}

Try it online!

Charcoal, 18 bytes
ＥθΦι¬⊙…θκ‹№…ιμλ№νλ

Try it online! Link is to verbose version of code. Explanation:
 θ                  Input array
Ｅ                   Map over strings
   ι                Current string
  Φ                 Map over characters
       θ            Input array
      …             Truncated to length
        κ           Outer index
    ¬               Logical Not
     ⊙              Any element exists where
          №         Count of
              λ     Current letter in
            ι       Outermost word
           …        Truncated to
             μ      Current letter index
         ‹          Is less than
               №    Count of
                 λ  Current letter in
                ν   Innermost word
                    Implicitly print each day's bought letters on their own line

PHP, UTF-8 aware (253 bytes)
<?php $p=[];for($i=1;$i<$argc;$i++){$a=$p;$b=[];for($j=0;$j<mb_strlen($s=$argv[$i]);$j++){$k=1;if(isset($a[$c=mb_substr($s,$j,1)]))if($a[$c]){$k=0;$a[$c]--;}if($k){echo $c;if(isset($b[$c]))$b[$c]+=$k;else $b[$c]=$k;}}$p=array_merge($p,$b);echo PHP_EOL;}

Stax, 7 bytes
é█üa%┐┤

Run and debug it
Output is newline separated.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Generate a Pronounceable Nonsense Word \$n\$ syllables long
Your task is to generate a nonsense word that is reasonably pronounceable with the specified number of 'syllables'. Each time the program is run possibly results in a different nonsense word.
Pronounceability
A pronounceable word is made up of syllables, which are in turn made up of a vowel group that is possibly sandwiched between two consonant groups. Not all sounds are pronounceable in all positions, and since this depends on the language, we'll use patterns understandable to English speakers
Starting consonant groups:
b
c
d
f
g
h
j
k
l
m
n
p
r
s
t
v
w
y
z
bl
br
ch
cl
cr
dr
fl
fr
gh
gl
gn
gr
kn
ph
pl
pr
qu
sc
sh
sk
sl
sm
sn
sp
st
th
tr
wh
wr
sch
scr
shm
shr
squ
str
thr
Vowel Groups:
a
e
i
o
u
ae
ai
ao
au
ea
ee
ei
eu
ia
ie
io
oa
oe
oi
oo
ou
ue
ui
Ending Consonant groups:
b
c
d
f
g
l
m
n
p
r
s
t
x
z
bt
ch
ck
ct
ft
gh
gn
lb
ld
lf
lk
ll
lm
ln
lp
lt
mb
mn
mp
nk
ng
nt
ph
pt
rb
rc
rd
rf
rg
rk
rl
rm
rn
rp
rt
rv
rz
sh
sk
sp
ss
st
zz
lch
lsh
lth
rch
rsh
rst
rth
sch
tch
Combining Syllables
Both starting and ending consonant groups are optional in general, however you cannot place a syllable ending with a vowel immediately before one starting with a vowel.
Disclaimer
In the interest of simplicity, certain English words can't actually be generated this way, such as vacuum, xylophone, mnemonic, pterodactyl, beautiful, blah, they, wow, and most plurals.
Overview
Possible syllable patterns using this key:
(SC) = starting consonant; (V) = vowel group; (EC) = ending consonant
For one syllable:

(SC)(V)(EC)
(V)(EC)
(SC)(V)
(V)

With two syllables:

(SC)(V)(EC)(SC)(V)(EC)
(SC)(V)(EC)(SC)(V)
(SC)(V)(EC)(V)(EC)
(SC)(V)(EC)(V)
(SC)(V)(SC)(V)(EC)
(SC)(V)(SC)(V)
(V)(EC)(SC)(V)(EC)
(V)(EC)(SC)(V)
(V)(EC)(V)(EC)
(V)(EC)(V)
(V)(SC)(V)(EC)
(V)(SC)(V)

... and so on
Examples
1 syllable

charst
tigh
shriegn
eess
shue
oo
cheezz

2 syllables

jazzcrap
whylprog
eating
umba
ola
have
ingsoc
greespheurz
bleuspoo

3 syllables

brokiompic
squirdshlicker
capital
opengtrass
doublethink
bigbrother
phoebliaptmoo
skolfblauquent

4 syllables

strawishoepick
patchworkzombie
prearneajoomie
slephotoschou
doubleplusgood

Coding
Input: an integer for the number of syllables to generate
Output: a (probably) nonsense word that many syllables long
Rules

Some form of (psuedo)randomness is required. All combinations of syllables should be (theoretically) possible to generate, though the distribution does not have to be uniform.

You may assume that your generator is aperiodic, so it doesn't have to be mathematically possible to generate every possible word (It might not have a long enough period in reality) and you don't need to provide any sort of proof that your generator can, in fact, produce every possible word.
Your generator must actually be able to produce at least 255 distinct values, so you can't just return 4 every time the generator is called.
What's ultimately important is that you somehow include all the above letter groups in your code, that each letter group has a nonzero probability of being picked, and each syllable pattern has a nonzero probability of occurring (if provided with true randomness).

You must support up to 16 syllable words
In addition to the rules on combining syllables, the output word must not have:

3 consecutive vowels (a e i o u; this can happen for qu words)
3 consecutive matching consonants

Good luck!

Note that this is distinct from Generate a pronounceable word for a few reasons:

Variable number of syllables specified by input rather than a strict 10-letter requirement.
This challenge adds non-exhaustive letter groups that must be (cleverly) encoded and allows for more variants of syllables, so code can't just be copied from the other challenge
Squirdshlicker. Need I say more?

I also forgot to dupe check, but it turns out this brings enough new to the table that it doesn't matter. After all, there are hundreds of quine variant challenges.

"I also forgot to dupe check, but it turns out this brings enough new to the table that it doesn't matter." Did someone confirm this? I feel like this isn't always true...

Downvoted for the large amount of "hardcodedness" required given your 3 long lists of consonants and vowels

Suggest adding doubleplusgood as an example, to match the quality of this challenge.

Why not "squirdschlicker"?  Gotta beat "strengths" on consecutive consonants :)

JavaScript (ES6),  407  403 bytes
f=n=>/[aeiou]{3}|(.)\1\1/.test(s=(h=k=>k?(g=s=>p=s.match(/.[a-z]*/g)[Math.random()*99|0]||(s>x&&p?'':g(s)))(x+'lBrClCrDrFlFrGlGrHJKKnPlPrQuScScrShmShrSlSmSnSquStrThThrTrVWWhWrY')+g('AAeAiAoAuEEaEeEiEuIIaIeIoOOaOeOiOoOuUUeUi')+g(x+'tCkCtFtLbLchLdLfLkLlLmLnLpLshLtLthMbMnMpNgNkNtPtRbRcRchRdRfRgRkRlRmRnRpRshRstRtRthRvRzSsTchXZz')+h(k-1):'')(n,p=x='BCChDFGGhGnLMNPPhRSSchShSkSpStTZB').toLowerCase())?f(n):s

Try it online!

Are you sure the [^aeiou]{3} is correct? Based on the word 'matching' and the 3-syllable example squirdshlicker containing rdshl, I think OP only means 3 of the same adjacent consonants (i.e. bbb isn't allowed), instead of 3 adjacent consonants in general.

@KevinCruijssen On second reading of the challenge, I think there's little doubt that your interpretation is correct. So I've updated my code accordingly.

05AB1E, 237 234 230 228 bytes
.•O0¦"ÐD›ô:ΓF9—∊‘àÕGÌ•3LŽZв₂в×S£V[1U.µ\µTΩiY.•1θ₆Ω–¸‡ÊΔιÃмº³ô»ÝAïG3_@|å“₄bÒs₃l¬t©ïÙK:≠•3LŽII₂в×S£«Ω1U}XižM•·Áy&ŒGηΩ¼αŸKq•6вèJ•Λ1"•bS>£Ω¼0U}TΩiY.•E–æƵHl¨åñyBY±(ú,ā]JùË‚aEuŒ—[K³|C~ôÙŸ„#¼ÑûĀdš+¢zsÄΘä¹ÊÌ₅ôθ•3LŽAE₆в×S£«Ω1U}J}Dγ€g3‹P#

-2 byte thanks to @MagicOctopusUrn.
Try it online or get a few more outputs.
Explanation:
.•O0¦"ÐD›ô:ΓF9—∊‘àÕGÌ•
                  "# Push compressed string "bcdfglmnprstzchghgnphshskspstsch"
  3L               # Push list [1,2,3]
    ŽA;            # Push compressed integer 8997
       ₂в          # Converted to Base-26 as list: [13,8,1]
         ×         # Repeat the digits [1,2,3] that many times: ["1111111111111","22222222","3"]
          S        # Convert it to a list of flattened digits
           £       # Split the string into parts of that size
            V      # Pop and store this string-list in variable `Y`
[                  # Start an infinite loop:
 1U                #  Reset variable `X` to 1
 .µ                #  Reset the counter_variable to 0
 \                 #  Discard the top of the stack (if any)
 µ                 #  Loop while the counter_variable is not equal to the (implicit) input:
  TΩi              #   If a random boolean is truthy:
     Y             #    Push the string-list we stored in variable `Y`
     .•1θ₆Ω–¸‡ÊΔιÃмº³ô»ÝAïG3_@|å“₄bÒs₃l¬t©ïÙK:≠•
                   #    Push compressed string "hjkvwyblbrclcrdrflfrglgrknplprquscslsmsnthtrwhwrscrshmshrsqustrthr"
       3L          #    Push list [1,2,3]
         ŽII       #    Push compressed integer 4608
            ₂в     #    Converted to Base-26 as list: [6,21,6]
              ×    #    Repeat the digits [1,2,3] that many times: ["111111","222222222222222222222","333333"]
               S   #    Convert it to a list of flattened digits
                £  #    Split the string into parts of that size
     «             #    Merge it with list `Y`
      Ω            #    Pop and push a random starting consonant group from this list
     1U            #    And set variable `X` to 1
    }              #   Close the if-statement
  Xi               #   If variable `X` is 1:
    žM             #    Push builtin string "aeiou"
      •·Áy&ŒGηΩ¼αŸKq•
                   #    Push compressed integer 13814931869773709280202935082102
        6в         #    Converted to Base-6 as list: [1,0,1,1,1,2,1,4,0,1,0,2,0,3,0,4,2,0,2,1,2,3,3,0,3,1,3,2,3,3,3,4,4,1,4,2,0,1,2,3,4]
          èJ       #    Index each into the string "aeiou", and join together: "aeaiaoaueaeeeieuiaieiooaoeoiooouueuiaeiou"
      •Λ1"•       "#    Push compressed integer 8388576
           b       #    Converted to binary: "11111111111111111100000"
            S>     #    Split into a list of digits, and each increased by 1
              £    #    Split the string into parts of that size
               Ω   #    Pop and push a random vowel group from this list
    ¼              #    Increase the counter_variable by 1
    0U             #    And then set variable `X` to 0
   }               #   Close the if-statement
  TΩi              #   If a random boolean is truthy:
     Y             #    Push the string-list we stored in variable `Y`
     .•E–æƵHl¨åñyBY±(ú,ā]JùË‚aEuŒ—[K³|C~ôÙŸ„#¼ÑûĀdš+¢zsÄΘä¹ÊÌ₅ôθ•
                   #    Push compressed string "xbtckctftlbldlflklllmlnlpltmbmnmpnkngntptrbrcrdrfrgrkrlrmrnrprtrvrzsszzlchlshlthrchrshrstrthtch"
       3L          #    Push list [1,2,3]
         ŽAE       #    Push compressed integer 2564
            ₆в     #    Converted to Base-36 as list: [1,35,8]
              ×    #    Repeat the digits [1,2,3] that many times: ["1","222...222","33333333"]
               S   #    Convert it to a list of flattened digits
                £  #    Split the string into parts of that size
     «             #    Merge it with list `Y`
      Ω            #    Pop and push a random ending consonant group from this list
     1U            #    And set variable `X` to 1
    }              #   Close the if-statement
  J                #   Join all strings on the stack together
 }D                #  After the while-loop: duplicate the resulting string
   γ               #  Split the copy into chunks, with adjacent characters that are
                   #  the same grouped together
    €g             #  Get the length of each chunk
      3‹           #  Check for each length if it's smaller than 3
        P          #  Check if all are truthy by taking the product, and if it is:
         #         #   Stop the infinite loop
                   # (after which the string at the top of the stack is output implicitly)

See this 05AB1E tip of mine (section How to compress strings not part of the dictionary?, How to compress large integers?, and How to compress integer lists?) to understand how the compression parts works.

Also žM•ô#‰¦λu¢!¡°gU€•6BS<èJ is 4 smaller than .•!m1±P1Ÿ6ºZ dâ4∍m–G¢”ãÔ2g• (base 6 conversion and replacement using built-in for AEIOU). TIO Link too long.

@MagicOctopusUrn Thanks! And saved 2 more bytes with žM•·Áy&ŒGηΩ¼αŸKq•6вèJ. :) PS: You can use url shorteners like https://tinyurl.com/ on PPCG, unlike most other SE's. :)

Jelly, 231 bytes
e€ØẹŒrḢƇ,ŒɠF>2Ẹ
“yŒʠT¬ḅɼṬɦṀUżGv¶æɲCĊQ>ṙȦẇɼṄ0IḤhDẋDċṀĊṪɗĖƇẊ;1JƒṾỊżỵhṖ8>Ȯ⁶]¦Qṭ|Ṛṇẹm⁵ØKƈBNɦÇȯ¢ṣḟPṇMʠ¬YėĊÇẒỊĿXJÑḷÞeȮȮɼ$ỴœeṂṠɲẓḊ⁺ċŻ⁽⁶Ẓ⁹<>#nẇṬ⁴\¤ÐṡḞF5ƙẇwḶȤYḍ¡¢~ṚⱮ-ṃƲ⁻Ṙ6ɱṬ?İẆḌỊþEØ»Ḳµe€ØẹIkḣ3)Z;€“squ“qu”$1¦
“Ø¦µ£‘ḃ3$Xµ³Ð¡ḊFµ⁺wØ2$¿ịÇX€Fß¹Ñ?

Try it online!
A full program that takes a single argument, the number of syllables required.
Explanation
The core of this is a 66-word compressed dictionary string. If the words are split into groups of consonants and vowels and the first 3 groups taken for each word, they generate the desired starting, vowel and end groups from the question. The exceptions are qu and squ because they have a vowel in, so these are added manually. The word list was built algorithmically from the Jelly dictionary using a Python script. Note some letter groups are repeated, but the question allows the outputs to not uniformly represent each possible combination. If this were preferred, it would be straightforward to make each group unique at the cost of two bytes (Q€).

Helper link 1: check whether more than 3 vowels in a row or more than 3 of the same letter in a row

                | Sample input: branggag
e€Øẹ            | For each letter, is it a vowel? [0, 0, 1, 0, 0, 0, 1, 0]
    Œr          | Run-length encode [[0, 2], [1, 1], [0, 3], [1, 1], [0, 1]]
      ḢƇ        | Filter only those with true first value, popping first value [[1], [1]]
        ,       | Pair with
         Œɠ     | Run lengths of input [[[1], [1]], [1, 1, 1, 1, 2, 1, 1]
           F    | Flatten [1, 1, 1, 1, 1, 1, 2, 1, 1]
            >2  | Greater than 2 [0, 0, 0, 0, 0, 0, 0, 0, 0]
              Ẹ | Any 0

Helper link 2: The three groups of strings

“yŒʠ...þEØ»                          | Compressed string: shmooze gaolbird hailshot shriech waeful furze ghaut cruelness stealthier gneiss shoeshine wheelchair wring build priorship knosp spoilfive karst through coalpit teschenite schoolkid theurgic zabtieh skiamachies yirth snazzier slimnastics scripted smirch droskies strift blepharism chaulmoogra glegness scarf fratch clerk brank jarvey flourless vorpal grex nard plumb larn philter sorbo tractabilities parcel mart damp rearm back bast bag bant baba boll bad bap becap basal ban bail bare
           Ḳ                         | Split at spaces
            µ        )               | For each word: e.g. hailshot
             e€Øẹ                    |   Check whether each character is a vowel [0, 1, 1, 0, 0, 0, 1, 0]
                 I                   | Increments of this [1, 0, -1, 0, 0, 1, -1]
                  k                  |   Split word at truthy values of this [h, ai, lsh, o, t]
                   ḣ3                |   Take the first three [h, ai, lsh]
                      Z              | Transpose (so now have three lists, start consonants, vowels, end consonants)
                        €        $1¦ | For the first group
                       ; “squ“qu”    | Append squ and qu

Main link

          µ³Ð¡                     | Repeat the following the input number of times, collecting results:
“Ø¦µ£‘                             |   18, 5, 9, 2
      ḃ3$                          |   bijective base 3: [1,2,3],[1,2],[2,3],[2]
         X                         |   Take one at random
              Ḋ                    | Remove first item (which will be the input to the link because if the way Ð¡ works
               F                   | Flatten; we now have e.g. [1,2,3,2,3,1,2,3,2]. This corresponds to SC V EC V EC AC V EC V
                µ⁺    ¿            | Do everything so far once and then repeat while:
                  wØ2$             |   The output contains two twos (i.e. vowel-vowel)
                       ịÇ          | Look these up in the previous link, so we now have a group of letter groups for each position
                         X€F       | Pick a random letter group for each position
                            ß¹Ñ?   | If helper link 1 is true, retry the whole of this link again. Otherwise implicitly output

Curious to see the explanation, but are you sure it's correct? I get an output gnuignaalfbi for input 4, but aa shouldn't be possible if I understood the challenge correctly. The section combining syllables states "..., however you cannot place a syllable ending with a vowel immediately before one starting with a vowel."

@KevinCruijssen missed that. Should now meet that requirement too. Thanks for pointing out

Nice answer, I like the dictionary strings you've used to make all the groups. Although I'm not sure why Jelly's dictionary contains words like shmooze gaolbird hailshot shriech waeful furze ghaut, haha. xD How large is Jelly's dictionary anyway?

@KevinCruijssen Large. There are 20453 words of less than 6 letters and 227845 large words.

Python 2, 522 510 bytes
from random import*
import re
c=choice
S,V,E=[map(str.lower,re.findall('[A-Z][a-z]*',x))for x in'BCDFGHJKLMNPRSTVWYZBlBrChClCrDrFlFrGhGlGnGrKnPhPlPrQuScShSkSlSmSnSpStThTrWhWrSchScrShmShrSquStrThr','AeAiAoAuEaEeEiEuIaIeIoOaOeOiOoOuUeUiAEIOU','BCDFGLMNPRSTXZBtChCkCtFtGhGnLbLdLfLkLlLmLnLpLtMbMnMpNkNgNtPhPtRbRcRdRfRgRkRlRmRnRpRtRvRzShSkSpSsStZzLchLshLthRchRshRstRthSchTch']
def f(n):w=c(['',c(S)]);exec"e=c(E);w+=c(V)[-(w[-1:]in V):]+c([c(S),e,e+c([x for x in S if x[0]*2!=e])])*(n>1);n-=1;"*n;return w+c(['',e])

Try it online!

Pyth, 346 335 bytes
McG.u+NYr9,VHSlH1smjOgs@L"eaiou"jC" ¤EÌ½]¢¨¦l#"5,4 17*Vd,Og"bcdfghjklmnprstvwyzblbrchclcrdrflfrghglgngrknphplprquscshskslsmsnspstthtrwhwrschscrshmshrsqustrthr"[18 29 6)Og"bcdfglmnprstxzbtchckctftghgnlbldlflklllmlnlpltmbmnmpnkngntphptrbrcrdrfrgrkrlrmrnrprtrvrzshskspssstzzlchlshlthrchrshrstrthschtch"[13 43 8)tuaGO<W!eeG^,1Z2 2Q]1

Try it online here.

Ruby, 381 379 375 bytes
Uses messy regex matches to get the consonant groups. Could probably be optimized.
->n,w=?a..s='zzz',a=[1]{s=(1..n).map{a=[w.grep(/^([^aeiouq]|[bcfgp][lr]|s?ch|dr|gn|kn|ph|s?qu|s[ct]r?|sh[mr]?|th?r?|s[klmnp]|wh|wr|gh)$/)+(a[-1]?[p]:[]),w.grep(/^[aeiou]{,2}$/),w.grep(/^([^aeiouqhjkvwy]|[bcflnprs]t|ck|gh|gn|l[bdfk-np]|m[bnp]|nk|ng|ph|r[bcdfgk-npvz]|[lr]?[stc]h|s[kps]|zz|rst|[st]ch)$/)<<p].map(&:sample)}*''while s=~/[aeiou]{3}|(.)\1\1|aa|eo|ii|iu|u[aou]/;s}

Try it online!

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Map values to any multidimensional array
Codegolf challenge - mapping values in a multidimensional array
[
  [0, 0, 0],
  [0, 0, 0],
  [0, 0, 0]
]

This 2D array is sick of being so false, and wants to find the truth about life, once and for all. Your task is to write a map function to act as a highway to all the values in this array.
An example implementation of this super function would be if the above array is defined as arr below:
arr.multimap(x => {
  return 1;
}

Which would result in the array being:
[
  [1, 1, 1],
  [1, 1, 1],
  [1, 1, 1]
]

This is a 2D number example, yours has to work in any dimension, and not be dimensionally-bias.

The rules

Must work in any type of dimensional array (1D, 2D, 3D, etc..)
Least bytes, wins!
Must only have one callback function which accounts for any level of dimensional interaction
Meta-languages get fewer points
Can simply be a function which applies the logic to an array given
Can be any arbitrary initial value, as long as you can replace it on-command

Comments are not for extended discussion. This conversation has been moved to chat.

JavaScript (Node.js), 35 27 17 bytes
-18 thanks to @Arnauld and @Shaggy

f=a=>a?a.map(f):1

console.log(f([
  [0, 0, 0],
  [0, [0, 0, 0], 0],
  [[0, 0, [0]], 0, 0]
]))

@Arnauld lol, you are right. Thanks!

21 bytes

@Arnauld: Or 17 bytes

@Shaggy Yup, but it's still unclear if the initial values are guaranteed to be falsy (see the last rule).

Jelly, 1 byte
‘

Try it online!
Replaces n with n + 1.
Because Jelly things.
Note that [x] displays as x in Jelly (single-element lists don't show as lists); the internal data is still a single-element list. You can make it show using Python's str: Try it online!.

Python 2, 29 26 25 bytes
-3 bytes thanks to @JonathanAllan
-1 byte thanks to @JoKing
f=lambda a:a<1or map(f,a)

Replaces 0 with True
Try it online!

Python 2, 26

@Neil the f= is necessary for a recursive function.

<[] can be <1

Perl 6, 4 bytes
!<<*

Try it online!
Replaces 0s with True. Extremely short for a non-esolang.
   *  # From the input
!     # Boolean not
 <<   # Each element recursively

Japt, 6 bytes
?¡ßX:1

Try it
¬Íª¡ßX

Try it

JavaScript, 36 bytes
t=>JSON.stringify(t).replace(/0/g,1)

Try it online!