(options)
| 40 | one world would, and there is only ever one world on a page. |
| 41 | ========================================================================== */ |
| 42 | export function createWorldEngine(options) { |
| 43 | const { container, onState, lite } = options; |
| 44 | |
| 45 | /* ============================================================= the two tiers |
| 46 | A phone is not a small desktop. It has a tile-based GPU with a fraction of |
| 47 | the bandwidth, a screen with three times the pixels per CSS unit, and a |
| 48 | thermal budget that a frame costing three passes over the scene will spend |
| 49 | in about ninety seconds — after which the whole device is throttled, not |
| 50 | just this page. |
| 51 | |
| 52 | So `lite` is one decision, taken by the page before this engine exists (it |
| 53 | configures a WebGL context, which cannot be reconfigured afterwards), and it |
| 54 | is spent in exactly two places: the resolution the frame is drawn at, and |
| 55 | how many times the scene is drawn for it. Nothing about the WORLD changes — |
| 56 | the same land, the same buildings, the same look. */ |
| 57 | const LITE = !!lite; |
| 58 | /* 2 is already a cap rather than the truth: a modern phone reports 3, and the |
| 59 | difference between 2 and 3 is invisible at arm's length and 2.25x the |
| 60 | fragments. On a handheld the same argument keeps going down one more step. */ |
| 61 | const dprCap = () => Math.min(devicePixelRatio, LITE ? 1.5 : 2); |
| 62 | |
| 63 | /* ============================================================================ |
| 64 | THE ART, and what it is arguing. |
| 65 | |
| 66 | The GROWTH machinery is the first pass's and is untouched, because it was |
| 67 | never the part that was wrong: |
| 68 | |
| 69 | 1. A district is NOT one building that gets taller. It is a PLACE that gets |
| 70 | bigger, busier and better tended. Land area is the attention channel — |
| 71 | "the more I read, the more land, the more life". Height is a supporting |
| 72 | voice, not the melody. |
| 73 | 2. Twelve levels, not five. A five-level ladder saturates hard on real data |
| 74 | (a four-year veteran reads a wall of 23 citadels), so the top of it |
| 75 | carries no information. Twelve steps keep separating people all the way up. |
| 76 | 3. Everything is generated from (niche, level) — no models, no textures, no |
| 77 | network. Two knobs, and the whole place re-composes. |
| 78 | |
| 79 | What the second pass changed is the LOOK. The first derived every realm's |
| 80 | materials from daily.dev tokens by mixing, which kept the palette on-brand |
| 81 | and made all six realms siblings of the same pastel family. The concept art |
| 82 | per realm says something louder — each realm is its own WORLD, with its own |
| 83 | light, its own rock and its own weather: |
| 84 | |
| 85 | 4. REALM MATERIALS COME FROM THE CONCEPT ART (`C` in taxonomy), not from |
| 86 | token mixes. DISTRICT ACCENTS STAY ON TOKENS: the realm is the place, the |
| 87 | district is the subject, and the subject is daily.dev's. Brand rides the |
| 88 | accent — lodestone band, roof trim, lamps, banners — where it is legible |
| 89 | and where it does not fight the light. |
| 90 | 5. THE UNDERSIDE IS REALM IDENTITY. Every island floats, and in every concept |
| 91 | image the bottom is the tell: crystal, wrapped roots, basalt columns, wet |
| 92 | crag, icicles, clay. One keel cone for all six threw that away. |
| 93 | 6. EVERY REALM GETS A LANDFORM, standing at L1 before a single building is. |
| 94 | Three realms used to have terrain of their own and three had only props, |
| 95 | which left half the set unreadable until L3. |
| 96 | ==========================================================================*/ |
| 97 | |
| 98 | /* ---------------------------------------------------------------- helpers */ |
| 99 | const clamp=(v,a,b)=>v<a?a:v>b?b:v; |
no test coverage detected