The Solar2D ‘Rosetta Stone’ to Content Scaling (sort of:)

Hello, solar2D world!

It was all GREEK to me.
And I was walkin’ like a newbie-Egyptian, not in denial of my ignorance
concerning all things ‘Content Scaling’ in Solar2D.

And, thanks to @Xedus pointing me in the direction of Rob’s…

…I stumbled upon the ‘Rosetta Stone’, so to speak, of Content Scaling.

But, I had to take it a step further to understand it more comprehensibly than
depicted in that very informative post.

I just personally (with my stubborn brain) needed a bit more to ‘set it in stone’.

I felt compelled to share it with the forum.

I don’t mean to clutter the forum with redundant material,
but my approach, ie. a STEP by STEP color-coded approach
that I used made me ‘personally’ understand it more thoroughly.

Any errors that you can point out will be greatly appreciated.
I think I got it correct though.

In this ‘Rosetta Stone’ post, specifically,
I like the way I emphasized (made clear) the scaling content ‘calculations’
by color-coding the steps and annotating those steps as they were carried out.

This helped to quickly associate what variables belonged to the Content Area (in orange)
and those which belonged to the Device’s actual content and corresponding device aspect ratio
( ie. depicted in blue or pink).

It should be no mystery why I chose orange, as opposed to green;
as green usually showcases the ‘safe’ content area.

I just wanted to pay homage to the history of Solar2D.
Besides, the Solar2D logo, still has lingering orange hues.

I did this little exercise solely for my sake, as a learning tool.
But, I knew someone else could probably benefit from my subtle addition to what Rob had done in the mentioned link above.

I am sure many of you have gone through these motions to wrap your brain around this issue.

We must.

Again, I like the color-coded calculations depicted in a (loosely speaking) “stairway-step” fashion,
that clearly make the calculations easy for a non ‘Carl Friedrich Gauss’ mind,
like mine, to take it all in, and make practical sense out of it.

One of the biggest takeaways, after I completed it anyway,
was that there is no mention of device screen resolutions (in pixels) for an actual device during the whole content-scaling ordeal; the process, for example, didn’t mention a 1920 × 1080 screen resolution nor mention of a 1024 x 768 screen resolution as being anything of concern;
rather, it deals with the config.lua defined Content Area ONLY;
and is concerned instead with the decimal values of the aspect ratios for a given Devices,
16:9 or 4:3, respectively in this post.

It reminded me that, we as developers need only focus on the ‘content area points’ that we have defined in config.lua, and, coding in that safe, scalable, protected ‘sandbox’, if you will;
‘Never mind the bollocks’ (aka nonsense), of device pixels and screen resolutions themselves.

All the while, making more sense of the display.contentWidth
and display.actualContentWidth, among others.

Of course, I won’t be surprised if I reinvented the wheel,
and this is already a click away somewhere else on this awesome forum;
Rob’s aforementioned post that inspired this post aside. Perhaps, humbly speaking of course, not as comprehensive as my ‘stairway-step’ program.

“Now, for only $300 dollars, you can sign up right now …for my eight-week program.”
Rex - From the Movie, Napoleon Dynamite

If not, I trust this will be helpful to many a spankin’-new, newbie.

I hope it is more helpful than confusing, and not at all annoyingly redundant.
Give it a try.

Decipher the mystery.

“Please, accept the mystery.”
From the movie, A Serious Man

CONTENT SCALING PART I

CONTENT SCALING PART II

To position buttons, and other UI game elements relative to screen edges, and, to see what inspired The Solard2D ‘Rosetta Stone’ to Scaling Content, see the link to Rob’s post at the top of this post.

QUESTION:

When scaling content areas, why are ratios ‘swapped’;
ie. for rectangular devices and ‘squarish’ devices?

Meaning, for a ‘rectangular-device’ at 16:9 (or 16 divided by 9 = 1.777778),
the greater number is the numerator, and the smaller number the denominator, when calculating actualContentWidth for a given device?

While, on the other hand, for the ‘squarish-device’ at 4:3 the ratio is ‘swapped’ and calculated as 3:4 (or 3 divided by 4 = 0.75) with the smaller number as the numerator, and the greater number as the denominator, when calculating the actualContentHeight for a given device?

To the mathematically inclined, I am certain that this is both painfully obvious and perhaps unnecessary to know such details.

But I was curious, as I could not answer that for myself.

Anyone?

