[Question]
  [
## Challenge
Given a string of any length, write it as a triangle, spiraling out from the center. For example, `abcdefghijklmnop` becomes:
```
   g  
  fah
 edcbi
ponmlkj
```
Or more explicitly:
[![enter image description here](https://i.stack.imgur.com/NyzLX.png)](https://i.stack.imgur.com/NyzLX.png)
If you like, you can spiral counter-clockwise instead:
```
   g  
  haf
 ibcde
jklmnop
```
Or add spaces uniformly:
```
      g   
    f a h 
  e d c b i  
p o n m l k j 
```
The input characters will be ascii, but may include spaces. Also, the number of characters may not be a perfect square (`Hello World!`):
```
  W
  Ho
oller
   !dl
```
A couple more edge cases. 2 letter input `ab`:
```
 a
  b
```
And 3 letter input `abc`:
```
 a
 cb
```
## Procedural Description
In case the above examples aren't clear, here's a procedural description of the process:
1. Put down your initial letter.
2. Move diagonally down and to the right (i.e., this direction `\`). So if you started at `(0,0)`, you will now be at (1,-1). Put down your second letter.
3. Move left one space a time, dropping a letter on each space, for a total of 3 spaces. That is, drop letters on `(0,-1)`, `(-1,-1)`, and `(-2, -1)`.
4. Next move diagonally up and to the right `/` two spaces, dropping letters on `(-1,0)` and `(0,1)`.
5. Now cycle back to moving diagonally down and to the right, continuing to step and drop letters as long as your current position is left-right adjacent to an existing letter.
6. Next move left again, continuing to step and drop letters as long as you are diagonally adjacent `/` to an existing letter.
7. Move diagonally up and to the right again `/`, stepping and dropping letters as long as your current position is left-right adjacent to an existing letter.
8. Repeat steps 5-7 until all letters are used up.
## More examples
## Rules
* Code golf, standard rules apply.
* Trailing spaces or newlines are ok.
* Consistent leading spaces or newlines are also ok, as long as the shape of the triangle is preserved.
  
[Answer]
# [Wolfram Language (Mathematica)](https://www.wolfram.com/wolframscript/), 99 bytes
```
sPrint@@@Array[s[[4# #-2#+1-#2&@@If[Abs@#2<2#,!##,#-Abs@#2|-#2]]]/._@__->" "&,2{L=Tr[1^s],L},-L]
```
[Try it online!](https://tio.run/##JY1BTsMwEEX3OUXqkbLBBtViSdFUCESlLECtxMIy0cR1mkASV7a7QKU9BDfghBwhTenmfT29xe8o1raj2BgaqtkQ/n5@X3zTR0Sce09fKih1CykICVdTATJDXFRqXgYEeSeBTwA4iIt/j11rfXNdYFGIe5ayjMt9Plt5NX0PmucHLnI9vO4aG7HCh5o8mWh9wEdTOwWcMb5yyzj@b0Zb9NtdfHK@05nOjktD/XGfMCrN2labuvn4bLvebRlP2LNtW5e@Od@uJ2enf5QXmvOw5DCcAA "Wolfram Language (Mathematica) – Try It Online")
Directly computes the index of each position: in Cartesian coordinates,
\$\operatorname{index}(x,y)=\textit{offset}+\begin{cases}2y(2y+1)-x,&|x|<-2y\\
2\left(y+|x|\right)\left(2\left(y+|x|\right)+1\right)+x,&\text{else}\end{cases}\$
where \$\textit{offset}\$ is the index of the "first" character (1, in Mathematica).
Takes a list of characters as input.
---
### Older approach, ~~123~~ ~~122~~ ~~109~~ 107 bytes
```
Print@@@Normal@SparseArray[i=0;p=2Length@#;(p+=ReIm[I[2+I,1-I][[⌈2√i++⌉~Mod~4-1]]-1])->#&/@#,2p," "]&
```
[Try it online!](https://tio.run/##JY7NSsQwGEX3fYoxhaI0Rae4GyoRUQyoyFRwEbL4Jk2bav7IxIWIXc/APIGP1xepHV3cczm7YyAqaSD2Aqa2mp5DbyMh5MkFA5rUHsJWXocAn6yvLla@Kh@k7aIi6erU59VaUsMoK3OKlwXljI2HXTnufvo8Hw/74dE1w2Wx5HzeWXGVZuckxaXHaIF4NrXkRkEAEWXYkluhHEsxQvjF1XGu6Gaj1n/EuzmFZzwbagF2@EoQbEQj2071b@/aWOcRTtC91NotXl3QzcnR4Q@bf4rjoeR7@gU "Wolfram Language (Mathematica) – Try It Online")
The direction of the (1-indexed) `i`th character relative to the previous character can be computed with \$\Big\lceil2\sqrt i\Big\rceil\bmod 4\$:
* 1: ↗
* 2: ↘
* 3,0: ←
[Answer]
# [Charcoal](https://github.com/somebody1234/Charcoal), ~~37~~ ~~36~~ 21 bytes
```
ＧＨ✳✳Ｅ⊖ＬθＩ§4174⌈⊗₂⊕ι²θ
```
[Attempt This Online!](https://ato.pxeger.com/run?1=RY7NCoJAFIVfRVxdQReFUNAqcpFQELWMFuN41alxrs6M_Wx7jTYuinqAXqa3SUjoLA_f-Ti3Fy-Y5sRk2z4amwXjz3VF8pKTmpOUdIJIaORWkDKwZBVEyDWWqCymsECV2wJqz_OdGTMWpjZWKZ7BDQej0O1KFFKoHCJqEtkNNnXDNK6JLMTq7xFeH98Z-k7tTe4m4ab_89y6wVG6uzdLeIpZXoj9QZaKqlob-0O- "Charcoal – Attempt This Online") Link is to verbose version of code. Explanation: Inspired by @KevinCruijssen's 05AB1E solution, but then using @att's formula to generate the directions.
```
       θ                Input string
      Ｌ                 Length
     ⊖                  Decremented
    Ｅ                   Map over implicit range
                  ι     Current index (0-indexed)
                 ⊕      Incremented (i.e. 1-indexed)
                ₂       Square rooted
               ⊗        Doubled
              ⌈         Ceiling
         §4174          Cyclically index to find direction
        Ｉ               Cast to integer
  ✳✳                    Convert to directions
ＧＨ                 ²θ   Draw path using input string
```
The path drawing command draws one character for the start and then `n-1` characters for each direction in the array. Unfortunately there aren't any single character strings that represent diagonal directions so I have to use integers instead; these start at `0` for right and increment for each 45° clockwise.
Previous 37 byte solution:
```
≔⮌⪪Ｓ¹θＦＬθＦ³Ｆ§⟦⊕⊗ι⁺³×⁴ι⊗⊕ι⟧κ¿θ✳⁻⁷×³κ⊟θ
```
[Try it online!](https://tio.run/##TU6xrsIwDNz5ioyOVAbUJ72BCYmlEkgI3vbEUFK3NU2dNnERfx/SCiQWn3w@351pS29caWPchUANwxkf6APCZbAkUPAwyUU8cQM6Uxudxqi3q9p5BQfkRloYtVbLnr9xJwVX@IT/go3HHlmwgr2bbjYhzRYnOwXIM/VHPQb4ydTCfiTfb@lwzVSXIqhWKUqdUheBPXk0Qo7hSJy8fj9e@SKeI9wwN9vGWN5MhXXT0r2zPbth9EFWcf2wLw "Charcoal – Try It Online") Link is to verbose version of code. Explanation:
```
≔⮌⪪Ｓ¹θ
```
Split the input into characters and reverse the list.
```
ＦＬθ
```
Loop a large enough number of times.
```
Ｆ³
```
Loop for each side of the triangle.
```
Ｆ§⟦⊕⊗ι⁺³×⁴ι⊗⊕ι⟧κ
```
Loop for the size of the side.
```
¿θ
```
Check whether there is still anything left to print.
```
✳⁻⁷×³κ⊟θ
```
Print the next character in the appropriate direction.
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E/wiki/Commands), ~~24~~ ~~20~~ ~~15~~ 13 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage)
```
2Iā¨t·îŽOGsèΛ
```
-7 bytes by porting [*@Neil*'s Charcoal answer](https://codegolf.stackexchange.com/a/210459/52210), using [*@att*'s formula](https://codegolf.stackexchange.com/a/210464/52210), so make sure to upvote both of them as well!
[Try it online.](https://tio.run/##ASoA1f9vc2FiaWX//zJJxIHCqHTCt8Ouxb1PR3PDqM6b//9IZWxsbyBXb3JsZCE) No test suite, because the `.Λ` builtin will keep its previous contents and there isn't any way to reset it ([this is what it would look like](https://tio.run/##yy9OTMpM/V@m5JlXUFpipaBkX6nDpeRfWgLh6VT@Nyo@0nhoRcmh7YfXHd3r7158eIXeudn/df5HKyUmJaekpqVnZGZl5@Tm5Rco6Sh5pObk5CuE5xflpCgCuYlJYCJZKRYA).
**Explanation:**
```
2              # Push a 2
 I             # Push the input-string
  ā            # Push a list in the range [1,length] (without popping)
   ¨           # Remove the last value to change the range to [1,length)
    t          # Take the square-root of each value
     ·         # Double each
      î        # Ceil each
       ŽOG     # Push compressed integer 6136
          s    # Swap so the list is at the top of the stack again
           è   # Index each value (0-based and modulair) into the 6136
            Λ  # Pop all three and use the Canvas builtin,
               # after which the result is implicitly output immediately afterwards
```
[See this 05AB1E tip of mine (section *How to compress large integers?*)](https://codegolf.stackexchange.com/a/166851/52210) to understand why `ŽOG` is `6136`.
The Canvas builtin uses three arguments to draw a shape:
* Character/string to draw: the input in this case
* Length of the lines we'll draw: `2` in this case
* The direction to draw in: `[3,6,6,6,1,1,3,3,3,6,6,6,6,6,6,6,1,1,1,1,3,...]`.
See the original answer below for an explanation of the Canvas builtin. Unlike the program below where the list of lengths are leading, here the list of directions are leading because we use a single length of `2`.
---
**Original ~~24~~ 20 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage) answer:**
```
ā·Ð·s>ø.ι˜DŠOð×«₆1ªΛ
```
Contains leading/trailing spaces and newlines (the longer the input, the more spaces/newlines)
[Try it online.](https://tio.run/##ATkAxv9vc2FiaWX//8SBwrfDkMK3cz7DuC7OucucRMWgT8Oww5fCq@KChjHCqs6b//9IZWxsbyBXb3JsZCE) No test suite, because the `.Λ` builtin will keep its previous contents and there isn't any way to reset it ([this is what it would look like](https://tio.run/##yy9OTMpM/V@m5JlXUFpipaBkX6nDpeRfWgLh6VT@P9J4aPvhCYe2F9sd3qF3bufpOS5HF/gf3nB4@qHVj5raDA@t0js3@7/O/2ilxKTklNS09IzMrOyc3Lz8AiUdJY/UnJx8hfD8opwURSA3MQlMJCvFAgA), where the test cases are drawn on top of one another).
**Explanation:**
```
ā           # Push a list in the range [1, length] of the (implicit) input (without popping)
            #  i.e. "Hello World!" → "Hello World!" and [1,2,3,4,5,6,7,8,9,10,11,12]
 ·          # Double each value in this list
            #  → [2,4,6,8,10,12,14,16,18,20,22,24]
  Ð         # Triplicate it
   ·        # Double each value of the top copy
            #  → [4,8,12,16,20,24,28,32,36,40,44,48]
    s       # Swap to get the other copy
     >      # Increase each by 1
            #  → [3,5,6,9,11,13,15,17,19,21,23,25]
      ø     # Create pairs of the top two lists
            #  → [[4,3],[8,5],[12,7],[16,9],[20,11],[24,13],[28,15],[32,17],[36,19],[40,21],[44,23],[48,25]]
       .ι   # Interleave it with the third list
            #  → [2,[4,3],4,[8,5],6,[12,7],8,[16,9],10,[20,11],12,[24,13],14,[28,15],16,[32,17],18,[36,19],20,[40,21],22,[44,23],24,[48,25]]
         ˜  # Flatten
            #  → [2,4,3,4,8,5,6,12,7,8,16,9,10,20,11,12,24,13,14,28,15,16,32,17,18,36,19,20,40,21,22,44,23,24,48,25]
D           # Duplicate this list of integers
 Š          # Triple-swap, so the stack order is list,input,list
  O         # Pop and sum the top list
            #  → 636
   ð×       # Create a string of that many spaces
     «      # And append it to the string
₆           # Push builtin 36
 1ª         # Convert it to a list of digits, and append 1: [3,6,1]
Λ           # Use the Canvas builtin with these three arguments,
            # after which the result is implicitly output immediately afterwards
```
The Canvas builtin uses three arguments to draw a shape:
* Character/string to draw: the input in this case, appended with trailing spaces
* Length of the lines we'll draw: the list `[2,4,3,4,8,5,6,12,7,8,16,9,10,20,11,...]`
* The direction to draw in: `[3,6,1]`. The digits in the range \$[0,7]\$ each represent a certain direction:
```
7   0   1
  ↖ ↑ ↗
6 ← X → 2
  ↙ ↓ ↘
5   4   3
```
So the `[3,6,1]` in this case translate to the directions \$[↘,←,↗]\$.
Here a step-by-step explanation of the output (we'll use input `"Hello_World!"` as example here):
Step 1: Draw 2 characters (`"He"`) in direction `3↘`:
```
H
 e
```
Step 2: Draw 4-1 characters (`"llo"`) in direction `6←`:
```
  H
olle
```
Step 3: Draw 3-1 characters (`"_W"`) in direction `1↗`:
```
  W
 _H
olle
```
Step 4: Draw 4-1 characters (`"orl"`) in direction `3↘`:
```
  W
 _Ho
oller
     l
```
Step 5: Draw 8-1 characters (`"d! "`) in direction `6←`:
```
   W
  _Ho
 oller
    !dl
```
Et cetera for all other trailing spaces.
[See this 05AB1E tip of mine for an in-depth explanation of the Canvas builtin.](https://codegolf.stackexchange.com/a/175520/52210)
[Answer]
# [JavaScript (V8)](https://v8.dev/), 222 bytes
```
s=>(g=(a,b,n=1)=>b?g([(c=(b+' '.repeat(n*8)).slice(0,n*8))[n*6-1],...[...a,c.slice(0,n*4-1)].map((l,i)=>c[n*6+i]+l+c[n*6-2-i])],b.slice(n*8),n+1):a)([s[0]],s.slice(1)).reduce((p,l,i,a)=>p+' '.repeat(a.length-i-1)+l+`
`,'')
```
[Try it online!](https://tio.run/##XY5Zb8IwEITf@RX0yWtiW6SqKlQpVL3pfZe2kSWcxART47hOSI8/nxqEKsTDSjOa3W92KmpRpk7Zita9Zhw1ZdSHPAJBEmKiEEf9ZD@HGNIIkgC1EXPSSlGB6fQwZqVWqYQuWbrYdHZpyAljLPYjSLqW79AQczYTFkAT5bHpYj1QPNDBUtJtqjjmJFkdLZDEBCHeExjiMu5yTspVFvpqJ7O5l2CJ5xHhiXb9P8G0NHk1ocoX@45Ra0QQwo11ylQwBjSQWhftYeF0toUwbv0HIkkzOc4navqhZ6awn66s5vXX98/vweHR8cnp2eD84vLq@ub27v7h8en5Zfj69r4B2OR53/wB "JavaScript (V8) – Try It Online")
It most definitely can be golfed more.  
I use a recursive algorithm, splitting the output into triangle 'layers', where each layer is a complete wrap (three sides) of the previous triangle.
Ungolfed
```
s=>(g=(a,b,n=1)=> // g is a recursive function; a: previous; b: rest; n: increment
  b ? // if there is more string to wrap
    g([ // wrap b around a as a triangle and recurse
        (c=(b+' '.repeat(n*8)).slice(0,n*8))[n*6-1],
        ...[...a,c.slice(0,n*4-1)].map((l,i)=>c[n*6+i]+l+c[n*6-2-i])
      ],
      b.slice(n*8),
      n+1)
  :a // otherwise return the triangle
  )
  ([s[0]],s.slice(1)) // run the function with the first letter and the rest
  .reduce((p,l,i,a)=>p+' '.repeat(a.length-i-1)+l+'\n','') // step the triangle to make it look like it is meant to
```
[Answer]
# JavaScript (ES8), 137 bytes
Expects an array of characters. Returns a string.
This version is based on [the formula used by @att](https://codegolf.stackexchange.com/a/210464/58563), modified to be more golf-friendly in JS.
```
a=>a.map((c,n)=>(m[y+=~(d=2*n**.5-1/n)%4%3?d&++x/x||-1:!x--]=m[y]||[...''.padEnd(x)])[x]=c,m=[],x=y=a.length)&&m.map(r=>r.join``).join`
`
```
[Try it online!](https://tio.run/##bY7LTsMwFET3@Qo3UlM7D1flsaFyWFXiD1hElmJs54VjBycUBwK/HgxlyWZmdO6VZjp2ZiO37TBl2gi5VmRlJGe4ZwOEPNWI5LAv5oR8QUGuYh3H@DY77DXa3myv70WUJG7vliU73G1cllHif@myFBjj3Q4PTJy0gA5RVDhKeNqTgqaOzIRhJXU9NSiK@t8uS3KLO9PqskQXD8r1WAQAhA9SKQMejVViE6YgZE8X5X8mZFU3bfesem2G/9iLHafX85ub38OABrgy9sR4A0dAcvDhG6z0EVTwZ/VI0dEjbvRolMTK1NCfPftE6zc "JavaScript (Node.js) – Try It Online") (raw output)
[Try it online!](https://tio.run/##bY9NU4MwEEDv/IqUsSXhI1i1FzvBU2e8ePHiAZghQoDWkGDAmlrwr2O0nZ687O683dm3u6N72uVq2/aBkAWbSjJRElHc0BbC3BeIRLCJDx75hgW5cYXr4lWwDAWa381vH4qF5@lQD0OwvJ/pIEiJmU2HIcYYOw5uabERBdQoRbFOSe43JE59TQ6EYs5E1ddosWj@XIpECu/kVmQZOmUrm9axBYD9yDiX4EUqXsxsH9j09RTzcypYWdXb3RtvhGz/Y@@q6z/2n/rwZVuphUupNjSvYQdIBI7GoJgpQQl/r@5StDYol6KTnGEuK2jaWLGW05zBMBFeWBlHImx0oc@s2ugWZkkiwPHq2J2fAwF4on2NSy6lghfquuAar9A4Zj5wKgedtxnviKYf "JavaScript (Node.js) – Try It Online") (with extra whitespace removed)
### How?
Given the position \$n\$ of the character, the direction \$0\le d\le 2\$ can be computed with:
$$d=\left(\left\lfloor2\sqrt{n}+1-\frac{1}{n}\right\rfloor\bmod 4\right)\bmod 3$$
The actual JS implementation is:
```
~(2 * n ** 0.5 - 1 / n) % 4 % 3
```
which evaluates to \$0\$, \$-1\$ or \$-2\$.
---
# JavaScript (ES8), ~~163~~ 157 bytes
Expects an array of characters. Returns a string.
```
a=>a.map(c=>((m[y]=m[y]||[...''.padEnd(x)])[x]=c,j%3%2?x--:y+=!!++x-j%3,k?k--:k=(n=j/3<<1)+(j++%3||n+2)),m=[],j=k=0,x=y=a.length)&&m.map(r=>r.join``).join`
`
```
[Try it online!](https://tio.run/##bY@9boMwHMR3nsJBIrFlcNuwNfmTKVLfoANCwuHbGJsamkJLn506Tccud6ffDacT/MqHzDT9GCidF2sJK4eIs473OIMI4y6eE7jJssSMsd2O9Tw/qxxPJCHxlEDmCy/09qcpCJ5nCpsNpVNgkd@eWotawArEQ3g8PhGKBaVeuCyK7gnxO4gTX0ALj/4EM3AmC1WNNdluu999A5FhQjcqTcndnXQ9xA5C7kshpUav2sh84/rI5Ze7Zn@WF2VVN6KVndL9f@zNDOP79WOaP10ncVipzZlnNR4QROjLLpjCRlTi2@chIQeLMq0GLQsmdYVtbdk3WX8A "JavaScript (Node.js) – Try It Online") (raw output)
[Try it online!](https://tio.run/##bY9Bb4IwGIbv/IpKprQC1Wl2mRZPJrvssssOQEIHBYTSssIcTPztrE7jaZfv/fJ8yffkLeiRNrE61K0rZMLGlIyUeBRXtIYx8SCs/D4klzEMPsbYsnBNk71IYIdC5HchiZ1iup6udp3rPvc2mUxsu3M1cspdqVFJoCDFYr3dPiIbFrY9XQ@DsFcIORXxQ6cgJVk6HekJxZyJrM3RbFb9@RXxFC7kQUQRuqYRjRvfAMB8YZxL8C4VTyamA0z6cZ3xLRKWZvmhKHklZP0f@1RN@3X87vof0wgNnEq1p3EOG0A8cNIGxfQKUnjp3IRoo1EsRSM5w1xmUJ@xYjWnMYOLQNiLTDsCYaI7fWPZvqthFAQCnB5Oza0ccMErbXOccikVvNP5HCzxEzqfIwdYmYVu37T3jMZf "JavaScript (Node.js) – Try It Online") (with extra whitespace removed)
### How?
This is a rather straightforward algorithm that draws the output character by character in a matrix \$m[\:]\$, keeping track of the position \$(x,y)\$ of the pen, a direction in \$\{0,1,2\}\$ and the number \$k\$ of characters to draw before the next direction change.
We move according to the following table:
```
 direction | moving towards | distance
-----------+----------------+----------
     0     | South-East     |  2t + 1       (t = turn number)
     1     | West           |  4t + 3
     2     | North-East     |  2t + 2
```
Which gives:
```
t = 0     t = 1        t = 2            t = 3
                                          2       
                         2               2.       
            2           2.              2..0      
  2        2.          2..0            2....0     
 2X       2.X0        2..X.0          2...X..0    
1110     2....0      2......0        2........0   
        11111110    2........0      2..........0  
                   111111111110    2............0 
                                  1111111111111110
```
In the JS implementation, we do not store the direction explicitly. Instead, we use a counter \$j\$ going from \$0\$ to \$+\infty\$ and use \$j\bmod 3\$ to figure out the current direction. We also do not store the turn number but compute \$n=2\cdot\lfloor j/3\rfloor\$, using the value of \$j\$ *before* it's incremented to account for the direction change (which means that \$n\$ is equal to \$2(t-1)\$ rather than \$2t\$ when the direction wraps to \$0\$).
Hence the following table:
```
     j mod 3     |  (j + 1) mod 3  |                     | new starting
 (old direction) | (new direction) |    new distance     | value for k
-----------------+-----------------+---------------------+--------------
        2        |        0        | (n + 2) + 1 = n + 3 |     n + 2
        0        |        1        |      2n + 3         |    2n + 2
        1        |        2        |       n + 2         |     n + 1
```
And the corresponding expression to update \$k\$:
```
k = (n = j / 3 << 1) + (j++ % 3 || n + 2)
```
The coordinates are updated with:
```
j % 3 % 2 ?          // if the direction is 1:
  x--                //   decrement x
:                    // else:
  y += !!++x - j % 3 //   increment y if the direction is 0
                     //   or decrement y if it's 2
                     //   increment x in both cases
```
[Answer]
# [R](https://www.r-project.org/), ~~205~~ ~~153~~ ~~147~~ ~~136~~ ~~132~~ 126 bytes
-52 from Dominic van Essen.  
-4 from Giuseppe.  
-4 again thanks to Giuseppe.  
-5 further thanks to Dominic van Essen
```
function(s,n=nchar(s))for(y in(x=-n:n)*2)cat(ifelse((i=(t=y-2*(r=abs(x))*!r<y)*t-t-2*(r<y)*x+x+1)>n," ",substring(s,i,i)),"
")
```
[Try it online!](https://tio.run/##bU@7UsMwEOzzFRdRRHJsZkjJIGr@gFq2z7FAnOB0CjY/b2QGN4RuZ29fx4uwd3QOaJchUyc@kk41WepGxzoZM0TWM3jSk23onkx1Mp0T7QcMCbX2Voudm1Ol2bo26cmYas8Ps6mkkR96xdNxOt6ZR6oVqDrlNpVWOpciX3tjarVTZrkBioIgoxPYRsG2CUaXgFEyE1xcyL86n1YTEGKPfQ0pQpLI2Je9RVZC2pJxoBzCAUZk3K3QbulayYgf2XevLcdPGuL0kt/eU7wgl0NwX3Mfz7fK/HVdM@4fqr3mnjCECM@RQ78vH38D "R – Try It Online")
[Answer]
# [R](https://www.r-project.org/), ~~270~~ ~~265~~ ~~252~~ ~~243~~ ~~232~~ ~~227~~ 225 bytes
*I finally managed to remove 2 more characters to bring the total to a number that can be represented in triangular form (as shown here). Code should be formatted conventionally to be run (as in the example on TIO); the '•' represents a newline (`\n`) character.*
```
              f
             unc
            tion(
           s,`~`=c
          bind,m=ma
         trix){n=nch
        ar(s)+1;p=m(,
       n^2,2);while(T<
      n){a=4*F;p[T+0:a,
     ]=c(F:-F,(-F:F)[-1]
    )~0:a-2*F;p[T+a+-2:a+
   3,]=(F=F+1)~(b=2*F-1):-
  b;T=T+2*a+4};m=m(" ",n,n)
 ;m[p[2:n-1,]+b+1]=el(strspl
it(s,''));apply(m,1,cat,"•")}
```
[Try it online!](https://tio.run/##NY/LboMwEEX3/gqLLrBjUxWaFaq3fAE7RBUDTnBrxtQ2eTRKfp06UrMb6Zy5utetwWkJB6PEul@gD9oC8Xx334m@0zDwSUwyKmd6BQH9KB3xlOVoFhPh8FnwgqLTqI0i9QfQqxTbTYXmpmZvpeSt6ElVZhUnWVVWtMnylt4jyIp/SbKsKCV7jyapRMVyeiediDTLaZl1qBY1KzaSbW8o9iAJTjhwoGhq5qYoIct5yzqWt0IZ4oPzs9Ehtk9TSpGcZ3MhE895LwNPUEJv6wsGGxQOowz4uRs/Z@NReuxUWBzgozTLv6f94wmDUoMaOPYW@2CdGrB@aDGkixkpLMakeFROoccpnukkCaP6WXT/3Tl7gr09fy3T7O1RuQiM/L0M9vCa0PUP "R – Try It Online")
Note that this approach has been comprehensively outgolfed by [att's approach](https://codegolf.stackexchange.com/questions/210454/spiralize-a-word-triangularly/210543#210543), although as consolation neither that nor any of the other current answers can be represented as a triangle...
Works by constructing the coordinates for each letter, then using this to put the letters into an empty matrix.
Commented:
```
triangle=
function(s){n=nchar(s)          # n is the number of letters
s=el(strsplit(s,''))            # first split the string into individual letters
p=matrix(,2,n^2)                # initialize p as a 2-row matrix to hold the coordinates
                                # (with plenty of columns so that we've enough to go all 
                                # the way round the outermost triangle)
                                # now, F is the current loop, starting at 0
while(T<=n){                    # T is the current letter index
a=4*F+1                         # a=the size of the 'arch' (number of letters going up & over)
p[,T+1:a-1]=                    # set the coordinates for the arch letters...
  rbind(                        # ...(rbind combines rows for y & x coordinates)...
    c(F:-F,(-F:F)[-1]),         # ...to y = F..-F, and then -F+1..F (so: up & then down again)
    1:a-2*F-1)                  # ...and x = across the arch from -2*F to +2*F
a=a+2                           # a=now the width of the base = size of arch + 2
p[,T+a+1:a-3]=                  # now set the coordinates of the base letters...
  rbind(                        #
    F+1,                        # ... base y = row F+1
    (b=2*F+1):-b)               # ... and x = goes (backwards) from 2*F+1..-2*F-1
T=T+2*a-2                       # update the current letter index
F=F+1}                          # increment the loop
p=p[,1:n]                       # delete any excess coordinates
p=p-min(p)+1                    # re-zero the coordinates to remove negatives
m=matrix(" ",b<-max(p),b)       # create a new matrix filled with " "
m[t(p)]=s                       # and fill it with the letters at the right positions
n=apply(m,1,cat,"               # finally, print each row
")}
```
[Answer]
# [Pip](https://github.com/dloscutoff/pip) `-l`, 70 bytes
```
sMC:Y#ax:w:y/2-/2Ly*2L++i/2{I++v<ys@w@x:a@vi%4%3?++x&i%4=1?--w++w--x}s
```
[Try it online!](https://tio.run/##K8gs@P@/2NfZKlI5scKq3KpS30hX38inUsvIR1s7U9@o2lNbu8ymstih3KHCKtGhLFPVRNXYXlu7Qg3IsjW019Ut19Yu19WtqC3@//@/bs7/xKTklNS09IzMrOyc3Lz8gsKi4pLSsvKKyioA "Pip – Try It Online")
... I'm not sure I want to try explaining this monstrosity in detail. The basic idea is to construct an over-big 2D array of spaces (`sMC:#a`) and then put the characters from the input string into the array at the proper indices (`s@w@x:a@v`). The rest of the code figures out what the "proper indices" are.
---
Alternate approach, 77 bytes:
```
a.:sX#aW<|a{UpaWa^@YxNl?v+1++v%2?v*2+1vl:xNl?RV^p.:lv%2?lPEpl.^pAEx}RVsX,#l.l
```
[Try it online!](https://tio.run/##K8gs@P8/Uc@qOEI5MdymJrE6tCAxPDHOIbLCL8e@TNtQW7tM1ci@TMtI27AsxwokGBQWV6BnlQMSzglwLcjRiytwdK2oDQorjtBRztHL@f//v27O/8Sk5JTUtPSMzKzsnNy8/ILCouKS0rLyisoqAA)
Builds the triangle as a list of lines, alternating between adding lines to the front/end of the list and adding characters to the front/end of each line. I was hoping this way might be shorter, but so far it seems it's not.
[Answer]
# [J](http://jsoftware.com/), 60 bytes
```
4 :'x(<"1(#x)++/\(3|4|>.2*%:i.#x){<:3 3#:3 2 8)}y',~' '"0/,~
```
[Try it online!](https://tio.run/##ndJbT8IwFADg9/2K4zbTDUq3bqi4AAmgiIqoeMFbQhQ2Lk6GyIQJ7q/PKmQmMhKwD01z2n4956TdQAUDVE4F27SGHIVBp9UegtvntPmy6Yx6nMzxBJAFGQMQhp8rkCBQqJaLQRIMNJbSPJWEsRyPKw@SPk1Os0SLbRodwmKTtKGDLrBJg5T86SHsI0C8qmA/gEqeAKczwpsRXgTh/SUkTdBiLCxOiCp6iPufglgW32n42A@N9Yu5N2bFMGXBSPA0TRR5FQbmyjqGCnWK6xQoNtgUofx2ZJniLSphWyIauy4j@pooLDrghvs0niWKmyGr04j9RrPRdsACVDJt24GaM7CbG2gWRQk2UHji8anRNK1Wu9N9tl96Tv918DZ030dj7yOXL@ztFw9Kh0fH5ZPK6dl59eLy6rp2c3unUk1Pbm3vpHYjTYxy0W/l8sviBRR8AQ "J – Try It Online")
Obligatory J answer because it's Jonah's challenge.
Because "replace a certain position inside an array with a value" is not a verb but an adverb, it can't be used in a train as-is, so it is wrapped inside an explicit inline verb.
Uses [att's formula](https://codegolf.stackexchange.com/a/210464/78410) to construct the directions.
### How it works
```
NB. input: a string (character vector) of length n
,~' '"0/,~  NB. create a large enough canvas (blank matrix of size 2n*2n)
        ,~  NB. concatenate two copies of self
       /    NB. outer product by...
  ' '"0     NB.   a constant function that returns blank per character
,~          NB. concatenate two copies of self
4 :'...'  NB. a dyadic explicit verb, where x is the input string and
          NB. y is the canvas generated above
x(...)}y    NB. replace some places of y by contents of x...
3|4|>.2*%:i.#x  NB. formula by att (gives 0, 1, or 2 per index)
(...){          NB. select the directions based on the above...
<:3 3#:3 2 8    NB. the matrix (0 -1)(-1 1)(1 1) i.e. L/RU/RD
(#x)++/\        NB. take cumulative sum (giving coords to place each char)
                NB. and add n to all elements
<"1             NB. enclose each row to satisfy the input format of }
```
[Answer]
# Scala, ~~322~~ 318 bytes
```
s=>((s zip Seq.unfold((0,0,0->0)){case(r,n,y->x)=>Option.when(n<s.size){val(c,t)=(math.sqrt(n).toInt%2,r+1-math.abs(x.sign))
(y->x,(t,n+1,(y+(c-1)*(1-t%2*2),x+1-c*2)))}}groupBy(_._2._1)toSeq)sortBy(_._1)map(_._2.sortBy(_._2._2)map(_._1)mkString)zipWithIndex)map{t=>" "*(math.sqrt(s.size).toInt-t._2)+t._1}mkString "\n"
```
[Try it in Scastie](https://scastie.scala-lang.org/7caCJTcPTcq8rywhD8dHcA) (doesn't work in TIO)
[Answer]
# [Perl 5](https://www.perl.org/), 163 bytes
```
sub f{                    #newlines and indentation added here for readability. 
  $_=' 'x1e3;
  @L=(51,$a=-1,-49)x($p=225);
  for$c(pop=~/./g){
    $P=$p+$L[1];
    $a++>0&&s/^(.{$P}) /$1$c/s&&($p=$P,$a=0,shift@L)||substr$_,$p+=$L[0],1,$c
  }
  s/.{50}/$&\n/gr
}
```
In short, it adds the next char from the input in the current direction unless it discovers it's time to change direction.
[Try it online!](https://tio.run/##Xc3LToNAGEDhvU@BzR/KBMowVRaGjKn3tqLitd5qQylQFGGcoYpSfHWcroyuT/IdFvLUbhqxmCpRBRPaVtolCTecnks1mxjg0w4xOptbqNSA0W7XRk6Ucwg0ljP6jU0cowo8CkwH94GMHfB1fdtSVYGfNFOWGikYCARYqOpKAG9lWoaYJ1HRc9FyKdei4DAxpEElYo0N@Q1qgc3KtmoM6mOGY143a4wnWaFEWsufBrMwiufJ80v6muXsjYti8f5Rfn7t7O7tHxwe9QfDY/fk9Mw7v7i8ur4Z3d7dt5DzC/TDNM2VUc7T2fqf8F@WsfkB "Perl 5 – Try It Online")
]