<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: HanoStudio</title>
    <description>The latest articles on DEV Community by HanoStudio (@hanostudio).</description>
    <link>https://dev.to/hanostudio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3979732%2F2bdb80ba-7520-46ac-96d2-cf411fb33222.png</url>
      <title>DEV Community: HanoStudio</title>
      <link>https://dev.to/hanostudio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hanostudio"/>
    <language>en</language>
    <item>
      <title>What Actually Makes a Unity Build So Large?</title>
      <dc:creator>HanoStudio</dc:creator>
      <pubDate>Sun, 21 Jun 2026 14:59:18 +0000</pubDate>
      <link>https://dev.to/hanostudio/what-actually-makes-a-unity-build-so-large-3jh4</link>
      <guid>https://dev.to/hanostudio/what-actually-makes-a-unity-build-so-large-3jh4</guid>
      <description>&lt;p&gt;Eight controlled Unity Android builds show how texture, audio, Korean font, and DOTween choices change APK size, with reproducible data and source code.&lt;/p&gt;

&lt;p&gt;Most developers know that textures are heavy and uncompressed audio is bad. But ask which setting added how many megabytes to a real APK, and the answer often gets vague.&lt;/p&gt;

&lt;p&gt;After 14 years of building and shipping Unity mobile games, I wanted measurements rather than folklore. I started with a minimal project, changed one variable at a time, built eight Android APKs, and then repeated the entire run.&lt;/p&gt;

&lt;p&gt;The largest difference between the two runs was &lt;strong&gt;8 bytes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For per-asset measurements, I used the &lt;a href="https://github.com/hellohanostudio/BuildAnalyzer/blob/main/Assets/BuildAnalyzer/Editor/BuildAssetSizeReporter.cs" rel="noopener noreferrer"&gt;BuildReport parser included in the public experiment repository&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Run it yourself:&lt;/strong&gt; The complete Unity project, build automation, both repeat-run CSVs, and every per-step raw report are public in the &lt;a href="https://github.com/hellohanostudio/BuildAnalyzer" rel="noopener noreferrer"&gt;BuildAnalyzer GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Unity &lt;code&gt;6000.3.7f1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Android APK, not AAB&lt;/li&gt;
&lt;li&gt;IL2CPP, ARM64 only&lt;/li&gt;
&lt;li&gt;Built-in Render Pipeline&lt;/li&gt;
&lt;li&gt;Development Build off&lt;/li&gt;
&lt;li&gt;Managed Stripping Level: Medium&lt;/li&gt;
&lt;li&gt;Engine code stripping enabled&lt;/li&gt;
&lt;li&gt;One scene with one camera, one directional light, and one cube&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The scene included a small reference harness so every test asset was genuinely referenced. That makes the &lt;strong&gt;14.32 MiB&lt;/strong&gt; baseline specific to this experiment, not a universal Unity minimum.&lt;/p&gt;

&lt;p&gt;I measured the APK itself with &lt;code&gt;FileInfo.Length&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;artifactBytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FileInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters because &lt;code&gt;BuildReport.summary.totalSize&lt;/code&gt;, the sum of packed assets, and the final compressed APK size are three different metrics.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;Each row changes one condition from the row immediately before it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Controlled change&lt;/th&gt;
&lt;th&gt;APK size&lt;/th&gt;
&lt;th&gt;Delta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Minimal experiment project&lt;/td&gt;
&lt;td&gt;14.32 MiB&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Referenced 2048x2048 texture, Android RGBA32&lt;/td&gt;
&lt;td&gt;28.12 MiB&lt;/td&gt;
&lt;td&gt;+13.80 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Same texture, Android ASTC 6x6&lt;/td&gt;
&lt;td&gt;16.14 MiB&lt;/td&gt;
&lt;td&gt;-11.98 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Add referenced 30-second stereo audio, PCM&lt;/td&gt;
&lt;td&gt;21.19 MiB&lt;/td&gt;
&lt;td&gt;+5.05 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Same audio, Vorbis quality 0.5&lt;/td&gt;
&lt;td&gt;16.60 MiB&lt;/td&gt;
&lt;td&gt;-4.59 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Add full Noto Sans KR dynamic font&lt;/td&gt;
&lt;td&gt;19.49 MiB&lt;/td&gt;
&lt;td&gt;+2.89 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Same font, app-specific subset&lt;/td&gt;
&lt;td&gt;16.63 MiB&lt;/td&gt;
&lt;td&gt;-2.86 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Add DOTween, preserved and referenced at runtime&lt;/td&gt;
&lt;td&gt;17.10 MiB&lt;/td&gt;
&lt;td&gt;+0.46 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4n12f0fchyzqvyc28fic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4n12f0fchyzqvyc28fic.png" alt="Bar chart of APK size after all eight controlled changes" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Texture: RGBA32 vs ASTC
&lt;/h2&gt;