“In 1930, the Republican-controlled House of Representatives, in an effort to alleviate the effects of the… Anyone? Anyone? …the Great Depression, passed the… Anyone? Anyone? The tariff bill? The Hawley-Smoot Tariff Act? … Anyone know the effects? Anyone? It did not work, and the United States sank deeper into the Great Depression.”
From the movie, Ferris Beullar

:slight_smile:

You know I could not pass that movie quote up.

Gilby

1 Like

Solar assumes portrait first from it’s time as a mobile-only SDK. Just swap for PC/Mac/Steam

1 Like

I see what you mean, @ponywolf.

I will be back, thanks!

When scaling content areas, why are ratios ‘swapped’;
ie. for rectangular devices and ‘near-square’ devices?

Meaning, for a ‘rectangular-device’ at 16:9 (or 16 divided by 9 = 1.777778),
the greater number is the numerator, and the smaller number the denominator, when calculating actualContentWidth for a given device?

While, on the other hand, for the ‘squarish-device’ at 4:3 the ratio is ‘swapped’ and calculated as 3:4 (or 3 divided by 4 = 0.75) with the smaller number as the numerator, and the greater number as the denominator, when calculating the actualContentHeight for a given device?

To the mathematically inclined, I am certain that this is both painfully obvious and perhaps unnecessary to know such details.

But I was curious, (imagine that:) and I could not answer that for myself.

Anyone?

chatGPT says: “verbatim”

This is actually a very good question, because what looks like a “ratio swap” is really a consequence of which dimension is being held constant and which dimension is being solved for.

Let’s use Solar2D terminology.

Suppose your content area is:
width = 320
height = 480

Aspect ratio:
320 / 480 = 0.666667

The General Formula

An aspect ratio is simply:
width / height
or
height / width

depending on which variable you’re solving for.

The ratio itself hasn’t changed.
You’ve merely rearranged the equation.

Case 1: Rectangular Device (Too Wide)

Imagine a phone that’s much wider than your content area.
Solar2D keeps the content height fixed and computes a larger width.

Starting from:
width / height = aspectRatio

Solve for width:
width = height × aspectRatio

For a 16:9 screen:
aspectRatio = 16/9 = 1.777778

So:
actualContentWidth = actualContentHeight × (16/9)

Notice:
16/9 appears naturally because you’re solving for width.

Case 2: Squarer Device (Too Tall)

Now imagine an iPad-like device.

The screen is relatively squarish.

Solar2D may keep the content width fixed and compute a larger height.

Start again with:
width / height = aspectRatio

Now solve for height:
height = width / aspectRatio

But dividing by a fraction is the same as multiplying by its reciprocal:
height = width × (1/aspectRatio)

For a 4:3 device:
aspectRatio = 4/3

Therefore:
height = width × (3/4)

And suddenly you see:
3/4 = 0.75
which looks like the ratio has been swapped.

But mathematically:
height = width / (4/3)
height = width × (3/4)
These are identical.

Why It Feels Weird
Most people think:

16:9 → 16/9

4:3 → 4/3

and expect to always use those numbers directly.

But the moment you solve for the opposite dimension, the reciprocal appears:
4/3 ↔ 3/4
16/9 ↔ 9/16

So what you’re seeing isn’t:
“Use width/height for wide screens and height/width for square screens.”

It’s actually:
“Use the aspect ratio when solving for width, and use its reciprocal when solving for height.”

Visual Intuition
Imagine a rectangle:

If height is known:
width = height × (width/height)

The ratio tells you how many widths fit into one height.

If width is known:
height = width × (height/width)

Now the reciprocal tells you how many heights fit into one width.
Same rectangle.
Different unknown.

How Solar2D Thinks About It
Internally, Solar2D is essentially doing:
deviceAspect = pixelWidth / pixelHeight
contentAspect = contentWidth / contentHeight

Then determining which dimension would overflow.
If the device is wider than the content area:

actualContentWidth =
contentHeight * deviceAspect

If the device is taller/squarer:
actualContentHeight =
contentWidth / deviceAspect

Notice that second formula:
contentWidth / (4/3)
becomes contentWidth * (3/4)
which is exactly the “swap” you’re noticing.

So the short answer is:
The ratio isn’t really being swapped because the device is squarish.
The reciprocal appears because Solar2D is solving for height instead of width.

Whenever you solve for the opposite dimension of an aspect-ratio equation, the reciprocal naturally emerges.

That’s one of those little algebraic details that game programmers use constantly without necessarily thinking about it after a while.

