a tiered waterfall in a rainforest gorge, spray, a rainbow and macaws
scenes 200×100 15 fps 31 colours, on a canvas 23.8 kB [report a bug]
·••··· ●•●•●●●•●●●•●●●•●•●•●•●•●●●•●●●•●•●•●•●•●●●•●●●•●●●•●●●•●•●•●•●•●•●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•••●•●•●•●•··• ●•●•●•●•●•●•●•●•●•●•●•· · ··• · ··• ··· · · · ●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●●●●●●●●●●●●●●•●●●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●●•●●●●●●•·•·••●••·●●· ···•●●●●●●●●●●●•●●●•●●●•· · · · · ··• · ·•●●●●●●●●●●●●●●●•●●●·●●●●●●●●●●●··●●•●•●•●●●•●●●•●●●•●●●•●•●•●•●•●•●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●●●•●•●•●·••••●••·•···•·••••· ····●•●•●•●•●•●•●•●•●•●•● · · ··•· · ···· · · · ·●●●●●●●●●●●●●●●●●●●•••●●●●●●●·•· ●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•••·••●•●•••··••●•·······●●●●●●●●●●●●●●●●●●●● ··· · ··•·· ●•●●●●●●●●●●●●●●●•● ··••●●●●· ··●•●●●•●•●•●●●•●●●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•······•·••••· ·•· ····· ●·●•·•●•●•●•●•●•●•●•· ·· ·· · · · · · ●●●●●●●●●●●●●●●●●●●··•●•● ······●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●··•···•·● ··········•••••●•●••●●●•●●●•●●· · ··· ··• · · ●●•●●●●●●●●●●•·•••···•·· · ·····●●●●●●•●●●●●●●●●●●●●●●●●●●•●●●•●●●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●●●•●●●•●●●•●●●•●●●•●•●•●•●•●•●•●•····· ··· ··· ··•·•••••••••·••●•●•●•●•● · ··· •·· · · · ··· · · ·●●●●●●●●●●●●··•••●·•·•·····•···●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●··········•···••●•••●•●·••●••·●●●●●●●·· · ··· · ··· · ··· · ●●●●●●●●●●●●●●· ······· ····•·•●•●••●●●•●●●●●●●•●●●●●●●•●•●•●•●•●•●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•· ··· · · · ··•·•••·•·•·•·•·••●•●•●•· · ·· ··· · · ··•• · · · ●●●●●●●●●●●●● · ····•···•••·●·•·••●••●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●•●········ ·••·•••·●•·•·•·•··•·●●●●· · · · · ··· · ··•••· · · ●●●●●●●●●●●●●·· ·······••·•·•·•••••••·●•●●●●●●●●●●●●●●●•●●●•●●●•●●●•●●●●●●●•●●●•●●●•●●●•●●●•●●●•●●●•●●●•●●●•●●●•●•●•●•●•●•••●•●•●•· ··· ··· •••·•••••••·• ••··●•●•● · · · · · · ····••●•··· · · · · ●●●●●●●●●●●•● ·······•●•●•••••••●•●••●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●•●●●•●·•·•···• ···•••••●•●•●•·•●••●●●●●● · ··· ··· ·· · · ····•••● · ●●●●●●●●•●•·· · ··· ••●···••••••·••·•·●●●●●●●●●●●●●●●●●•●•●•●•●•●●●•●●●•●•●•●•●•●•●•●•●•●••·••●•●•●•••●•●•●·●•●•●•●•●••••••·•·•···● · · · ··•·•••·●·•·••••●·●•●• · · · ····· · ··●•● · · · · ·●●●●●••●•●•• · ·····•●••···●·●•••●·●•●••·•●●●●●●●●●●●●●●●●●●•●•●•●•●●●●●●●●●●●●●●●●●●●●●•●•••●•●•●•●•••●•●•●•●●●●●●●·●•●••·•·•●··•······ · ····•·•••••·●•••••●• · ······· ··· · ·•● · · · ●●●·●••●•···········•·•·•·•·• •·•·•·●·••●·••••●●●●●●●●●•●•●•●•••●•●••●●●●•●●●•●●●•●•●•●•●•••●•●••·•·•·••●••·●••●●•●●●···· ·•·•········· · ··· ····••·•·•••••••• ······· ··•· · · · •·· · ··· ··· ··●●●·●·•·•···· ······•·●•• •·········•·•·••●••••●●•●•●•●●●●●•●•●●●•●•••●●●●●●●●●●●•●•●•●•●•●•●•••••••••●•••●•••••●●••··••·•····●········ ·••···•·•••·••••••••●•· · ··• · •·••· ·· · ·· •·•·· · ··· ·•· • · ····••·•·•··● ·•··· ····•·•·••••●•●•●•●•••●•●•●••·●•●•●•●•●•●•●•●•●•●•●•●••·•••·●·••••●••·•·●••·•······ · • · •··•··••••· · ··· ····••• •·• · · · ··· • · ··· · · ··· · ·••·• ·•······· •···· ··•·••·•●·• •·······●···•·•••••••••·••●•●·●•●•●•●•●••●●•●●●•●●●•●•●•●•●•●•●•●•●•●•••●••·•••••••····•·•• •●●··•·•·•·•●•●•······· ··•·●●•·•·•···· · ··•·· · · ··· ···· • ••·•· • ·•· · · · ·•·•··•·● • ····· ·•· • • ···•••··•·●·••••••••••••●•●•●•●•●•●•●•●•●•●•●•••●•●•·•●·●••·••··•·•••·● •·•·••••···•·•·•• ·•●••·· · • ● •·•··•····•···· · ·•• · · ····· · ······· · · ····•·•·●•●·· ····•··●·••••••·●•••·•••••●•●•·•••●·•·●·•·•··•●••·●•••●•●•●•••●●●●●•●●●●●•●•●•●••••·•·••··•••••·••·••·••··•·•·•••·•······•●••···•·····•·• ●·•·•••·•·· · · ··•···· · · ····· · ··· •·••········· • · ·····•·····••·•·•·•·•••·•·•···· •·•···•·•••••••••••··•●·●•●•••●•●••••••••••········ ··•··•··· ··•·•·•·•·•·· •·• · ·•••· ··•·· · · · ····• ●·• · ··· · · · •••·•••·· · · · · •·●·•·•·•···•·····••·••·• •·•·●••·•·•••••·•••·●····•····●••·••••••●••·•●●•●●●•●●●•●·••●•••●••···●···· •·•····•··•·•••••·•·•·•·●·●•●••••···•·····•·· ·•·••·••••··· · ··· · · · · ··•·•••·· · •●·•·· ··· ····· ··•···· • ··●·•·•···•···•·•··•··●·······•••••••••••···●●●•●•●•●●●••••••••••••····•· ···•···•· ··•••··••···· ···•●••••••·•···· · ••••· ····•• · · · ··· · · · ····· · · ··· · · · •·••········••···•••·•••·●·•···•••·•·••●·•••·•·• ···••···●·•·●•••●•••●·•●●●●●●●●●●•●•●•••●•••••●······ •·•·· ····•·•·●·•·••······••●•●••••·•··•····•·· · ····•·• • ······· · · · · ••····· · ···· •••••·•·• ···•··•·•···•···•··•··· ··•···· ··••••••••••••●•●•●•●●●••••••••••••••·· ·•· ··•·•·· ·····•····• · •·• ····•••••·••· ··· ·•· · · · ··• · · · · ····• · · · · · •·········••··•·•••·•·•·•··••·•·●••••·•·•••···········●·· ·•••••••••••●●●●●●●●●●●•●·••••••●••••·●···· •·•···●·•···•••···• •••·· ··•·•·•••••·· ··· · ··· · ··•· •· · ··· · · · · · · ···· ·· ········· · · ····•·· ······•····••·······●·········••••••••••••●●●•●●●•●●●•••••••••••••·•• ····•···• ····•·• ··· •·······•···•·•••·· · •·· · · · · ··· · · · · · · ··· · · · ··· · · ·••·· · ··•·•·····• · · ····●•••••··•·•·•···•••·•···•···•····•· ••••••••●•••●●●●●●●●●●●·●•••••••●•●·•···•••·•····•··•••••·•••·•·•·• ··•·••••●••·· ······· •······ · •·• · ··· · · ·· · · · · · · · ··•·· · · · · ···•••••••· •·····•···•·•·········· ··· •••·•••·••●•●•●•●●●•●••••••••••••·•·•·········· ···••·· ··•·····•·······•••···· · ··· · ··•· · · · ··• · · · ··• · · ··· ·· ····•······ ····•·•·• · · · · ··●•●•●•• ··•••··•··•·•••·••·····•·•· ··••••••••●•●●●●●●●●●●●•••••••●••••••····••·•···•···•·•·•·•·•·•···• ··•••••·•·•·· ··•·····•· · · · · •······ ··•·•• · ·• · · ·· ··•········ · · · · · · ·••·•••···· •·•······••···•·•····•· · ··••••••••●•●•●●●•●●●••••••••••••·•••···●···●····••·······•·•·•·•·· ··•·•······ ··· · ·· · · ··· · ···••·• · · · •·· · · · · · ··•••••··••·· · · · · · ··••••●••·•·•·••·••·•·●••••···· ·•··· ····••••●•●•●●●●●●●●●●●•••••●•●•●•••●••·●·•·••·•• ••·••·•·•••••·•••···· •••·•·• ····• •···· · · · ····•·· ····••●• · · ·· · •·· · · · · · · · •••••••·····•······••·•···· •·· · · · •·••••••●•●•●•●●●•●●••••••••••·••••·•····•·•●·· · •··••·•·•···········••··• · · · ··· · · ··•·· ··· · · · · · · · · · · · •······ · · · · ····••••●••·•·•··••·●·•·•••···· ····●·· ··••••●•●●●●●●●●●●●●●•●•●•••●••·●••••••·●•··●•• ··●•●···•••·•···• · · ··•·•·· ····• ··· · · · ··••• · ···· · · ·•·· · · · · · · ··•·•••·•·····●·······•·•··•· ····· ··· ··•·••••●•●•●●●•●•●••••••••••••••••·••· ···•••· ··•···•·•·····•·· · · ····••····· •·· · ····• ·•·· · · · · · · · · · · · · ·••········ · · ······•••••••·•·••········•·●·····•·•·· ··· ··••●•●●●●●●●●●●●●●•●●••●••••·••●•••●···•·●••·●·•··••••••·•·•·· · · ··•••••••···· · •···•·· · · ··••• ··••• · · · ··· ····· · ······•·•·•·•·•·•·•·•···· •····•····· · · · · ··••••●•●•●•●●●•●●•••••••••··••••·••···•·●●•·•······•········ · · · ··•······ · ··· · · ··• ·••·· · · · · · · · · · · ·••·· ··•·•·······•·•·•·•••••••·••··•·····●••·•·•·•······ ··· ••●•●●●●●●●●●●●●●•●•●•••••●·•••••••·●•··●●●···●·•·•••···•·· · · ··•·••·••···•·····•···· · · ··•·●•··· · · · ·••·· ···•·········•·•···•••••·•·●····•· ·•●·●·•·•·· ·•· · · · ·•••●•●•●●●•●●●•●••••••·•••••••·•••·•··•●•·•····•·•········ · ····•·········· · ·•·· · ··•·· ·· · · · · · · · · · · · · · · · •···· •·•·· · ··•·•·•·•·•••••••·•·····•·●·●•••●·•·· ··• ········●•●●●●●●●●●●●●●•●••••••••·••••••●·•·••●●●··••·•·•·•·•·••••· ··•·•••·•·•·•·•·•·· · ····· · ····· · ··• · · · · •·· · ····· ··· ··•·····•••·•·•··•· ···•·•●···•·· ···•· ··· ···•••●•●●●•●●●•●●●•••••••••··•·•••·•·•··●●•······•·•·•···•·• · ····•·············· ·· · · · · · · · · · · ······· ·••·· · · ··•·•·• · ··· •·•·•••••••·•······•●•·••·•·····●·······•·••●●●•●●●●●●●●●•●•••••●••·●•••••••••••●●●···•·•·•••••·•·••····• ··· · ··•·•···•·· ··· · · · · · · · · ····· ··· · ··•·· ····· · ····•·•·· · · ····•·•••·•••··•· ·•●•●···•·•···· · ········●•●•●•●●●•●•●•••●·•••••••••••••·•····•●●●·····•·•·····•·•······ · ····•••······ · · · ·· · · ··•·•······ ····••• · •·•·· · · ··••••· ··· • •·•·•·••••●••·•·· ·•●●•···•••·•·····•·•·•••●●•●•●●●●●●●●●•●●••●•••●·•••••••••·•·●●●··•··•••·•·•·•·•·•·•·•··•· · ··•••·•·· ···•····· · ····· · · · ·· ··• · ··• ·• · · · · ··••· · ······•···•·•••••••·· · ••· ····•·•·· · ··•···•·●•●••●●•●•●•●●••●·•••••··••·•••·••··•●●•·•· ··•·······•···•·· ··• · · ··•·•· · · ··· · · · · ····• · · · •···••· ··•·· · · · ··•••·· ······•···•••••••••··•· ·•●·• ··•·•·· ····•···●••●●•●•●●●•●●●●●•●••••••••·●•••●·•·●·••●●●··•··••··•·•·•·•·•·· ····· ····••• · · · · ····· · · · ··· · · · ····•· · ·•·•· •·· · · ····•·· ··• ··•·····•·•·•·•·•·● · ●•· · ··•·•·· · ··•···•·●•●•●•●●●•●•●•••●·•·•••••·•••••••···••●●·•··········•·····• · · · ··•·•·•·· · · · · · ··· · ····••• ·•· · · ··· · · ·••·· ··• · ··•·····•···•·•·•••·•·•••••••·· ·●●·····•·•·•···········•●●•●●●●●•●●●●●•●●••••••●·●•••••••●·●•●●●·· ··•·•·•·•••·•·•·• · · · •·•••·· · · · · ····· · · ··•·· · ··· •·•·•· • · ···· ·· · · · · · ··•·•·•·· •·····•·•·•·· • ●●· · ···••·•·•·•·•·•···••●•●•●••●●•●••••••••••••·●••••••·•·•●●·•·· ······•·•···•·•·· ··· · ··•···· · · · · · · · · · ····· ··••• ··••· · · · · •········ · ····· ····•••·•••·•···•·•••••·· ·●●·● ··•·•••••••·•••·•••·••••••••●•●•●•●•●•●•●•●•••●•●••••••·●••••···•···•·•·•·•·•·•·· · ··· ··•···· · · · · •·· ····· · ··•·•·· ···•• ••· · ••······ · ··· ··· ··• • · · •···•·•·•···· · ●••·····•···•···· ··· ··· ····•·•·•••••••••••·•••·●••·•••·•·•••·●·········•·•···•···· ··· ··· ··• · · · · ·· · · · · · ··· · •·· · • · · · · · · ··•···· · ··· · · · •·•·•·· · ··•·•••••••·•••··●●••···•···•·•·····●●●•●•●•●●●●●●●•●●●•●●●●●•••••••••••••••••●●●●•·•·•·•·•·•••·•·•·•••·•·······•·· ··· · · · •···· · ··•·•·• · · · · · · •·· · · · · · ··• ··• · · ··•·•••·•······ ●●•··•······•···· ●•●•••••●•●•●•●•●•●•●•●•●••••·•••·•·•·•••·••●•●····••···•·••········•···· ··•·· · · · · · · ··•·•·· · · · · ·· ····· ·••·· ··· •·· ····•····•· ····•••·•·•••·•·••·●●•·•··•·•·•·•·· ·•●•●•●•●•●•●●●•●•●●●•●●●●●••••••·•••••••·••●●●●●···•·•·•·•••••·•·•·•········ · · · · · ··· ··· · ··••• · · · · · · ·· ····· ··· · ···· ··•·• •·•·······•·· · · •·•·····•·······●•●···•·•·•·•···· ••●•••●•●•●•●●●•●•●•●•●•●••·•·•··••••••·•·••●•●•········•·•·•······ · · ··· · · · · ··· · ··· · ··• · · · · ····•·•·•·• · · •···••●••·· · · ····•·•···· ·•••••••••··•·•·•●●●•·•·•••·•·•·•·●•●●●•●•●•●•●●●•●•●●●•●●●●●••·•·•·•••••••·••●•●●●·•·•·•·•·•••·•·•·•·· · ··• · ··· ······· ··· •·····••· · ··•·· · · ····•••· · ·· ·••·•· · · · ··•·•·· ··• ·••···•••······•●•●•··•·•·•······•••●•••••●••●●•●•••●•●•●•●••••·•·•·•••·•••·••●•●•····•·········•·•·· · ····· · ···· · · ·•···· · ··• ··· • ······ · · ······· · · · ····· ····••······· •·•·•••·•···•·●●●●•·•·•·•······•●•●•●•●•●•●•●●●•●•●●●•●●●●●•●•●·••••●•••●•••●●●•●·•·•••·•·•·•·•••·•·· ··•·•·· · ······· ····· ······••· · · · · · · ··· ··••··•···•·· · · · · · · ··• · •·•·•·····•·••· ·•·•●•●••·•·•···· ··●••●●•●•●•●•●•●•●•●•●•●●●•●●●•••••••●•••••••••●●●••·•·•·•···•···•···• ··•·•·· · · ··•·· · ·• •· · •· · ····• · ··●•• •·•··••·· · ··· •·· · · · ··•···•···•••••••·•••·····●●●●•••·•·•·····●•●•●•●•●•●•●●●●●●●●●●●●●●●●●●●•●•••••●•●•●•●•●●●●●•●••••••·•·•·•••••·•·•·••• ······•••·•·· ●•· ·····•• · · · · · ••·•·•· · ···· ·•••• · ··•·• · · •·•·•·•·•·•·· · ·•●●●••·•···· • ·•●•●•••●•●•●•●•●•●•●•●•●•●•●•●•••●·•·••••••••••●•●••••••••·•·•·•·••··• ····•·· · ··•······ · · ··· · ·· · · •·●••·•···· · · · •·•·· ··••●•●·· · ····•·• ·•· ··•·•·•·•·•·• · ··●●●●●·•·•·······●•●•●•●•●•●●●●●●●•●•●•●•●•●●●•●•●•••••••••••••●●●•●•●•●•●••••••••••·••· ··•·· · · ··•••·•·· ··· ·••·· ·•●•· · ··•· · •• · · ••·· ·••••· ········· · · ······•···•·· · ·●●•●·•·•·· ·····•••●•●•●•●•●•●•●•●•●•●•●•●•●•●•••●·•·•·••••••••●•●•••●•●•●••••·•·••·•· ··•·· · · ··••●••·• ·· •·· ·••· ··• · ● · ·· · · · · •···· ··••●•· · ··•·•·• · · ····•·•·•·•·••• ····●●●••••·········●·••●●●●●●●●●•●•●•●•●•●•●•●•●•●•●●•••·•·••••••••●●●•●•●•●•●••••·•••·• · •·· · · ···••·· ·· ··· · ····●•· · · ··•· ·· •·· · · ··•• · ··•·· · · •···· ······•······ ·•●●●·•·• ··· ··••••●•●•●•●•●•●•●•••••••●•●•●•••●•●·•···•·•·•·••●•●••••••••••••••···· · ··· · · · ··●• • · ·· · • · ··· · •• · · · ·••···· ···•· · · · •·• · · ··•·•···•·•••••••·•···●●●●•·•·······•·●•●●●●●●●•●•●•●•●•●•●•●●●•●●●•●•●••••·•·•·••••●●●•●•••●•●•●••••••·•·· ····· · · · · · ·•··· · · •····•· · · · · ·• · ··· · · ··•• ······•·· · ····•···•···•••••••·· ·●●•●······ · ··••••●•●•●•●•••••••●•●•●•●•●•●●●•●•●···· ··•·••••●•●••••••••••••••·••······· · ··· ··· ·● · ···· • · · · · · · · · · · · ••·· · ··••●·●·•·•·•·· · ····••··•·•••••••·•·•··•●●●••·········••●•●●●•●•●•●•●•●•●●●●●●●●●●●●●●●•●●•·•···•••·••••●●●•••••••●•●••••••·•·•·•·· ····· ··· · ·•· · · · ·····•· · ··· ···· · ••·· ·••••●••·•·· · · · ··•·•·····•·•·········●•●●●·········••●•••●•●•●•••●•●•●•●●●•●●●•●•●•●•●•●••···•·•·•·••••●•●·•••••••••••·•·•·•·•·• · · · ··• •·· · ···• ··· ··· · · · •·· · ··•·●••·••·•· · · ····•·•·•·•••·•·•·•·•·••●●●•······•·••●•●•●•●•●•●•●●●●●●●●●•●●●●●●●●●●●•●••••·•••••·•·••●●●●•·••••••••●••••••••············· · · •·• · · ······· · · ····•• •• · •· · ···· · ·• • ···· · · · ····•···•···•···•···•·•●●•● ····•·••●•●•••●•●•●•●•●•●•●●●•●●●•●•●•●●●•••●·•·•••·•···•·••●•●••·•·•••••••••••••···· · · · ··· · •••• •·· · ····••• • ··· · · ··· · •···· ····• · ··•···· ······•·•···•·•·•••·•••·•··•●●●•····••••●•●•●•••●●●•●●●●●●●●●●●•●●●●●●●●●●••●••••••••••·••••●●●●•·•••••·•••••••·●••·•··········•• ••●•• · · ·••···· ······••●• • · · · · · ··· · ··· · · • · ······· · ······•·•·•·····••●●• ··•·••●•••●•••••●•●•●•●•●•●•●●●•●●●•●●●•●••••·•·•••·······••●●●···•·•·•·•·•·•·•••·•········ · ••· ••● ·· · · ··••• • ······•••·•····••·· · · · · · ······•·•·· · ·••·•••••••••·•·••●•●···••••●•●•••●•●•●●●●●•●●●•●●●●●●●●●●●●●●●●●••••·•••••·•·•·••●●●●•·•·•••••·•••·•••·•·•·•·•·•· ··• ·•••● · · •···· · · ··●• · • ·•••••·· •·· · · · · · ··•·••• · · ·••·•·•·•·•••·•·•●●•····••●•••••••●•••●•●•●•●•●•●●●•●●●•●●●•●●●••·●·•·•·•·•···•·••●•●·•····••·•·•·•••••·•••···•·• ·•··••●•••• · · ·· · ·• • · · ••••●• ······· · · ··· · · ··•·•·••••· ····•••·•·•·•••·•••·●●●·•·••●•●•●•●•●●●•●●●•●●●●●●●●●●●●●●●•●●●•●●●••••••·•••••·••••●●●●•·•·•·●••·•·•••••••·•••·•·••· ··• ••●•• •· · · •···· · · · ··•• ·· ··• •• •·· · · · · · ··· · ··•·• · · ········•·•···•·••●•··••••••••••●•●•••●•●•●•●•●•●•●●●•●•●•●●●•●••·•·●••·•·•···•·••●●●·······•·•·•••••·•·•·•·•·•·· ··•··· ····· ··••● · · ····· ● · •·•·· · ··· · · · · ····•··•• ··· •·•·•·•·•·•••···••●•●·••●•●•●•••●●●•●•●●●●●●●●●•●●●●●●●●●●●●●●●●●••••●●·•·•••·•·••●●●●•·······•·•••••·•••·•·•••·•·· •••·· · · · •·•···· · ····•·•• ··· ·· · · · · ··•·•·•·•···•·•·········•·••····●•●•••••••••••••●••••●●•●•●•●•●•●●●•●●●•●●●•●•●•••●·●·•·•·•·•·•·••●•●·····•··••••·•·•·•···•·•·•···· •· •·•·· · ··•·•·•·• · ··· · · · · •···· · •·•·····•••·•·••··•••·•·•·•·•·•·••··•··●●•●•●•●•●•••••●•●•●•●●●●●●●●●●●•●●●●●●●●●●●●●●●••••••••••••••·••●●●●•·•·•·•·•••·•••·•·•••·•·•·•·•·· · · · ··· ·•·•●·······••••●••• • · ···· · ··•·· · ··•······ ··• •·•·····•••·••••••●•••●•●•●•••●•●•••••●•••●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●••••••••••·•·•·•·•·•···•···•·· · ··· · •·· ··••••● · · ··•·• · · ······· · · ··• · · ··• •·•·· •••·•·•·•·••●·••••••●•●•●●●•●•●•●•●•●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●●●●●●●●●●•●•●•●••••·•·•·•••••·•·•·•·• ··• · · · · ····•······ ··●••· · ···•· · •·· · ·· · · ··· ··•·· ··•••·····•·••••••••●•••●•●•●•••●•••••••●•●●●•●•●•●●●•●●●•●●●•●●●•●●●•●●●•●•●•●•●•●•●•●•●•●•●••••••••••·•·•·•···•···•· ··· · · · · · · •·· ··••● · ··••· · ··· ·••···· · · · ·· · · · · ··• ··•·•••·•·•·••●•●•••●•●•●•●•●•●•●•●•●•●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●●•●•●•●•●•●•••●••·•••·•••·•···•·· ··•·· · · ······· ·•······●•· · · •·• ····•··· · · ··· · · · · ··• ········•·•·••••••••••••••••••••••••●•●•●•●•●●●•●●●•●•●•●•●•●●●•●●●•●●●•●●●•●•●•●•●•••••••••••••••••••●···•·•······ ······ ·· · · ··· · · · · ····•· •·••●••··· · · ··· · · · · ··••·••·•·•·••••••••••••••••●•●•••••••••••●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●•●•●•●•●•••••••••••••••●•●·•·•·•·•·· ··•·• · •·· · · ···••·· ··· · · · · ••·•●••••••·· · · · · · · · ··•·········••••●•●•●•••••••●•••••••••••••••●•••●•●●●•●●●•●●●•●●●•●●●•●•●•●●●•●•●•●•●••••••••••••••••••••••••···•••·· ····· · ••• · ··•·· ····· · ···•●·●•●•·•●·····• · · ··· ··· ··· ··· •·•·•·•·••••••••●•●•●•●•●•●•●•●•●•●•●•••••••●•●•●●●●●●●●●●●•●•●●●●●•●●●•●•●•●•●•●•●•••••●••••••••••••••••••·••●••······ · · •· ··· · · ·······•• · · · · · · •• ·••·· · ··· · · ··· ········•·•·•·•·•·•·•·•·•••••••·•••·•••·•••••••·••●•●•●•●•••●•●•●•●•●•●•••●••••••••••••••••••••••••·•·•·•·•·•·•·••··· · · · · · •·· · · ···· · · •••··· · · ··•·······•···•·•·•·•·••••••••••••••••••••••●•●•●•●•●•●•●•●•••●•●•●•●•●•●•●•●•●•●•●•••●•●•●•••●•●•●•●•●••••••••••••••••••••••••·•·· ··· · · · · · · · ·••·· · ··· · ···· ···· · ····•·· · ········•·•·•·•·•·•·•·•·•·•·•·•·•••••·•·•••·••••••●•••••••••••●•●•●•●•●•●•●••••••••••••••••·•••·•••••••·•·•·•·•·•·•·•·•···•·· · · · · ····· · · ••· · · · •·•···· ··· •·· · ··•·•·•·•·•·•·••••••••••••••••••••••••••••••••••••••••••••••●•••●•••●•••••●••••••••••••••••••••••••••••••••••••••••••••·•·•·• · · ····· · · ··· · · ·••···· · ···· • ••·· · · · ····•···•···•·•·•·•••••••••••·•·•••·•·•·•·•·•·•·•·•·•·•••••·•·•••••••••••·•••·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·······• ··· ··· ·· · · •····· ·••· ··· ●·· •• · •·· · · · · ••· •···•••·•••••·•••••·••••••••●•●•●•●•●••••••·•••·•••••••••••••••••••••••••••·•••••••·•••••••·•••·•••••••·•••••••·•••·•••·•·•·•••·•·•·•· · •·· · ··•·····•·••••●••·•• • •••·•· ···· ·••••·••••··•···•••·•·•·•·•·•·•·•·•·•·•·•·•••••••••••••••••••••••·•·•·•·•·•·•••·•·•·•·•·•••••••••·•·•·•·•••••••·•·•·•·•·•·•·•·•···•·•·•·•·•·•·· • ··· ·· •••••••••·•·•· • ·••••·•·• · •···· ··· ·•●•●•●••••·••• •••••·•·•••••••·•••·•••·•••·•••·•••·•••·••••••••●••••••·•••·•••••••••••·•••••••••••·•••·•••••••·•••·•••·•••·••●••·•·•·•·•·· ·•••• ••●•••· · ·••·••••●••·• · ··•··••••·•· ·· · ·•·•·•·•••••••••·•···••··••●•••●••·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•··••·••●·•·•·· ····•·•·•·•••· ·• •••••••••·• ··••·•·●•●•• •···· ··•···••●•••·•●••···•••··•••●••••••••·•••·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•••·•·•·•••·•·•·•••·•••·•·•·•·•·•·•·•·•·•·•·•·•·•·•••••••···•·●•••• ••••··•••·●••·••••· · · ·• •••••••••●••·· ··•·•·•••••······ · •·•·•••••••·•••·•·•··••••••••••·•••••••••••••••••·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•····••••·•···•·•·•·•·•·•·•···· •·●•••●·••●·•·• · ·•••••••●•●••••···· ··••••••●•●•●•••••••••··●•●•●•●•●•●••·•·•·•·•·•·•••·•·•·•·•·•·•·••••●•••●•••●•••●••••••·•·•·•••••••••••·•·•·•••••••·•·•·•·•••••·••••●•●••·•·•·••••••••••••••··· · ●••••·•·••●•●••·· ·••··· ●•●•●●●•●●●•●●●•●•●•●•●•●●●•●●●•●•●•●•●•●●●•●●●•●●●•●●●•●•●•●•●•●•●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•••●•●•●•●•··• ●•●•●•●•●•●•●•●•●•●•●•· · ··• · ··• ··· · · · ●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●●●●●●●●●●●●●●•●●●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●●•●●●●●●•·•·••●••·●●· ···•●●●●●●●●●●●•●●●•●●●•· · · · · ··• · ·•●●●●●●●●●●●●●●●•●●●·●●●●●●●●●●●··●●•●•●•●●●•●●●•●●●•●●●•●•●•●•●•●•●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●●●•●•●•●·••••●••·•···•·••••· ····●•●•●•●•●•●•●•●•●•●•● · · ··•· · ···· · · · ·●●●●●●●●●●●●●●●●●●●•••●●●●●●●·•· ●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•••·••●•●•••··••●•·······●●●●●●●●●●●●●●●●●●●● ··· · ··•·· ●•●●●●●●●●●●●●●●●•● ··••●●●●· ··●•●●●•●•●•●●●•●●●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•······•·••••· ·•· ····· ●·●•·•●•●•●•●•●•●•●•· ·· ·· · · · · · ●●●●●●●●●●●●●●●●●●●··•●•● ······●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●··•···•·● ··········•••••●•●••●●●•●●●•●●· · ··· ··• · · ●●•●●●●●●●●●●•·•••···•·· · ·····●●●●●●•●●●●●●●●●●●●●●●●●●●•●●●•●●●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●●●•●●●•●●●•●●●•●●●•●•●•●•●•●•●•●•····· ··· ··· ··•·•••••••••·••●•●•●•●•● · ··· •·· · · · ··· · · ·●●●●●●●●●●●●··•••●·•·•·····•···●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●··········•···••●•••●•●·••●••·●●●●●●●·· · ··· · ··· · ··· · ●●●●●●●●●●●●●●· ······· ····•·•●•●••●●●•●●●●●●●•●●●●●●●•●•●•●•●•●•●•●●●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•· ··· · · · ··•·•••·•·•·•·•·••●•●•●•· · ·· ··· · · ··•• · · · ●●●●●●●●●●●●● · ····•···•••·●·•·••●••●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●•●········ ·••·•••·●•·•·•·•··•·●●●●· · · · · ··· · ··•••· · · ●●●●●●●●●●●●●·· ·······••·•·•·•••••••·●•●●●●●●●●●●●●●●●•●●●•●●●•●●●•●●●●●●●•●●●•●●●•●●●•●●●•●●●•●●●•●●●•●●●•●●●•●•●•●•●•●•••●•●•●•· ··· ··· •••·•••••••·• ••··●•●•● · · · · · · ····••●•··· · · · · ●●●●●●●●●●●•● ·······•●•●•••••••●•●••●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●•●●●•●·•·•···• ···•••••●•●•●•·•●••●●●●●● · ··· ··· ·· · · ····•••● · ●●●●●●●●•●•·· · ··· ••●···••••••·••·•·●●●●●●●●●●●●●●●●●•●•●•●•●•●●●•●●●•●•●•●•●•●•●•●•●•●••·••●•●•●•••●•●•●·●•●•●•●•●••••••·•·•···● · · · ··•·•••·●·•·••••●·●•●• · · · ····· · ··●•● · · · · ·●●●●●••●•●•• · ·····•●••···●·●•••●·●•●••·•●●●●●●●●●●●●●●●●●●•●•●•●•●●●●●●●●●●●●●●●●●●●●●•●•••●•●•●•●•••●•●•●•●●●●●●●·●•●••·•·•●··•······ · ····•·•••••·●•••••●• · ······· ··· · ·•● · · · ●●●·●••●•···········•·•·•·•·• •·•·•·●·••●·••••●●●●●●●●●•●•●•●•••●•●••●●●●•●●●•●●●•●•●•●•●•••●•●••·•·•·••●••·●••●●•●●●···· ·•·•········· · ··· ····••·•·•••••••• ······· ··•· · · · •·· · ··· ··· ··●●●·●·•·•···· ······•·●•• •·········•·•·••●••••●●•●•●•●●●●●•●•●●●•●•••●●●●●●●●●●●•●•●•●•●•●•●•••••••••●•••●•••••●●••··••·•····●········ ·••···•·•••·••••••••●•· · ··• · •·••· ·· · ·· •·•·· · ··· ·•· • · ····••·•·•··● ·•··· ····•·•·••••●•●•●•●•••●•●•●••·●•●•●•●•●•●•●•●•●•●•●•●••·•••·●·••••●••·•·●••·•······ · • · •··•··••••· · ··· ····••• •·• · · · ··· • · ··· · · ··· · ·••·• ·•······· •···· ··•·••·•●·• •·······●···•·•••••••••·••●•●·●•●•●•●•●••●●•●●●•●●●•●•●•●•●•●•●•●•●•●•••●••·•••••••····•·•• •●●··•·•·•·•●•●•······· ··•·●●•·•·•···· · ··•·· · · ··· ···· • ••·•· • ·•· · · · ·•·•··•·● • ····· ·•· • • ···•••··•·●·••••••••••••●•●•●•●•●•●•●•●•●•●•●•••●•●•·•●·●••·••··•·•••·● •·•·••••···•·•·•• ·•●••·· · • ● •·•··•····•···· · ·•• · · ····· · ······· · · ····•·•·●•●·· ····•··●·••••••·●•••·•••••●•●•·•••●·•·●·•·•··•●••·●•••●•●•●•••●●●●●•●●●●●•●•●•●••••·•·••··•••••·••·••·••··•·•·•••·•······•●••···•·····•·• ●·•·•••·•·· · · ··•···· · · ····· · ··· •·••········· • · ·····•·····••·•·•·•·•••·•·•···· •·•···•·•••••••••••··•●·●•●•••●•●••••••••••········ ··•··•··· ··•·•·•·•·•·· •·• · ·•••· ··•·· · · · ····• ●·• · ··· · · · •••·•••·· · · · · •·●·•·•·•···•·····••·••·• •·•·●••·•·•••••·•••·●····•····●••·••••••●••·•●●•●●●•●●●•●·••●•••●••···●···· •·•····•··•·•••••·•·•·•·●·●•●••••···•·····•·· ·•·••·••••··· · ··· · · · · ··•·•••·· · •●·•·· ··· ····· ··•···· • ··●·•·•···•···•·•··•··●·······•••••••••••···●●●•●•●•●●●••••••••••••····•· ···•···•· ··•••··••···· ···•●••••••·•···· · ••••· ····•• · · · ··· · · · ····· · · ··· · · · •·••········••···•••·•••·●·•···•••·•·••●·•••·•·• ···••···●·•·●•••●•••●·•●●●●●●●●●●•●•●•••●•••••●······ •·•·· ····•·•·●·•·••······••●•●••••·•··•····•·· · ····•·• • ······· · · · · ••····· · ···· •••••·•·• ···•··•·•···•···•··•··· ··•···· ··••••••••••••●•●•●•●●●••••••••••••••·· ·•· ··•·•·· ·····•····• · •·• ····•••••·••· ··· ·•· · · · ··• · · · · ····• · · · · · •·········••··•·•••·•·•·•··••·•·●••••·•·•••···········●·· ·•••••••••••●●●●●●●●●●●•●·••••••●••••·●···· •·•···●·•···•••···• •••·· ··•·•·•••••·· ··· · ··· · ··•· •· · ··· · · · · · · ···· ·· ········· · · ····•·· ······•····••·······●·········••••••••••••●●●•●●●•●●●•••••••••••••·•• ····•···• ····•·• ··· •·······•···•·•••·· · •·· · · · · ··· · · · · · · ··· · · · ··· · · ·••·· · ··•·•·····• · · ····●•••••··•·•·•···•••·•···•···•····•· ••••••••●•••●●●●●●●●●●●·●•••••••●•●·•···•••·•····•··•••••·•••·•·•·• ··•·••••●••·· ······· •······ · •·• · ··· · · ·· · · · · · · · ··•·· · · · · ···•••••••· •·····•···•·•·········· ··· •••·•••·••●•●•●•●●●•●••••••••••••·•·•·········· ···••·· ··•·····•·······•••···· · ··· · ··•· · · · ··• · · · ··• · · ··· ·· ····•······ ····•·•·• · · · · ··●•●•●•• ··•••··•··•·•••·••·····•·•· ··••••••••●•●●●●●●●●●●●•••••••●••••••····••·•···•···•·•·•·•·•·•···• ··•••••·•·•·· ··•·····•· · · · · •······ ··•·•• · ·• · · ·· ··•········ · · · · · · ·••·•••···· •·•······••···•·•····•· · ··••••••••●•●•●●●•●●●••••••••••••·•••···●···●····••·······•·•·•·•·· ··•·•······ ··· · ·· · · ··· · ···••·• · · · •·· · · · · · ··•••••··••·· · · · · · ··••••●••·•·•·••·••·•·●••••···· ·•··· ····••••●•●•●●●●●●●●●●●•••••●•●•●•••●••·●·•·••·•• ••·••·•·•••••·•••···· •••·•·• ····• •···· · · · ····•·· ····••●• · · ·· · •·· · · · · · · · •••••••·····•······••·•···· •·· · · · •·••••••●•●•●•●●●•●●••••••••••·••••·•····•·•●·· · •··••·•·•···········••··• · · · ··· · · ··•·· ··· · · · · · · · · · · · •······ · · · · ····••••●••·•·•··••·●·•·•••···· ····●·· ··••••●•●●●●●●●●●●●●●•●•●•••●••·●••••••·●•··●•• ··●•●···•••·•···• · · ··•·•·· ····• ··· · · · ··••• · ···· · · ·•·· · · · · · · ··•·•••·•·····●·······•·•··•· ····· ··· ··•·••••●•●•●●●•●•●••••••••••••••••·••· ···•••· ··•···•·•·····•·· · · ····••····· •·· · ····• ·•·· · · · · · · · · · · · · ·••········ · · ······•••••••·•·••········•·●·····•·•·· ··· ··••●•●●●●●●●●●●●●●•●●••●••••·••●•••●···•·●••·●·•··••••••·•·•·· · · ··•••••••···· · •···•·· · · ··••• ··••• · · · ··· ····· · ······•·•·•·•·•·•·•·•···· •····•····· · · · · ··••••●•●•●•●●●•●●•••••••••··••••·••···•·●●•·•······•········ · · · ··•······ · ··· · · ··• ·••·· · · · · · · · · · · ·••·· ··•·•·······•·•·•·•••••••·••··•·····●••·•·•·•······ ··· ••●•●●●●●●●●●●●●●•●•●•••••●·•••••••·●•··●●●···●·•·•••···•·· · · ··•·••·••···•·····•···· · · ··•·●•··· · · · ·••·· ···•·········•·•···•••••·•·●····•· ·•●·●·•·•·· ·•· · · · ·•••●•●•●●●•●●●•●••••••·•••••••·•••·•··•●•·•····•·•········ · ····•·········· · ·•·· · ··•·· ·· · · · · · · · · · · · · · · · •···· •·•·· · ··•·•·•·•·•••••••·•·····•·●·●•••●·•·· ··• ········●•●●●●●●●●●●●●●•●••••••••·••••••●·•·••●●●··••·•·•·•·•·••••· ··•·•••·•·•·•·•·•·· · ····· · ····· · ··• · · · · •·· · ····· ··· ··•·····•••·•·•··•· ···•·•●···•·· ···•· ··· ···•••●•●●●•●●●•●●●•••••••••··•·•••·•·•··●●•······•·•·•···•·• · ····•·············· ·· · · · · · · · · · · ······· ·••·· · · ··•·•·• · ··· •·•·•••••••·•······•●•·••·•·····●·······•·••●●●•●●●●●●●●●•●•••••●••·●•••••••••••●●●···•·•·•••••·•·••····• ··· · ··•·•···•·· ··· · · · · · · · · ····· ··· · ··•·· ····· · ····•·•·· · · ····•·•••·•••··•· ·•●•●···•·•···· · ········●•●•●•●●●•●•●•••●·•••••••••••••·•····•●●●·····•·•·····•·•······ · ····•••······ · · · ·· · · ··•·•······ ····••• · •·•·· · · ··••••· ··· • •·•·•·••••●••·•·· ·•●●•···•••·•·····•·•·•••●●•●•●●●●●●●●●•●●••●•••●·•••••••••·•·●●●··•··•••·•·•·•·•·•·•·•··•· · ··•••·•·· ···•····· · ····· · · · ·· ··• · ··• ·• · · · · ··••· · ······•···•·•••••••·· · ••· ····•·•·· · ··•···•·●•●••●●•●•●•●●••●·•••••··••·•••·••··•●●•·•· ··•·······•···•·· ··• · · ··•·•· · · ··· · · · · ····• · · · •···••· ··•·· · · · ··•••·· ······•···•••••••••··•· ·•●·• ··•·•·· ····•···●••●●•●•●●●•●●●●●•●••••••••·●•••●·•·●·••●●●··•··••··•·•·•·•·•·· ····· ····••• · · · · ····· · · · ··· · · · ····•· · ·•·•· •·· · · ····•·· ··• ··•·····•·•·•·•·•·● · ●•· · ··•·•·· · ··•···•·●•●•●•●●●•●•●•••●·•·•••••·•••••••···••●●·•··········•·····• · · · ··•·•·•·· · · · · · ··· · ····••• ·•· · · ··· · · ·••·· ··• · ··•·····•···•·•·•••·•·•••••••·· ·●●·····•·•·•···········•●●•●●●●●•●●●●●•●●••••••●·●•••••••●·●•●●●·· ··•·•·•·•••·•·•·• · · · •·•••·· · · · · ····· · · ··•·· · ··· •·•·•· • · ···· ·· · · · · · ··•·•·•·· •·····•·•·•·· • ●●· · ···••·•·•·•·•·•···••●•●•●••●●•●••••••••••••·●••••••·•·•●●·•·· ······•·•···•·•·· ··· · ··•···· · · · · · · · · · ····· ··••• ··••· · · · · •········ · ····· ····•••·•••·•···•·•••••·· ·●●·● ··•·•••••••·•••·•••·••••••••●•●•●•●•●•●•●•●•••●•●••••••·●••••···•···•·•·•·•·•·•·· · ··· ··•···· · · · · •·· ····· · ··•·•·· ···•• ••· · ••······ · ··· ··· ··• • · · •···•·•·•···· · ●••·····•···•···· ··· ··· ····•·•·•••••••••••·•••·●••·•••·•·•••·●·········•·•···•···· ··· ··· ··• · · · · ·· · · · · · ··· · •·· · • · · · · · · ··•···· · ··· · · · •·•·•·· · ··•·•••••••·•••··●●••···•···•·•·····●●●•●•●•●●●●●●●•●●●•●●●●●•••••••••••••••••●●●●•·•·•·•·•·•••·•·•·•••·•·······•·· ··· · · · •···· · ··•·•·• · · · · · · •·· · · · · · ··• ··• · · ··•·•••·•······ ●●•··•······•···· ●•●•••••●•●•●•●•●•●•●•●•●••••·•••·•·•·•••·••●•●····••···•·••········•···· ··•·· · · · · · · ··•·•·· · · · · ·· ····· ·••·· ··· •·· ····•····•· ····•••·•·•••·•·••·●●•·•··•·•·•·•·· ·•●•●•●•●•●•●●●•●•●●●•●●●●●••••••·•••••••·••●●●●●···•·•·•·•••••·•·•·•········ · · · · · ··· ··· · ··••• · · · · · · ·· ····· ··· · ···· ··•·• •·•·······•·· · · •·•·····•·······●•●···•·•·•·•···· ••●•••●•●•●•●●●•●•●•●•●•●••·•·•··••••••·•·••●•●•········•·•·•······ · · ··· · · · · ··· · ··· · ··• · · · · ····•·•·•·• · · •···••●••·· · · ····•·•···· ·•••••••••··•·•·•●●●•·•·•••·•·•·•·●•●●●•●•●•●•●●●•●•●●●•●●●●●••·•·•·•••••••·••●•●●●·•·•·•·•·•••·•·•·•·· · ··• · ··· ······· ··· •·····••· · ··•·· · · ····•••· · ·· ·••·•· · · · ··•·•·· ··• ·••···•••······•●•●•··•·•·•······•••●•••••●••●●•●•••●•●•●•●••••·•·•·•••·•••·••●•●•····•·········•·•·· · ····· · ···· · · ·•···· · ··• ··· • ······ · · ······· · · · ····· ····••······· •·•·•••·•···•·●●●●•·•·•·•······•●•●•●•●•●•●•●●●•●•●●●•●●●●●•●•●·••••●•••●•••●●●•●·•·•••·•·•·•·•••·•·· ··•·•·· · ······· ····· ······••· · · · · · · ··· ··••··•···•·· · · · · · · ··• · •·•·•·····•·••· ·•·•●•●••·•·•···· ··●••●●•●•●•●•●•●•●•●•●•●●●•●●●•••••••●•••••••••●●●••·•·•·•···•···•···• ··•·•·· · · ··•·· · ·• •· · •· · ····• · ··●•• •·•··••·· · ··· •·· · · · ··•···•···•••••••·•••·····●●●●•••·•·•·····●•●•●•●•●•●•●●●●●●●●●●●●●●●●●●●•●•••••●•●•●•●•●●●●●•●••••••·•·•·•••••·•·•·••• ······•••·•·· ●•· ·····•• · · · · · ••·•·•· · ···· ·•••• · ··•·• · · •·•·•·•·•·•·· · ·•●●●••·•···· • ·•●•●•••●•●•●•●•●•●•●•●•●•●•●•●•••●·•·••••••••••●•●••••••••·•·•·•·••··• ····•·· · ··•······ · · ··· · ·· · · •·●••·•···· · · · •·•·· ··••●•●·· · ····•·• ·•· ··•·•·•·•·•·• · ··●●●●●·•·•·······●•●•●•●•●•●●●●●●●•●•●•●•●•●●●•●•●•••••••••••••●●●•●•●•●•●••••••••••·••· ··•·· · · ··•••·•·· ··· ·••·· ·•●•· · ··•· · •• · · ••·· ·••••· ········· · · ······•···•·· · ·●●•●·•·•·· ·····•••●•●•●•●•●•●•●•●•●•●•●•●•●•●•••●·•·•·••••••••●•●•••●•●•●••••·•·••·•· ··•·· · · ··••●••·• ·· •·· ·••· ··• · ● · ·· · · · · •···· ··••●•· · ··•·•·• · · ····•·•·•·•·••• ····●●●••••·········●·••●●●●●●●●●•●•●•●•●•●•●•●•●•●•●●•••·•·••••••••●●●•●•●•●•●••••·•••·• · •·· · · ···••·· ·· ··· · ····●•· · · ··•· ·· •·· · · ··•• · ··•·· · · •···· ······•······ ·•●●●·•·• ··· ··••••●•●•●•●•●•●•●•••••••●•●•●•••●•●·•···•·•·•·••●•●••••••••••••••···· · ··· · · · ··●• • · ·· · • · ··· · •• · · · ·••···· ···•· · · · •·• · · ··•·•···•·•••••••·•···●●●●•·•·······•·●•●●●●●●●•●•●•●•●•●•●•●●●•●●●•●•●••••·•·•·••••●●●•●•••●•●•●••••••·•·· ····· · · · · · ·•··· · · •····•· · · · · ·• · ··· · · ··•• ······•·· · ····•···•···•••••••·· ·●●•●······ · ··••••●•●•●•●•••••••●•●•●•●•●•●●●•●•●···· ··•·••••●•●••••••••••••••·••······· · ··· ··· ·● · ···· • · · · · · · · · · · · ••·· · ··••●·●·•·•·•·· · ····••··•·•••••••·•·•··•●●●••·········••●•●●●•●•●•●•●•●•●●●●●●●●●●●●●●●•●●•·•···•••·••••●●●•••••••●•●••••••·•·•·•·· ····· ··· · ·•· · · · ·····•· · ··· ···· · ••·· ·••••●••·•·· · · · ··•·•·····•·•·········●•●●●·········••●•••●•●•●•••●•●•●•●●●•●●●•●•●•●•●•●••···•·•·•·••••●•●·•••••••••••·•·•·•·•·• · · · ··• •·· · ···• ··· ··· · · · •·· · ··•·●••·••·•· · · ····•·•·•·•••·•·•·•·•·••●●●•······•·••●•●•●•●•●•●•●●●●●●●●●•●●●●●●●●●●●•●••••·•••••·•·••●●●●•·••••••••●••••••••············· · · •·• · · ······· · · ····•• •• · •· · ···· · ·• • ···· · · · ····•···•···•···•···•·•●●•● ····•·••●•●•••●•●•●•●•●•●•●●●•●●●•●•●•●●●•••●·•·•••·•···•·••●•●••·•·•••••••••••••···· · · · ··· · •••• •·· · ····••• • ··· · · ··· · •···· ····• · ··•···· ······•·•···•·•·•••·•••·•··•●●●•····••••●•●•●•••●●●•●●●●●●●●●●●•●●●●●●●●●●••●••••••••••·••••●●●●•·•••••·•••••••·●••·•··········•• ••●•• · · ·••···· ······••●• • · · · · · ··· · ··· · · • · ······· · ······•·•·•·····••●●• ··•·••●•••●•••••●•●•●•●•●•●•●●●•●●●•●●●•●••••·•·•••·······••●●●···•·•·•·•·•·•·•••·•········ · ••· ••● ·· · · ··••• • ······•••·•····••·· · · · · · ······•·•·· · ·••·•••••••••·•·••●•●···••••●•●•••●•●•●●●●●•●●●•●●●●●●●●●●●●●●●●●••••·•••••·•·•·••●●●●•·•·•••••·•••·•••·•·•·•·•·•· ··• ·•••● · · •···· · · ··●• · • ·•••••·· •·· · · · · · ··•·••• · · ·••·•·•·•·•••·•·•●●•····••●•••••••●•••●•●•●•●•●•●●●•●●●•●●●•●●●••·●·•·•·•·•···•·••●•●·•····••·•·•·•••••·•••···•·• ·•··••●•••• · · ·· · ·• • · · ••••●• ······· · · ··· · · ··•·•·••••· ····•••·•·•·•••·•••·●●●·•·••●•●•●•●•●●●•●●●•●●●●●●●●●●●●●●●•●●●•●●●••••••·•••••·••••●●●●•·•·•·●••·•·•••••••·•••·•·••· ··• ••●•• •· · · •···· · · · ··•• ·· ··• •• •·· · · · · · ··· · ··•·• · · ········•·•···•·••●•··••••••••••●•●•••●•●•●•●•●•●•●●●•●•●•●●●•●••·•·●••·•·•···•·••●●●·······•·•·•••••·•·•·•·•·•·· ··•··· ····· ··••● · · ····· ● · •·•·· · ··· · · · · ····•··•• ··· •·•·•·•·•·•••···••●•●·••●•●•●•••●●●•●•●●●●●●●●●•●●●●●●●●●●●●●●●●●••••●●·•·•••·•·••●●●●•·······•·•••••·•••·•·•••·•·· •••·· · · · •·•···· · ····•·•• ··· ·· · · · · ··•·•·•·•···•·•·········•·••····●•●•••••••••••••●••••●●•●•●•●•●•●●●•●●●•●●●•●•●•••●·●·•·•·•·•·•·••●•●·····•··••••·•·•·•···•·•·•···· •· •·•·· · ··•·•·•·• · ··· · · · · •···· · •·•·····•••·•·••··•••·•·•·•·•·•·••··•··●●•●•●•●•●•••••●•●•●•●●●●●●●●●●●•●●●●●●●●●●●●●●●••••••••••••••·••●●●●•·•·•·•·•••·•••·•·•••·•·•·•·•·· · · · ··· ·•·•●·······••••●••• • · ···· · ··•·· · ··•······ ··• •·•·····•••·••••••●•••●•●•●•••●•●•••••●•••●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●•●••••••••••·•·•·•·•·•···•···•·· · ··· · •·· ··••••● · · ··•·• · · ······· · · ··• · · ··• •·•·· •••·•·•·•·••●·••••••●•●•●●●•●•●•●•●•●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●●●●●●●●●●•●•●•●••••·•·•·•••••·•·•·•·• ··• · · · · ····•······ ··●••· · ···•· · •·· · ·· · · ··· ··•·· ··•••·····•·••••••••●•••●•●•●•••●•••••••●•●●●•●•●•●●●•●●●•●●●•●●●•●●●•●●●•●•●•●•●•●•●•●•●•●•●••••••••••·•·•·•···•···•· ··· · · · · · · •·· ··••● · ··••· · ··· ·••···· · · · ·· · · · · ··• ··•·•••·•·•·••●•●•••●•●•●•●•●•●•●•●•●•●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●●●•●•●•●•●•●•••●••·•••·•••·•···•·· ··•·· · · ······· ·•······●•· · · •·• ····•··· · · ··· · · · · ··• ········•·•·••••••••••••••••••••••••●•●•●•●•●●●•●●●•●•●•●•●•●●●•●●●•●●●•●●●•●•●•●•●•••••••••••••••••••●···•·•······ ······ ·· · · ··· · · · · ····•· •·••●••··· · · ··· · · · · ··••·••·•·•·••••••••••••••••●•●•••••••••••●•●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●•●•●•●•●•●•••••••••••••••●•●·•·•·•·•·· ··•·• · •·· · · ···••·· ··· · · · · ••·•●••••••·· · · · · · · · ··•·········••••●•●•●•••••••●•••••••••••••••●•••●•●●●•●●●•●●●•●●●•●●●•●•●•●●●•●•●•●•●••••••••••••••••••••••••···•••·· ····· · ••• · ··•·· ····· · ···•●·●•●•·•●·····• · · ··· ··· ··· ··· •·•·•·•·••••••••●•●•●•●•●•●•●•●•●•●•●•••••••●•●•●●●●●●●●●●●•●•●●●●●•●●●•●•●•●•●•●•●•••••●••••••••••••••••••·••●••······ · · •· ··· · · ·······•• · · · · · · •• ·••·· · ··· · · ··· ········•·•·•·•·•·•·•·•·•••••••·•••·•••·•••••••·••●•●•●•●•••●•●•●•●•●•●•••●••••••••••••••••••••••••·•·•·•·•·•·•·••··· · · · · · •·· · · ···· · · •••··· · · ··•·······•···•·•·•·•·••••••••••••••••••••••●•●•●•●•●•●•●•●•••●•●•●•●•●•●•●•●•●•●•●•••●•●•●•••●•●•●•●•●••••••••••••••••••••••••·•·· ··· · · · · · · · ·••·· · ··· · ···· ···· · ····•·· · ········•·•·•·•·•·•·•·•·•·•·•·•·•••••·•·•••·••••••●•••••••••••●•●•●•●•●•●•●••••••••••••••••·•••·•••••••·•·•·•·•·•·•·•·•···•·· · · · · ····· · · ••· · · · •·•···· ··· •·· · ··•·•·•·•·•·•·••••••••••••••••••••••••••••••••••••••••••••••●•••●•••●•••••●••••••••••••••••••••••••••••••••••••••••••••·•·•·• · · ····· · · ··· · · ·••···· · ···· • ••·· · · · ····•···•···•·•·•·•••••••••••·•·•••·•·•·•·•·•·•·•·•·•·•••••·•·•••••••••••·•••·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·······• ··· ··· ·· · · •····· ·••· ··· ●·· •• · •·· · · · · ••· •···•••·•••••·•••••·••••••••●•●•●•●•●••••••·•••·•••••••••••••••••••••••••••·•••••••·•••••••·•••·•••••••·•••••••·•••·•••·•·•·•••·•·•·•· · •·· · ··•·····•·••••●••·•• • •••·•· ···· ·••••·••••··•···•••·•·•·•·•·•·•·•·•·•·•·•·•••••••••••••••••••••••·•·•·•·•·•·•••·•·•·•·•·•••••••••·•·•·•·•••••••·•·•·•·•·•·•·•·•···•·•·•·•·•·•·· • ··· ·· •••••••••·•·•· • ·••••·•·• · •···· ··· ·•●•●•●••••·••• •••••·•·•••••••·•••·•••·•••·•••·•••·•••·••••••••●••••••·•••·•••••••••••·•••••••••••·•••·•••••••·•••·•••·•••·••●••·•·•·•·•·· ·•••• ••●•••· · ·••·••••●••·• · ··•··••••·•· ·· · ·•·•·•·•••••••••·•···••··••●•••●••·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•··••·••●·•·•·· ····•·•·•·•••· ·• •••••••••·• ··••·•·●•●•• •···· ··•···••●•••·•●••···•••··•••●••••••••·•••·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•••·•·•·•••·•·•·•••·•••·•·•·•·•·•·•·•·•·•·•·•·•·•·•••••••···•·●•••• ••••··•••·●••·••••· · · ·• •••••••••●••·· ··•·•·•••••······ · •·•·•••••••·•••·•·•··••••••••••·•••••••••••••••••·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•·•····••••·•···•·•·•·•·•·•·•···· •·●•••●·••●·•·• · ·•••••••●•●••••···· ··••••••●•●•●•••••••••··●•●•●•●•●•●••·•·•·•·•·•·•••·•·•·•·•·•·•·••••●•••●•••●•••●••••••·•·•·•••••••••••·•·•·•••••••·•·•·•·•••••·••••●•●••·•·•·••••••••••••••··· · ●••••·•·••●•●••··
download
use it
[docs][copy it in]html
<script type="module" src="https://ascii.rest/ascii.js"></script> <ascii-art piece="jungle-falls"></ascii-art>
No install and no build step. ascii.js defines the <ascii-art> tag, loads the piece from ascii.rest, plays it while it is on screen, and holds the first frame for anyone who prefers reduced motion.
react
// npm install ascii.rest
import { Ascii } from "ascii.rest/react";
import { jungleFalls } from "ascii.rest/pieces";
<Ascii piece={jungleFalls} /> A client component, so it works in the Next.js app router as it is. Pass the name instead, piece="jungle-falls", to fetch the piece only when it mounts.
astro
--- // npm install ascii.rest import Ascii from "ascii.rest/astro"; --- <Ascii piece="jungle-falls" />
Renders the first frame on the server, so the page is whole before any script runs, then plays the piece once it loads.
typescript
// npm install ascii.rest
import { mount } from "ascii.rest";
import { jungleFalls } from "ascii.rest/pieces";
const el = document.querySelector<HTMLCanvasElement>("canvas")!;
const stop = mount(el, jungleFalls); mount plays a piece in a <pre>, or on a <canvas> for the coloured ones, and returns a function that stops it. Every piece, option and frame is typed.
terminal
npx ascii.rest jungle-falls
Plays it in your terminal, in colour, until you press a key. Add --seconds 5 to stop it on its own; npx ascii.rest list shows every piece. In a CLI of your own, play("jungle-falls", { seconds: 2 }) from ascii.rest/terminal shows it as a splash screen.
/*
* jungle falls: a tall waterfall in two tiers down a mossy rainforest gorge in
* late morning. White water streams over the lips and down the rock, churns
* into foam on a turquoise pool and throws up spray that drifts across a
* rainbow. Palms, ferns and hanging vines frame both sides, sun shafts slant
* in from the left, and a pair of macaws crosses the gorge every sixteen
* seconds.
*
* Each frame is shaded in colour cell by cell on a square grid, then drawn as
* a halftone: every cell is a dot whose size is its brightness, ordered-
* dithered so gradients read as texture, in the palette colour nearest its hue.
*/
import type { Frame, Meta } from "../types.ts";
export const meta = {
name: "jungle falls",
category: "scenes",
note: "a tiered waterfall in a rainforest gorge, spray, a rainbow and macaws",
cols: 200,
rows: 100,
cell: 1,
fps: 15,
ground: "#07130d",
still: 6, // the macaws in view
palette: [
"#0d2616", "#173d1f", "#225a26", "#2f7a2c", "#45983a", "#6bb544", "#9ccf55", "#c9e27a",
"#2a3436", "#465256", "#6c7676", "#9aa29c",
"#f7fcfc", "#d6eef0", "#a8dcdf", "#6cc5c6", "#35aeb0", "#1d8b92", "#11636c",
"#c9e6ef", "#93c9e2", "#fff1c2", "#f2cf6b",
"#e5483b", "#f08c34", "#3d84d6", "#8b6bd0", "#a92d25",
"#5b8f7a", "#8fb8a0", "#5e4a36",
],
} satisfies Meta;
const W = 200, H = 100;
const POOL = 80; // the pool's surface, where the lower fall lands
const LEDGE = 50; // the shelf between the two tiers
const BASE_X = 101; // where the lower fall plunges
const RAIN = [118, 116, 56]; // the rainbow's centre and radius
const SUN = [30, -40]; // the sun, up and to the left, out of frame
const LOOP = 16; // the macaws cross once every LOOP seconds
const DOTS = " ·•●";
const COVER = [0, 0.3, 0.6, 1]; // how much each dot fills, against the largest
const BAYER = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5].map((v) => v / 16 - 0.47);
const SKY = 0, CANOPY = 1, ROCK = 2, FALL = 3, WATER = 4, LEAF = 5, TRUNK = 6, VINE = 7;
// The falls: lip row (0 for the cliff top), foot row, centre at the lip and the
// foot, half width at the lip and the foot. Two tiers in the middle, two
// threads down the sides.
const FALLS: [number, number, number, number, number, number][] = [
[0, LEDGE - 1, 100, 100.5, 7, 9.5],
[LEDGE + 1, POOL + 1, 101, 101, 14, 20],
[31, POOL + 1, 131, 134, 1.6, 3],
[37, POOL + 1, 71, 69, 1.2, 2.4],
];
function hash(x: number, y: number): number {
let h = Math.imul(x | 0, 374761393) + Math.imul(y | 0, 668265263);
h = Math.imul(h ^ (h >>> 13), 1274126177);
return ((h ^ (h >>> 16)) >>> 0) / 4294967296;
}
// Value noise, wrapping every `period` lattice cells in x when period > 0.
function noise(x: number, y: number, period: number): number {
const xi = Math.floor(x), yi = Math.floor(y);
const fx = x - xi, fy = y - yi;
const u = fx * fx * (3 - 2 * fx), v = fy * fy * (3 - 2 * fy);
let x0 = xi, x1 = xi + 1;
if (period) {
x0 = ((xi % period) + period) % period;
x1 = (x0 + 1) % period;
}
const a = hash(x0, yi), b = hash(x1, yi), c = hash(x0, yi + 1), d = hash(x1, yi + 1);
return a + (b - a) * u + (c - a) * v + (a - b - c + d) * u * v;
}
function fbm(x: number, y: number, octaves: number, period: number): number {
let s = 0, n = 0, amp = 0.5, f = 1;
for (let i = 0; i < octaves; i++) {
s += amp * noise(x * f, y * f, period * f);
n += amp;
amp *= 0.5;
f *= 2;
}
return s / n;
}
const clamp = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);
const smooth = (a: number, b: number, v: number) => {
const k = clamp((v - a) / (b - a));
return k * k * (3 - 2 * k);
};
const mix = (a: number, b: number, k: number) => a + (b - a) * k;
const hex = (s: string) => [1, 3, 5].map((i) => parseInt(s.slice(i, i + 2), 16) / 255);
// The rainbow's bands, inside to outside.
const BOW = [
[0.55, 0.42, 0.82], [0.24, 0.52, 0.84], [0.42, 0.74, 0.34], [0.95, 0.82, 0.38], [0.94, 0.55, 0.2], [0.9, 0.28, 0.23],
];
export default function jungleFalls(): Frame {
const P = meta.palette.map(hex);
const N = W * H;
const out: string[] = new Array(N);
// Nearest palette colour, cached on a 32-step cube.
const lut = new Uint8Array(32768).fill(255);
const nearest = (r: number, g: number, b: number): number => {
const k = (Math.min(31, (r * 31.99) | 0) << 10) | (Math.min(31, (g * 31.99) | 0) << 5) | Math.min(31, (b * 31.99) | 0);
if (lut[k] !== 255) return lut[k];
let best = 0, bd = 1e9;
for (let i = 0; i < P.length; i++) {
const dr = P[i][0] - r, dg = P[i][1] - g, db = P[i][2] - b;
const d = 0.3 * dr * dr + 0.5 * dg * dg + 0.2 * db * db;
if (d < bd) (bd = d), (best = i);
}
return (lut[k] = best);
};
// --- the gorge, built once ----------------------------------------------
const mat = new Uint8Array(N);
const shade = new Float32Array(N); // lit-ness of rock and leaves
const depth = new Uint8Array(N); // jungle layer: 0 far, 1 middle, 2 near
const moss = new Float32Array(N);
const wet = new Float32Array(N);
const fallU = new Float32Array(N); // across a fall, -1 to 1
const fallV = new Float32Array(N); // down a fall, 0 at the lip
const spray = new Float32Array(N); // where the spray hangs, before it billows
// the cliff top, dipping a little where the upper fall pours over
const ctop = (x: number) => 17 + 4 * fbm(x * 0.06, 1.3, 3, 0) + 2.5 * Math.exp(-(((x - 100) / 9) ** 2));
// the far forest on top of the cliff, a line of hazy crowns
const crown = (x: number) => ctop(x) - 2 - 7 * fbm(x * 0.11, 5.1, 3, 0);
// Jungle edges, measured in from each side: far, middle and near layers.
// They open out toward the pool.
const edge = (y: number, layer: number, side: number) => {
const s = layer * 7 + side * 31;
const base = [64, 52, 36][layer] - side * 3;
const wob = [7, 10, 14][layer];
return base + wob * (fbm(y * (0.08 + layer * 0.02), s, 3, 0) - 0.5) - [16, 14, 4][layer] * smooth(70, 98, y);
};
// Each layer's canopy top, by distance in from its side: the near trees
// close in over the corners, the rest stop short so the palms stand clear
// against the sky.
const canopy = (d: number, layer: number, side: number) =>
[26, 28, 34][layer] * smooth([0, 4, 8][layer], [22, 26, 32][layer], d) - 8 * fbm(d * 0.14, 40 + layer * 3 + side * 9, 3, 0);
for (let r = 0; r < H; r++) {
const y = r + 0.5;
for (let x = 0; x < W; x++) {
const k = r * W + x;
const px = x + 0.5;
const ct = ctop(px);
if (y < crown(px)) mat[k] = SKY;
else if (y < ct) {
mat[k] = CANOPY;
const n = fbm(px * 0.3, y * 0.3, 3, 0);
shade[k] = clamp(0.3 + (n - fbm((px - 1) * 0.3, (y - 1) * 0.3, 3, 0)) * 8 + 0.4 * smooth(ct, ct - 6, y));
} else if (y < POOL + 0.5) {
mat[k] = ROCK;
// blocky rock: broad light and shade, vertical seams, lit from the left
const n = fbm(px * 0.1, y * 0.07, 4, 0);
const nl = fbm((px - 1.5) * 0.1, (y - 1) * 0.07, 4, 0);
const seam = noise(px * 0.45, y * 0.05, 0);
shade[k] = clamp(0.4 + (n - nl) * 9 + 0.4 * (n - 0.5) - 0.3 * smooth(0.6, 0.85, seam));
// moss gathers on the cliff top, the shelf, and in patches
const m = fbm(px * 0.09 + 20, y * 0.16, 3, 0);
moss[k] = clamp(0.8 * smooth(0.58, 0.7, m) + 0.8 * smooth(ct + 4, ct, y));
// the shelf between the tiers juts out, its top lit and mossy
if (Math.abs(px - 101) < 26 - 4 * fbm(px * 0.2, 4, 2, 0) && y >= LEDGE - 1.5 && y < LEDGE + 2.5) {
shade[k] = y < LEDGE ? 0.95 : 0.3 - 0.1 * (y - LEDGE);
moss[k] = y < LEDGE ? 1 : 0.2;
}
} else mat[k] = WATER;
// the falls over the rock
if (mat[k] === ROCK) {
let near = 99;
for (const [lip, foot, c0, c1, w0, w1] of FALLS) {
const top = lip || ct - 0.5;
if (y < top - 1 || y >= foot) continue;
const f = (y - top) / (foot - top);
const cx = mix(c0, c1, f), hw = mix(w0, w1, f) * (1 + 0.14 * (noise(y * 0.3, c0, 0) - 0.5));
const d = Math.abs(px - cx) - hw;
if (d < 0 && y >= top) {
mat[k] = FALL;
fallU[k] = (px - cx) / hw;
fallV[k] = y - top;
}
near = Math.min(near, d);
}
wet[k] = smooth(6, 0, near);
}
// the jungle, far to near, the nearest layer on top
for (let layer = 0; layer < 3; layer++) {
const inL = px < edge(y, layer, 0) && y > canopy(px, layer, 0);
const inR = W - px < edge(y, layer, 1) && y > canopy(W - px, layer, 1);
if (!inL && !inR) continue;
mat[k] = LEAF;
depth[k] = layer;
// clumps of foliage, lit on their upper left faces
const f = 0.24 - layer * 0.04;
const n = fbm(px * f + layer * 9, y * f, 4, 0);
const nl = fbm((px - 1.5) * f + layer * 9, (y - 1.5) * f, 4, 0);
shade[k] = clamp((n - 0.3) * 1.8) * clamp(0.4 + (n - nl) * 12);
}
// spray hangs over the plunge pool and the shelf
spray[k] = Math.exp(-(((px - BASE_X) / 36) ** 2)) * smooth(POOL - 38, POOL - 2, y) * smooth(POOL + 8, POOL, y) +
0.7 * Math.exp(-(((px - 100) / 17) ** 2)) * smooth(LEDGE - 14, LEDGE - 1, y) * smooth(LEDGE + 9, LEDGE + 1, y);
}
}
// --- palms and ferns: stamped fronds over the near jungle ----------------
const stamp = (cx: number, cy: number, rad: number, s: number) => {
for (let yy = Math.floor(cy - rad); yy <= cy + rad; yy++) {
for (let xx = Math.floor(cx - rad); xx <= cx + rad; xx++) {
if (xx < 0 || xx >= W || yy < 0 || yy >= H) continue;
if ((xx + 0.5 - cx) ** 2 + (yy + 0.5 - cy) ** 2 > rad * rad + 0.15) continue;
const k = yy * W + xx;
mat[k] = LEAF;
depth[k] = 2;
shade[k] = s;
}
}
};
// a frond: a drooping midrib with leaflets combed off both sides
const frond = (x0: number, y0: number, ang: number, len: number, droop: number, seed: number) => {
const dx = Math.cos(ang), dy = Math.sin(ang);
const steps = Math.ceil(len * 2);
for (let i = 0; i <= steps; i++) {
const s = i / steps;
const x = x0 + dx * len * s, y = y0 + dy * len * s + droop * s * s * len;
// the curve's direction here, for the leaflets to hang off
const tx = dx, ty = dy + 2 * droop * s;
const tl = Math.hypot(tx, ty);
stamp(x, y, 0.7, 0.6);
if (i % 3) continue;
const leaf = (1.2 + 4.2 * Math.sin(Math.PI * Math.min(1, s * 1.1))) * (0.8 + 0.4 * hash(i, seed));
for (const side of [-1, 1]) {
// leaflets sweep back and hang down a little
const lx = (-ty / tl) * side - (0.4 * tx) / tl, ly = (tx / tl) * side - (0.4 * ty) / tl + 0.5;
const ll = Math.hypot(lx, ly);
const up = ly / ll < 0.2; // leaflets on the upper side catch the sun
for (let j = 1; j <= leaf; j += 0.8) {
stamp(x + (lx / ll) * j, y + (ly / ll) * j, 0.45, up ? 0.95 - 0.3 * (j / leaf) : 0.5 - 0.2 * (j / leaf));
}
}
}
};
// a palm: a leaning trunk, a bezier from the root to the crown, and fronds
const palm = (rx: number, ry: number, qx: number, qy: number, kx: number, ky: number, seed: number) => {
for (let i = 0; i <= 240; i++) {
const s = i / 240;
const x = (1 - s) * (1 - s) * rx + 2 * (1 - s) * s * qx + s * s * kx;
const y = (1 - s) * (1 - s) * ry + 2 * (1 - s) * s * qy + s * s * ky;
const rad = 2.8 - 1.2 * s;
for (let yy = Math.floor(y - rad); yy <= y + rad; yy++) {
for (let xx = Math.floor(x - rad); xx <= x + rad; xx++) {
if (xx < 0 || xx >= W || yy < 0 || yy >= H) continue;
const ox = xx + 0.5 - x, oy = yy + 0.5 - y;
if (ox * ox + oy * oy > rad * rad) continue;
const k = yy * W + xx;
mat[k] = TRUNK;
// ringed bark, lit on the left
shade[k] = clamp(0.4 - 0.6 * (ox / rad)) * (yy % 3 === 0 ? 0.65 : 1);
}
}
}
const n = 8;
for (let i = 0; i < n; i++) {
const a = -Math.PI * 1.1 + (i / (n - 1)) * Math.PI * 1.2 + 0.25 * (hash(i, seed) - 0.5);
const len = 19 + 9 * hash(i, seed + 1);
frond(kx, ky, a, len, 0.3 + 0.35 * hash(i, seed + 2), seed * 10 + i);
}
};
palm(16, 104, 18, 56, 42, 15, 3);
palm(188, 104, 190, 54, 160, 12, 7);
// ferns spilling up from the bottom corners
const ferns: [number, number, number][] = [[4, 101, 1], [26, 102, 1], [46, 103, 1], [196, 101, -1], [174, 102, -1], [156, 103, -1]];
for (const [fx, fy, dir] of ferns) {
for (let i = 0; i < 5; i++) {
const a = -Math.PI / 2 + dir * (0.25 + i * 0.32) + 0.15 * (hash(fx, i) - 0.5);
frond(fx, fy, a, 13 + 6 * hash(i, fx), 0.55, fx * 3 + i);
}
}
// the vines draping the cliff from its rim: [x, top row, length, sway phase]
const vines: [number, number, number, number][] = [];
for (let i = 0; i < 10; i++) {
const left = i < 5;
const x = left ? 62 + i * 4.6 + hash(i, 1) * 2 : 118 + (i - 5) * 4.8 + hash(i, 2) * 2;
if (Math.abs(x - 100) < 12) continue;
vines.push([x, Math.floor(ctop(x)) - 1, 14 + 26 * hash(i, 3), hash(i, 4) * 6.28]);
}
// a faint unevenness in the sky
const haze = new Float32Array(N);
for (let k = 0; k < N; k++) haze[k] = fbm((k % W) * 0.04, Math.floor(k / W) * 0.1, 3, 0);
const vine = new Uint8Array(N);
const shafts = new Float32Array(280);
return (t, { color } = {}) => {
// vines sway a little, more toward their tips
vine.fill(0);
for (const [vx, top, len, ph] of vines) {
for (let i = 0; i < len; i++) {
const s = i / len, r = top + i;
const x = Math.round(vx - 0.5 + 0.9 * s * s * Math.sin(t * 0.9 + ph) + 1.5 * Math.sin(i * 0.15 + ph));
if (x < 0 || x >= W || r >= H) continue;
vine[r * W + x] = 1;
// leaves on alternate sides
if (hash(i, vx | 0) > 0.5) {
const lx = x + (hash(vx | 0, i) > 0.5 ? 1 : -1);
if (lx >= 0 && lx < W) vine[r * W + lx] = 2;
}
}
}
// Sun shafts slant down and to the right; they depend only on the cell's
// place across them, so they are tabled once a frame.
for (let i = 0; i < shafts.length; i++) {
const p = i - 70;
shafts[i] = smooth(0.55, 0.8, noise(p * 0.16 + t * 0.04, 3.1 + t * 0.08, 0)) * smooth(-20, 50, p);
}
for (let r = 0; r < H; r++) {
const y = r + 0.5;
for (let x = 0; x < W; x++) {
const k = r * W + x;
const px = x + 0.5;
let m = mat[k];
let cr = 0, cg = 0, cb = 0, floor = 0.15;
let air = 1; // how much of the mist and the sun shafts sit in front of this cell
if (vine[k] && m !== TRUNK && !(m === LEAF && depth[k] === 2)) m = VINE;
if (m === SKY) {
// bright late morning blue, paling toward the rim, warm near the sun
const v = y / 20;
const ds = Math.hypot(px - SUN[0], y - SUN[1]);
const sun = Math.exp(-ds / 60) * 0.5;
const veil = 0.9 + 0.15 * haze[k];
cr = (0.5 + 0.35 * v) * veil + sun;
cg = (0.74 + 0.18 * v) * veil + sun * 0.95;
cb = (0.9 + 0.06 * v) * veil + sun * 0.7;
floor = 0.3;
} else if (m === CANOPY) {
// the far forest on the rim, softened by distance
const s = shade[k];
cr = 0.24 + 0.32 * s, cg = 0.42 + 0.4 * s, cb = 0.28 + 0.22 * s;
floor = 0.2;
} else if (m === ROCK) {
// slate stone, darker where the spray wets it, green where moss grows
const s = shade[k], w = wet[k], mo = moss[k];
cr = (0.07 + 0.27 * s) * (1 - 0.4 * w);
cg = (0.09 + 0.28 * s) * (1 - 0.35 * w);
cb = (0.1 + 0.28 * s) * (1 - 0.3 * w);
const g = 0.25 + 0.75 * s;
cr = mix(cr, 0.12 * g + 0.02, mo * 0.8);
cg = mix(cg, 0.48 * g + 0.05, mo * 0.8);
cb = mix(cb, 0.1 * g + 0.02, mo * 0.8);
// spray glistening on the wet rock
if (w > 0.3 && hash(x + ((t * 6) | 0) * 13, r) > 0.95) (cr += 0.5 * w), (cg += 0.55 * w), (cb += 0.55 * w);
floor = 0.05;
} else if (m === FALL) {
// falling water: streaks pulled downward, glassy green at the lip,
// ragged and thin at the edges where the dark rock shows through
const u = fallU[k], v = fallV[k];
const speed = 8 + 1.4 * v; // it speeds up as it falls
const s1 = noise(px * 0.65, (y - t * speed) * 0.09, 0);
const s2 = noise(px * 1.4 + 31, (y - t * speed * 1.3) * 0.2, 0);
const s = 0.6 * s1 + 0.4 * s2;
const lip = smooth(4, 0, v);
const edgeK = smooth(1, 0.55, Math.abs(u));
const white = clamp(smooth(0.28, 0.68, s) * (0.6 + 0.4 * edgeK) + 0.3 * edgeK);
cr = mix(0.3, 0.98, white), cg = mix(0.56, 1, white), cb = mix(0.6, 1, white);
// a glassy turquoise sheet just over the lip, breaking white below
cr = mix(cr, 0.25 + 0.5 * s, lip), cg = mix(cg, 0.72 + 0.25 * s, lip), cb = mix(cb, 0.72 + 0.25 * s, lip);
// the rock behind shows through the thin edges
const thin = (1 - edgeK) * (1 - smooth(0.35, 0.62, s));
cr = mix(cr, 0.08, thin), cg = mix(cg, 0.11, thin), cb = mix(cb, 0.12, thin);
floor = 0.2;
air = 0.5; // white water outshines the shafts
} else if (m === WATER) {
// the pool: aerated pale turquoise near the falls, deep toward us
const v = (y - POOL) / (H - POOL);
const dx = (px - BASE_X) / 1.6, dy = (y - POOL) * 3.2;
const d = Math.sqrt(dx * dx + dy * dy);
const near = Math.exp(-d / 30);
cr = 0.05 + 0.2 * near - 0.03 * v;
cg = 0.45 + 0.3 * near - 0.15 * v;
cb = 0.48 + 0.28 * near - 0.14 * v;
// ripples running out from the plunge, broken by noise
const rip = Math.sin(d * 0.42 - t * 4.5) * 0.5 + 0.5;
const brk = noise(px * 0.12, y * 0.6 - t * 0.5, 0);
const crest = smooth(0.7, 0.95, rip) * smooth(0.35, 0.7, brk) * (0.5 + 0.5 * near);
cr += 0.55 * crest, cg += 0.5 * crest, cb += 0.45 * crest;
// the falls reflected, a pale broken column under each
const wob = smooth(0.4, 0.9, noise(px * 0.5, y * 0.8 - t * 2, 0));
let boil = 0;
for (const [, , , c1, , w1] of FALLS) {
const refl = Math.exp(-(((px - c1) / (w1 * 0.9)) ** 2)) * wob * smooth(H, POOL + 4, y);
cr += 0.25 * refl, cg += 0.28 * refl, cb += 0.28 * refl;
if (w1 < 5) boil += Math.exp(-(((px - c1) / 5) ** 2)) * smooth(POOL + 6, POOL, y);
}
// churning foam at the plunge, flecks spreading out toward us
const zone = Math.exp(-(((px - BASE_X) / 25) ** 2)) * smooth(POOL + 15, POOL, y);
const ch = fbm(px * 0.16 + Math.sin(t * 1.3) * 0.6, y * 0.4 - t * 1.2, 2, 0);
const foam = clamp(smooth(0.4, 0.6, ch) * zone * 1.7 + smooth(0.78, 0.92, brk) * near * 0.7 + boil * ch);
cr = mix(cr, 0.96, foam), cg = mix(cg, 0.99, foam), cb = mix(cb, 1, foam);
floor = 0.15;
} else if (m === LEAF) {
// three layers of green: hazy and pale far off, deep and sunlit near
const lay = depth[k];
const flick = lay === 2 ? 0.1 * Math.sin(t * 1.7 + hash(x >> 2, r >> 2) * 6.28) : 0;
const b = clamp(shade[k] * (lay === 2 ? 1.1 : 1) + (lay === 2 ? 0.06 : 0) + flick);
if (lay === 0) {
cr = 0.12 + 0.3 * b, cg = 0.28 + 0.42 * b, cb = 0.2 + 0.24 * b;
air = 0.9;
floor = 0.12;
} else if (lay === 1) {
cr = 0.03 + 0.3 * b * b, cg = 0.1 + 0.55 * b, cb = 0.03 + 0.1 * b;
air = 0.55;
floor = 0.04;
} else {
cr = 0.01 + 0.55 * b * b * b, cg = 0.03 + 0.78 * b * b, cb = 0.01 + 0.14 * b * b;
air = 0.15;
floor = 0;
}
} else if (m === TRUNK) {
// grey palm bark, a dark silhouette lit down its left side
const s = shade[k];
cr = 0.1 + 0.55 * s * s, cg = 0.085 + 0.47 * s * s, cb = 0.06 + 0.34 * s * s;
air = 0.15;
floor = 0.1;
} else {
// a vine across the gorge, dark stem, bright leaves
if (vine[k] === 2) (cr = 0.4), (cg = 0.78), (cb = 0.2);
else (cr = 0.12), (cg = 0.3), (cb = 0.1);
air = 0.4;
floor = 0;
}
// Spray billows up from the plunge and the shelf and drifts right.
const e = spray[k] * air;
if (e > 0.02) {
const dn = fbm(px * 0.05 - t * 0.25, y * 0.08 + t * 0.55, 2, 0);
const mist = clamp(e * (smooth(0.3, 0.7, dn) * 1.1 + 0.15));
cr = mix(cr, 0.9, mist * 0.85), cg = mix(cg, 0.96, mist * 0.85), cb = mix(cb, 0.97, mist * 0.85);
// The rainbow lives in the spray, strongest where the mist is thick.
const dr = Math.hypot(px - RAIN[0], y - RAIN[1]) - RAIN[2];
if (dr > -6 && dr < 6) {
const q = ((dr + 6) / 12) * (BOW.length - 1);
const i = Math.min(BOW.length - 2, Math.floor(q)), f = q - i;
const a = Math.min(0.85, Math.sin(((dr + 6) / 12) * Math.PI) * (0.35 + mist * 1.6 + e * 0.6));
cr = mix(cr, mix(BOW[i][0], BOW[i + 1][0], f), a);
cg = mix(cg, mix(BOW[i][1], BOW[i + 1][1], f), a);
cb = mix(cb, mix(BOW[i][2], BOW[i + 1][2], f), a);
}
}
// Sun shafts through the gorge, warm, fading toward the pool; they lift
// the shadows most, the way light shows in humid air.
const sh = shafts[Math.max(0, Math.min(279, (px - 0.62 * y + 70) | 0))] * smooth(H, 10, y) * air * 0.75;
cr = mix(cr, 1, sh * 0.9), cg = mix(cg, 0.94, sh * 0.85), cb = mix(cb, 0.7, sh * 0.7);
// Dot size from brightness, dithered. Then the colour makes up what the
// dot size could not: a small dot is drawn brighter and a large one
// dimmer, so a gradient stays smooth across the dither's steps. Dark
// stone and shade are only lifted so far, so they keep their depth.
const peak = Math.max(cr, cg, cb, 1e-4);
const level = clamp(floor + (1 - floor) * Math.pow(peak, 0.85) * 0.95);
const step = Math.max(0, Math.min(3, Math.round(level * 3 + BAYER[(r & 3) * 4 + (x & 3)])));
out[k] = DOTS[step];
if (color) {
const want = step ? Math.min(1, (level + 0.06) / COVER[step]) : 0;
const s = Math.min(2.2, (0.3 + 0.7 * want) / peak);
color[k] = nearest(clamp(cr * s), clamp(cg * s), clamp(cb * s));
}
}
}
// The macaws: a pair crossing left to right, wings beating out of step.
const ph = (t % LOOP) / LOOP;
for (let b = 0; b < 2; b++) {
const bx = -30 + ph * 270 - b * 24;
const by = 29 + b * 6 + 2.5 * Math.sin(ph * Math.PI * 4 + b);
const flap = Math.sin(t * 7 + b * 2.1);
for (let r = Math.floor(by - 10); r <= by + 10; r++) {
for (let x = Math.floor(bx - 18); x <= bx + 8; x++) {
if (x < 0 || x >= W || r < 0 || r >= H) continue;
const lx = x + 0.5 - bx, ly = r + 0.5 - by;
let c = -1;
// the long pointed tail trailing behind and a touch low, blue tipped
const tl = -lx - 4;
if (tl > 0 && tl < 13 && Math.abs(ly - tl * 0.1) < 1.3 * (1 - tl / 14)) c = tl > 8 ? 25 : 23;
// body, head and a pale hooked beak
if ((lx / 4.6) ** 2 + (ly / 1.7) ** 2 < 1) c = 23;
if ((lx - 4.4) ** 2 + (ly + 0.6) ** 2 < 2.6) c = lx > 4.6 && ly < -0.6 ? 12 : 23;
if (lx > 5.6 && lx < 7.2 && ly > -1 && ly < 1) c = 13;
// the wing: red at the shoulder, a yellow band, blue flight feathers
const tip = -flap * 8;
const reach = 1 - Math.abs(lx + 0.5) / 3.8;
if (reach > 0 && Math.abs(tip) > 0.8) {
const f = ly / (tip * reach);
if (f > 0.15 && f < 1) c = f < 0.4 ? 27 : f < 0.58 ? 22 : 25;
}
if (c < 0) continue;
out[r * W + x] = "●";
if (color) color[r * W + x] = c;
}
}
}
const lines: string[] = [];
for (let r = 0; r < H; r++) lines.push(out.slice(r * W, (r + 1) * W).join(""));
return lines.join("\n");
};
}