5
\$\begingroup\$

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.

\$\endgroup\$
  • 3
    \$\begingroup\$ code-golf and popularity-contest are mutually exclusive. Seeing as you want "least bytes win", remove the popularity-contest \$\endgroup\$ – mniip Feb 8 '14 at 13:33
  • \$\begingroup\$ @mniip done editing! \$\endgroup\$ – user16165 Feb 8 '14 at 13:41
  • \$\begingroup\$ 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. \$\endgroup\$ – Timwi Feb 8 '14 at 20:47
  • \$\begingroup\$ @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). \$\endgroup\$ – FireFly Feb 8 '14 at 21:11
15
\$\begingroup\$

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>
\$\endgroup\$
  • \$\begingroup\$ You forgot to add "+Javascript". in the title \$\endgroup\$ – Mhmd Feb 8 '14 at 15:56
  • \$\begingroup\$ Thanks! \$\endgroup\$ – Timwi Feb 8 '14 at 15:57
  • \$\begingroup\$ 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! \$\endgroup\$ – FireFly Feb 8 '14 at 21:12
  • 1
    \$\begingroup\$ @FireFly: Fixed! :) \$\endgroup\$ – Timwi Feb 8 '14 at 22:06
  • \$\begingroup\$ Nice colors! You can probably save some by making a function like g=function(s){return "height"+h+"width"+w} \$\endgroup\$ – Not that Charles Feb 10 '14 at 1:37
10
\$\begingroup\$

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

\$\endgroup\$
7
\$\begingroup\$

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.

\$\endgroup\$
  • 2
    \$\begingroup\$ I don't think that's how rainbow's colors are ordered :/ \$\endgroup\$ – mniip Feb 8 '14 at 18:05
  • 6
    \$\begingroup\$ @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..... \$\endgroup\$ – Level River St Feb 8 '14 at 19:57
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ – Level River St Feb 8 '14 at 20:04
  • 3
    \$\begingroup\$ That was an unnecessary comment... I do understand that 's a joke, although I find it saddening (for now?). \$\endgroup\$ – mniip Feb 8 '14 at 21:43
6
\$\begingroup\$

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

\$\endgroup\$
  • 1
    \$\begingroup\$ +1 for awesome graphics. But is it a rainbow or a nuclear bomb / supernova? \$\endgroup\$ – Level River St Feb 9 '14 at 10:42
  • \$\begingroup\$ @steveverrill - I know, but otherwise it would be too longer. I've just finished an alternative version, do you like it? \$\endgroup\$ – Andrea Ciceri Feb 9 '14 at 16:14
  • \$\begingroup\$ I like them both. It wasn't a criticism, just an alternative interpretation. \$\endgroup\$ – Level River St Feb 9 '14 at 23:10
  • \$\begingroup\$ Replacing import pygame as p with from pygame import* and removing all occurences of p. would save some bytes. \$\endgroup\$ – Jonathan Frech Sep 6 '17 at 15:40
5
\$\begingroup\$

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

\$\endgroup\$
4
\$\begingroup\$

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

\$\endgroup\$
2
\$\begingroup\$

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)

\$\endgroup\$
  • \$\begingroup\$ that doesn't work for me in FF \$\endgroup\$ – Not that Charles Feb 10 '14 at 1:40
  • \$\begingroup\$ @Charles Yes I've noticed it, I've tested it only on Chrome \$\endgroup\$ – Fez Vrasta Feb 10 '14 at 7:47
  • \$\begingroup\$ 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}() \$\endgroup\$ – Florent Feb 10 '14 at 17:02
  • \$\begingroup\$ @Florent: unaxpected token illegal :\ \$\endgroup\$ – Fez Vrasta Feb 10 '14 at 18:49
  • \$\begingroup\$ Strange, runs fine in Chrome's console \$\endgroup\$ – Florent Feb 11 '14 at 8:32
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
  • \$\begingroup\$ Tricky. But where is the 7th color? \$\endgroup\$ – manatwork Feb 10 '14 at 15:49
  • \$\begingroup\$ @manatwork Fixed \$\endgroup\$ – Florent Feb 10 '14 at 15:57
  • \$\begingroup\$ 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. \$\endgroup\$ – manatwork Feb 10 '14 at 16:01
  • \$\begingroup\$ @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) \$\endgroup\$ – Florent Feb 10 '14 at 16:12
  • 1
    \$\begingroup\$ I 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. \$\endgroup\$ – manatwork Feb 10 '14 at 16:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy