title: TextClip animations (e.g. adding text with moving letters to a video) not working, except for the demo sentence in docs
body: <p>I took this example of text effects applied to video using moviepy and ran it locally, only changing the text itself, and it doesn't work with any sort of text I entered. For example, if I replace <code>Cool Effect</code> with <code>Quick Effect</code> the video will show <code>Q      ff</code> instead.</p>
  <p>Likewise, <code>The quick brown fox jumped over the lazy dogs</code> becomes <code>f</code>.</p>
  <p>Source of this code example: <a href="https://zulko.github.io/moviepy/examples/moving_letters.html" rel="nofollow noreferrer">https://zulko.github.io/moviepy/examples/moving_letters.html</a> is the author of <code>moviepy</code>.</p>
  <pre><code>import numpy as np
  
  from moviepy.editor import *
  from moviepy.video.tools.segmenting import findObjects
  
  # WE CREATE THE TEXT THAT IS GOING TO MOVE, WE CENTER IT.
  
  screensize = (720,460)
  txtClip = TextClip('Cool effect',color='white', font=&quot;Amiri-Bold&quot;,
                     kerning = 5, fontsize=100)
  cvc = CompositeVideoClip( [txtClip.set_pos('center')],
                          size=screensize)
  
  # THE NEXT FOUR FUNCTIONS DEFINE FOUR WAYS OF MOVING THE LETTERS
  
  
  # helper function
  rotMatrix = lambda a: np.array( [[np.cos(a),np.sin(a)], 
                                   [-np.sin(a),np.cos(a)]] )
  
  def vortex(screenpos,i,nletters):
      d = lambda t : 1.0/(0.3+t**8) #damping
      a = i*np.pi/ nletters # angle of the movement
      v = rotMatrix(a).dot([-1,0])
      if i%2 : v[1] = -v[1]
      return lambda t: screenpos+400*d(t)*rotMatrix(0.5*d(t)*a).dot(v)
      
  def cascade(screenpos,i,nletters):
      v = np.array([0,-1])
      d = lambda t : 1 if t&lt;0 else abs(np.sinc(t)/(1+t**4))
      return lambda t: screenpos+v*400*d(t-0.15*i)
  
  def arrive(screenpos,i,nletters):
      v = np.array([-1,0])
      d = lambda t : max(0, 3-3*t)
      return lambda t: screenpos-400*v*d(t-0.2*i)
      
  def vortexout(screenpos,i,nletters):
      d = lambda t : max(0,t) #damping
      a = i*np.pi/ nletters # angle of the movement
      v = rotMatrix(a).dot([-1,0])
      if i%2 : v[1] = -v[1]
      return lambda t: screenpos+400*d(t-0.1*i)*rotMatrix(-0.2*d(t)*a).dot(v)
  
  
  
  # WE USE THE PLUGIN findObjects TO LOCATE AND SEPARATE EACH LETTER
  
  letters = findObjects(cvc) # a list of ImageClips
  
  
  # WE ANIMATE THE LETTERS
  
  def moveLetters(letters, funcpos):
      return [ letter.set_pos(funcpos(letter.screenpos,i,len(letters)))
                for i,letter in enumerate(letters)]
  
  clips = [ CompositeVideoClip( moveLetters(letters,funcpos),
                                size = screensize).subclip(0,5)
            for funcpos in [vortex, cascade, arrive, vortexout] ]
  
  # WE CONCATENATE EVERYTHING AND WRITE TO A FILE
  
  final_clip = concatenate_videoclips(clips)
  final_clip.write_videofile('../../coolTextEffects.avi',fps=25,codec='mpeg4')
  </code></pre>
  <p>I have poured over this snippet and don't see where the &quot;text&quot; itself could be changing. Probably something to do with the <code>letters</code> variable and <code>findObjects</code>, which locates each letter in the <code>TextClip</code> and loops through them.</p>
  <p>But I'd like to know more about moviepy and why these 4 effects don't work generally. I have looked through github and youtube, over hundreds of projects, to find someone who demonstrates these, but haven't found any better examples.</p>
  <p>If you solve this, I'll probably release a public github package / repo that makes it easier to apply these to video. The docs for moviepy almost entirely omit the <code>TextClip</code> feature.</p>
  <p><a href="https://www.youtube.com/watch?v=jj5qrHl5ZS0" rel="nofollow noreferrer">enter link description here</a></p>
  <p>== UPDATE ==</p>
  <p>After a suggestion from @Rotem, I tried messing with the <code>findObjects(clip, rem_thr)</code> <code>rem_thr</code> param. It defaults to 500, meaning that detected objects smaller than 500 are ignored. Changing that to any of these other thresholds (500, 250, 50, 10, 1) doesn't solve the issue:</p>
  <pre><code>500 (test text arrive wiggly) findObjects found 18 letters from string of length 23
  250 (test text arrive wiggly) findObjects found 20 letters from string of length 23
  50 (test text arrive wiggly) findObjects found 22 letters from string of length 23
  10 (test text arrive wiggly) findObjects found 22 letters from string of length 23
  1 (test text arrive wiggly) findObjects found 22 letters from string of length 23
  </code></pre>
  <p>(I realized after that there are only 20 letters in the string, but I was check for number of characters, including the whitespace. So <code>22</code> matches number of letters plus dots over lower case <code>i</code>s. And 20 is the desired number. So tweaking with the <code>rem_thr</code> is important, but there's a different optimal detection size for every font size. That's tricky, but demands a better wrapper function to manage.)</p>
  <p>What DOES help is maximizing the contrast with letters:</p>
  <pre><code>caption = TextClip(&quot;some text&quot;,
      color='white',
      bg_color=&quot;black&quot;,
      kerning=5,
      fontsize=33)
  </code></pre>
  <p>With <code>bg_color</code> was not specified, it only found one letter regardless of <code>rem_thr</code>.</p>
  <p>Setting <code>bg_color</code> to black helped it find letters. Perhaps I need to use a blocky fat font for this to work, white on black, and then remove the background before applying it to the video.</p>
  <p>But this demo is definitely hard to use reliably.</p>