&lt;p&gt;The test texture was an opaque, deterministic 2048x2048 noise image with mipmaps disabled. Using high-entropy pixels prevented APK ZIP compression from making an uncompressed texture look artificially cheap.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Android format&lt;/th&gt;
&lt;th&gt;Packed texture&lt;/th&gt;
&lt;th&gt;APK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RGBA32&lt;/td&gt;
&lt;td&gt;16.00 MiB&lt;/td&gt;
&lt;td&gt;28.12 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ASTC 6x6&lt;/td&gt;
&lt;td&gt;1.78 MiB&lt;/td&gt;
&lt;td&gt;16.14 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ASTC reduced the texture's packed contribution by &lt;strong&gt;88.84%&lt;/strong&gt; and removed &lt;strong&gt;11.98 MiB&lt;/strong&gt; from the APK. The ASTC build was still 1.82 MiB above baseline; compression did not make the texture free.&lt;/p&gt;

&lt;p&gt;The practical lesson is not simply "use ASTC." Pick a format and block size that your target devices support, then inspect the visual cost on real hardware. But leaving a large mobile texture as RGBA32 is an expensive default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audio: PCM vs Vorbis
&lt;/h2&gt;

&lt;p&gt;The audio input was deterministic 30-second stereo PCM at 44.1 kHz. It contained several tones plus noise so it behaved more like real content than a silent WAV.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Android format&lt;/th&gt;
&lt;th&gt;Packed audio&lt;/th&gt;
&lt;th&gt;APK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PCM&lt;/td&gt;
&lt;td&gt;5.05 MiB&lt;/td&gt;
&lt;td&gt;21.19 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vorbis, quality 0.5&lt;/td&gt;
&lt;td&gt;0.46 MiB&lt;/td&gt;
&lt;td&gt;16.60 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Vorbis reduced the packed audio by &lt;strong&gt;90.98%&lt;/strong&gt; and removed &lt;strong&gt;4.59 MiB&lt;/strong&gt; from the APK.&lt;/p&gt;

&lt;p&gt;That does not make Vorbis correct for every clip. Short, latency-sensitive effects and long music tracks have different runtime requirements. The important part is that import format is a measurable build-size decision, not a housekeeping detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Korean font: full source vs app subset
&lt;/h2&gt;

&lt;p&gt;For the font test I used the same Noto Sans KR Regular dynamic font in both builds. The first build embedded the full source font. The second used a subset containing the characters required by a small example UI plus ASCII letters, digits, and punctuation.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Font condition&lt;/th&gt;
&lt;th&gt;Packed font&lt;/th&gt;
&lt;th&gt;APK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full Noto Sans KR&lt;/td&gt;
&lt;td&gt;5.94 MiB&lt;/td&gt;
&lt;td&gt;19.49 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App-specific subset&lt;/td&gt;
&lt;td&gt;0.07 MiB&lt;/td&gt;
&lt;td&gt;16.63 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Subsetting reduced the packed font data by &lt;strong&gt;98.88%&lt;/strong&gt; and removed &lt;strong&gt;2.86 MiB&lt;/strong&gt; from the APK.&lt;/p&gt;

