{deck}
version:1
card:0
size:[512,342]
name:"pleasing pattern producer 2.deck"

{card:Producer}
script:"Producer.0"
{widgets}
pattern:{"type":"contraption","size":[300,300],"pos":[4,29],"script":"Producer.1","def":"3x3 pleasing pattern","widgets":{"pleaser":{"size":[300,300]},"points":{"size":[70,350],"pos":[337,-50],"row":8,"col":0},"upmostright":{"size":[30,30],"pos":[270,0]},"upmost":{"size":[30,30],"pos":[135,0]},"upmostleft":{"size":[30,30]},"middleright":{"size":[30,30],"pos":[270,135]},"middle":{"size":[30,30],"pos":[135,135]},"middleleft":{"size":[30,30],"pos":[0,135]},"bottomright":{"size":[30,30],"pos":[270,270]},"bottom":{"size":[30,30],"pos":[135,270]},"bottomleft":{"size":[30,30],"pos":[0,270]},"flickerspeed":{"size":[100,63]},"animationspeed":{"size":[100,62],"pos":[-132,118],"value":420},"shiftingspeed":{"size":[100,62],"pos":[-132,238],"value":35},"animation":{}}}
clear:{"type":"button","size":[60,20],"pos":[448,29],"script":"Producer.2","text":"Clear"}
flickerspeed:{"type":"slider","size":[200,25],"pos":[308,304],"script":"Producer.3","interval":[0,360],"value":300,"step":12}
flicker speed sticker:{"type":"field","size":[96,16],"pos":[308,287],"locked":1,"border":0,"style":"plain","value":"Flicker speed"}
horizontalshift:{"type":"button","size":[112,16],"pos":[308,64],"script":"Producer.4","text":"Horizontal shift","style":"check","value":0}
verticalshift:{"type":"button","size":[112,16],"pos":[308,82],"script":"Producer.5","text":"Vertical shift","style":"check","value":0}
drawing:{"type":"button","size":[112,16],"pos":[308,46],"script":"Producer.6","text":"Drawing","style":"check","value":0}
shiftingspeed:{"type":"slider","size":[200,25],"pos":[308,261],"script":"Producer.7","interval":[0,60],"value":35}
shifting speed sticker:{"type":"field","size":[96,16],"pos":[308,244],"locked":1,"border":0,"style":"plain","value":"Shifting speed"}
animationspeed:{"type":"slider","size":[200,25],"pos":[308,218],"script":"Producer.8","interval":[0,600],"value":420,"step":60}
drawing speed sticker:{"type":"field","size":[96,16],"pos":[308,201],"locked":1,"script":"Producer.9","border":0,"style":"plain","value":"Drawing speed"}
undo:{"type":"button","size":[60,20],"pos":[448,184],"script":"Producer.10","text":"Undo"}
ascendingshift:{"type":"button","size":[112,16],"pos":[308,100],"script":"Producer.11","text":"Ascending shift","style":"check","value":0}
descendingshift:{"type":"button","size":[117,16],"pos":[308,118],"script":"Producer.12","text":"Descending shift","style":"check","value":0}
save:{"type":"button","size":[60,20],"pos":[448,81],"script":"Producer.13","text":"Save"}
animation:{"type":"field","size":[96,16],"pos":[308,29],"border":0,"value":"Animation"}
author:{"type":"button","size":[60,20],"pos":[448,120],"script":"Producer.14","text":"Author"}
gallery:{"type":"button","size":[60,20],"pos":[448,144],"script":"Producer.15","text":"Gallery"}

{script:Producer.0}
brush["pattern painter" image["%%IMG3ACAAIAKEjxi76Z+YnAFaQHO7SvvKfeIlllCJOugarebhsljM0rVt4vrO9/4PHAUls2HF2ECCjJ1fy/nknaSWHacYu8Jk2u0IUgA="]]

brush["hard edge" image["%%IMG2ACAAIAH/Af8B/wH/AQQ="]]

on radiobutton me do
 others:drawing,horizontalshift,verticalshift,ascendingshift,descendingshift
 (1 drop distinct me,others)..value:0
 pattern.locked:me.value
 pattern.animation:if me.value me.name else "none" end
