Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2006-208
$eventId
ID of event: wwdc2006
$eventContentId
ID of session without event part: 208
$eventShortId
Shortened ID of event: wwdc06
$year
Year of session: 2006
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC06 • Session 208

Introducing Core Animation

Graphics and Media • 43:08

Core Animation is an exciting new layer-based animation framework that can enhance your application with eye-catching animations, dazzling interactive visualizations and enhanced UI. See how you can use Core Animation to composite and animate 2D, 3D, and even Quartz Composer-based content into dynamic scenes. Don't miss the opportunity to learn how Core Animation can revolutionize the visual qualities of your application!

Speakers: Ralph Brunner, John Harper

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it may have transcription errors.

Hello, and welcome to the strawberry themed core animation session. The animation you see in the background here has not been made with core animation, but it could be. I bet it's like 500 lines of code. Anyway, yeah, that's me. So let me talk a bit about the entertainment for the coming hour. So I will give you a brief introduction of what Core Animation is, an architectural overview that fits in the system, and what are the key components that make it work. And we're going to talk about layers and their APIs and the animation model.

And towards the end, we're going to talk a bit about how it fits in with the higher-level frameworks, like AppKit, and how Interface Builder helps you to get to these features a bit easier than writing code. OK. So-- kind of the motivation. So it turns out that doing these composite animated dynamic UIs is kind of hard. And what you think about-- somebody got that joke. OK.

So if you think about, say, the Keynote Canvas that you're seeing here, or iChat U+3, where you see a picture here, or Front Row, you tend to have a lot of images and text moving around. You try to get smooth animation and seamless compositing and these kind of things. And you have to do quite a bit of work to get that. So we thought, well, that is the kind of type of work that the OS could do for you. And let me give you a short demo to give you a kind of visual of what I'm talking about.

OK, so this is kind of a toy app. It's a recipes browser. So you select, say, desserts, and then move over, and then scroll through your list of something. And you scroll further, and these kind of things. And you notice it's smooth animation. There are definitely several layers being composited here. That's all for the demo for now. Just keep that image in mind as I'm going forward.

So a bunch of examples, yeah, you can read those. It is used in Leopard for a slideshow, the time machine, the workspaces, preferences pane, and the composition picker, the image-- what is it? Picture taker panel now? These kind of things. Here's kind of the architecture diagram how this all fits in. So core animation sits primarily on top of core image, and which in turn then sits on top of OpenGL, and some of it sits on top of Quartz. So this is kind of an interesting point, that core animation, every single frame, will build a filter chain in core image that then renders its output. On top of core animation, there are essentially the clients. So the dot dot dot is your app. Wow.

Cocoa sits on top of it. QuickTime sits on top of it. And as I mentioned before, a bunch of system apps are using it. OK. So this is kind of the goals for the framework slide. So the goal is really to get high performance compositing animation, which really means 60 frames per second or whatever the refresh rate of your display is.

It's also important to have something that one can-- is in kind of a manageable state to work with. And for that, we chose an NSView-like recursive abstraction. So you have a layer, and it has a bunch of sublayers, and it kind of does what you expect. So if you move that layer, all its children layer move with it, and these kind of things. Also important is to have an abstract interface for animations. And what that really means, you don't have a callback that says, OK, what do we do this frame, and then this time, this time, and once more. So nothing that really runs at 60 frames per second. You want to have a sufficiently abstract representation of that, which is, OK, this object needs to move from A to B, and it takes half a second.

So the key message on this slide is the animation is done for you by core animation. And it happens on a separate thread. The key there is if you do animation in your run loop, well, you're kind of at the mercy of the other workload that the run loop has to do. Every now and then, an application goes and hits the disk and reads the database and stuff like that. That's really not good for smooth animation. So that's why all the animation happens on a separate thread.

So how to get performance? Well, first rule is minimize redraw. And what I mean with that is the layer has to produce content. Well, there's a function being called, and you're doing your drawing, essentially. And the key is you do that only once. Essentially, you get a key when the layer content is needed for the first time. You get that callback, and from then on, The contents of the layer is stored in a buffer. So all the animation can happen without application code. That ties into my second bullet point here, is minimize application code during resize and re-layout. If you resize your window, most of the content actually doesn't need to be redrawn. It just needs to be repositioned. Imagine you have a title, and the title just slides. It has to be centered in the window. But other than that, having bits for the title is perfectly sufficient.