&lt;p&gt;This is specifically a &lt;strong&gt;dynamic source-font&lt;/strong&gt; comparison. A TextMeshPro static atlas has different tradeoffs, and a dynamic font may need fallback glyphs or downloadable language packs. Do not quote this percentage for every font pipeline. Do measure the character coverage your product actually ships.&lt;/p&gt;

&lt;h2&gt;
  
  
  DOTween: the part PackedAssets did not explain
&lt;/h2&gt;

&lt;p&gt;For the final step I enabled the DOTween Free DLL for Android, preserved it through linking, and referenced it at runtime through the experiment harness.&lt;/p&gt;

&lt;p&gt;The APK grew by &lt;strong&gt;0.46 MiB&lt;/strong&gt;. But &lt;code&gt;PackedAssetInfo&lt;/code&gt; attributed only &lt;strong&gt;192 bytes&lt;/strong&gt; to the DLL path.&lt;/p&gt;

&lt;p&gt;Most of the increase appeared elsewhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;libil2cpp.so&lt;/code&gt; compressed size grew by about 0.36 MiB.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;global-metadata.dat&lt;/code&gt; compressed size grew by about 0.06 MiB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the result that changed how I think about the analyzer. A per-asset report is necessary, but it cannot explain all code growth. A useful build analyzer needs to show at least three layers separately:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Final artifact bytes&lt;/li&gt;
&lt;li&gt;Packed asset contributions&lt;/li&gt;
&lt;li&gt;Native and managed code or metadata changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F64c8unjk3ra0tu277glf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F64c8unjk3ra0tu277glf.png" alt="Unity Editor evidence window showing measured APK, packed asset, importer, and repeatability data" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What surprised me
&lt;/h2&gt;

&lt;p&gt;The texture was the largest single increase, but the font result was more useful. A full Korean dynamic font added 2.89 MiB to this APK; an app-specific subset recovered almost all of it.&lt;/p&gt;

&lt;p&gt;The second surprise was the metric mismatch. In the final build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APK artifact: &lt;strong&gt;17.10 MiB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BuildReport.summary.totalSize&lt;/code&gt;: &lt;strong&gt;143.54 MiB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Packed asset sum: &lt;strong&gt;5.60 MiB&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these values is wrong. They answer different questions. Reporting one as if it were another creates a very convincing but incorrect chart.&lt;/p&gt;

&lt;p&gt;Finally, the two full experiment runs were remarkably stable. Across 16 APK builds, each matching step differed by at most 8 bytes. That made the large deltas easy to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Build size is not one big mistake. It is an accumulation of import formats, referenced content, font coverage, enabled code, engine modules, and packaging.&lt;/p&gt;

&lt;p&gt;The controlled experiment produced three high-value changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ASTC 6x6: &lt;strong&gt;-11.98 MiB&lt;/strong&gt; versus RGBA32&lt;/li&gt;
&lt;li&gt;Vorbis quality 0.5: &lt;strong&gt;-4.59 MiB&lt;/strong&gt; versus PCM&lt;/li&gt;
&lt;li&gt;App-specific Korean font subset: &lt;strong&gt;-2.86 MiB&lt;/strong&gt; versus the full font&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact numbers belong to this project and configuration. The method is the reusable part: fix the build settings, change one variable, measure the final artifact, and use BuildReport to explain what changed without mistaking it for the artifact itself.&lt;/p&gt;

&lt;p&gt;You can clone the &lt;a href="https://github.com/hellohanostudio/BuildAnalyzer" rel="noopener noreferrer"&gt;public experiment repository&lt;/a&gt; and run all eight builds from the Unity menu or command line.&lt;/p&gt;

