How to Create a Page Curl in Corona

Posted by

Page curl effect in Corona SDKAs Corona SDK rises as one of the top platforms for eBook app publishing, the demand for a great-looking page curl effect is also growing.

Therefore, we’ve put together a small project and tutorial that goes over the basic implementation so you can go ahead and implement a page curl in your own apps. Most likely, you’ll have to make adjustments based on how your app is designed (whether you’re using storyboard, etc.)

At the end of this tutorial, there’s a short video that demonstrates this very page curl effect in action.

At the end of the tutorial, I’ll provide you with the resources needed to do this for an iPhone and an iPad in portrait orientation (landscape orientation resources are also included). If you’re targeting a different device configuration/orientation, then by the time you’re finished with the tutorial, you should have an idea of how to produce the page curl resources on your own (hint: the “animation” only consists of two images files).

While we don’t have an API for creating page curls just yet, it can still be done. Currently, there are two ways to implement the effect in Corona:

  1. Use a frame-based animation. This requires you have several full-screen images that will “flip” through to create the animation (similar to how you’d animate a character, but using much larger resources). This method is obviously a resource-hog (and could actually crash your app, depending on your target device).
     
  2. Create an “optical illusion” using a single image, a bitmap mask, and transitions (recommended).

In case you haven’t already guessed, we’ll be going over option #2.

Step 1. Preliminary Work

In order to create page curl effect, you’ll obviously need some pages. Most likely, the “pages” in your app will probably be represented by display groups. For the sake of simplicity, we’ll use two static images to represent the pages: page1.jpg and page2.jpg.

Corona eBook Pages

You’ll also need two more images. One that will represent the “page curl”, and a bitmap mask. With the mask, pay close attention to the fact that it has black edges on the top, bottom, and right-sides of the image:

Corona Page Curl and Mask

And here’s the code to load the pages, and the curl image (loading the bitmap mask will come later):

Step 2. Page Curl Functions

The functions below are responsible for beginning the next and previous page-turning effects. I’ll explain the logic behind it all, but first, here’s the code:

The gotoNext() is responsible for a “next page” curl effect, while the gotoPrevious() does the opposite (initiates a “previous page” curl effect).

Here’s the order-of-logic for the gotoNext() function:

  1. Insert the page-to-turn and the curl image into the ‘turnGroup’ display group.
     
  2. Apply the bitmap mask to the turnGroup.
     
  3. Ensure the reference point for the page and curl is set to the bottom right.
     
  4. Rotate the curl image and place it in its start position.
     
  5. Begin the transition.

And here’s gotoPrevious() in a nutshell:

  1. Ensure the curl image is visible.
     
  2. Setup the onComplete listener for the transition (which is responsible for hiding the page curl and removing the bitmap mask from the turnGroup).
     
  3. Begin the animation transition.

Step 3. Initiate the Page Curl

For demonstration purposes, I’ll call gotoNext() after a 2 second delay, and then 3 seconds later the page will turn back to the first page:

timer.performWithDelay( 2000, function() gotoNext( page1, curlPage, 500 ); end )
timer.performWithDelay( 5000, function() gotoPrevious( curlPage, 500 ); end )

And here is is in action:

And there you have it—a lightweight, efficient way to implement a great-looking page curl effect in Corona. Remember, you’ll have to create your own page curl graphic and mask depending on your target resolution and orientation, but as long as you make them look similar to the one’s shown in this tutorial, the outcome should be the same.

Also, depending on your target resolution, you may have to make small adjustments as far as where the page curl image initially begins, how fast the animation goes, etc. In the project files, I’ve included masks and pages for iPhone and iPad dimensions in both portrait and landscape orientations.

When you’re ready: Download the project files from Github.

Ready to get started?

Create amazing games and apps for iOS & Android

22 Comments

Pukki VisualsDecember 6th, 2011 at 4:26 am

Thanx for this! Great stuff and gives me an idea of Corona “image-transition” module. That would be cool and come in need for many coders out there. Actually should be built-in.. *wink wink* ;)

Dave HaynesDecember 6th, 2011 at 1:01 pm

When you guys post code in your blog using gist, it doesn’t show up in google reader… You might try something like http://www.blogtrog.com for posting code to the blog. I was reading it in Google Reader and going, what the heck? No code?

JoseDecember 6th, 2011 at 4:48 pm

Hey Jonathan,

Great job on the eff

I admit to not having read the code yet, but is it possible to have the the back of the page that’s curling show a simulated “see thru” effect of the front page as in iBooks for the iPhone? Also, how would this work with an iPad in landscape? Will the curl also show the back page if there’s content on the front and on the back?

Thanks

vlaDDecember 8th, 2011 at 6:27 am

Cool stuff.I’m keen on creating apps though I’m only a novice in programming but that doesn’t prevent me from making complex and profitable apps.I’m using snappii.com and consider this service to be the most flexible concerning design opportunities among its competitors.

johnDecember 13th, 2011 at 1:39 pm

Hi Jonathan,
You have a video on Youtube on “How to make a character Jump”. I am really interested in it. I was not able to see the codes by whatching the video and I can not find it anywhere on the blog. Can you please share the codes for that tutorial? Thank you for the help and great work as always.

Jonathan BeebeDecember 13th, 2011 at 1:45 pm

@john: You can get the code from the “Jumping” video here: https://github.com/jonbeebe/Character-Jump

I also updated the video with a link to get the project files as well. For others interested, here’s the link: http://youtu.be/oE_45hJVf-E?hd=1

JohnDecember 14th, 2011 at 5:24 pm

Great!! Thanks.

TanyaDecember 15th, 2011 at 11:14 pm

Hi Jonathan,
Nice tutorial. Any date yet on when the Corona Ebook under templates will be made available? Have been anxiously checking it for a couple of months now.
Thanks :)

AlexDecember 31st, 2011 at 8:54 pm

Thanks for this great tutorial. What’s the best approach to add pages? I have about 100 pages I would like to integrate into this :)

Thanks and happy new year!!!
Alex

Robert BinghamJanuary 5th, 2012 at 8:57 am

Alex that easy way to do that is to Edit the main.lua file in Notepad, Notepadd ++ or editor of your choice. Ensure you dimensions on the “pages” is set to 320×480.

and do the following with your code:

local page3 = display.newImageRect( “page3.jpg”, display.contentWidth, display.contentHeight )
page3:setReferencePoint( display.TopleftReferencePoint )
page3:toBack() – make sure 3nd page is underneath the first one

local page4 = display.newImageRect( “page4.jpg”, display.contentWidth, display.contentHeight )
page4.x, page4.y = display.contentWidth*0.5, display.contentHeight*0.5
page4:toBack() – make sure 4th page is underneath the first one

local page5 = display.newImageRect( “page5.jpg”, display.contentWidth, display.contentHeight )
page5:setReferencePoint( display.TopleftReferencePoint )
page5:toBack() – make sure 5th page is underneath the first one

local page6 = display.newImageRect( “page6.jpg”, display.contentWidth, display.contentHeight )
page6.x, page6.y = display.contentWidth*0.5, display.contentHeight*0.5
page6:toBack() – make sure 6th page is underneath the first one

local page7 = display.newImageRect( “page7.jpg”, display.contentWidth, display.contentHeight )
page7:setReferencePoint( display.TopleftReferencePoint )
page7:toBack() – make sure 7th page is underneath the first one

you will need to change the local page”Number”
as well each subsequent page”" to refelect the page that you have. once your past that point you have to include how the page is handled once a user clicks or touches or attempts to swipe the page as this example is set to automatically transition the pages back and forth (see the last couple of lines of code in the main.lua file)

iAZZoZiTTiJanuary 10th, 2012 at 12:08 pm

Thanks for this excellent tutorial .

I have 2 questions :
1st Question : – As you will see in the code below – I made 4 pages with this page curl feature and I registed the 2nd and 3rd pages to swipe function (event) which makes the pages curl when I swipe over them .

========================================
local function swipe(event)
local currentPage = event.target
if event.phase == “moved” then
if event.xStart > event.x then
gotoNext (currentPage, curlPage, 1000)
elseif event.x > event.xStart then
gotoPrevious(curlPage,1000)
end
end
return true
end
========================================
- The code before swipe function is same to the one in this tutorial except that I have 4 pages -

page1:addEventListener( “touch” , function() gotoNext( page1,curlPage,1000 ) return true end )
page2:addEventListener( “touch” , swipe )
page3:addEventListener( “touch” , swipe )
page4:addEventListener( “touch” , function() gotoPrevious(curlPage,1000) return true end )
========================================

every things go right when I go from the 1st to 2nd and go back to 1st , and same thing when I go from 2nd to 3rd page and go back to 2nd , and same thing with the 3rd and 4th pages .

The problem is that when I reach the 4th page and try to go back to the 2nd page throught the 3rd page , the curl page works fine but the 3rd page stuck and doesn’t move . And same thing when I reach the 3rd page and try to go back to the 1st page throught the 2nd page , the curl page works fine but the 2nd page stuck and doesn’t move .

Obviously that when the 2nd and 3rd pages call the function gotoNext () which is found in the function swipe (event). After , they no longer call the function gotoPrevious () which is found in function swipe (event) as well .

***************************

2nd Question : What I sould do to make the curl page and other pages curl from left to right to make like an Arabic book – who read and write from right to left – ?

Sorry for my huge post and questions ^_^

ViniciusJanuary 19th, 2012 at 9:22 am

It’s possible to use this code with Director class or even Storyboard? Anyone had already tried?

Thanks

Vinicius ArmelinJanuary 19th, 2012 at 9:29 am

Hey guys, it’s possible to use this code with Director class or even Storyboard? Anyone had already tried?

Thanks

SimonJanuary 27th, 2012 at 2:28 pm

For Director Class…you can use it this way.
-
-====================================================
local localGroup = display.newGroup()

local background = display.newImage( “background.png” )
local turnNextPageImage = display.newImage( “nextIcon.png” )
turnNextPageImage.x = display.contentWidth/2
turnNextPageImage.y = display.contentHeight/2

local turnPreviousPageImage = display.newImage( “backIcon.png” )
turnPreviousPageImage.x = display.contentWidth/2
turnPreviousPageImage.y = display.contentHeight/2 + 100

local page1 = display.newImageRect( “page1.jpg”, display.contentWidth, display.contentHeight )
page1:setReferencePoint( display.TopleftReferencePoint )
page1.x, page1.y = display.contentWidth*0.5, display.contentHeight*0.5
page1.isVisible = false– = .3

local curlPage = display.newImageRect( “curlPage.png”, display.contentWidth, display.contentHeight )
curlPage.x, curlPage.y = display.contentWidth*0.5, display.contentHeight*0.5
curlPage.isVisible = false

— group to hold the page that will be turned (as well as the “curl” page)
local turnGroup = display.newGroup()

— The following function will turn the page “back”
local function gotoPrevious( event )

local time = time or 500
if event.phase == “began” then
curlPage.isVisible = true
local hideCurl = function()
curlPage.isVisible = false
director:changeScene( “screen2″, “moveFromLeft” )
end

transition.to( turnGroup, {maskX=display.contentWidth*0.5+100, time=1500 } )
turnPreviousPageImage.isVisible = false
turnNextPageImage.isVisible = false
background.isVisible = false
transition.to( curlPage, { rotation=45, x=display.contentWidth+(display.contentWidth*0.10), y=display.contentHeight + (display.contentHeight*0.25), time=1000, onComplete=hideCurl })

end
end

local function goToPage( event )
if event.phase == “began” then

turnNextPageImage:removeEventListener(“touch”, goToPage)
turnGroup:insert( page1 )
turnGroup:insert( curlPage )

– mask should match dimensions of content (e.g. content width/height)
local curlMask = graphics.newMask( “mask_320x480.png” ) – iPhone portrait
–local curlMask = graphics.newMask( “mask_768x1024.png” ) – iPad portrait
turnGroup:setMask( curlMask )

– set initial mask position
turnGroup.maskX = display.contentWidth * 0.5+100
turnGroup.maskY = display.contentHeight * 0.5

– prepare the page-to-be-turned and the curl image
page1:setReferencePoint( display.BottomLeftReferencePoint )
curlPage:setReferencePoint( display.BottomRightReferencePoint )
curlPage.rotation = 45
curlPage.x = display.contentWidth+(display.contentWidth*0.10)
curlPage.y = display.contentHeight + (display.contentHeight*0.25)
curlPage.isVisible = true

local function changePage(event)
director:changeScene( “screen3″, “moveFromLeft” )
end

– show pagecurl animation and transition away (next page should already be in position)
local time = time or 500

local function hideCurrentPage(event)
curlPage.isVisible = false
end

transition.to( turnGroup, { maskX=-display.contentWidth*0.75, time=1500, onComplete=hideCurrentPage } )
transition.to(turnNextPageImage,{time=1500,alpha=0})
turnPreviousPageImage.isVisible = false
background.isVisible = false
transition.to( curlPage, { rotation=0, x=0, y=display.contentHeight+20, time=1500, onComplete=changePage} )
curlPage.yScale = curlPage.y * 0.2
end
end

turnNextPageImage:addEventListener(“touch”, goToPage)
turnPreviousPageImage:addEventListener(“touch”, gotoPrevious)

–================================================

Hope this helps.

Vinicius ArmelinJanuary 31st, 2012 at 5:04 am

@Simon

I’ll try it. =]

Thanks

RobertFebruary 3rd, 2012 at 2:14 pm

The idea is nice, but both the example by Jonathan and the Director version by Simon are still “proof of concept”. When implementing the example by Jonathan with a series of pages I also encounter the issue reported by iAZZoZiTTi. And in the Director example you will see a black page during the curl – not very pretty. Anyway, as a “proof of concept” very valuable, but please do not stop working on a solid solution.

MarcosMarch 18th, 2012 at 8:23 pm

Dear sirs,

How can I implement Page Curl Effect in StoryBoard ?

Thank you,
Marcos

JeffreyMarch 19th, 2012 at 5:07 pm

Hello,

I want to make an Ibook to upload to Apple Ibook store. Can I use your software to do this sort of book with curls or is this only for the app store?

AlanMarch 26th, 2012 at 10:44 am

I have encountered the same problem as iAZZoZiTTi, in that if I want to use more than one page in this way I can only go back once (e.g. ig I go forward to page 5 I can only go back to page 4). If I try to go back futher, the ‘curl’ image shows up, but the page remains on the same page. I have tried using print statements in the goToNext() function, and have noticed that it does not always add the corerct number of objects to the turnGroup. I have a ‘pagetext’ object and a ‘pagebackground’ for each page and apply this to both pages. The first time it is called (on a pagebackground) it inserts 2 objects into the turnGroup (the currentPage and the curlPage), however when the pagetext object uses the same function (on the line immediately after the first call), it only inserts the currentPage parameter into the turnGroup – not the curlPage one. I presume that this is somehow causing the problem, but I have no idea why it is happening?

BasantaMarch 28th, 2012 at 6:59 am

i want to curl the page from bottom to top,can anybody please help me????????

LucianeMarch 31st, 2012 at 9:50 pm

Has anyone implemented page curl with storyboard?

FreeDevzApril 13th, 2012 at 9:17 pm

Having same problem as Alan, any updates on this?

Leave a comment

Your comment