So in the case where essentially the application doesn't do anything special, so it doesn't process an event, then essentially there should be no application code running at the frame rate. So everything has been described in advance, all the motion and so on. And the application just does nothing and waits for events. And all these together then ensure a consistent frame rate, well, as you can expect. So let me talk a bit more how that actually happens under covers.

So first, there is a concept we call the layer tree, which is the representation that the application sees. So you have layers, you have sublayers, and you have the nice visual here in orange. And that's the application exposed API. So this is the data structure you work with. And it has this concept of implicit animation and implicit layout, which I will explain a bit later. Kind of the man behind the curtain is the green tree here, which we call the render tree, which is a copy of that data structure. And that's the data structure that is being traversed at 60 frames a second. And it all does the explicit animation and is managed by the runtime. So your application will never see the render tree, but it's kind of important to know that it's there. Because this is what it does. So we have a kind of a visual here. On the left side, imagine this is your code. And you want to change the position of a layer. So you essentially say, set frame origin to some xy value. And that is instantaneous from your application's perspective. So your layer data structure has updated.

It's now at position xy. But the render tree is doing the animation from the original point to the new location. Similarly, if you add or remove a layer, what happens is there is, for example, a fade-in animation going on. And the third example I have is if you replace an entire subtree with a new subtree, you get a transition effect.

So first bullet point is kind of the most important piece of the entire session. If you change the properties of your layer, it triggers implicit animation. And the key is-- On your side, that change is instantaneous. And the fact that there is animation going on happens completely transparently to you.

So, there's also an ability to batch multiple animations together. Essentially you say something like begin transaction, then add two layers, remove two others, and change the content of a fifth one. And then you say commit transaction, and then all of these animations happen at the same time. So this ensures that even though all the rendering is done on a second thread, that they're never part of a partial update visible.

I also would like to make the point that layers are lightweight. That kind of sounds odd if you actually have bits around representing the bitmap. But what I mean with that is the actual layer data structure is around 100 bytes. And the reason for that is you can actually build systems that have fairly large numbers of layers, like in the thousands. So the example I just showed, the recipe browser, that's in the dozens. But the example you saw in the keynote with the album art building the city, it's about 6,000 layers. So at that point, even though most of these layers reference the same bits-- there weren't actually 6,000 albums in that demo-- but the state of the layers needs to be present. So having that small is kind of important. And yeah, all of this is configurable. So when you set the position, you get the slide animation for free by SOTUSEP Week. But you can specify durations, timing curves, motion paths, transition types, and these kind of things.

So under the hood, I alluded to that before, when the rendering happens-- The entire scene is described as a core image processing graph, essentially. And that, in turn, sits on top of OpenGL. There's also a second render implementation available, which is essentially rendering into a core graphics context. And what that enables is you can render your scene into a PDF file, which then is your spool file format, and you can actually print this stuff. So there's a caveat here. Core image filters at this point cannot be expressed in a PDF. So actually these layers that have core image filters on it will get rasterized.

OK, a word about the compositing model. It's kind of what you expect. It's back to front. So if you have a bunch of pure layers, the first one in the array is the one that goes to the back. The next one goes on top of it. And the next one goes on top of the other two, and so on. And because everything is sitting on top of core image, you can add filter effects. There are actually three different hooks on the layer data structure to add filter effects. Let me give you an example of those. So the most obvious one is the content filter, which is a filter that gets run on the content of the layer. And so I tried to visualize that here by having a text layer, which has a distortion on it. And underneath, there's the flower picture layer.

Similarly, there is a background filter, which is the filter that gets applied before the layer is composited into the scene. And it's reasonably visible on the screen. So an example here is you can put a blur underneath that Seattle 2002 badge to essentially reduce the contrast of the scene underneath and give it a bit more polished look.

And the third filter is the compositing filter itself. So you specify how the contents of your layer is merged into the rest of the scene. And most likely, you're going to use the default, which is source over, which is good for 95% of all cases. There are some cases where it can change. And I have an example here. So if you want to add this mirror flare, then this is an object that kind of emits light. So it's better to use the addition compositing mode instead of source over.

OK, in the keynote you saw a lot of 3D, which was kind of misleading. So although you can 3D-- and let me talk a bit about what that means-- the concept is really a layer can have a transform, perspective transform. So it's the concept of you have a bunch of planes stacked, somehow arranged in space. And Core Animation will do the depth sorting for you. However, it will not handle layer intersections. So if you have two layers that intersect, then you will get Corrupt rendering.

That essentially makes sure that transparency works as expected. But I'd really like to stress the latest point. It's not a 3D engine. It really works with layers and not with 3D object. There is no Z-buffer. And if you're trying to implement Doom 3 with this, you're probably going to be in trouble. With that, I would like to go back to the strawberry demo.

and explain a bit more what this application is actually doing. So at this point, what you notice, there is a selection layer which has this little pulsing glow on it. So this is the CI Bloom filter that is running there, and there is an animation set up which just pulses it up and down every once a second. So the application is not doing anything. Once it's set up that animation, it's just running by itself. What the application is doing, it's waiting for events. And if I hit the arrow down key, all it is doing here, it is setting the xy position of that selection layer to be on the new item. So the animation that's happening is implicit. It's done in the render tree. And as far as the application is concerned, as soon as I hit that key, the layer is at the new position.

That allows you to do things-- let me add the Shift key here to make a bit of slow motion. So if I actually Q up two key up strokes or QD two key down strokes, you see there's a single animation going on. Because from the application's perspective, it set it to the second position, and then right after that, set it to the third position. While the render tree is interpolating from the current position to whatever the goal state is. So it will slide two elements up in this case.

Similarly, if I move sideways, what's happening here is there's a transition effect going on. So there's a subtree which makes up these layers, and there's a subtree which makes up these layers. And essentially, all I'm doing is I'm replacing the original subtree with a new subtree, and the transition animation is set to slide. That's how you get this effect. Note that the title actually is doing a crossfade.

Now let me do that in slow motion to make it obvious. So actually two different-- transition effects are set for that single keystroke. And one interesting detail, the slide animation needs to know whether it has to slow the slide left or right. So that's what happens as well. So once we get the keystroke, we set the transition to be left or right to give us the illusion that this is actually some kind of spatial arrangement.

One pane over, we have an image with alpha. We have resizing. We mentioned that. So I can just take this window and go resize it. And you see text is reflowing. And what's happening is most of these layers don't get redrawn on a resize, because in fact, the title just moves to a new position. The image just moves to a new position, and so on. It's the center layer which has the text which needs to reflow. So that one gets an event to redraw. And everything else is-- oops, that was an interesting glitch. So everything else is just working. OK.

Last item I would like to show is you can also put movies in layers. So note that the movie has rounded corners and they're nicely anti-alias. So you can add a mask to a movie. And essentially, things just happen as they should. It's going to go on like this, and it's not particularly interesting. OK. So with that, the demo is over. And I'm going to invite John Harper up to talk about a really important thing, which is code. John Harper: Sounds different. Thank you.

[John Harper]

Okay. John Harper: Thank you. OK, so now we're going to talk about the APIs involved here. So the key thing to remember is that Core Animation is basically a property-based, kind of data-driven model, which means that you set up this tree of these objects, which Raph was talking about, and you set a bunch of properties, maybe set some animations up, and let it run. So you've probably seen the new property stuff in Objective-C2, and we take a huge amount of use of that. And that basically means you can say let or something instead of using these weird brackets. And the other important thing is since we have this database model, we have the idea of a transaction. And a transaction basically is a way of batching up changes to the render tree such that you never see little partial updates or anything like that. So the idea is that you basically have one transaction per event loop, or per run through the event loop. And then everything is committed from the layer tree to the render tree in one go. And you just see this kind of nice atomic update on screen. So now we're going to go through basically the different things that make up a layer. These are all basically Objective-C properties. And they break down into a few groups, which we're going to step through. First of all, you give your layer some geometry. And this is pretty similar to NSView, where you have a bound direct. In our case, the frame is slightly different in that it's based as a position and a transform. And the position is basically a point in the super layer where the layer will show up. We also allow you to have rounded corners and this 4 by 4 matrix. And this LK transform is basically like CGF on transform, except it's a 4 by 4.

OK. So once you've set up the geometry, if you think of these kind of multiple components forming the Les image, the next point is the background. And this is an arbitrary CG color. So you can have things like shadings, which are gradients, or patterns, or just solid colors. Once you have the background, on top of the background, you get the content. And typically, the content is a CG image or a few other types of object. This little guy here is too small to fill his actual bounds. So we've aligned them to the bottom right-hand side of the bounds. And we've done that through this contents gravity property. And there's a bunch of options. You can just align it or tell it to resize or whatever you feel is the right thing. So as Ralph mentioned, it's a fully recursive compositing model, so every layer has a set of sub-layers. And you can either just set this array directly by saying layer.sublayers equals something, or we give you a bunch of convenient methods to say, can I add sub-layer, remove sublayer, things like that. OK, finally, we let you put a border, which is just a stroked line, basically, on top of the content. This is kind of nice, because often you want to have some kind of border around your content.

And you want to be able to animate it, so it's just nice not to have to draw it with CG or something like that. Again, this can be any type of color object, so you can have gradient-based borders or whatever. OK, so now we've basically made up the content for the layers. We've got the background and the content, the actual image and the sub layers on the border, we basically turn that into a single CI image and then pass it through these next stages, the first of which is we let you apply filters, as Rob showed in some of his slides. So in this case, it's just a simple morphology filter to give it some kind of-- something that stands up on the stage.

The next stage after filters is you can apply a shadow, typically not a red one. And the shadow, you have these various parameters. It's pretty simple stuff, just to kind of blur the layer and colorize this alpha channel. OK, finally, you get to supply a global opacity. So obviously, this is proper group opacity, and you don't have to worry about any of that stuff.

OK, so once we've finished this filtered layer, and we've applied the opacity on the filter, we use the compositing filter to put this into the backdrop. But I guess the one interesting thing is that it's not the backdrop, it's potentially the filtered backdrop. And we'll come to what that means on the next slide, where you can apply a mask to the layer. And a mask is not just something that cuts out the shape. It's actually dissolving the content of the previous stage mask into the unfiltered backdrop. So you can have things like, this is basically how you apply your background blurs, because you can blur the entire backdrop and then mask out everything that's outside the layer itself. And there are two ways to specify the mask. You can either just say, give me a mask the size of my layer, or supply another kind of sub-layer, which can be anything, we just take it as alpha channel. So this means you can actually have animating masks or Quartz Composer masks, or whatever you want.

OK. So that was basically the layer. The layer is represented in the render tree. And this is mostly just the OK layer, which is the base class. OK obviously doesn't have a core animation. And so OK layer is the simple thing. You basically can give it an image, or you can draw into a virus context. But then we give you a number of other layer subclasses, which are just basically convenience things. I mean, there's not a whole lot you can do yourself. So for example, there's a scroll layer, which gives you some convenient methods for doing scrolling and asking where the visible region is and things like that. There's an OpenGL layer, so you can basically put any type of OpenGL rendering into a layer. And this is both static content or animating. So this is how we suggest you do media layers of any sort. So this is how all the video examples work. You just have an OpenGL layer and something which creates a visual context and puts the movie into the GL layer. And obviously, we have a course Compose layer which sits on top of that. Finally, there's a text layer, which Ralph was using in his cooking example. And it's basically just a very simple thing, which subclasses the base class and then supply a string, which is then rendered via core text.

OK, so now we know a little bit about what a layer is. We can look at how you actually use them. So obviously, first of all, it's just like any object. It's the object. You allocate one. And then you configure it to basically look like-- or rather, to have the properties that will end up making it look like what you want. So you would, for example, set the background color or set the border width or the shadow or whatever.

And then once you're happy with that, you add it to a parent layer, which is kind of like adding it as one of the sublayers of the parent sublayer's property. And once it's added to a super layer, then at some point it will be committed into the render tree, typically when the event loop next kind of iterates around.

And when it's being committed, we give you the option to do two things. Firstly, you can layout the layers, sub-layers. And so this is a useful thing, because you only really want to layout once per commit. And you can position your sub-layers in such a way that reflects the current size of the layer, or the current state, or whatever. And the next thing we do while we're committing is, once you have the sizes nailed down, then we can let you choose to update the content of the layer. So if you're drawing into a CG context, for example, then you get the chance then to do the equivalent of the drawRect method in NSView. So then it's been committed into the render tree, and at that point, it's on screen. It can animate. It can do whatever it wants. And finally, at some point, you probably want to remove it from the layer tree, which will then queue up another transaction to remove from the render tree, and then it's gone, and at some point, it probably gets deallocated.

So we could go through that in code just to give you a feel of what it actually looks like. So first of all, we create a layer, standard Objective-C kind of idioms. Then in this case, we're not going to do any kind of implicit layout or anything like that. We're just going to give it a fixed position and size. So the position is in its super layer, and the size is in its own coordinate space. And then again, we're not going to do any implicit drawing. We are just going to give it an image reference as content, something we prepared earlier.

And finally, we add it to the lettering. We've already created a super layer, and adding it to this layer will make sure it gets committed. OK, what's next? OK. Like I said, layout is this thing that happens as one of the steps of the commit process. And typically, you just get to set the position and size of the sublabs of the layer. But basically, it's just a hook. So if you want to do something else, that's fine.

And so basically, whenever you change the size of a layer, we mark that the layer needs to be re-layered. That's a word. Or you can do this explicitly by saying set needs layout. And then what that does is it kind of marks the layer as saying, next time you commit it, call this layout sublays method. And the layout sublays is something you can override in a subclass. And then basically just kind of look at the sublays and say, do any of them need to be repositioned? And if so, move them around. And the other thing is that-- If every layer subclass was to define its own layout behavior, you end up with a lot of duplicated code. For example, lots of things have something that looks like a grid or something that looks like a box or whatever. So we have this layout manager idea, which is basically layout via delegation. So every layer has a layout managed property, which you can set to some other object. And then when layout happens on this layer, the default layout sublayer's implementation will just call the layout manager. And this is a nice way of-- you have a bunch of things that you want to do grid layout or circles or whatever you want. You can kind of encapsulate those algorithms in a single class and then just kind of add them to each layer. Currently, we only provide one built-in layout manager.

And it's a constraint-based system. So what that means is you can add the constraint layout manager to your super layer. And then on every layer, you can describe the relationships between itself and its siblings and its super layer. So for example, you can say that the right edge of this layer is aligned to the left edge of a sibling called something. So we found this to be very flexible, and this was how Ralph's resizing thing was actually working. Finally, if you want to use the Atget style stuff, we have that as well.

OK. So next we do drawing. And as I showed in the example, if you want to, you don't have to do any of this kind of subclassing stuff. You can just set the contents of the layer to be an image. And that's pretty straightforward. Otherwise, we have basically the same method which you have for layout and very similar to how NSView works, which is you can say set needs display. And then sometime later, the display method will be called. And by default, that creates some kind of CG context which matches the type of data we would prefer to render. And then you get the chance to render whatever you want into the CG context.

Right. So the next point is that there are some types of layers which need to render every time they-- or rather, need to redraw every time their size changes. So since that's such a common thing, we let you basically just set this needsDisplayOnBalanceChange property to true. And when you do that, we automatically call the setNeedsDisplay method.

OK, so the next big thing, obviously, is animation. As Raf said, all our animation is declarative. And what that basically means is you describe what you want it to do, not provide some code that doesn't. So first of all, you create an animation object. There's a number of built-in classes which describe types of animations, like from to or keyframe or whatever. So first of all, you create your animation. You set the properties which describe what you want it to do, for example, what property you want it to change, the from, the two values, the duration, things like that.

And then you add it to allow using one of these methods. And then after that, it's all autonomous. You don't have to worry about it. So basically, we have two ways of really triggering animations. I mean, the underlying model is the same. We have these animation objects. But you can either have it set up so that-- excuse me.

When you modify a property, then an animation will be implicitly created and added to the LabVIEW. And this is kind of done by this actions metaphor, which basically lets you get a callback whenever a property changes, and then you can either supply an animation or delegate it to someone else.