&lt;p&gt;Next, I will apply the same measurement loop to a real mobile project and track which changes survive contact with production assets.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm a Unity client developer with 14 years of experience in mobile and live-service games. I write about optimization problems I keep encountering in production.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiment files
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repository: &lt;a href="https://github.com/hellohanostudio/BuildAnalyzer" rel="noopener noreferrer"&gt;hellohanostudio/BuildAnalyzer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Automation: &lt;a href="https://github.com/hellohanostudio/BuildAnalyzer/blob/main/Assets/BuildAnalyzer/Editor/ExperimentBuildRunner.cs" rel="noopener noreferrer"&gt;&lt;code&gt;ExperimentBuildRunner.cs&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Raw results: &lt;a href="https://github.com/hellohanostudio/BuildAnalyzer/blob/main/Results/experiment-results-run1.csv" rel="noopener noreferrer"&gt;&lt;code&gt;experiment-results-run1.csv&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/hellohanostudio/BuildAnalyzer/blob/main/Results/experiment-results-run2.csv" rel="noopener noreferrer"&gt;&lt;code&gt;experiment-results-run2.csv&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Per-step BuildReport exports: &lt;a href="https://github.com/hellohanostudio/BuildAnalyzer/tree/main/Results/raw" rel="noopener noreferrer"&gt;&lt;code&gt;Results/raw&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Unity API: &lt;a href="https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Build.Reporting.BuildReport-packedAssets.html" rel="noopener noreferrer"&gt;&lt;code&gt;BuildReport.packedAssets&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Build.Reporting.PackedAssetInfo.html" rel="noopener noreferrer"&gt;&lt;code&gt;PackedAssetInfo&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Font: &lt;a href="https://github.com/google/fonts/tree/main/ofl/notosanskr" rel="noopener noreferrer"&gt;Noto Sans KR from Google Fonts&lt;/a&gt;, SIL Open Font License 1.1&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>unity3d</category>
      <category>gamedev</category>
      <category>android</category>
      <category>performance</category>
    </item>
    <item>
      <title>5 Reasons Your Unity Mobile UI Breaks Across Devices</title>
      <dc:creator>HanoStudio</dc:creator>
      <pubDate>Fri, 12 Jun 2026 15:14:26 +0000</pubDate>
      <link>https://dev.to/hanostudio/5-reasons-your-unity-mobile-ui-breaks-across-devices-5a94</link>
      <guid>https://dev.to/hanostudio/5-reasons-your-unity-mobile-ui-breaks-across-devices-5a94</guid>
      <description>&lt;p&gt;&lt;em&gt;And a Practical Pre-Release Checklist for Safe Areas, Aspect Ratios, and Localization&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Mobile UI often looks fine in the Unity Editor.&lt;/p&gt;

&lt;p&gt;Then you test it on a real device.&lt;/p&gt;

&lt;p&gt;The top currency bar is too close to the notch. The bottom button overlaps with the home indicator. A popup looks fine on 16:9, but gets cut off on a smaller phone. German or French text overflows outside the button. The tablet layout feels stretched and empty.&lt;/p&gt;

&lt;p&gt;After 14 years of shipping Unity mobile games, these are the five UI issues I keep seeing across real projects.&lt;/p&gt;

&lt;p&gt;They are not always caused by bad UI design. Most of the time, they come from small assumptions that only break when the game is tested across different devices, safe areas, and languages.&lt;/p&gt;

&lt;p&gt;In this post, I want to share 5 common reasons Unity mobile UI breaks across devices, and a simple checklist you can use before release.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5sqfp6g71qfplo7wk4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5sqfp6g71qfplo7wk4p.png" alt="The same Unity mobile menu before and after a UI QA scan"&gt;&lt;/a&gt;&lt;br&gt;
The same Unity mobile menu before and after a UI QA scan&lt;/p&gt;

&lt;p&gt;The same menu before and after a UI QA scan.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;1. Applying Safe Area to Everything&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;One of the most common mistakes is applying Safe Area to the entire Canvas.&lt;/p&gt;

&lt;p&gt;At first, this feels safe. If everything is inside the Safe Area, nothing should overlap with the notch or home indicator, right?&lt;/p&gt;

&lt;p&gt;But in practice, this often creates another problem.&lt;/p&gt;

&lt;p&gt;Backgrounds, dim overlays, screen effects, and full-screen visuals should usually fill the entire screen. If you place them inside the Safe Area, the screen can look visually cropped or incomplete.&lt;/p&gt;

&lt;p&gt;A better structure is to separate full-screen visuals from important interactive UI.&lt;/p&gt;