end

{end}

{script:Producer.1}
on cycle do
 
end
{end}

{script:Producer.2}
on click do
 pattern.points:()
end

{end}

{script:Producer.3}
on change x do
 pattern.flickering:x
end
{end}

{script:Producer.4}
on click do
 (drawing,verticalshift,ascendingshift,descendingshift)..value:0
 pattern.locked:me.value
 pattern.animation:if me.value "horizontal" else "none" end
end
{end}

{script:Producer.5}
on click do
  (drawing,horizontalshift,ascendingshift,descendingshift)..value:0
 pattern.locked:me.value
 pattern.animation:if me.value "vertical" else "none" end
end
{end}

{script:Producer.6}
on click do
 (horizontalshift,verticalshift,ascendingshift,descendingshift)..value:0
 pattern.locked:me.value
 pattern.animation:if me.value "drawing" else "none" end
end
{end}

{script:Producer.7}
on change x do
 pattern.shifting:x
end
{end}

{script:Producer.8}
on change x do
 pattern.animating:x
end
{end}

{script:Producer.9}
on change val do
 
end
{end}

{script:Producer.10}
on click do
 pattern.points:-1 drop pattern.points
end
{end}

{script:Producer.11}
on click do
 (drawing,horizontalshift,verticalshift,descendingshift)..value:0
 pattern.locked:me.value
 pattern.animation:if me.value "ascending" else "none" end
end
{end}

{script:Producer.12}
on click do
 (drawing,horizontalshift,verticalshift,ascendingshift)..value:0
 pattern.locked:me.value
 pattern.animation:if me.value "descending" else "none" end
end
{end}

{script:Producer.13}
on click do
 local frames:("topleft",   "topmiddle",   "topright",
               "bottomleft","bottommiddle","bottomright")
 local spaces:0
 local places:("Producer","Author") drop deck.cards
 each card in places
  each p in frames take card.widgets
   if (()~p.points)&!spaces spaces:1 p.points:pattern.points end
  end
 end
 if !spaces
  local prescript:"on click do\n go[\""
  local postscript:"\"]\nend"
  local newer:(1+count places) fuse "Gallery ",""
  local older:(  count places) fuse "Gallery ",""
  deck.paste[deck.copy[deck.cards[(count places) fuse "Gallery ",""]]].name:newer
  deck.cards[newer].widgets..points:()
  deck.cards[newer].widgets.topleft.points:pattern.points
  deck.cards[older].widgets.next.script:newer fuse prescript,postscript
  deck.cards[newer].widgets.back.script:older fuse prescript,postscript
 end
end
{end}

{script:Producer.14}
on click do
  go["Author"]
end
{end}

{script:Producer.15}
on click do
  go["Gallery 1"]
end
{end}

{card:Author}
{widgets}
crest:{"type":"contraption","size":[128,128],"pos":[192,96],"locked":1,"def":"3x3 pleasing pattern","widgets":{"pleaser":{"size":[128,128],"animated":1,"border":1,"brush":17},"points":{"size":[70,178],"pos":[165,-50],"value":{"value":[5,2,3,7,1,9,6,4,8,5,5]}},"upmostright":{"size":[13,13],"pos":[115,0],"show":"none","text":"3"},"upmost":{"size":[12,13],"pos":[58,0],"show":"none","text":"2"},"upmostleft":{"size":[13,13],"show":"none","text":"5"},"middleright":{"size":[13,12],"pos":[115,58],"show":"none","text":"7"},"middle":{"pos":[58,58],"animated":1,"show":"none","text":"10"},"middleleft":{"size":[13,12],"pos":[0,58],"show":"none","text":"8"},"bottomright":{"size":[13,13],"pos":[115,115],"show":"none","text":"6"},"bottom":{"size":[12,13],"pos":[58,115],"show":"none","text":"9"},"bottomleft":{"size":[13,13],"pos":[0,115],"show":"none","text":"4"},"flickerspeed":{"size":[100,27]},"animationspeed":{"size":[100,27],"pos":[-132,50],"value":180},"shiftingspeed":{"size":[100,27],"pos":[-132,101]},"animation":{"value":"drawing"}}}
go to Gopher:{"type":"button","size":[60,20],"pos":[333,96],"script":"Author.0","text":"Gopher"}
go to WWW:{"type":"button","size":[60,20],"pos":[333,204],"script":"Author.1","text":"WWW"}
go to Gopher hole:{"type":"button","size":[60,20],"pos":[119,96],"script":"Author.2","text":"Gopher"}
go to website:{"type":"button","size":[60,20],"pos":[119,204],"script":"Author.3","text":"WWW"}
index label:{"type":"field","size":[150,20],"pos":[29,52],"border":0,"align":"right","value":"Author's indices:"}
documentation label:{"type":"field","size":[150,20],"pos":[333,52],"border":0,"value":"Deck's documentation:"}
back:{"type":"button","size":[60,20],"pos":[226,240],"script":"Author.4","text":"Back"}

