Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Screwtapello

61
Posts
3
Topics
12
Followers
7
Following
A member registered Oct 02, 2017 · View creator page →

Creator of

Recent community posts

In the “Events” section of the Decker documentation, one of the listed events is view for any widget, described as “The surrounding card is active, repeatedly at 60hz.” I expected this to be something like “The surrounding card is active and the widget’s animated property is true, repeatedly at 60hz.”

Have I missed something? Is there some way to get a 60hz event without setting the animated property?

The Canvas is the only widget that has both click and release events, and the Button is the only widget that responds to keyboard presses, so you can’t make something that starts when you hold a key and stops when you release.

However, you can make the button send a click, then wait a while, then send a release, which is probably as close as you’re going to get:

on click do
 canvas1.event["click" 0,0]
 sleep[15] # in 60ths of a second
 canvas1.event["release" 0,0]
end

That can look a little weird, since Decker disables all interactive widgets (drawing them greyed out) until the sleep time is complete, but it prevents the player from doing more things while the previous things are still going on.

If you don’t want to freeze things like that, you can build something a little more complex that lets Decker keep doing things while you wait. Create a field to hold the timer countdown, and change the button click handler to:

on click do
 canvas1.event["click"]
 field1.data:15
 field1.animated:1
end

So when the button is clicked, it sends the click event to the Canvas, it loads 15 into the field, and sets the field to be animated (so Decker sends it view events 60 times a second). The field’s view handler looks like this:

on view do
 me.data:me.data - 1
 if me.data = 0
  canvas1.event["release" 0,0]
  me.animated:0
 end
end

So every time view is called (that is, 60 times a second), it subtracts 1 from the value it stores. When it reaches 0, it sends the release event to the canvas, and turns off animation again. As a result, when the button is clicked, the canvas is “clicked”, then things keep happening as usual while the timer ticks down, and when it does the canvas is “released”.

The field can be made “Show None” if you don’t want the player to see it; if you make the button “Show None” then it won’t react to the keyboard. However, you can make the button use the “Invisible” style to hide it, and “Show Transparent” to make it invisible even when clicked. You can also just move it off-screen.

When you click a link in a field, that sends a link event to the field. If the field doesn’t handle it, it bubbles up to the card the field is on - in this case, the contraption’s prototype. If the prototype doesn’t handle the event, it bubbles up to the default event handlers, including this one:

on link x do
 go[x]
end

If you want clicking a link to anything other than go straight to the target, you have to add your own on link... handler to interrupt the default handling.

The easiest thing is just to put it into the prototype’s script, especially if you always want clicking a link in one of these text fields to display an alert before moving on, something like:

on link target do
 alert["You have clicked a link. This will be reported to the authorities."]
 go[target]
end

If you want different contraptions to have different behaviour, you’ll want the link event inside the prototype to become a link event on the contraption, by putting something like this in the prototype’s script:

on link target do
 # forward the event to the contraption
 card.event["link" target]
end

Then you can put different on link... handlers on different copies of the contraption, for different behaviour.

You can’t put an active widget into a rich text field, but you can put a link into a rich text field, and there’s a link event that fires when the user clicks on a link, so that would probably be the easiest way to deal with it.

If you really need a button, you could put a few blank lines at the end of the rich text field, put an extra button inside the contraption, and have an event handler that continually adjusts the position of the button based on the field’s .scroll property. You’ll probably also need to use the maxscroll helper function from that post to figure out whether you’re within (button height) pixels of the end of the content. You may also need to mess with widget ordering to make sure the button appears above the rich text field but behind the horizontal scroll bar.

For the second question, when you say “Font Importer”, do you mean the deck described in this post? For the font you describe, you’ll need the deck as described in the OP, and the changes to support sizes other than 8x8, and the changes to support modern versions of Decker. You should also have your font as black text on a white background - if you want it to appear in white, you can use Decker’s text formatting tools later. Lastly, importing a font adds it to the list of fonts embedded in that deck - to use it anywhere else, save the deck to a file, then open the deck where you want to use the font in Decker, drag-and-drop the deck-with-the-font onto Decker, which should bring up the Font/DA Mover where you can copy it across.