Once you see it as “solving for width vs. solving for height,” the mystery disappears.


Gilby says: “In summary”

“Cool-beans”
From the movie, Hot Rod

I keep forgetting about chatGPT!

Apparently, chatGPT has seen every movie that I have seen.

And that’s great, because chatGPT gets most of my Jokes!

I made a joke to chatGPT about the movie, 51st Dates, concerning issues of “memory”,
and, not surprisingly, chatGPT understood what I meant, when I was bummed that chatGPT couldn’t always remember me.

I’m over it!

:slight_smile:

Guess I need to pay a monthly fee for chatGPT to remember me.

Gilby

Your messages are quite a bit too long for me to carefully read through them (and that’s saying something :sweat_smile:), but I may have caught two things to make it complete for Solar2D specifically:

  • Scale mode decides what happens to the overflow axis:

    • “letterbox”: the whole content area fits, and the non-constraining axis extends past the nominal area. That extra space is the fillable letterbox region, and actualContentWidth/Height grow there.

    • “zoomEven”: fills the screen instead, so the non-constraining axis is cropped, not grown. actualContentWidth/Height match the viewable (uncropped) area, which is smaller than nominal on that axis.

    • “zoomStretch”: ignores aspect ratio and distorts, so there’s no reciprocal to talk about.

In the aspect-preserving modes, actualContentWidth / actualContentHeight always equals the device’s pixel aspect ratio. Whether the other axis grows or shrinks is purely the scale mode.

  • Constraining axis isn’t “wide device vs square device”, it’s the device aspect compared to your content aspect. A 4:3 device is the grow-width case or the grow-height case depending on whether your content area is taller or wider than 4:3.
1 Like

I put the thread into chatGPT and it said

Because he’s overcomplicating a simple coordinate-space issue.

The basic mistake is this: he’s treating aspect ratios like magic values that “swap” depending on device type. They don’t. You either solve for width or solve for height. That’s it.

For Solar2D:

contentWidth / contentHeight = deviceWidth / deviceHeight

So:

actualContentWidth = actualContentHeight * deviceAspect

or:

actualContentHeight = actualContentWidth / deviceAspect

The “swap” is just the reciprocal appearing when solving the other side of the equation. Not a Solar2D mystery tablet from ancient Egypt.

XeduR’s correction is right: the important distinction is not “wide vs square device”; it is device aspect compared with your configured content aspect, plus the selected scale mode. letterbox grows the spare axis, zoomEven crops it, and zoomStretch distorts it.

So the failure is mainly:

  1. confusing screen pixels with content coordinates
  2. thinking ratios are being deliberately “swapped”
  3. ignoring that the constraining axis depends on relative aspect ratios
  4. writing 5,000 words where two algebra lines would do

Classic forum archaeology: dig long enough and eventually someone rediscovers division.

FYI, my chat is set to professional with a sense of humour!

1 Like

Thanks you guys, I appreciate your help, and input. I tend to get excited. :slight_smile: I will refrain from the lengthy posts. And, will do my best to figure this out. The pieces are starting to come together.

I will get it.

Thanks Again!

Gilby

The way I remember someone describing it long ago that made it click for me went something like this:

First, forget all about the device and understand how corona units work. In config.lua you set the content area to whatever you like, such as width=320, height=480. The height-to-width ratio is 480/320 = 1.5. It’s 1.5 times as tall as it is wide.

Imagine this creates a piece of paper, 1.5 times as tall as wide. You can set something to x=0, y=0 and it appears at the top left. The bottom right of the paper is at x=320, y=480. The exact centre is x=160, y=240. And so on. Similarly, If you give something, say, a width of 160 and a height of 120, it will be half the width of the paper and one quarter its height. All pretty simple. Now imagine that this piece of paper is actually infinite. You can place things at negative values or at values beyond 320 and 480, but at its core this 320 by 480 segment still exists.

Now you want to actually put stuff on a device. Immediately there’s an issue. What if the aspect ratio of the device isn’t 1.5? That’s where content scaling comes in. Imagine the piece of paper as a tiny dot in the centre of the screen. You scale it up bigger and bigger until it fits according to a rule. What rule? Depends what scaling you’ve chosen. If you’ve chosen “letterbox” the content area (the 320 by 480 bit) will scale up until if fills the screen either vertically or horizontally, whichever comes first. If the aspect ratio isn’t the same as the device, this leaves black bars either at the top and bottom or at the sides. On the other hand, if you choose “zoomEven”, the paper will expand until the the content area covers the entire screen. If the aspect ratio on device is different to the content area, then some of the content will appear off-screen, either top and bottom, or at the sides.

