Create a seven-color rainbow with animation

5

3

Goal

Use any graphics library or environment that can use colours and animation to create a rainbow.

Rules

  • The rings should emerge one by one in some kind of animation or succession
  • The rainbow must have at least 7 colours.

Winning Criteria

Fewest bytes wins.

user16165

Posted 2014-02-08T13:11:36.127

Reputation:

3[tag:code-golf] and [tag:popularity-contest] are mutually exclusive. Seeing as you want "least bytes win", remove the [tag:popularity-contest] – mniip – 2014-02-08T13:33:01.777

@mniip done editing! – None – 2014-02-08T13:41:45.357

I’ve edited the question a bit in an attempt to improve it. Please anyone let me know if there’s anything else I can do to keep it from being downvoted or closed. – Timwi – 2014-02-08T20:47:23.783

@Timwi I removed my downvote for the time being, good job fixing it up. I think it's still not very specific about what makes an okay rainbow though, which seems bad for a code-golf task (I think I would've preferred popularity-contest, but it's a tad late for that I guess). – FireFly – 2014-02-08T21:11:06.003

Answers

15

HTML + CSS + JavaScript (447 440 439 432 428 434 390 388 383 bytes)

(Byte size went up at one point in order to fulfill “appear one by one” requirement)

(Some credit to Fez Vrasta’s answer for reminding me of the existence of document.write)

<script>for(d=document,i=0;k=i>>1,k<7;setTimeout(function(w){d.getElementById(w).id="x"+w},555*k,i++))d.write("<b id="+i+"><style>b{width:0;height:0;transition:width 2s,height 2s;border-radius:50ex 50ex 0 0;position:fixed;bottom:-4ex}#x"+i+"{left:"+(9+4*k)+"ex;width:"+(80-6*k)+"ex;height:"+(40-3*k)+"ex;box-shadow:"+(i%2&&"inset 0")+" 0 6ex hsl("+50*k+",99%,50%)}</style>")</script>

Screenshot (see JSFiddle for the full animation)

rainbow picture

Explanation

The rainbow is created by having 7 pairs of <b> elements, which are all positioned using position:absolute and a width, height, left and bottom. Within each pair, they have the same position and size, but one has an “outer” (standard) box-shadow, the other an inset one, thus creating the nice fuzzy bands. The colors are calculated using hsl(), allowing us to vary only the hue but having the same saturation (99%) and lightness (50%) for all. The <b> tags are nested inside each other, but this doesn’t matter because all of their positioning is relative to the page.

In the beginning, they all have IDs 0, 1, etc., and a styling rule that applies to all b elements sets their width and height to 0, making them invisible. The code also outputs styling rules for elements with ID x0, x1, etc., which initially do not apply.

A setTimeout is then used to successively change their IDs from 0 to x0, from 1 to x1 and so on. This triggers a CSS transition which causes them to appear one by one.

<script>
    for (d = document, i = 0;      // i loops from 0 to 14
         k = i >> 1, k < 7;        // k loops from 0 to 7
         setTimeout(
             function(w) {
                 // Code to change the element IDs, triggering the CSS transition
                 d.getElementById(w).id = "x" + w
             },
             555 * k,     // 555 milliseconds delay between the appearance of each band
             i++          // This argument is passed into the timeout function
         )
    )
        // For-loop body; creates a <b> element and a <style> element
        d.write(
            // The <b> element (with its initial ID)
            "<b id=" + i + ">" +
            "<style>" +
                // CSS rules that apply to all elements (esp. transition!)
                "b{width:0;height:0;transition:width 2s,height 2s;" +
                "border-radius:50ex 50ex 0 0;position:fixed;bottom:-4ex}" +
                // CSS rules for this specific element
                "#x" + i + "{" +
                    "left:" + (9+4*k) + "ex;" +
                    "width:" + (80-6*k) + "ex;" +
                    "height:" + (40-3*k) + "ex;" +
                    // “i%2” is either 0 or 1; therefore,
                    // “i%2 && "inset 0"” is either 0 or "inset 0"
                    "box-shadow:" + (i%2 && "inset 0") + " 0 6ex " +
                        // 99% is shorter than 100% ;-)
                        "hsl(" + 50*k + ",99%,50%)" +
                "}" +
            "</style>"
        )