{script:Author.0}
on click do
 go["gopher://verisimilitudes.net/12026-07-07"]
end
{end}

{script:Author.1}
on click do
 go["http://verisimilitudes.net/2026-07-07"]
end
{end}

{script:Author.2}
on click do
 go["gopher://verisimilitudes.net"]
end
{end}

{script:Author.3}
on click do
  go["http://verisimilitudes.net"]
end
{end}

{script:Author.4}
on click do
  go["Producer"]
end
{end}

{card:Gallery 1}
image:"%%IMG3AgABVgKEj6nL7Q+jnLTai7PevPsPhuJIluaJpurKtu4Lx/JM1/aN5/rO9/4PDAqHxKLxiEwql8ym8wmNSqfUqvWKzWq33K73Cw6Lx+Sy+YxOq9fstvsNj8vn9Lr9js/r9/y+/w8YKDhIWGh4iJiouMjY6PgIGSk5SVlpeYmZqbnJ2en5CRoqOkpaanqKmqq6ytrq+gobKztLW2t7i5uru8vb6/sLHCw8TFxsfIycrLzM3Oz8DB0tPU1dbX2Nna29zd3t/Q0eLj5OXm5+jp6uvs7e7v4OHy8/T19vf4+fr7/P3+//DzCgwIEECxo8iDChwoUMGzp8CDGixIkUK1q8iDGjxo0cO3r8CDKkyJEkS5o8iTKlypUsW7p8CTOmzJk0a9q8iTOnzp08e/r8CTSo0KFEixo9ijSp0qVMmzp9CjWq1KlUq1q9ijWr1q1cu3r9Cjas2LFky5o9izat2rVs27p9Czeu3Ll069q9izev3r18+/r9Cziw4MGECxs+jDix4sWMGzt+DDmy5MmUK1u+jDmz5s2cO3v+DDq06NGkS5s+jTq16tWsW7t+DTu27Nk5A9CeYntG7tsfdsfwzZsD8BfDg2co3gK5cQvKWTRfLuG5CunQH1BHcb06g+wmuGtP4J1E+O8Gxosw/x09CPXV2Xtwvxy+cPIX5G+wzxu/Bv2z+WPwHxuAzNFXgYAFEkhBAAZOsKBrDUbwIGsRWodggjVMqBqGDWiIGocLeGgaiOBVyOCFJEZng4ijqYgAi6G5WN6JEMAIAI2e0WhjZzjKSKGJPG6Y4o9A+iikAjsWaWSQSPKQ45ItItjkjFAWEeViVTpwZWJZbjdlE1v6paCX8Ylp3JcolklmcGZCOCYTa/L1Zo9oLhHnXnVy2aYSd+a1Z5LQ9fnkn3RqB2iM7SUR5qFIFIoXoIkSagSjetX5KHlxVmqpmZgS+OWmXergaYWhyjAqiTaWeiKq00mqmIqqCunhq0jKKhytTioooK1Ogqefrrt+CJ+vv26Ia32snoZrssoue+ywzj4LbbTSTktttdZei2222m7LbbfefgtuuOKOS2655p6Lbrrqrstuu+6+C2+88s5Lb7323otvvvruy2+//v4LcMACD0xwwQYfjHDCCjuU7AjCzlismsyeF/F6E7/GrLIhLLtxxhWX5vHF74ncQcgc32iyx72pPHLKJEvmcsots1xrzDRbabPLJetcc84hH+azzT3LfF/QPAtm9NH/+Vx00j8b5nTG+xk9ddQaN2b1wzU6fVzWlnFtbNRLU61jzmFbfbbSK5rMXNYfR8c2xi9D7PbbdF+dn91Y1o03hHovDHjggg9OOCUFAA=="
{widgets}
topleftframe:{"type":"contraption","size":[128,128],"pos":[16,26],"def":"pattern frame","widgets":{}}
bottomleftframe:{"type":"contraption","size":[128,128],"pos":[16,170],"def":"pattern frame","widgets":{}}
topmiddleframe:{"type":"contraption","size":[128,128],"pos":[192,26],"def":"pattern frame","widgets":{}}
bottommiddleframe:{"type":"contraption","size":[128,128],"pos":[192,170],"def":"pattern frame","widgets":{}}
toprightframe:{"type":"contraption","size":[128,128],"pos":[368,26],"def":"pattern frame","widgets":{}}
bottomrightframe:{"type":"contraption","size":[128,128],"pos":[368,170],"def":"pattern frame","widgets":{}}
animationspeed:{"type":"slider","size":[128,16],"pos":[16,320],"script":"Gallery 1.0","interval":[0,600],"value":300,"step":60}
shiftingspeed:{"type":"slider","size":[128,16],"pos":[368,320],"script":"Gallery 1.1","interval":[0,60],"value":14}
topleft:{"type":"contraption","size":[116,116],"pos":[22,32],"locked":1,"def":"3x3 pleasing pattern","widgets":{"pleaser":{"size":[116,116],"animated":1,"border":1,"brush":16},"points":{"size":[70,166],"pos":[153,-50],"value":{"value":[5,2,3,7,1,9,6,4,8,5,5]},"row":6},"upmostright":{"pos":[104,0],"show":"none","text":"3"},"upmost":{"pos":[52,0],"show":"none","text":"2"},"upmostleft":{"show":"none","text":"5"},"middleright":{"pos":[104,52],"show":"none","text":"7"},"middle":{"pos":[52,52],"animated":1,"show":"none","text":"11"},"middleleft":{"pos":[0,52],"show":"none","text":"8"},"bottomright":{"pos":[104,104],"show":"none","text":"6"},"bottom":{"pos":[52,104],"show":"none","text":"9"},"bottomleft":{"pos":[0,104],"show":"none","text":"4"},"flickerspeed":{"size":[100,24]},"animationspeed":{"pos":[-132,45]},"shiftingspeed":{"size":[100,24],"pos":[-132,92],"value":14},"animation":{"value":"drawing"}}}
topmiddle:{"type":"contraption","size":[116,116],"pos":[198,32],"locked":1,"def":"3x3 pleasing pattern","widgets":{"pleaser":{"size":[116,116],"animated":1,"border":1,"brush":8},"points":{"size":[70,166],"pos":[153,-50],"value":{"value":[5,2,3,7,1,9,6,4,8,5]}},"upmostright":{"pos":[104,0],"show":"none","text":"3"},"upmost":{"pos":[52,0],"show":"none","text":"2"},"upmostleft":{"show":"none","text":"5"},"middleright":{"pos":[104,52],"show":"none","text":"7"},"middle":{"pos":[52,52],"animated":1,"show":"none","text":"1"},"middleleft":{"pos":[0,52],"show":"none","text":"8"},"bottomright":{"pos":[104,104],"show":"none","text":"6"},"bottom":{"pos":[52,104],"show":"none","text":"9"},"bottomleft":{"pos":[0,104],"show":"none","text":"4"},"flickerspeed":{"size":[100,24]},"animationspeed":{"pos":[-132,45]},"shiftingspeed":{"size":[100,24],"pos":[-132,92],"value":14},"animation":{"value":"horizontal"}}}
topright:{"type":"contraption","size":[116,116],"pos":[374,32],"locked":1,"def":"3x3 pleasing pattern","widgets":{"pleaser":{"size":[116,116],"animated":1,"border":1,"brush":13},"points":{"size":[70,166],"pos":[153,-50],"value":{"value":[5,2,3,7,1,9,6,4,8,5]}},"upmostright":{"pos":[104,0],"show":"none","text":"3"},"upmost":{"pos":[52,0],"show":"none","text":"2"},"upmostleft":{"show":"none","text":"5"},"middleright":{"pos":[104,52],"show":"none","text":"7"},"middle":{"pos":[52,52],"animated":1,"show":"none","text":"1"},"middleleft":{"pos":[0,52],"show":"none","text":"8"},"bottomright":{"pos":[104,104],"show":"none","text":"6"},"bottom":{"pos":[52,104],"show":"none","text":"9"},"bottomleft":{"pos":[0,104],"show":"none","text":"4"},"flickerspeed":{"size":[100,24]},"animationspeed":{"pos":[-132,45]},"shiftingspeed":{"size":[100,24],"pos":[-132,92],"value":14},"animation":{"value":"ascending"}}}
bottomleft:{"type":"contraption","size":[116,116],"pos":[22,176],"locked":1,"def":"3x3 pleasing pattern","widgets":{"pleaser":{"size":[116,116]},"points":{"size":[70,166],"pos":[153,-50],"value":{"value":[1,2,3,5,4,7,8,9,6]}},"upmostright":{"pos":[104,0],"show":"none","text":"3"},"upmost":{"pos":[52,0],"show":"none","text":"2"},"upmostleft":{"show":"none","text":"1"},"middleright":{"pos":[104,52],"show":"none","text":"9"},"middle":{"pos":[52,52],"show":"none","text":"4"},"middleleft":{"pos":[0,52],"show":"none","text":"5"},"bottomright":{"pos":[104,104],"show":"none","text":"8"},"bottom":{"pos":[52,104],"show":"none","text":"7"},"bottomleft":{"pos":[0,104],"show":"none","text":"6"},"flickerspeed":{"size":[100,24]},"animationspeed":{"pos":[-132,45]},"shiftingspeed":{"size":[100,24],"pos":[-132,92],"value":14},"animation":{}}}
bottommiddle:{"type":"contraption","size":[116,116],"pos":[198,176],"locked":1,"def":"3x3 pleasing pattern","widgets":{"pleaser":{"size":[116,116]},"points":{"size":[70,166],"pos":[153,-50],"value":{"value":[1,2,4,5,7,9,5,6,2,3]}},"upmostright":{"pos":[104,0],"show":"none","text":"10"},"upmost":{"pos":[52,0],"animated":1,"show":"none","text":"2"},"upmostleft":{"show":"none","text":"1"},"middleright":{"pos":[104,52],"show":"none","text":"8"},"middle":{"pos":[52,52],"animated":1,"show":"none","text":"4"},"middleleft":{"pos":[0,52],"show":"none","text":"3"},"bottomright":{"pos":[104,104],"show":"none","text":"6"},"bottom":{"pos":[52,104],"show":"none"},"bottomleft":{"pos":[0,104],"show":"none","text":"5"},"flickerspeed":{"size":[100,24]},"animationspeed":{"pos":[-132,45]},"shiftingspeed":{"size":[100,24],"pos":[-132,92],"value":14},"animation":{}}}
bottomright:{"type":"contraption","size":[116,116],"pos":[374,176],"locked":1,"def":"3x3 pleasing pattern","widgets":{"pleaser":{"size":[116,116]},"points":{"size":[70,166],"pos":[153,-50]},"upmostright":{"pos":[104,0],"show":"none"},"upmost":{"pos":[52,0],"show":"none"},"upmostleft":{"show":"none"},"middleright":{"pos":[104,52],"show":"none"},"middle":{"pos":[52,52],"show":"none"},"middleleft":{"pos":[0,52],"show":"none"},"bottomright":{"pos":[104,104],"show":"none"},"bottom":{"pos":[52,104],"show":"none"},"bottomleft":{"pos":[0,104],"show":"none"},"flickerspeed":{"size":[100,24]},"animationspeed":{"pos":[-132,45]},"shiftingspeed":{"size":[100,24],"pos":[-132,92],"value":14},"animation":{}}}
back:{"type":"button","size":[32,16],"pos":[192,320],"script":"Gallery 1.2","style":"invisible"}
next:{"type":"button","size":[32,16],"pos":[288,320],"script":"Gallery 1.3","style":"invisible"}
home:{"type":"button","size":[32,16],"pos":[240,320],"script":"Author.4","style":"invisible"}