And then, obviously, it gets added to the layer, and everything happens. But sometimes, that's not quite good enough. You can get a lot of the way with implicit animations, but every now and then, you really need to add more than one animation or change more than one property to get the effect you want. So in that case, you probably want to program the animation model directly. And in that case, you just create the animation as we talked about, and then add it to the layer. And then you can remove it later if necessary.

OK, some more animation. So like I mentioned, there are a number of different animation types. Firstly, we have the basic animation, which is a way of specifying a from value and a to value and a property that should change, and some other timing parameters. And similar to that, there's a keyframe animation. These two are very closely related, except that the keyframes are an array of values rather than just two endpoints. So this lets you do very kind of intricate kind of multi-frame animation. So this is how a lot of the things in the city demo were done. Next, we have transitions, which I guess Ralph also showed, and transitions are where you don't really want to animate a property, but you want to animate the layer as a whole. So these can be things like image processing operations, or move the entire thing, or whatever. And there's actually a way to specify any CI filter which implements the standard transition model and use that as an animation. Finally, you can create an animation out of a number of sub-animations. And again, this is for the more intricate things, where you want one animation with a single name that modifies a number of properties. OK.

And I guess one of the big things we haven't talked about at all yet is timing. And LACIT is a composition model not only in space, but also in time. So every object in the system is part of this hierarchical timing model. And what that basically means is that everything has a begin time, which is relative to the timeline of its parent object. So for layers, every layer can have a start time. And then that's some number of seconds since its parent started.

something which should repeat, and a number of other properties. And obviously, animations fit this nicely as well, because they are just kind of a sub-object of the layer in some sense. So the animation's timeline is relative to the letter's timeline. And animations also have an extra feature, which you can kind of specify a timing curve. So you get your ease in, ease out, or you can basically actually specify anything that fits a Bezier spline, a one-segment Bezier spline. OK. And as I said, let's-- Let's also do that.

OK, so here's some actual code, which is trying to animate the opacity property of a layer. Simple thing you could do with the animation system. So basically, we're going to create the animation. We're going to set the property we want to change. We're going to set the values, which is basically 1 for opaque and 0 for transparent. And we're going to say, do this over the duration of a second. And then once we've done that, we just kind of add it to the layer. And the key argument is kind of important, basically the you The animation system for each-- or rather, the set of animations attached to each layer is kind of a dictionary. So every layer can only have one animation per key. And this is kind of crucial for the implicit animations because, as Ralph showed, if you hit the key more than once, and the animation-- sorry, and the layer moves five times, one animation moving from the current screen value to the target state, you don't want to have five animations queued up. So basically, that's what the key is for.

OK, what else? All right. Yeah, so we haven't talked at all about how you actually use these things. We've told you how to create a tree when you have to actually take the root of the tree and make it visible. And in Leopard, NSView will basically support rendering from layers directly, which you'll hear more about later. But for now, what we really need to know about is that you can take a layer and assign it as the visual representation of a view, and then the view system will kind of Take that and do the most optimal thing to get it to the screen as much as it needs to. So there's these two methods.

One, set the layer. And then there's this other one called setOnceLayer. And it's the setOnceLayer which actually turns on the rendering model. OK. So now I think I'm going to do a couple of demos, which is just basically to show a few features of the system. OK. So this one. OK.

So first of all, this little application, which is just a red window. And we can open a bunch of icons in here. And so what we did is we loaded a bunch of images, created a number of layers, set each layer as the content-- sorry, set each image as the content of each layer, and then added this kind of rotation animation just to give it some life. And then we have kind of a mouse-down, mouse-drag event handler, which looks for the thing under the mouse and is going to kind of set the transform to do a scaling effect on the layer. So you get kind of this kind of Doc Magnify type thing. The other thing is that we're using the layout system to do all the positioning. So we have this layout manager which packs the layers into a 1D box. So we change the transform, and then at some point, the layout manager will be called to reposition everything. So that's nice, and I can do this. Oh, and the other thing, obviously, is we have a selection filter, which is a CI filter generator type thing, which has a Gaussian blur and some kind of exposure adjusting just to give it some pop. And I guess the other thing is that we can change the LayoutManager. That's the nice thing about these things is I can set it to kind of instead of flowing horizontally, I can just say wrap across the window. So I can do this. Obviously, I'm still using the exact same code to set the scale factor and the filters and all that kind of stuff. And so as an experiment, we can kind of add a bunch more icons and see what we can get going. I needed to copy these a few times.

