Draw an ASCIIrisk

Python 3, 110 bytes

s='%c';print(('\n'.join(['%10c%c']*9+[s*21]*2+[' '*(8-i)+s*2+'  '*i+s*2for i in range(9)]))%(*range(32,128),))

Generates the template

         xx
         xx
         xx
         xx
         xx
         xx
         xx
         xx
         xx
xxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxx
        xxxx
       xx  xx
      xx    xx
     xx      xx
    xx        xx
   xx          xx
  xx            xx
 xx              xx
xx                xx

with %c for x, then uses string interpolation on range(32,128) to insert the ASCII values into the pattern.

Try it online!

Python 2 is one byte longer, with longer tuple unpacking but shorter print.

s='%c';print('\n'.join(['%10c%c']*9+[s*21]*2+[' '*(8-i)+s*2+'  '*i+s*2for i in range(9)]))%tuple(range(32,128))

V, 54, 50 bytes

¬ ~9ñ9É 11|á
ñ2ñ20lá
ñ$18é 9ñ^y|Ehé
Pf xxywk$hP>ñd

Try it online!

Unlike usual, this program does not contain any unprintable characters.

Explanation:

¬ ~                     " Insert the entire printable ASCII range
   9ñ           ñ       " 9 times:
     9É                 "   Insert 9 spaces at the beginning of this line
        11|             "   Move to the 11'th column on this line
           á<CR>        "   And append a newline after the 11'th column

Now the buffer looks like this:

          !
         "#
         $%
         &'
         ()
         *+
         ,-
         ./
         01
23456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

Now we build up the middle:

2ñ        ñ             " Two times:
  20l                   "   Move 20 characters to the right (because 'l' == 'right', duh)
     á<CR>              "   Append a newline

Here's where it gets a little weird.

$                       " Move to the end of this line 
 18é                    " Insert 18 spaces before the last character
     9ñ                 " Repeat the following 9 times:
       ^                "   Move to the first non-whitespace character
        y|              "   Yank all the whitespace before the current character. 
                        "   We'll call this the "Leading whitespace register"
          E             "   Move to the end of the current WORD (up to before a space)
           h            "   Move back one character
            é<CR>       "   And insert a newline before the current character
P                       "   Paste the leading whitespace for indentation
 f                      "   Move forward to a space
   xx                   "   Delete two characters
                        "   (Note how we are inbetween the two bottom branches right now)
     yw                 "   Yank everything upto the next branch (all spaces)
                        "   We'll paste this on the line up so that we can yank it again later
                        "   To keep track of how far apart the branches are
       k$               "   Move up a line and to the end of that line
         hP             "   Move back a character and paste the whitespace we yanked
           >            "   Indent this line by one space
            ñ           "   End the loop

Here's an important note. The > command is actually an operator, which means it doesn't do anything without an argument, the text to operate on. For example,

>_      "Indent the current line
>>      "Indent the current line
>j      "Indent the current and next line
>G      "Indent every line

But since this command is in a loop, we can save a character by not giving an operator. At the end of a loop, if any operator is pending it will fill in _ (the current line) as an argument implicitly.

Now I'll admit this loop is a little weird, and it can be hard to keep track of what all text should look like at any given moment. So you can use this simpler program to see what it will look like after N loops.

If you set it to 9, you can see that we have a little bit of extra text to get rid of. (Just the current line).

So we delete the current line with dd. But wait! You know how I said that operators have to take an argument which is sometime implicitly filled in? Arguments are also implicitly filled at the end of the program. So rather than dd or d_ (which are equivalent), we can simply to d and let V fill in the _ for us.


05AB1E, 40 38 37 36 35 bytes

žQ2ô376S3*£`2ôvyN·ð×ýð«}rsJ2äsr)˜.c

Try it online!

Explanation

žQ                                   # push the printable ascii chars
  2ô                                 # split into pairs
    376S                             # split the number 376 into a list of digits
        3*                           # multiply each by 3 to get [9,21,18]
          £                          # divide the pairs of ascii chars into 
                                     # pieces of these sizes
           `                         # flatten list to stack
            2ô                       # split the "legs" of the asterisk into pairs of pairs
              v                      # loop over the pairs of pairs
               yN·ð×ý                # join the pairs by index*2 spaces
                     ð«              # append a space
                       }             # end loop
                        rs           # move the middle section to top of stack
                          J2ä        # convert to a string split into 2 pieces
                             sr      # rearrange the stack in the correct order
                               )˜    # wrap in a flattened list
                                 .c  # pad each element with spaces on either side