{script:Gallery 1.0}
on change x do
 card.widgets..animating:x
end
{end}

{script:Gallery 1.1}
on change x do
 card.widgets..shifting:x
end
{end}

{script:Gallery 1.2}
on click do
  alert["This is the first gallery card!"]
end
{end}

{script:Gallery 1.3}
on click do
  alert["This is the last gallery card!"]
end
{end}

{contraption:3x3 pleasing pattern}
size:[120,120]
resizable:1
margin:[0,0,0,0]
description:"Breathe life into a pleasing pattern, where the image is split across a grid and the pen never lifts.\n\nThis is a 3x3 grid."
script:"3x3 pleasing pattern.0p"
template:"on cycle do\n \nend"
attributes:{"name":["points_string","brush","pattern","style","flickering","shifting","animating","animation","border"],"label":["Points","Brush","Pattern","Button style","Flicker speed","Shifting speed","Animation speed","Animation type","Border"],"type":["string","string","number","string","number","number","number","string","bool"]}
{widgets}
pleaser:{"type":"canvas","size":[120,120],"pos":[0,0],"locked":1,"volatile":1,"script":"3x3 pleasing pattern.1p","scale":1}
points:{"type":"grid","size":[70,170],"pos":[157,-50],"script":"3x3 pleasing pattern.2p","scrollbar":1,"headers":1,"lines":1,"value":{"value":[]}}
upmostright:{"type":"button","size":[12,12],"pos":[108,0],"script":"3x3 pleasing pattern.3p"}
upmost:{"type":"button","size":[12,12],"pos":[54,0],"script":"3x3 pleasing pattern.4p"}
upmostleft:{"type":"button","size":[12,12],"pos":[0,0],"script":"3x3 pleasing pattern.5p"}
middleright:{"type":"button","size":[12,12],"pos":[108,54],"script":"3x3 pleasing pattern.6p"}
middle:{"type":"button","size":[12,12],"pos":[54,54],"script":"3x3 pleasing pattern.7p"}
middleleft:{"type":"button","size":[12,12],"pos":[0,54],"script":"3x3 pleasing pattern.8p"}
bottomright:{"type":"button","size":[12,12],"pos":[108,108],"script":"3x3 pleasing pattern.9p"}
bottom:{"type":"button","size":[12,12],"pos":[54,108],"script":"3x3 pleasing pattern.10p"}
bottomleft:{"type":"button","size":[12,12],"pos":[0,108],"script":"3x3 pleasing pattern.11p"}
flickerspeed:{"type":"slider","size":[100,25],"pos":[-132,0],"interval":[0,360],"value":312,"step":12}
animationspeed:{"type":"slider","size":[100,25],"pos":[-132,47],"script":"Producer.9","interval":[0,600],"value":300,"step":60}
shiftingspeed:{"type":"slider","size":[100,25],"pos":[-132,95],"interval":[0,60],"value":22}
animation:{"type":"field","size":[100,20],"pos":[-132,-50],"style":"plain","value":"none"}