</script>

Timwi

Posted 2014-02-08T13:11:36.127

Reputation: 12 158

You forgot to add "+Javascript". in the title – Mhmd – 2014-02-08T15:56:15.123

Thanks! – Timwi – 2014-02-08T15:57:55.533

As much as I like this answer and the animation, the rings don't seem to emerge one by one as far as I can tell, which the question seems to require. Still, very nice rainbow! – FireFly – 2014-02-08T21:12:02.607

1@FireFly: Fixed! :) – Timwi – 2014-02-08T22:06:10.510

Nice colors! You can probably save some by making a function like g=function(s){return "height"+h+"width"+w} – Not that Charles – 2014-02-10T01:37:55.817

@Charles: Have you tried that? I can’t really see how that shortens it... function and return are very long, and width/height occur only three times. – Timwi – 2014-02-10T01:40:09.450

@Timwi you're right. Sorry bout that. – Not that Charles – 2014-02-10T01:53:13.933

10

Bash + ImageMagick, 226 bytes

r=400
s=""
for c in 008 40c 03f 07f 0c0 ee0 f80 c00
do
s="-stroke '#$c' -draw 'circle 250,280 $r,$r' $s"
eval "convert -size 500x220 xc:'#008' -fill none -strokewidth 10 $s r$r.png"
r=$[r+7]
done
convert -delay 50 r*.png r.gif

Produces the following GIF animation:

an animated rainbow

r3mainer

Posted 2014-02-08T13:11:36.127

Reputation: 19 135

7

BBC BASIC, 101 106 Bytes

FORC=1TO7GCOLC:A=GET:R=700-C*50FORX=-R TO R:LINE640+X,SQR(R^2-X^2)-200,640+X,SQR((R+50)^2-X^2)-200NEXTNEXT

EDIT: added A=GET: so that user must press a key to make each ring appear, to comply with animation requirement. Deleted one unnecessary white space after LINE. The original code can still be seen on the screenshot.

Runs at the command line in Mode 6. Emulator at www.bbcbasic.co.uk

program screenshot

I posted this to show how concise BBC basic was. No complicated libraries to include, all you had to do was type MODE6 and away you went.

Also to demonstrate the drawing of a circle using pythagoras theorem. Ungolfed version:

FOR C=1 TO 7
  A=GET                             :REM wait for user to press a key 
  GCOL C                            :REM change graphics colour to C
  R=700-C*50                        :REM select the inner radius
  FOR X = -R TO R                   :REM scan through X values 
    LINE 640+X,SQR(R^2-X^2)-200,   640+X,SQR((R+50)^2-X^2)-200
  NEXT
NEXT

The centre of the circle is at 640,-200. For the inner circle, the Y coordinate (before subtracting 200) is the square root of R^2-X^2, so we are using Pythagoras theorem.

It was specified that the rings be drawn "one by one" so for each X value the program draws a line directly upwards from the inner radius of the current colour to the outer radius. The Y coordinate for finishing the line is the square root of (R+50)^2-X^2 so the radius is 50 more.

Unfortunately the algorithm cannot reach the last bit of the left and right sides of the outer circle, because if we try to go there, the calculation for the inner circle gives a negative square root and the program crashes. The easiest workaround was simply to put the centre of the circle off the bottom of the screen. You can still see a little bit of the uncoloured area at the sides, though.

Level River St

Posted 2014-02-08T13:11:36.127

Reputation: 22 049

2I don't think that's how rainbow's colors are ordered :/ – mniip – 2014-02-08T18:05:22.633

6@mniip Haha, I see you have yours in the "Newton" order but I am not the only one who doesn't. The spec said minimum seven colours, no order was specified. No one has used the "Hamilton" order yet: Red and yellow and pink and green, orange and purple and blue. My rings emerge slowly (BBC Basic!) This is the way this game works. Client asks for minimum bytes, accepts lowest offer based on 30 year old platform , then their staff have to maintain it..... – Level River St – 2014-02-08T19:57:43.677

1@mniip Sorry I just realised you're 15. That was a joke. You probably haven't experienced bad management decisions yet, so you won't find it very funny. – Level River St – 2014-02-08T20:04:40.683

3That was an unnecessary comment... I do understand that 's a joke, although I find it saddening (for now?). – mniip – 2014-02-08T21:43:07.297

6

Python 2 with Pygame

First version - 210 198 bytes

import pygame as p
s=p.display.set_mode((720,360))
c=p.Color(0,0,0)
for i in range(360,0,-1):
    c.hsla=(i,100,50,100)
    p.draw.circle(s,c,(360,360),i)
    __import__('time').sleep(0.1)
    p.display.flip()

This creates a window showing the drawing of a rainbow from the circumference to the center. It takes 36 seconds to complete the rainbow.

enter image description here

Alternative version - 235

import pygame as p
s=p.display.set_mode((720,360))
c=p.Color(0,0,0)
for j in range(360,-45,-45):
    for i in range(j,0,-1):
        c.hsla=(j-i,100,50,100)
        p.draw.circle(s,c,(360,360),j-i)
        __import__('time').sleep(0.01)
        p.display.flip()

This alternative version draws some rings with a cooler animation.

enter image description here

Andrea Ciceri

Posted 2014-02-08T13:11:36.127

Reputation: 301

Replacing import pygame as p with from pygame import* and removing all occurences of p. would save some bytes. – Jonathan Frech – 2017-09-06T15:40:00.437

1+1 for awesome graphics. But is it a rainbow or a nuclear bomb / supernova? – Level River St – 2014-02-09T10:42:10.293

@steveverrill - I know, but otherwise it would be too longer. I've just finished an alternative version, do you like it? – Andrea Ciceri – 2014-02-09T16:14:35.530

I like them both. It wasn't a criticism, just an alternative interpretation. – Level River St – 2014-02-09T23:10:57.653

5

Mathematica, 177

I doubt this is the shortest Mathematica way to do it.

ListAnimate@Table[Graphics[{Thickness[0.1], Table[{ColorData["Rainbow"]@i, Circle[{0, 0}, 7 i]}, {i, 0, m, 1/7}]}, PlotRange -> {{-8, 8}, {0, 8}}], {m, 0, 1, 1/7}]

rainbow

user11030

Posted 2014-02-08T13:11:36.127

Reputation:

4

GLSL - 234 200

(heroku flavor)

At the cost of 34 characters, added animation

precision lowp float;uniform vec2 resolution;uniform float time;void main(){float f=distance(gl_FragCoord.xy/resolution,vec2(.5,0))*9.;gl_FragColor=f>2.4&&f<8.?vec4(sin(f+time)+.5,sin(f+2.+time)+.5,sin(f+4.+time)+.5,1):vec4(0,0,0,0);}

http://glsl.heroku.com/e#14103.1

non-animated answer:

precision lowp float;uniform vec2 resolution;void main(){float f=distance(gl_FragCoord.xy/resolution,vec2(.5,0))*9.;gl_FragColor=f>2.4&&f<8.?vec4(sin(f)+.5,sin(f+2.)+.5,sin(f+4.)+.5,1):vec4(0,0,0,0);}

http://glsl.heroku.com/e#14103.0

mniip

Posted 2014-02-08T13:11:36.127

Reputation: 9 396

2

JavaScript: 304 239

i=-1,s=85,t=20;(function r(){if(++i<7){document.write('<b style=position:absolute;width:80px;text-align:center;font-size:'+s+'px;top:'+t+'px;color:'+['f00','f90','cf0','3f0','0ff','06f','c0f'][i]+'>∩</b>');setTimeout(r,999);s-=5;t+=5}})()

JavaScript 232

(thanks @Florent for the split idea)

i=7,s=85,t=20;(function r(){if(--i){document.write('<b style=position:absolute;width:80px;text-align:center;font-size:'+s+'px;top:'+t+'px;color:'+'f007f907cf073f070ff706f7c0f'.split(7)[i-1]+'>∩</b>');setTimeout(r,999);s-=5;t+=5}})()



