# Let it snow()

**URL:** <https://discourse.julialang.org/t/let-it-snow/72950>\
**Category:** Community\
**Tags:** repl, snow\
**Created:** [December 11, 2021, 9:54pm UTC](https://discourse.julialang.org/t/let-it-snow/72950 "2021-12-11T21:54:56Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ianshmean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ianshmean/32/216042_2.png) [@ianshmean](https://discourse.julialang.org/u/ianshmean)\
**Post date:** [December 11, 2021, 9:54pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/1 "2021-12-11T21:54:56Z")

</div>

Let it `snow()`

![juliasnow](https://global.discourse-cdn.com/julialang/original/3X/a/0/a07fe4045ac536651537252f6c51b5b1e5a5236a.gif)

The code could definitely be golfed…

```julia
function snow(io = stdout)
    h, w = displaysize(io)
    iob = IOBuffer()
    ioc = IOContext(IOContext(iob, io), :displaysize=>(h,w))
    print(io, repeat("\n", h), "\e[", h, "A\e[1G") # new lines and move back up
    air = ones(Int, w, h)
    flakes = [" ", "*", "❄︎", "❅", "❆"]
    scsin(t) = ((sin(t) / 2) + 0.5) * (0.1 / 3)
    likelihood(t) = scsin(t) + scsin(t * 1.00001) + scsin(t * 0.9999)
    try
        while true
            for x in 1:w, y in h:-1:1
                air[x,y] = if y == 1 # new flakes
                    rand() < likelihood(time()) ? rand(2:length(flakes)) : 1
                elseif y == h # accumulate bottom
                    ((rand() < 0.95 && air[x,y] > 1) || (air[x, y-1] > 1 && rand() < 0.2)) ? 2 : 1
                elseif all(>(1), air[x, y:end]) # melt pile sometimes
                    rand() < 0.95 ? 2 : 1
                elseif (air[x, y-1] > 1 && all(>(1), air[x, (y+1):end])) # if flake coming and piled up below
                    rand() < 0.1 ? 2 : 1
                else # fall downwards otherwise
                    air[x, y-1]
                end
            end
            print(ioc, "\e[", h, "A\e[1G") # move back to start
            print.((ioc,), flakes[air])
            print(ioc, "\e[", h, "A\e[1G") # move back to start
            Base.banner(ioc)
            printstyled(ioc, "julia> ", color = :green, bold = true)
            println(ioc, "snow()")
            print(io, String(take!(iob)))
            sleep(1/8)
        end
    catch e
        isa(e,InterruptException) || rethrow()
    end
    nothing
end

```

---

<div class="post-metadata">

**Author:** ![cormullion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cormullion/32/49131_2.png) [@cormullion](https://discourse.julialang.org/u/cormullion)\
**Post date:** [December 11, 2021, 10:37pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/2 "2021-12-11T22:37:14Z")

</div>

`❄︎❅❆` options? 🤣

---

<div class="post-metadata">

**Author:** ![logankilpatrick](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/logankilpatrick/32/38123_2.png) [@logankilpatrick](https://discourse.julialang.org/u/logankilpatrick)\
**Post date:** [December 12, 2021, 12:58am UTC](https://discourse.julialang.org/t/let-it-snow/72950/3 "2021-12-12T00:58:03Z")

</div>

This is awesome! Please share it on Twitter and Tag the Julia account. I also want to set my REPL up to show this in the background when I am running code 😄

---

<div class="post-metadata">

**Author:** ![logankilpatrick](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/logankilpatrick/32/38123_2.png) [@logankilpatrick](https://discourse.julialang.org/u/logankilpatrick)\
**Post date:** [December 13, 2021, 4:02pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/4 "2021-12-13T16:02:48Z")

</div>

@ianshmean: [https://twitter.com/JuliaLanguage/status/1470423267576008704?s=20](https://twitter.com/JuliaLanguage/status/1470423267576008704?s=20)

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [December 13, 2021, 4:33pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/5 "2021-12-13T16:33:22Z")

</div>

This could be a perfect Easter Egg for Julia 1.8…

EDIT: By the way, does Julia have any ?

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [December 13, 2021, 4:36pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/6 "2021-12-13T16:36:25Z")

</div>

`julia --lisp` might count.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 13, 2021, 4:59pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/7 "2021-12-13T16:59:45Z")

</div>

The first snowflakes `*` were falling vertically on my REPL.

However, the last ones ` *, ❄︎, ❅, ❆` seem to fall with strong side winds…

Aren’t the JuliaMono fonts mono-flake?

---

<div class="post-metadata">

**Author:** ![cormullion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cormullion/32/49131_2.png) [@cormullion](https://discourse.julialang.org/u/cormullion)\
**Post date:** [December 13, 2021, 5:24pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/8 "2021-12-13T17:24:46Z")

</div>

Might be that your terminal app is struggling with the adverse weather conditions - it looks good in my MacOS Terminal.

---

<div class="post-metadata">

**Author:** ![ianshmean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ianshmean/32/216042_2.png) [@ianshmean](https://discourse.julialang.org/u/ianshmean)\
**Post date:** [December 13, 2021, 11:01pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/9 "2021-12-13T23:01:44Z")

</div>

If you want to control the wind, change the width of the terminal window after starting it.  
It’s a ~~bug~~ _feature_

---

<div class="post-metadata">

**Author:** ![TheCedarPrince](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thecedarprince/32/17323_2.png) [@TheCedarPrince](https://discourse.julialang.org/u/TheCedarPrince)\
**Post date:** [December 2, 2023, 5:03am UTC](https://discourse.julialang.org/t/let-it-snow/72950/10 "2023-12-02T05:03:32Z")

</div>

I was just trying to find this! Just in time for that time of year! ❄ 🎄 🎅 ☕

---

<div class="post-metadata">

**Author:** ![mcreel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcreel/32/30088_2.png) [@mcreel](https://discourse.julialang.org/u/mcreel)\
**Post date:** [December 2, 2023, 7:06am UTC](https://discourse.julialang.org/t/let-it-snow/72950/11 "2023-12-02T07:06:26Z")

</div>

Hah, that’s great, thanks for the bump.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 24, 2023, 11:09am UTC](https://discourse.julialang.org/t/let-it-snow/72950/12 "2023-12-24T11:09:24Z")

</div>

Adding a tree under the snow:

```julia
using Printf
foreach(i-> @printf("%19s%-19s\n", "❅".^(i,i-1)...), 1:9)
foreach(_-> @printf("%19s\n", "❅"), 1:3)

```

Happy Holidays!

---

<div class="post-metadata">

**Author:** ![ianshmean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ianshmean/32/216042_2.png) [@ianshmean](https://discourse.julialang.org/u/ianshmean)\
**Post date:** [December 25, 2023, 4:23am UTC](https://discourse.julialang.org/t/let-it-snow/72950/13 "2023-12-25T04:23:03Z")

</div>

Adding the tree to the scene (and making it work on 1.11 given the banner moved to REPL)

```julia
using REPL, Printf
function snow(io = stdout)
    h, w = displaysize(io)
    iob = IOBuffer()
    ioc = IOContext(IOContext(iob, io), :displaysize=>(h,w))
    print(io, repeat("\n", h), "\e[", h, "A\e[1G") # new lines and move back up
    air = ones(Int, w, h)
    flakes = [" ", "*", "❄︎", "❅", "❆"]
    scsin(t) = ((sin(t) / 2) + 0.5) * (0.1 / 3)
    likelihood(t) = scsin(t) + scsin(t * 1.00001) + scsin(t * 0.9999)
    try
        while true
            for x in 1:w, y in h:-1:1
                air[x,y] = if y == 1 # new flakes
                    rand() < likelihood(time()) ? rand(2:length(flakes)) : 1
                elseif y == h # accumulate bottom
                    ((rand() < 0.95 && air[x,y] > 1) || (air[x, y-1] > 1 && rand() < 0.2)) ? 2 : 1
                elseif all(>(1), air[x, y:end]) # melt pile sometimes
                    rand() < 0.95 ? 2 : 1
                elseif (air[x, y-1] > 1 && all(>(1), air[x, (y+1):end])) # if flake coming and piled up below
                    rand() < 0.1 ? 2 : 1
                else # fall downwards otherwise
                    air[x, y-1]
                end
            end
            print(ioc, "\e[H") # move back to home
            foreach(space -> print(ioc, flakes[space]), air)
            print(ioc, "\e[H") # move back to home
            print(ioc, "\e[$(h-13)B\e[1G") # move to 12th row from bottom, col 1
            foreach(i-> @printf(ioc, "%19s%-19s\n", "❅".^(i,i-1)...), 1:9) # tree
            foreach(_-> @printf(ioc, "%19s\n", "❅"), 1:3) # trunk
            print(ioc, "\e[H") # move back to home
            @static VERSION > v"1.11.0-0" ? REPL.banner(ioc) : Base.banner(ioc)
            printstyled(ioc, "julia> ", color = :green, bold = true)
            println(ioc, "snow()")
            print(io, String(take!(iob)))
            sleep(1/8)
        end
    catch e
        isa(e,InterruptException) || rethrow()
    end
    nothing
end

```

---

<div class="post-metadata">

**Author:** ![GHTaarn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ghtaarn/32/216007_2.png) [@GHTaarn](https://discourse.julialang.org/u/GHTaarn)\
**Post date:** [December 25, 2023, 4:40am UTC](https://discourse.julialang.org/t/let-it-snow/72950/14 "2023-12-25T04:40:15Z")

</div>

This is cool, wouldn’t it be worthy of being released as a Julia package on Github or even the General registry?

---

<div class="post-metadata">

**Author:** ![GHTaarn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ghtaarn/32/216007_2.png) [@GHTaarn](https://discourse.julialang.org/u/GHTaarn)\
**Post date:** [December 25, 2023, 5:14pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/15 "2023-12-25T17:14:35Z")

</div>

Removing the snowless rectangle around the tree:

```julia
using REPL

function snow(io = stdout)
    h, w = displaysize(io)
    iob = IOBuffer()
    ioc = IOContext(IOContext(iob, io), :displaysize=>(h,w))
    print(io, repeat("\n", h), "\e[", h, "A\e[1G") # new lines and move back up
    air = ones(Int, w, h)
    flakes = [" ", "*", "❄︎", "❅", "❆"]
    scsin(t) = ((sin(t) / 2) + 0.5) * (0.1 / 3)
    likelihood(t) = scsin(t) + scsin(t * 1.00001) + scsin(t * 0.9999)
    try
        while true
            for x in 1:w, y in h:-1:1
                air[x,y] = if y == 1 # new flakes
                    rand() < likelihood(time()) ? rand(2:length(flakes)) : 1
                elseif y == h # accumulate bottom
                    ((rand() < 0.95 && air[x,y] > 1) || (air[x, y-1] > 1 && rand() < 0.2)) ? 2 : 1
                elseif all(>(1), air[x, y:end]) # melt pile sometimes
                    rand() < 0.95 ? 2 : 1
                elseif (air[x, y-1] > 1 && all(>(1), air[x, (y+1):end])) # if flake coming and piled up below
                    rand() < 0.1 ? 2 : 1
                else # fall downwards otherwise
                    air[x, y-1]
                end
            end
            foreach(space -> print(ioc, flakes[space]), air)
            for itree in 1:12
                print(ioc, "\e[H") # move back to home
                if itree <= 9
                    print(ioc, "\e[$(h-14+itree)B\e[$(19-itree)G")
                    printstyled(ioc, "x"^(2*itree-1), color=:green)
                else # Trunk
                    print(ioc, "\e[$(h-14+itree)B\e[18G")
                    printstyled(ioc, "-", color=:reverse)
                end
            end
            print(ioc, "\e[H") # move back to home
            @static VERSION > v"1.11.0-0" ? REPL.banner(ioc) : Base.banner(ioc)
            printstyled(ioc, "julia> ", color = :green, bold = true)
            println(ioc, "snow()")
            print(io, String(take!(iob)))
            sleep(1/8)
        end
    catch e
        isa(e,InterruptException) || rethrow()
    end
    nothing
end

```

---

<div class="post-metadata">

**Author:** ![boywithacoin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/boywithacoin/32/205435_2.png) [@boywithacoin](https://discourse.julialang.org/u/boywithacoin)\
**Post date:** [December 26, 2023, 6:04pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/16 "2023-12-26T18:04:30Z")

</div>

shouldn’t snowflakes be random and not following some trig function?

---

<div class="post-metadata">

**Author:** ![ianshmean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ianshmean/32/216042_2.png) [@ianshmean](https://discourse.julialang.org/u/ianshmean)\
**Post date:** [December 27, 2023, 3:23am UTC](https://discourse.julialang.org/t/let-it-snow/72950/17 "2023-12-27T03:23:56Z")

</div>

The trig part is introducing slow variations to the likelihood of the random generation of flakes to simulate wind flurries.

---

<div class="post-metadata">

**Author:** ![ianshmean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ianshmean/32/216042_2.png) [@ianshmean](https://discourse.julialang.org/u/ianshmean)\
**Post date:** [December 21, 2024, 6:07pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/18 "2024-12-21T18:07:54Z")

</div>

Hey ChatGPT. It’s 2024, the tree has grown, and other trees have started to grow around it. Also someone has put flashing lights on the trees…

```julia
using REPL

function snow(io = stdout)
    # Grab terminal dimensions
    h, w = displaysize(io)
    iob = IOBuffer()
    ioc = IOContext(IOContext(iob, io), :displaysize=>(h,w))
    
    # Clear the screen, move cursor up
    print(io, repeat("\n", h), "\e[$(h)A\e[1G")

    # The grid that holds falling snow
    air = ones(Int, w, h)

    # Snowflake characters (index 1 is empty space)
    flakes = [" ", "*", "❄︎", "❅", "❆"]

    # Small sinusoidal helper to vary snowfall probability
    scsin(t) = ((sin(t) / 2) + 0.5) * (0.1 / 3)
    likelihood(t) = scsin(t) + scsin(t * 1.00001) + scsin(t * 0.9999)

    # Print a single tree line with random “lights”
    function printtreeline(ioc, length_of_line)
        for i in 1:length_of_line
            if rand() < 0.12
                # White light
                printstyled(ioc, "o", color=:white, bold=true)
            else
                # Standard green branch
                printstyled(ioc, "x", color=:green)
            end
        end
    end

    # Draw a single “pine” at (base_row, center_col) with specified height + trunk
    function draw_tree(ioc, base_row, center_col; height=12, trunk_height=3)
        # Print each level from top to bottom
        for lvl in 1:height
            row = base_row - height + lvl
            col = center_col - (lvl - 1)
            
            print(ioc, "\e[$(row);$(col)H")
            printtreeline(ioc, 2*lvl - 1)
        end
        
        # Print trunk
        for trunk_lvl in 1:trunk_height
            row = base_row + trunk_lvl
            print(ioc, "\e[$(row);$(center_col)H")
            printstyled(ioc, "│", color=:reverse)
        end
    end

    try
        while true
            # Update the snowfall in 'air'
            for x in 1:w, y in h:-1:1
                air[x,y] = if y == 1
                    # Spawn new snowflakes at top
                    rand() < likelihood(time()) ? rand(2:length(flakes)) : 1
                elseif y == h
                    # Accumulate at bottom
                    ((rand() < 0.95 && air[x,y] > 1) ||
                     (air[x, y-1] > 1 && rand() < 0.2)) ? 2 : 1
                elseif all(>(1), air[x, y:end]) # melt pile sometimes
                    rand() < 0.95 ? 2 : 1
                elseif (air[x, y-1] > 1 && all(>(1), air[x, (y+1):end]))
                    rand() < 0.1 ? 2 : 1
                else
                    # Normal falling
                    air[x, y-1]
                end
            end

            # Print updated snow
            foreach(space -> print(ioc, flakes[space]), air)

            # Draw main (bigger) tree
            main_tree_height = 14
            trunk_height = 4
            main_base_row = h - 2  
            main_center_col = div(w, 2)
            draw_tree(ioc, main_base_row, main_center_col; 
                      height=main_tree_height, trunk_height=trunk_height)

            # Draw some smaller trees around it
            draw_tree(ioc, main_base_row-2, main_center_col - 20; height=10, trunk_height=3)
            draw_tree(ioc, main_base_row-2, main_center_col + 20; height=10, trunk_height=3)
            draw_tree(ioc, main_base_row-6, main_center_col - 35; height=8, trunk_height=2)
            draw_tree(ioc, main_base_row-6, main_center_col + 35; height=8, trunk_height=2)

            # Move cursor home
            print(ioc, "\e[H")

            # REPL banner + prompt
            @static VERSION > v"1.11.0-0" ? REPL.banner(ioc) : Base.banner(ioc)
            printstyled(ioc, "julia> ", color = :green, bold = true)
            println(ioc, "snow()")

            # Flush buffer
            print(io, String(take!(iob)))

            # Slight pause
            sleep(1/8)
        end

    catch e
        isa(e, InterruptException) || rethrow()
    end
    nothing
end

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 21, 2024, 6:25pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/19 "2024-12-21T18:25:44Z")

</div>

Genius! Our favorite snow master is back.

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [December 21, 2024, 7:09pm UTC](https://discourse.julialang.org/t/let-it-snow/72950/20 "2024-12-21T19:09:19Z")

</div>

For those of us on phone can we get a gif?

[Next page](https://discourse.julialang.org/t/let-it-snow/72950.md?page=2)