{script:3x3 pleasing pattern.0p}
buttons:upmostleft,upmost,upmostright,
        middleleft,middle,middleright,
        bottomleft,bottom,bottomright

animations:"none","horizontal","vertical",
           "ascending","descending","drawing"

on get_border   do pleaser.border   end
on set_border x do pleaser.border:x end

on get_brush   do pleaser.brush   end
on set_brush x do pleaser.brush:x end

on get_pattern   do pleaser.pattern   end
on set_pattern x do pleaser.pattern:x end

on get_style   do upmostleft.style end
on set_style x do buttons..style:x end

on get_flickering   do flickerspeed.value                              end
on set_flickering x do flickerspeed.value:x&last flickerspeed.interval end

on get_animating   do animationspeed.value                                end
on set_animating x do animationspeed.value:x&last animationspeed.interval end

on get_shifting   do shiftingspeed.value                               end
on set_shifting x do shiftingspeed.value:x&last shiftingspeed.interval end

on get_animations do animations end

# This setting function adjusts the canvas' animation bit as an optimization.
on get_animation   do animation.text end
on set_animation x do
 if x in animations animation.text:x end
 pleaser.animated:!"none"~animation.text
 if !pleaser.animated draw["none"] end
end

on wipe do
 pleaser.clear[]
 points.value:()
 buttons..text:""