&lt;p&gt;Example structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Canvas
├── FullScreenLayer
│   ├── Background
│   ├── Dim
│   └── ScreenEffect
│
├── SafeAreaLayer
│   ├── TopHUD
│   ├── CurrencyArea
│   ├── NavigationButtons
│   └── BottomMenu
│
└── PopupLayer
    ├── DimBackground
    └── PopupRoot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backgrounds and full-screen effects can extend to the full screen.&lt;/li&gt;
&lt;li&gt;Buttons, HUD, currency, navigation, and readable UI should stay inside the Safe Area.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Safe Area is not for everything. It is mainly for important UI that the player needs to read or tap.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Testing Only One Aspect Ratio&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Many UI bugs are not visible when testing only 16:9.&lt;/p&gt;

&lt;p&gt;Mobile devices have many different screen shapes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 16:9
 18:9
 19.5:9
 20:9
 4:3
 Tablet ratios
 Foldable or unusual ratios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A layout that looks good on one phone can easily break on another.&lt;/p&gt;

&lt;p&gt;Common problems include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bottom buttons moving too close to the edge&lt;/li&gt;
&lt;li&gt;Top HUD stretching too much&lt;/li&gt;
&lt;li&gt;Popups becoming too tall&lt;/li&gt;
&lt;li&gt;Side margins looking too wide on tablets&lt;/li&gt;
&lt;li&gt;Important UI elements being pushed outside the screen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When testing Unity mobile UI, it is better to check layout behavior across multiple aspect ratios before release.&lt;/p&gt;

&lt;p&gt;At minimum, I like to test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Small phone
 Tall phone
 iPhone-style notch device
 Android device with navigation bar
 Tablet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if you do not have all physical devices, using Unity Device Simulator or custom Game View resolutions can help catch many layout problems early.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Ignoring Localization Text Overflow&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Localization can break a layout that looked perfectly fine in English.&lt;/p&gt;

&lt;p&gt;A short English button label can become much longer in other languages.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Start
 Start Game
 Spiel starten
 Commencer le jeu
 게임 시작하기
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your UI was only tested with English text, you may miss issues like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Button text overflowing&lt;/li&gt;
&lt;li&gt;Popup titles becoming two lines&lt;/li&gt;
&lt;li&gt;Labels overlapping icons&lt;/li&gt;
&lt;li&gt;Text being clipped inside fixed-size containers&lt;/li&gt;
&lt;li&gt;Smaller devices not having enough horizontal space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is especially important for mobile UI because the available space is already limited.&lt;/p&gt;

&lt;p&gt;When testing localized UI, check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; [  ] Long button labels
 [  ] Popup titles
 [  ] Shop item names
 [  ] Mission descriptions
 [  ] Error messages
 [  ] Settings menu labels
 [  ] Small screen layouts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Localization QA should not happen only at the end. It should be part of layout testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Making Popups Too Rigid&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Popups are another common source of mobile UI bugs.&lt;/p&gt;

&lt;p&gt;A popup may look fine on a large phone, but on a smaller device:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The title gets too close to the top&lt;/li&gt;
&lt;li&gt;The content area becomes too tall&lt;/li&gt;
&lt;li&gt;The confirm button is pushed near the home indicator&lt;/li&gt;
&lt;li&gt;The popup is clipped vertically&lt;/li&gt;
&lt;li&gt;Text cannot fit inside the panel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A safer popup structure is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; PopupRoot
 ├── Title
 ├── ScrollContent
 └── ButtonArea
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key idea is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep the title visible.&lt;/li&gt;
&lt;li&gt;Keep the main buttons visible.&lt;/li&gt;
&lt;li&gt;Let the content area scroll if the screen is too small.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of making the entire popup fixed-height, consider giving it a maximum height and allowing the content area to shrink or scroll.&lt;/p&gt;