(2 edits)

You left Decker running for 24.8 days?

EDIT: Wait, no, I see what’s going on.

Native Decker computes sys.ms as a float, Web Decker takes a float from the browser and truncates it into a 32-bit integer.

I guess it shouldn’t matter if you’re using sys.ms for performance timing (duration:sys.ms - start) but it does make problems if you’re trying to divide the clock with a modulus operator.

This was my first jam - it’s been really interesting playing with all the submissions, and encouraging to get such lovely comments on mine.

Thanks to everyone who participated!

This was lovely. Very simple, but it’s fun to explore a new place, and this definitely gave me nostalgia for Myst and games like it.

I like the palette! Very moody and retrospective.

This has been my first ever jam of any kind, and I was thinking about doing more of them, so reading about your experiences on card10 was interesting, and has given me something to think about. Thanks!

This is pretty cool! Obviously Decker is not designed for this kind of thing, but that only makes it more cool. :)

I couldn’t get the metronome or the one-voice synthesiser to work, but the tutorial cards and mouse-tracking and even the tone generator worked fine.

As a proof-of-concept, I wasn’t expecting much beyond the addition example on the first card, but you clearly went a lot further than that! Well done!

This is very cute! The sound effects help a lot - are the barks also courtesy of Buddy the Dog?

You’re right, that was pretty dark, but in a dark-humour kind of way. The name/gender screens in the introduction were a fun way to introduce the subject matter, and all the pictures of Deo were really well drawn.

I played enough times to get a picture with Deo, and now I feel like I’m an accomplice to some kind of crime.

I learned about frogs, chickens, and the Philippines today! Thank you! And your drawings are extremely cute.

Those feelings are a bit outside my experience, but you express them well. The crumpled blank paper aesthetic makes me feel isolation and emptiness, which I think is what you were going for.

That’s some fun abuse of Decker widgets. I was particularly impressed by the sliders-as-toggles on the last card!

I think on loop is checked when you visit a new card, so that the new card has a chance to stop the loop, or start a new one. For example, if one card represents the player standing beside a waterfall, it would be more atmospheric if a loop of waterfall noise played whenever that card was visible. When the player visits that card, the loop should start immediately (even if some other loop was already part-way through playing) and when the player leaves that card, the loop should stop immediately (even if the waterfall noise was part-way through). Calling on loop on card transitions makes that kind of effect possible.

If your two songs are less than 10 seconds in total, you could combine them into one sound and loop that quite easily.

If your two songs are more than 10 seconds long in total, you might add a “last loop started at” field on the same card as the counter that switches between them. When you start playing a sound, update the counter, and set the “last loop started at” field to sys.ms (the current time in milliseconds). When on loop is called, it passes in the old sound - if the “last loop started at” time, plus the duration of the old sound in milliseconds (old.duration*1000, since the duration is in seconds), is nearly equal to sys.ms, then we’re probably looping because we got to the end of the sound. If the start time + the duration is greater than sys.ms, then the loop has been called early, probably because of a card change. If you return the original sound, it will continue playing it, rather than restarting it.

This is pretty handy!

As a tip, since the YouTube URL is always based on the base URL, the ID, and the timestamp, instead of creating it at insert time and adding it as an extra column, you can create it when the user clicks on the grid. That way, you get extra space on-screen for the description column, and if you edit the timestamp, you don’t also have to edit the URL to make it “stick”.

Also, that is a very cool video to use as the default example. :)

I love all the era-appropriate clip-art! The contrast between the wholesome pictures and the cynical tone is fun.

That’s a nice collection of photos, and the dithering makes them just a bit more surreal. I particularly like the way you’ve filled some parts with Decker patterns - a creepy door with a sky filled with cute polka-dots behind it just adds to the creepiness.

One minor issue: on the final card, the “END” text isn’t locked, so you can select it and type over it; I assume that’s unintended.