end

on instill x do
 points.value:9&1|floor x
 get_points[]
end

on get_points do
 points.value.value
end

on set_points x do
 wipe[]
 if (!x~list "")&!0=count x # This test was particularly annoying to figure out.
  instill[x]
 end
 view[]
end

# Points should be attributes, and only a string suffices for the purpose.
# That hardship is in handling no points, covered by the points attribute.
on get_points_string   do "," fuse me.points    end
on set_points_string x do me.points:"," split x end

on act button id do
 local points:get_points[]
 if !id~last points # A point shouldn't be inserted directly after itself.
  button.text:count instill[points,id]
 end
 button.animated:1<sum id=points
 # This manual view event is very important, and the deck doesn't work without it.
 button.event["view"]
 draw[]
end

on switch button id do
 button.toggle["solid" !card.locked]
 if (!"none"~button.style) #&0~flickerspeed.step%sys.frame
  copies:sum id=get_points[]
  chosen:copies%floor sys.frame/last flickerspeed.interval-flickerspeed.value
  listed:extract value index where gindex=chosen where value=id from points.value
  button.text:if listed 1+first listed end
  button.animated:1<copies
 end
end

on no_warp do
 buttons..pos+buttons..size/2
end

# The warp functions transform the positions derived from the buttons, for draw[].
# Most calculate the distance of the transformation, doubling it for the duration.
# They map their point in the transformation to changes, added to those positions.