&lt;p&gt;This is especially useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terms popups&lt;/li&gt;
&lt;li&gt;Mission descriptions&lt;/li&gt;
&lt;li&gt;Shop item details&lt;/li&gt;
&lt;li&gt;Event notices&lt;/li&gt;
&lt;li&gt;Settings panels&lt;/li&gt;
&lt;li&gt;Localization-heavy UI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;5. Trusting the Editor Too Much&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The Unity Editor is useful, but it does not always represent the real device experience.&lt;/p&gt;

&lt;p&gt;A UI can look fine in the Editor and still fail on device because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safe Area differences&lt;/li&gt;
&lt;li&gt;Device-specific navigation bars&lt;/li&gt;
&lt;li&gt;Notches and rounded corners&lt;/li&gt;
&lt;li&gt;DPI and scaling differences&lt;/li&gt;
&lt;li&gt;Touch comfort issues&lt;/li&gt;
&lt;li&gt;Real font rendering&lt;/li&gt;
&lt;li&gt;Platform-specific behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before release, it is important to test on actual devices when possible.&lt;/p&gt;

&lt;p&gt;But even before device testing, you can catch many problems with a structured checklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A Simple Unity Mobile UI Pre-Release Checklist&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here is a practical checklist I use when reviewing mobile UI before release.&lt;/p&gt;

&lt;p&gt;Safe Area&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; [  ] Top HUD does not overlap with the notch
 [  ] Bottom buttons do not overlap with the home indicator
 [  ] Important buttons are inside the Safe Area
 [  ] Backgrounds still fill the entire screen
 [  ] Full-screen effects are not accidentally constrained by Safe Area
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aspect Ratio&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; [  ] UI works on 16:9
 [  ] UI works on tall phones
 [  ] UI works on small phones
 [  ] UI works on tablets
 [  ] UI does not stretch too much on wide layouts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Popup&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; [  ] Popup fits on small screens
 [  ] Main action buttons are always visible
 [  ] Long content can scroll
 [  ] Close button is easy to tap
 [  ] Popup title does not overlap with other elements
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Localization&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; [  ] Long translated button text fits
 [  ] Popup titles support longer text
 [  ] Text does not overlap with icons
 [  ] Important labels are not clipped
 [  ] Small screens are tested with long strings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Touch Comfort&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; [  ] Buttons are not too close to screen edges
 [  ] Important buttons have enough padding
 [  ] Bottom UI is not too close to the home indicator
 [  ] Close buttons are easy to tap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Unity mobile UI does not usually break because of one big mistake.&lt;/p&gt;

&lt;p&gt;It breaks because of many small assumptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assuming one aspect ratio is enough&lt;/li&gt;
&lt;li&gt;assuming English text is representative&lt;/li&gt;
&lt;li&gt;assuming Safe Area should apply to everything&lt;/li&gt;
&lt;li&gt;assuming popups will always fit&lt;/li&gt;
&lt;li&gt;assuming the Editor view is close enough to real devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best way to reduce these issues is to test UI with a clear checklist before release.&lt;/p&gt;

&lt;p&gt;Safe Area, aspect ratios, localization, popups, and touch comfort should be reviewed together.&lt;/p&gt;

&lt;p&gt;That is what helps catch layout problems before players do.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Resource&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Going through this checklist manually across every device ratio and language takes a long time — I know because I did it for years.&lt;/p&gt;

&lt;p&gt;So I built ScreenFit QA, a Unity editor tool that runs these checks automatically.&lt;/p&gt;

&lt;p&gt;It scans your UI across multiple device resolutions, safe areas, and long localized strings, then reports broken layouts before release.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4fx6lvp36npg12konb3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4fx6lvp36npg12konb3.gif" alt="ScreenFit QA finding safe-area, touch-target, text-overflow, and localization issues"&gt;&lt;/a&gt;&lt;br&gt;
ScreenFit QA finding safe-area, touch-target, text-overflow, and localization issues&lt;/p&gt;

&lt;p&gt;If this article's checklist felt useful, ScreenFit is that checklist, automated:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://hanostudio.gumroad.com/l/screenfit" rel="noopener noreferrer"&gt;See ScreenFit QA on Gumroad&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>gamedev</category>
      <category>mobile</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