I just played through the current version. It was fun, even if the setting was a bit gruesome.

When I started playing, it took me a while to figure out I could click on the person in the other cell; I didn’t recognise it as the silhouette of a person at first.

In the “guess the ages of the children” puzzle, I got a bit annoyed that one of the clues was apparently “on the wall behind me”, but I couldn’t find a way to turn around; I actually rewound the game back to the previous section looking at the desk to see if there was a number on the wall I couldn’t remember. Turns out there wasn’t, and even if there had been a way to get that clue it wouldn’t have helped - it’s not necessary to solve the puzzle. I feel like it’s a distraction to mention it at all. On the other hand, I really liked the final clue - it was a great “But why would.. ohhh!” moment.

I used two hints on “guess the occupation” and one hint on “guess the number of the safe”, but I made it through.

There’s a certain audacity in publishing a photo album as a series of low-resolution, dithered black-and-white images, and I really admire it. They look great!

I know a lot of Decker projects are just people trying to make a cool little thing, so I don’t expect a credit, but “Screen melt transitions by Screwtapello” would be nice.

Are you using a .deck file (which you have to load into a program running on your desktop or laptop) or a .html file (which you run in a web browser)?

If you are using a .deck file, you don’t need to replace it. You can replace the old Decker.exe with a new one downloaded from Itch, and it will be up-to-date.

If you are using a .html file in a web browser, it contains both your deck and a copy of Decker that runs in the browser. To update that version of Decker, you can:

  • go to https://beyondloom.com/decker/tour.html which always has the latest HTML version of Decker
  • from the File menu, choose “Open…”
  • you should be prompted for a deck to open; choose the deck you want to update
  • your deck should now be running in the updated Decker in the browser
  • from the File menu, choose “Save As…”
  • when asked, choose a filename that ends in .html and click Save
  • your browser should start downloading a file with the name you chose; it will be your deck wrapped in an updated version of Decker

Thanks!

When you assign a value to a name in an event handler, like this:

on view do
 p:1+2
end

…when Decker decides the thing is being viewed:

  • it calls the view event handler
  • it creates a new name p inside that event handler
  • it assigns the value 3 to p
  • the event handler ends
  • p vanishes along with it

If you have some other event handler somewhere else, like on click do ... end, that event handler does not have access to p, it can’t use the value. If you say p:2*3 in that event handler, it will have its own p that will also vanish when the event handler completes.

In the first code block in your comment, you have:

on view do   
p:"%p" parse "%e" format sys.now  utc_offset:1  
p.hour:24%utc_offset+p.hour  b:(p.hour)
me.text:"%f:" format b      
end

That creates a p with date-time information in it, it adjusts the hour part of that date time, it uses the p for some text formatting, and then the event handler ends and that p is lost.

In your second code-block, which I assume is from a button’s on click do ... event handler, you have:

...
p:"%p" parse "%e" format sys.now
...
if (p.hour=12)&(p.minute=13) 
...

Because that’s a separate event handler, that’s a separate and unrelated p, and its p.hour has not been modified. Every event handler where you want to use the modified time, you need to modify it again.

Also, a little further down:

...
elseif ((p.hour) <10) & ((p.hour) >20) 
...

I don’t think the hour can be less than ten and greater than 20. Perhaps you wanted to switch those around to be “greater than 10 and less than 20”?

Assuming that’s what you want, here’s a button that behaves that way (although it uses Decker’s built-in alert[] rather than the dd.say[] module):

%%WGT0{"w":[{"name":"timelock","type":"button","size":[95,20],"pos":[226,161],"script":"on click do\n p:\"%p\" parse \"%e\" format sys.now  utc_offset:1  \n p.hour:24%utc_offset+p.hour\n\n if ((p.hour) >10) & ((p.hour) <20)\n  alert[\"###ACCES AUTORISE ENTRE 20H ET 10H###\"]\n else\n  alert[\"###ACCES INTERDIT ENTRE 10H ET 20H###\"]\n end\nend","text":"Attempt Unlock"}],"d":{}}