# The horizontal and vertical warpings are almost identical.
# They differ calculating distance, and in their last lines.
on horizontal_warp do
 positions:buttons..pos+buttons..size/2
  distance:mag first (first positions)-last positions
  duration:(2*distance)%floor sys.frame/10/shiftingspeed.value
  measured:distance%duration
 if duration>distance measured:distance-measured end
 positions+measured*(1,0,-1)*list 1,0
end

on vertical_warp do
 positions:buttons..pos+buttons..size/2
  distance:mag last (first positions)-last positions
  duration:(2*distance)%floor sys.frame/10/shiftingspeed.value
  measured:distance%duration
 if duration>distance measured:distance-measured end
 positions+measured*(1,1,1,0,0,0,-1,-1,-1)*list 0,1
end

# The ascending and descending warp functions are similar, but more complicated.
# Unlike the other two, the transformations of the points have different speeds.
on ascending_warp do
 positions:buttons..pos+buttons..size/2
  distance:(last positions)-first positions
         x:first distance
         y: last distance
       bxy:list if x>y 1,y/x else (x/y),1 end
   smaller:positions[5]-positions[1]
         x:first smaller
         y: last smaller
       sxy:list 0.5*if x>y 1,y/x else (x/y),1 end
  distance:max distance
  duration:(2*distance)%floor sys.frame/10/shiftingspeed.value
  measured:distance%duration
 if duration>distance measured:distance-measured end
 # Remembering how conformance works with left lists of one element was a pain.
 positions+((1,0,0,0,0,0,0,0,-1)*measured*bxy)+(0,1,0,1,0,-1,0,-1,0)*measured*sxy
end

on descending_warp do
 positions:buttons..pos+buttons..size/2
  distance:positions[2]-positions[6]
         x:mag first distance
         y:mag  last distance
       bxy:list if x>y 1,y/x else (x/y),1 end
   smaller:positions[3]-positions[1]
         x:mag first smaller
         y:mag  last smaller
       sxy:list 0.5*if x>y 1,y/x else (x/y),1 end
  distance:max distance
  duration:(2*distance)%floor sys.frame/10/shiftingspeed.value
  measured:distance%duration
 if duration>distance measured:distance-measured end
 positions+(((list 0, 0),(list  0, 0),(list -1,1),
             (list 0, 0),(list  0, 0),(list  0,0),
             (list 1,-1),(list  0, 0),(list  0,0))*measured*bxy)+
           ( (list 0, 0),(list -1, 1),(list  0,0),
             (list 1,-1),(list  0, 0),(list -1,1),
             (list 0, 0),(list  1,-1),(list  0,0))*measured*sxy
