Sprites
Sprite properties, geometry, puppeting, naming, sprite channels, and runtime sprite state semantics.
What a sprite is
A sprite is an instance of a cast member occupying a Score channel for a span of frames. Its properties (position, size, ink, blend, visibility, behaviors) are independent of the member: two sprites can show the same member differently.
sprite(5).member = member("ball")
sprite(5).loc = point(200, 150)
sprite(5).ink = 36 -- Background Transparent
sprite(5).blend = 50 -- 50% opacity
sprite(5).visible = TRUEGeometry properties
| Property | Meaning |
|---|---|
loc | point(locH, locV): stage position of the member's regPoint. |
locH / locV | Components of loc. |
locZ | Depth override; defaults to the channel number. Higher draws in front. |
rect | On-stage bounding rect. Reading gives current geometry; writing stretches the sprite. |
width / height | Rect dimensions; writing stretches. |
quad | Four corner points (D8.5+): arbitrary quadrilateral distortion for bitmaps. |
rotation | Degrees clockwise (bitmap/text/flash/vector members). |
skew | Degrees of horizontal skew. |
flipH / flipV | Mirroring flags. |
regPoint (member) | Anchor; see Cast members. |
constraint | Sprite number whose rect constrains this sprite's loc (used for sliders). |
Geometry pipeline order (must be reproduced exactly): member pixels -> regPoint anchor -> stretch to sprite rect (if resized) -> flip -> rotation/skew about the regPoint -> quad (if set, replaces rot/skew path) -> stage placement at loc.
the stretch of sprite (legacy) flags whether the sprite uses authored size vs member natural size; assigning width/height/rect sets it. Resetting a stretched sprite to natural size: assign member rect dimensions or toggle puppeting off and let score state reassert.
Appearance properties
| Property | Meaning |
|---|---|
ink | Compositing mode 0-41; see Ink modes. |
blend | 0-100 opacity percentage (works with most inks). |
foreColor / backColor | Color pair used by 1-bit members, fields, and some inks (background key for Background Transparent). |
visible | Channel visibility. Affects the CHANNEL, persists across spans; classic gotcha. |
trails | Leaves previous frames' pixels on stage (no erase). |
directToStage (member) | Media draws over everything, ignores ink/compositing. |
mask (member, digital video) / maskImage (imaging) | Masking inputs. |
Identity and structure
sprite(5).spriteNum -- 5
sprite(5).name -- MX 2004 sprite names
sprite("hudPanel").loc -- lookup by name
sprite(5).memberNum -- member number (assign to swap image fast)
sprite(5).castLibNum
sprite(5).scriptInstanceList -- attached behavior instances
sprite(5).scriptNum -- first behavior's script member number
the currentSpriteNum -- sprite whose handler is executing
the spriteNum of me -- behavior's own channelSprite names (MX 2004) let code survive channel reordering; name assignment requires score recording. Preservation-era content (D8.5 and earlier) is entirely channel-number based.
Puppeting and runtime authority
puppetSprite 5, TRUE -- Lingo owns channel 5 (score updates stop)
sprite(5).puppet = TRUE -- same, property formAuthority rules (see also The object model):
- Non-puppeted sprites: score data re-syncs channel state at each frame boundary; Lingo writes persist only until then (but are visible during the current frame's render and hit testing).
- Puppeted sprites: Lingo state persists until
puppetSprite n, FALSE, which also snaps the channel back to authored score state on the next sync. - Behavior property writes to their own sprite auto-persist for the span (MX 2004 auto-puppet).
- A channel with no authored sprite can be puppeted and populated entirely from Lingo (
sprite(5).member = ...), the standard dynamic-object technique beforemakeScriptedSprite(MX 2004) formalized it. endSpritefires when a puppeted channel's span logically ends only if there was an authored span; fully dynamic channels never generate span events, and their behaviors (attached viascriptInstanceList) must be managed manually.
Interaction properties
| Property | Meaning |
|---|---|
moveableSprite | User can drag the sprite directly. |
editable | Editable text sprite (fields/text): receives focus and typing. |
cursor | Cursor ID or [castMember, maskMember] pair while over the sprite. |
hilite (member) | Button member checked/highlight state. |
mouseOverButton | Rollover state for button members. |
Hit testing (the clickOn, rollover(), mouse events) uses sprite geometry, ink, and member type; Matte ink hits only the visible (non-white-matte) area, other inks hit the bounding box. Full rules and open questions: Input and hit testing.
Sprite relationship operators
sprite 3 intersects 5 -- bounding/quad areas overlap (TRUE/FALSE)
sprite 3 within 5 -- sprite 3's area entirely inside sprite 5'sThese are documented as operating on the sprites' bounding areas (quads when rotated); with Matte ink the comparison uses matte outlines. Collision code in old games is built on these plus manual rect math.
Reading decompiled sprite code
Common patterns worth recognizing:
-- channel pool allocation (dynamic UIs)
repeat with ch = 900 to 950
if sprite(ch).memberNum < 2 then exit repeat
end repeat
puppetSprite ch, TRUE
-- member-swap animation
sprite(ch).memberNum = baseNum + (the frame mod 4)
-- offscreen parking instead of hiding
sprite(ch).locH = -2000The parking idiom means emulators must keep offscreen sprites fully alive (events, stepFrame, memory) rather than culling them.