Copy that text to the clipboard, then in Decker you should be able to switch to the widget-editing mode and use Edit → Paste Widgets to add the button to the current card, where you can poke at it.

I was having a rough day yesterday, and having something so beautiful and cheerful and playful to look through absolutely brightened my day!

I did find some minor problems:

On the card “lockeddecks”, the label “How to lock a deck” is editable, and I think it shouldn’t be?

On the card “gridscale”, it says Decker’s Fat Bits mode was named after “a program that magnified the screen on classic Macs”, but it links to a program for OS/2, not for classic Macs, and the program came out six years after MacPaint was released with a Fat Bits mode.

I think the real reason Decker has a “Fat Bits” mode is because somebody somewhere had the experience of using HyperCard (or MacPaint), seeing “Fat Bits” mode in a menu, enabling it out of curiosity, and then (after a moment’s confusion) realising it was a super-power for making even better art. “Zoom” is a thing you find in professional software like Microsoft Word and Photoshop, “Fat Bits” is playful discovery and better suited to Decker.

It’s hard to squeeze all that into a little “why is zoom called fat bits” aside, though. :/

Still, this is an amazing resource. There was a lot of stuff in there I didn’t already know (especially about the art side of things) and probably things I didn’t know I needed yet - but at least now I can look them up easily. I will definitely be showing it to people who want to know about Decker!

As somebody coming from a Python background, it’s taking me a while to adjust to making the most use of Decker’s strengths. So far, I’ve found the “Cards are Workbenches” to be the most empowering thing - where in Python I might write a suite of unit-tests, in Decker I can drop down some sliders and a canvas, wire them up, and see the thing I’m working on updating at 60fps. And once I’ve gotten the thing to work the way I want, other cards can just read the values of those sliders.

I discovered a bunch of things from that post, including:

  • making a button transparent, and then drawing a custom icon behind it
  • there’s a navigation history so that go["Back"] always does the right thing
  • the correspondence between foo.key and foo["key"] is not just for dicts (as in JavaScript) but you can also do card.event.reset instead of card.event["reset"] to invoke an event handler
  • I had thought about “cards as objects”, but didn’t realise it could be so ergonomic to use them that way; the link between cards and contraptions seems even stronger

Thanks for writing it!

I love the intro animation where the letters teleport in, Mega Man style. Very cool!

You’re almost there, but unfortunately Decker doesn’t allow you to add a pressed attribute to a button like that. If you want to keep track of a flag like “treasure taken”, the easiest thing would be to make a button in the puzzle-room called treasuretaken, configure it to be a checkbox, and “Show None”. Then the button that takes the treasure can do:

on click do
 treasuretaken.value:1
end

(note that you have to say 1, not true: Decker’s scripting language Lil does not recognise true and false specially, and treats them both as undefined variables)

…and the button that checks for taken treasures can do:

on click do
if puzzleroom1.treasuretaken.value & puzzleroom2.treasuretaken.value
 dd.open[deck]
 dd.say["You successfully stolen all treasures!"]
 dd.close[]
 go["end"]
else
 alert["You must collect all treasures to leave!"]
end
end

(note that the way to say “both these things must be true” is & not and - Lil does not recognise and either)

Ah, here’s what I see:

  • when I start the game, no sound
  • when I click on the background, the background loop plays once
  • when I click on the “next” button, there’s still no background music
  • if I press the left-arrow key on the keyboard to go back to the first card, the background loop begins playing, and loops properly

From the documentation, under Web-Decker and Native-Decker:

Most web browsers do not allow programs to play audio until the user has interacted with a page, so any play[] commands issued before a user has clicked, tapped, or pressed a keyboard key will have no effect.

I think this is what you’re bumping into, since your deck tries to play audio when the first card appears. The simplest workaround would be to also start looping the sound on the second card, so that whether somebody’s using Web Decker or Native Decker, they get the background loop eventually. A more complex solution would be to add a pre-title card that the user has to click through to get to the title card.