end

# While similar, the drawing warp is too unlike the others to be considered equal.
# I tried and failed to force it into the same interface as the others, in draw[].
# I'd later like to see it make itself a point at a time, entirely eliding line[].
# Nonetheless, as animations shouldn't be written to assume frames, it's unlikely.
# The return value of this one is every point that should be drawn, but no others.

on drawing_warp points do
 positions:buttons..pos+buttons..size/2
     spots:positions@points-1
  distance:    each pair in -2 window spots (    first pair)-    last pair end
  distance:sum each pair in distance    max (mag first pair),mag last pair end
  duration:distance%floor sys.frame/60/animationspeed.value
   partial:duration/distance/count points
   segment:ceil partial
  fragment:1%partial
     spots:segment take spots
     final:-2 take spots
     final:(first final)+fragment*(last final)-first final
 if ((count points)~count spots)&
    1>mag sum floor final-first -1 take spots # This is a hack.
  card.event["cycle"]
 end
 (-1 drop spots),list final
end

on draw animated do
 buttons..toggle["solid" !card.locked]
 animated:animated|animation.text
 pleaser.animated:!"none"~animation.text
 pleaser.clear[]
 local points:get_points[]
 if animated~"drawing"
  pleaser.line[drawing_warp[points]]
 else
  positions:if animated~      "none"         no_warp[]
        elseif animated~  "vertical"   vertical_warp[]
        elseif animated~"horizontal" horizontal_warp[]
        elseif animated~"descending" descending_warp[]
        elseif animated~ "ascending"  ascending_warp[] end
  pleaser.line[positions@points-1]
  # A cycle event is fired when an animation is finished.
  # Comparing the starting positions and those new works.
  # This technique may be flawed, I'll need to see later.
  if (!animated~nil)&(!animated~"none")&positions~buttons..pos+buttons..size/2
   card.event["cycle"]
  end
 end
end

on view do
 each b id in buttons switch[b 1+id] end
 draw[]
end
{end}

{script:3x3 pleasing pattern.1p}
on view do
 draw[animation.text]
end
{end}

{script:3x3 pleasing pattern.2p}
on click row do
 
end
{end}

{script:3x3 pleasing pattern.3p}
on click do
 act[me 3]
end

on view do
 switch[me 3]
end

{end}

{script:3x3 pleasing pattern.4p}
on click do
 act[me 2]
end

on view do
 switch[me 2]
end

{end}

{script:3x3 pleasing pattern.5p}
on click do
 act[me 1]
end

on view do
 switch[me 1]
end

{end}

{script:3x3 pleasing pattern.6p}
on click do
 act[me 6]
end

on view do
 switch[me 6]
end

{end}

{script:3x3 pleasing pattern.7p}
on click do
 act[me 5]
end

on view do
 switch[me 5]
end

{end}

{script:3x3 pleasing pattern.8p}
on click do
 act[me 4]
end

on view do
 switch[me 4]
end

{end}

{script:3x3 pleasing pattern.9p}
on click do
 act[me 9]
end

on view do
 switch[me 9]
end

{end}

{script:3x3 pleasing pattern.10p}
on click do
 act[me 8]
end

on view do
 switch[me 8]
end

{end}

{script:3x3 pleasing pattern.11p}
on click do
 act[me 7]
end

on view do
 switch[me 7]
end

{end}

{contraption:pattern frame}
size:[25,25]
resizable:1
margin:[5,5,5,5]
description:"This decorative frame surrounds patterns in the galleries."
image:"%%IMG3ABkAGQKEEanLeR+enCbC2rK1qNK/dZ2WiU7EfReKiuqKtOk7xjV9yDKejztfO7lwuhuv2AIih7Tl7OUEBn9Hn5FoTVZZHlLDBFZ6xl7GuCdlYsqLRwE="
attributes:{"name":[],"label":[],"type":[]}

{contraption:prototype1}
size:[100,100]
margin:[0,0,0,0]