I haven't actually tried it on this machine, so I hope it works OK. OK, so we have a 50 or so. You can get a lot more than this, but it's not really stressing it at all. OK, so next demo is totally different. And this one has 3D, which I guess you saw a bit of this in Peter's part in Bertrand's talk. But this is basically a 3D file browser of some sort. So you can kind of position these things in space and rotate them. And basically, it's planes in space, we like to say.

And what that means is that there are a number of layers, one layer per item in the stack. And each of those has a number of sub layers. Obviously, each sub layer has a border color, which is yellow, and some text. The text is being resized as we select and unselect. And that's kind of cool. The nice thing is the animation.

So when I move backwards-- that's kind of slow-- when I move backwards, we add an animation. This is actually using a mix of implicit and explicit animations to push this-- to move the thing. we're either moving in or moving out along the z-axis. The other thing I should mention about animations is that there's also kind of a notification system so you can get messages when they start and finish. And that's what we're using in this case to know that at some point the layer has actually moved out of the scene and we can delete it. OK, I think that's about all I wanted to share.

OK. So I think I'm going to hand it back to Ralph. RALPH GANTS: Thank you. OK, so first I would like to mention that you heard the word layer kit in this presentation sometimes, which was kind of referring to core animation. The reason for that is that was the code name for this project till last Friday. And the context switch in my mind is not happening that quickly. That's also the reason why all the APIs start with LK, just in case you wonder. OK, a word about AppKit.

So in Leopard, AppKit has a mode where you can essentially have NSViews backed by LKLayers. And what this essentially means is it's a flag on a view that says, host this on a layer. And then that view and all its subviews get hosted on LKLayers. And that has really nice effects that can make use of all of the core animation. That didn't sound right.

Usually that is a one-to-one mapping, so every view gets a layer. And for you, essentially what changes is instead of getting the drawRect call every single time something happens, you get it once and then the content of that view is cached. In some cases you don't want that. So imagine you want to pop up some, you drag an object around and you want to pop up a snapping guide, then that would be a good example of taking a layer which just is that guide, add it to the view temporarily to give some visual feedback, and then once on mouse up, you would remove it again. And go to session 132, Cocoa Animation Techniques, tomorrow at 3:30, which talks all about how to get this stuff into Cocoa. Unfortunately, it's at the same time as the Core Image session, so if you're interested in making new filters to add effect to your layers, then you're in a pickle. OK. So in Interface Builder, that's actually exposed in a checkbox. So it's this once layer checkbox that you have to add to the view. And then from then on, everything happens pretty much automatically. And with that, we'll go to another demo.

OK, so let me go back to my strawberries here. One thing I did forget to show in the last demo is actually that LK scroll layer. which is used here. So there's a group layer, which is an ALCXR layer that manages all these different entries. And the entries are actually created on demand, so they're not visible at the beginning of the app. OK. Another example I would like to make here is-- So this is a movie playing on a layer, and it has the audio spectrum, gets represented by my boss, essentially. It gets squeezed and scratched appropriately.

So the kind of important part of this piece is that it's actually the controls that are on top of this view, the frequency and background filter. translucency, these are standard AppKit controls that get mixed together with little trees of LayerKit data. So that kind of illustrates that the integration is actually pretty seamless. And the good news about that demo is it's actually sample code that you can get.

OK, with that, let's go back to the slides. Yeah. So there are three labs. I'm sure everybody here took their laptops out during that hour and wrote their first layer kit-- sorry, core animation application. And if you had run into problems, then the core animation lab is actually at 3:30, just following this session. There's also the graphics and imaging late night lab, which is tomorrow night, 6:00 to 10:00, I think. Just any questions about graphics and imaging is probably a welcome. And then there is on Thursday the Core Image Lab that you can visit if you have specific questions about the Core Image. One thing I would like to point out, if you're interested in expanding the visual vocabulary of Core Animation, one way to do that is to write a Core Image image unit. Because Core Animation will load image units, and you can just specify any filter that you have as a plug-in. And so you saw the glow effect in the strawberries demo. you could have arbitrary filters going in there.