yea I know my rainbow sucks >_<"

rainbowsucks

to test it just run this code in the JS console (F12)

Fez Vrasta

Posted 2014-02-08T13:11:36.127

Reputation: 1 078

that doesn't work for me in FF – Not that Charles – 2014-02-10T01:40:31.597

@Charles Yes I've noticed it, I've tested it only on Chrome – Fez Vrasta – 2014-02-10T07:47:53.260

226: i=6,s=85,t=20;!function r(){document.write('<b style=position:absolute;width:80px;text-align:center;font-size:'+s+'px;top:'+t+'px;color:'+'c0f106f10ff13f01cf01f901f00'.split(1)[i]+'>∩</b>');s-=5;t+=5;i--?setTimeout(r,1e3):0}() – Florent – 2014-02-10T17:02:08.057

@Florent: unaxpected token illegal :\ – Fez Vrasta – 2014-02-10T18:49:25.920

Strange, runs fine in Chrome's console – Florent – 2014-02-11T08:32:38.747

I've tested it on Chrome console as well – Fez Vrasta – 2014-02-11T08:42:31.800

1

Powershell: 270b (arbitrary width/height) / 307b (screen dimensions)

For a rainbow spanning most of the screen, the following leaks like a sieve, but seems to work (for 307 bytes):

$d=@{};Add-Type -A System.Drawing -Pas|foreach{$d[$_.Name]=$_};$g=$d.Graphics::FromHwnd(0);$v=$g.VisibleClipBounds;$y=$h=$v.Height;$h/=9;$c=0;@(65281,11861886,16776961,16744448,256,23296,65536)|foreach{$g.DrawArc((New-Object $d["Pen"]($d.Color::FromArgb(-$_),$h)),-$h,$y-$h*$c++-$h,$v.Width+2*$h,$h,0,-180)}

Ungolfed

$d=@{};
Add-Type -A System.Drawing -Pas | foreach { $d[$_.Name]=$_ };        # import .NET naespace "System.Drawing" and copy its members into the $d array
$g = $d.Graphics::FromHwnd(0);                                       # build a Graphics object for the screen
$v = $g.VisibleClipBounds;                                           # determine the screen size
$y = $h = $v.Height;                                                 # init start point for arcs and band height
$h /= 9;                                                             # allow space for 7 bands + clear above and below
$c=0                                                                 # counter

@(65281,11861886,16776961,16744448,256,23296,65536) | foreach {      # ARGB color values for bands (no clever calculation here, just Color.Red.ToARGB(), Color.Orange.ToARGB(), etc...)
    $g.DrawArc(
        (New-Object $d["Pen"](
            $d.Color::FromArgb(-$_),                                 # build a pen from the current color, using width = band-height
            $h
        )),
        -$h,                                                         # x-pos for start of arc (pushed slightly offscreen to avoid weird wide-pen effect)
        $y-$h*$c++-$h,                                               # y-pos for start of arc (moves up each time because of counter increment)
        $v.Width+2*$h,                                               # width of arc (pushed offscreen to avoid weird wide-pen effect)
        $h,                                                          # height of arc always the same
        0,-180                                                       # arc sweep clockwise between 0 and 180 degrees from x-axis)
    )
}

Of course, if you don't factor the screen size or the wide-pen effect, and just go with any arbitary width/height, you can lose the VisibleClipBounds stuff for approx 270 bytes, but your "animation" speed will be affected by the number of pixels it has to draw:

$d=@{};Add-Type -A System.Drawing -Pas|foreach{$d[$_.Name]=$_};$g=$d.Graphics::FromHwnd(0);$y=$h=300;$h/=9;$c=0;@(65281,11861886,16776961,16744448,256,23296,65536)|foreach{$g.DrawArc((New-Object $d["Pen"]($d.Color::FromArgb(-$_),$h)),0,$y-$h*$c++-$h,400+2*$h,$h,0,-180)}

Results

Window-redraw makes it particularly difficult to get a screencap of the full-screen one in action, but the arbitrary-sized one (with the wide-pen awkwardness) looks like:

Screencap of results

Edit: OK, I've managed to get a fullscreen cap, but not before some of my screen redrew:

Screencap of results

jimbobmcgee

Posted 2014-02-08T13:11:36.127

Reputation: 371

1

Disclaimer: The following solutions work only in Chrome Dev Tools!
Note: The following solutions will draw a rainbow with an infinite radius, thus arcs are not curved!


JavaScript (ES6), 121

i=0;'f43f82fd03c407d72eb2c'.replace(/.../g,p=>setTimeout("console.log('%c'+' '.repeat(99),'background:#"+p+"')",1e3*i++))

Thanks to @manatwork for this one!

JavaScript, 126

for(c='f43f82fd03c407d72eb2c',i=7;i--;)setTimeout("console.log('%c'+' '.repeat(99),'background:#'+c.substr("+i+"*3,3))",1e3*i)

Details:

for(
  // Colors:
  //   - #f43 (red)
  //   - #f82 (orange)
  //   - #fd0 (yellow)
  //   - #3c4 (green)
  //   - #07d (blue)
  //   - #72e (indigo)
  //   - #b2c (purple)
  c='f43f82fd03c407db1c',
  // Iterate through each color
  i=6; i--;
)
  // Delay the arc emergence
  setTimeout(
    // Display a colored line into the console
    "console.log('%c'+' '.repeat(99),'background:#'+c.substr("+i+"*3,3))",
    // 1 second
    1e3*i
  )

Rainbow:

rainbow

Florent

Posted 2014-02-08T13:11:36.127

Reputation: 2 557

Tricky. But where is the 7th color? – manatwork – 2014-02-10T15:49:28.297

@manatwork Fixed – Florent – 2014-02-10T15:57:22.163

You forgot to update the character count in the post heading. But before counting the code, remove the -color part. By the way, defining c as array of strings and accessing it by index instead of substr() seems to be shorter by 1 character. – manatwork – 2014-02-10T16:01:24.600

@manatwork The character count is right (132). Previous was 129. Moreover, I'm unable to reduce the size of this solution by removing substr (and defining the array as ['f43','f82','fd0','3c4','07d','72e','b2c'], or with a number and then split on it) – Florent – 2014-02-10T16:12:29.703

Sorry, my mistake, I described a wrong attempt. – manatwork – 2014-02-10T16:14:47.007

And sorry again, no idea why, but although the code was modified by the site's inplace updating functionality, the heading stayed at 129 until a full reload. – manatwork – 2014-02-10T16:16:54.143

@manatwork No problem. Thanks for noticing the -color suffix. – Florent – 2014-02-10T16:20:47.500

shouldn't the rainbow be made out of half-rings as described by the OP? (ps. your code doesn't work on my FF Nightly, it doesn't print a colored stripe but just plain text) – Fez Vrasta – 2014-02-10T16:25:10.933

1I think finally I found a shorter one: i=0;'f43f82fd03c407d72eb2c'.replace(/.../g,p=>setTimeout("console.log('%c'+' '.repeat(99),'background:#"+p+"')",100*i++)). And is even more ES6. – manatwork – 2014-02-10T16:34:15.867

@manatwork Well done! – Florent – 2014-02-10T16:43:28.750

@FezVrasta I've added a note explaining why arcs are not curvy. – Florent – 2014-02-10T16:49:11.697

@florent I'm not sure this is a valid reason ._. – Fez Vrasta – 2014-02-10T17:02:11.617

“The following solutions work only in Chrome Dev Tools!” – Sorry, but how could they work in anything Chrome related while Chrome doesn't implemented Harmony yet? So absolutely no String.repeat() and no fat arrow functions in Chrome. (At least not in the latest stable version.) – manatwork – 2014-02-11T11:23:51.350

@manatwork String.repeat works in Chrome with experimental JavaScript setting activated. About fat arrows function, traceur can fix that. – Florent – 2014-02-11T12:55:33.710

Thank you, @Florent. All this sounds interesting, will have to look them up. – manatwork – 2014-02-11T13:01:04.727