1 Like

Thanks @hasty

I do feel confident understanding what you just mentioned, so thanks for the reinforcement of that knowledge. :slight_smile:

I just seem to be overly-cautious / slightly, still-confused as to deciding on my background “size”; knowing now, it’s more about ‘aspect ratio’ rather than ‘size’, per se.

I know now (at a minimum) to safely focus on target aspect ratios, 4:3, 3:2 and 16:9, or 4:3, 16:9, and 21:9, and have been given advice reinforced by chatGPT to set my background to the ‘middle-ground’, And I plan on going through the design motions to do just that.

Initially, when I ignorantly designed my background, I just used a background of 2048 x 1024 (landscape), and everything looked great on ALL virtual simulator devices.

Of course, I know now that this gives me an aspect ratio of 2, which numerically, appeals to Me. But various device aspect ratios could care less what makes me feel “1” with the Universe.

Just out of curiosity, now that modern devices are capable of larger images, what would happen if I did just use a 2048 x 1024 “@1x” background.jpg?; content area = 1200 x 800; knowing of course, I will have ‘fringe’ background content that will and will not be visible depending on the device.

I guess I ask this from the point of view of trying to find that background aspect ratio that is not in ‘excess’ of that which is needed.

Thanks

Gilby

Subjectivity aside, I still find Solar2D’s approach to screen scaling outdated; I believe they should rethink this scaling style. Given that Solar2D is used for both games and commercial apps, it is one of the few frameworks where black bars appear if scaling isn’t handled correctly. You are also left “hoping” your layout fits every resolution, depending on your config.lua settings. as if the outcome were unpredictable. I know there is no 100% perfect scaling method, but the approaches used by other mobile frameworks aren’t as problematic as Solar2D’s.

This is constructive criticism from someone who uses the framework and really wants to see it keep improving.

1 Like

I use this configuration for my games

    content = {
        width = 540,
        height = 960,
        scale = "letterbox",
        fps = 60,
        xAlign = "center",
        yAlign = "center",
        shaderPrecision = "highp",
    },

I also abandoned @2x years ago and just load 2x images for game assets. My splash screen is 1,400x800, positioned dead center with no scaling, and this fills everything from an iPad to the tallest iPhones/Androids.

Essentially my content units are half HD but it renders at HD. Just works for me!

1 Like

There should be no need to hope it fits, as long as the config.lua is set up correctly. If you’re running into black bars, you’re probably using display.contentWidth and display.contentHeight instead of display.actualContentWidth and display.actualContentHeight.

That being said, I do agree with you that the content scaling and positioning issues could be made simpler and more convenient. Solar2D gives developers the ability to use most feasible scaling types/techniques, but that also leaves a lot of room for mistakes.

One quite big omission, in my opinion, is the lack of a built-in responsive layout system. You can calculate the screen layout from the display. properties, e.g. screen’s real minX, minY, maxX and maxY, like I do in my screen.lua module, but the lack of a built-in system means everyone has to reinvent the wheel or find a solution someone else has already come up with.

2 Likes

Hello everyone,

I am “excited” (as per usual) to say that I am making great progress with my understanding of all things Content Scaling!

I just want to point out one bit of the mundane, minutiae, that would only concern the newbie.

If you notice, as many seasoned developers probably did, in my config.lua file above I referred to letterbox as letterBox, with a capital “B’“.

Having gotten so used to naming variables using this convention, ie. lower case for the first letter of the first word, and an Upper case letter for first letter of the second word, I blindly defined letterbox as letterBox. And since I have only been using the 'solar2D simulator, there would be no issue.

But I assume, outside of the simulator, this particular variable naming ‘may’ confuse Solar2D on a given device at runtime.

I only make mention of this for someone newer to Solar2D than myself, and just want to point out that the proper way to define letterbox, is using all lowercase.

If I have actually gotten this wrong too, I won’t be surprised.

But I am just trying to make certain I know what I am doing!

Thanks to anyone that can verify this for me.

:slight_smile:

Actually, this doesn’t apply only to this part of config.lua, it applies to the code syntax in general, as lowercase and uppercase letters are treated differently in programming.

1 Like

Only in case sensitive programming languages though - some, like basic, pascal, SQL are different. Also “letterbox” (from the TV world of letterboxing movies) is a single word and not a compound.

1 Like