1

I am just starting to learn to do SVG Animations, and I'm trying to make a command-line style 'typewriter' effect, typing out several different lines of text, one after the other.

I would like the finished animation to do the following:

  1. Show a prompt with a blinking Full Block cursor, blinking 3 times. (fig. 1)
  2. Type out a line of text, letter by letter, with the cursor following at the end (not blinking) like an actual CLI. (fig. 2 but with cursor following)
  3. Show the full line with the cursor at the end, blinking 3 times immediately after the full line is typed out.
  4. 'Delete' the line, letter by letter. (fig. 3 but cursor following)
  5. Repeat with a different line of text, and so forth.

Fig. 4 is what I have so far, but as you can see, there are a couple of problems:

  1. No following cursor.
  2. There's a pause after the line is fully typed and before the cursor starts blinking. Also after having blinked, before starting the 'delete' part.
  3. It seems that there's a slight apparent movement of the text, when hiding the typed out text and simultaneously showing the text used for the 'delete' part.
  4. I haven't figured out how to conveniently make the whole animation loop with different lines of text. I have tried to just copy-paste it and change id attributes, but the XML is getting very large and confusing, so I haven't had any luck.

Fig. 1:

<svg
    xmlns='http://www.w3.org/2000/svg'
    xmlns:xlink='http://www.w3.org/1999/xlink'
    viewBox='0 0 1152 50'
    style='background-color: #000000;'
    width='1152px' height='50px'>

    <!-- Show prompt -->
    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
        dominant-baseline='middle' x='0%' y='21' text-anchor='start'>
        <!-- 1 non-breaking space followed by '❯' -->
        &#160;&#10095;

    </text>
    
    <!-- Blink cursor -->
    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
        dominant-baseline='middle' x='0%' y='21' text-anchor='start'>
        <!-- 3 non-breaking spaces followed by '█' -->
        &#xa0;&#xa0;&#xa0;&#x2588;

        <animate id="blinker" attributeName="opacity" dur="1s" values="1;0" repeatCount="3" begin="0s" calcMode="discrete"/>
        <set attributeName="opacity" to="0" begin="blinker.end"></set>
    </text>
</svg>

Demo: https://jsfiddle.net/ja0x5rs8/

Fig. 2:

<svg
    xmlns='http://www.w3.org/2000/svg'
    xmlns:xlink='http://www.w3.org/1999/xlink'
    viewBox='0 0 1152 50'
    style='background-color: #000000;'
    width='1152px' height='50px'>
    <style>
        @font-face {
        font-family: 'Inconsolata';
        font-style: normal;
        font-weight: 400;
        font-stretch: normal;
        font-display: fallback;
        }
    </style>

    <!-- Show prompt -->
    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
        dominant-baseline='middle' x='0%' y='21' text-anchor='start'>
        <!-- 1 non-breaking space followed by '❯' -->
        &#160;&#10095;

    </text>    

    <path id='typer_path'>
        <animate id='d1' attributeName='d' begin='0s'
                        dur='3500ms' fill='remove'
                        values='m0,25 h0; m0,25 h1152'
                        keyTimes='0; 1' />
    </path>
    
    
    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
            dominant-baseline='middle'
            x='0%' text-anchor='start'>
    
        <animate id="show1" attributeName="opacity" values="100" begin="0s" dur="500" calcMode="discrete"></animate>
    
        <textPath xlink:href='#typer_path'>
                &#xa0;&#xa0; hashcat -m 0 511c04a3d19150f1903ef5b92d748a65 -a 3 -1 aeiou -2 bcdfghjklmnpqrstvwxz &#039;?1?2?1?2?s?d?d?d?d&#039; -w 4 -O&#x2588;
    
            </textPath>
    </text>
</svg>

Demo: https://jsfiddle.net/u3ypnwrm/

Fig. 3:

<svg
    xmlns='http://www.w3.org/2000/svg'
    xmlns:xlink='http://www.w3.org/1999/xlink'
    viewBox='0 0 1152 50'
    style='background-color: #000000;'
    width='1152px' height='50px'>
    <style>
        @font-face {
        font-family: 'Inconsolata';
        font-style: normal;
        font-weight: 400;
        font-stretch: normal;
        font-display: fallback;
        }
    </style>
    
    <!-- Show prompt -->
    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
        dominant-baseline='middle' x='0%' y='21' text-anchor='start'>
        <!-- 1 non-breaking space followed by '❯' -->
        &#160;&#10095;

    </text>

    <path id='typer_path'>
        <animate id='d1' attributeName='d' begin='0s'
                        dur='1500ms' fill='remove'
                        values='m0,25 h1152; m0,25 h0'
                        keyTimes='0; 1' />
    </path>
    
    
    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
            dominant-baseline='middle'
            x='0%' text-anchor='start'>
    
        <animate id="show1" attributeName="opacity" values="100" begin="0s" dur="500" calcMode="discrete"></animate>
    
        <textPath xlink:href='#typer_path'>
                &#xa0;&#x276f; hashcat -m 0 511c04a3d19150f1903ef5b92d748a65 -a 3 -1 aeiou -2 bcdfghjklmnpqrstvwxz &#039;?1?2?1?2?s?d?d?d?d&#039; -w 4 -O&#x2588;
    
            </textPath>
    </text>