Does looping work for you in the official All About Sound deck? In my browser (Firefox on Linux) I can click “Start Loop” and it runs for at least 11 loops (that’s when I got bored).

What browser are you using, on what platform?

How long is the sound that you’re looping?

How long does it pause for?

(1 edit)

When you use go[] with a transition, the transition animation needs two Images to animate between, so it sends the view[] event to the target card to see what it’s going to look like. Then, when the transition is complete and the new card is visible, it gets another “view” event like normal.

So no, you’re not doing something wrong, that’s just how Decker works.

If you’re struggling to get the solutions in that other thread working, here’s another alternative: by default, a transition takes 30 frames (half a second), so if view gets called twice within the same second, it’s probably because of a transition, and we can ignore the second one.

If you put a field named lastview on your card, you can use it to keep track of the last time view was called, like this:

on view do
 # If the current frame is more than
 # 60 frames (one second) since
 # the last time view[] was called,
 # call realview[].
 if sys.frame > lastview.data + 60
  realview[]
 end

 # Log that view[] was called
 show["viewed" card.name]

 # Update our records for next time
 lastview.data:sys.frame
end

on realview do
 show["real view"]
end

You should make the lastview field invisible and locked so that players don’t accidentally mess with it.

If you go to this card without a transition, in the Listener you should see the log messages:

"real view"
"viewed" card1

If you go to this card with a transition, you should see the log messages:

"real view"
"viewed" card1
"viewed" card1

realview[] was called for the first view, but the second view happened so soon afterwards, that it skipped calling realview[] the second time.

Ah, yeah. The “margins” of a prototype also divide up the prototype background into a 3x3 grid. When a contraption is resized: the top-left tile of the prototype is drawn at the top-left corner of the contraption; the top-centre tile of the prototype is tiled horizontally across the top of the contraption; the top-right tile of the prototype is drawn at the top-right corner of the contraption, and so forth.

The default introduction/tutorial deck you get when you launch Decker has a page on “contraptions”, and one of the examples is a “resizable decorative border” contraption that demonstrates the behaviour nicely.

If you want to draw the background with code, you’ll need a canvas widget if only because the Image protocol you get from card.image doesn’t provide a lot of drawing primitives. You can use a “hidden” canvas widget, draw the background you want, then do card.image:canvas.copy[0,0 canvas.lsize] to paste it onto the contraption background, or (much easier) just make the canvas widget cover the area of your prototype, and Decker’s default resize behaviour (with the margins and such) will make sure it stays in place as the contraption is resized.

Lil’s vector-handling made more sense to me when I learned that it was inspired by a language called K, which was inspired by a language called APL, which was designed (among other things) to be a more modern alternative to traditional mathematical notation. Mathematicians will use + to represent addition of integers or complex numbers or matrixes or anything other random thing that obeys the algebraic laws of addition, and APL (and eventually Lil) uses + in a similar way.

If you think about vectors in the way they’re normally handled in languages that weren’t designed around the concept (like Python or Fortran), then yeah, you’re not going to get the full benefit. I also have found Lil to be a bit mind-bending (I came up with 1+0*range 5 for what I’ve now learned is more idiomatically expressed as 5 take 1), but it’s still so much more approachable than APL or even K, and there’s this whole cool retro-themed multimedia sketchpad tool built around it.

If you can provide an example contraption that exhibits the behaviour you describe, that would help. If you can set it up in a new deck, you can select the contraption, do Edit → Copy Widgets, and then paste the result into a reply here. That’s what I did to create the examples in my reply - if you copy a contraption, Decker even includes its prototype.

Is there ANY way to resize an internal canvas(es) on a contraption resize?

If you make your prototype “resizable” (when you’re editing a prototype, from the “Prototype” menu make sure the last item “Resizable” is ticked), then you should be able to resize the contraption when you add it to a card. If you also tick “Show Margins” in the Prototype menu, you’ll also get four little handles you can use to mark the left, right, top and bottom margins of the prototype: any part of a widget that is between the edge of the prototype and the margins will stay at that fixed distance from the edge, any part of a widget that is in the middle will be proportionally resized as the contraption is resized.