</svg>

Demo: https://jsfiddle.net/L0tdsu1w/

Fig. 4:

<svg xmlns='http://www.w3.org/2000/svg'
    xmlns:xlink='http://www.w3.org/1999/xlink'
    viewBox='0 0 1152 50'
    style='background-color: #000000;'
    width='1152px' height='50px'>


    <!-- PROMPT START -->
    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
            dominant-baseline='middle' x='0%' y='21' text-anchor='start'>
            <!-- 1 non-breaking space followed by '❯' -->
            &#xa0;&#x276f;

        </text>
    <!-- PROMPT END -->

    <!-- CURSOR BLINK START -->
        <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
            dominant-baseline='middle' x='0%' y='21' text-anchor='start'>
            <!-- 3 non-breaking spaces followed by '█' -->
            &#xa0;&#xa0;&#xa0;&#x2588;

            <animate id="blinker" attributeName="opacity" dur="1s" values="1;0" repeatCount="3" begin="0s" calcMode="discrete"/>
            <set attributeName="opacity" to="0" begin="blinker.end"></set>
        </text>
    <!-- CURSOR BLINK END -->



    <!-- TYPER START -->
    <path id='path0'>
        <animate id='d1' attributeName='d' begin='blinker.end'
                        dur='3500ms' fill='remove'
                        values='m0,25 h0 ; m0,25 h1152' keyTimes='0; 1' />
    </path>


    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
            dominant-baseline='middle'
            x='0%' text-anchor='start'>

        <animate id="show" attributeName="opacity" values="100" begin="blinker.end" dur="500" calcMode="discrete"></animate>

        <textPath xlink:href='#path0'>
                &#xa0;&#xa0;&#xa0;hashcat -m 0 511c04a3d19150f1903ef5b92d748a65 -a 3 -1 aeiou -2 bcdfghjklmnpqrstvwxz &#039;?1?2?1?2?s?d?d?d?d&#039; -w 4 -O█

            </textPath>
    </text>
    <!-- TYPER END -->


    <!-- POST PROMPT START -->
    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14' opacity="0"
            dominant-baseline='middle' x='0%' y='21' text-anchor='start'>

            &#xa0;&#xa0;&#xa0;hashcat -m 0 511c04a3d19150f1903ef5b92d748a65 -a 3 -1 aeiou -2 bcdfghjklmnpqrstvwxz &#039;?1?2?1?2?s?d?d?d?d&#039; -w 4 -O

            <animate id="post_hider" attributeName="opacity" dur="1s" values="0;1" repeatCount="3" begin="d1.end" calcMode="discrete"/>
        </text>
    <!-- POST PROMPT END -->


    <!-- POST CURSOR BLINK START -->
        <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14' opacity="0"
            dominant-baseline='middle' x='0%' y='21' text-anchor='start'>

            &#xa0;&#xa0;&#xa0;hashcat -m 0 511c04a3d19150f1903ef5b92d748a65 -a 3 -1 aeiou -2 bcdfghjklmnpqrstvwxz &#039;?1?2?1?2?s?d?d?d?d&#039; -w 4 -O█

            <animate id="post_blinker" attributeName="opacity" dur="1s" values="1;0" repeatCount="3" begin="d1.end" calcMode="discrete"/>
            <set attributeName="opacity" to="0" begin="post_blinker.end"></set>
        </text>
    <!-- POST CURSOR BLINK END -->



    <!-- DELETER START -->
    <path id='path1'>
        <animate id='d1_1' attributeName='d' begin='post_blinker.end'
                        dur='3500ms' fill='remove'
                        values='m0,25 h1152; m0,25 h0' keyTimes='0; 1' />
    </path>


    <text font-family='"Inconsolata", monospace' fill='#126D08' font-size='14'
            dominant-baseline='middle'
            x='0%' text-anchor='start'>

        <animate id="show_1" attributeName="opacity" values="100" begin="post_blinker.end" dur="500" calcMode="discrete"></animate>

        <textPath xlink:href='#path1'>
            &#xa0;&#xa0;&#xa0;hashcat -m 0 511c04a3d19150f1903ef5b92d748a65 -a 3 -1 aeiou -2 bcdfghjklmnpqrstvwxz &#039;?1?2?1?2?s?d?d?d?d&#039; -w 4 -O█

            </textPath>
    </text>
    <!-- DELETER END -->

</svg>

Demo: https://jsfiddle.net/1aub6dqs/

3

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.