%%WGT0{"w":[{"name":"prototype11","type":"contraption","size":[98,91],"pos":[86,66],"def":"prototype1","widgets":{"canvas1":{"size":[81,41]}}}],"d":{"prototype1":{"name":"prototype1","size":[100,100],"resizable":1,"margin":[0,25,0,0],"widgets":{"canvas1":{"type":"canvas","size":[83,46],"pos":[8,9]}}}}}

If you paste the above widget definition into a card, you’ll get a contraption with a canvas in the top half of it. The top edge of the canvas is between the top edge of the prototype and the top margin, so it stays at a fixed distance from the top of the contraption as it is resized. The bottom edge of the canvas is between the top and bottom margins, so it moves proportionally as the contraption is resized.

If you are trying to write code to reposition widgets in a deck, that should work, but it may be overidden by the “built in” resizing behaviour described above? I’m not sure, I haven’t tried it.

But, then that raises another question, I am uncertain where to initialize long term state on a card or contraption.

The best place to put long-term state on a card or contraption is in a widget. Widgets don’t have to be in the centre “white” part of a prototype, you can stash them in the dark-grey border area - but make sure they’re locked so the user can’t accidentally interact with them. For most data types (numbers, strings, lists, dicts, tables) you can just use a regular field, and read and write its .data property. If you want to store a bunch of images (such as sprites), the best way is to use a rich-text field; you can paste the images in, and access them from code by reading the .images property.

Also, is there a working example of get_ and set_ for prototypes?

If you edit a prototype and choose “Script…” from the Prototype menu, you can enter a handler like this:

on get_foo do
 "here's a foo"
end

Then, let’s say you make a contraption from this prototype, called mycontraption. If you say mycontraption.foo, that will evaluate to the string "here's a foo". Here’s a pasteable example of that in action:

%%WGT0{"w":[{"name":"mycontraption","type":"contraption","size":[100,100],"pos":[86,66],"def":"prototype1","widgets":{}},{"name":"button1","type":"button","size":[84,20],"pos":[93,40],"script":"on click do\n alert[mycontraption.foo]\nend","text":"Gimme a foo"}],"d":{"prototype1":{"name":"prototype1","size":[100,100],"margin":[0,0,0,0],"script":"on get_foo do\n \"here's a foo\"\nend","widgets":{}}}}

Setting works the same way: define on set_foo val do ... end and it will be called when code does mycontraption.foo:somevalue.

If you want to be able to get and set values interactively, rather than just through code, you can also use “attributes”, but that’s an optional, additional layer on top of get_foo and set_foo that you don’t have to worry about otherwise.

That’s a good point, thanks!

I’m working on a deck right now, using my laptop, and I’ve been using the arrow keys to quickly switch between cards. I gave it to a friend (who is unfamiliar with Decker) to test on their phone, and their very first comment was “when I swipe left to go to the next card, it takes me to the previous card instead”.

I want to address this, but I’m not sure how.

  • I could say “that’s just how it is, deal with it”, but I imagine other people will get tripped up by this too
  • I could override the navigate event to work “backwards”, which will make touch-screens feel more natural, but then arrow-key navigation is weird
  • I could override the navigate event to do nothing, which prevents a convenient shortcut but also prevents confusion

I already have “back” and “next” buttons on every card, as well as a table-of-contents card, so losing the navigation shortcuts wouldn’t be the worst thing in the world, and that is probably what I’ll go for.

Are there any other alternatives?

The “Patterns Interface” section of the Decker docs describes the animated patterns as:

A list of up to 256 pattern indices for animated patterns.

You can include solid “red” and “black” in the animated sequence because they have pattern indices (35 and 1). But if you want a pattern pattern, those are described as:

An 8x8 image interface comprised of patterns 0 and 1.

So actual patterns can’t have red in them, only patterns 0 and 1, which are (by default) white and black. You could set palette 32 to be red instead of white to get red-and-black animations, but that would make every white pixel red, which probably isn’t what you want.