AI-Generated 3D Scenes: First Impressions Are Easy, Engineering Depth Is Hard

    This article examines what separates a visually striking AI-generated 3D scene from one that is genuinely maintainable. Using a representative test case—a single-file, zero-dependency WebGL2 tidal gate scene—it breaks down prompt design across static, dynamic, and constraint layers; explains how default-camera composition shapes first impressions; and shows why the water level should serve as the single source of truth driving boats, wet marks, plaza flooding, and gate logic. It also covers the engineering essentials of building a dependency-free single-file renderer and provides a five-point evaluation framework and practical checklist for assessing AI-generated 3D code.

    1. Starting with a Typical Test Case

    Using AI coding tools to generate front-end 3D scenes has become routine for many teams: type “build me a water gate scene,” and within seconds you get a runnable chunk of rendering code. But there is a gulf between “it runs” and “it looks good,” and another gulf between “it looks good” and “it’s usable.”

    A representative test case is designed as follows:

    • Deliverable: A single offline HTML file;
    • Subject: A giant ring-shaped water gate, a terraced sea city, and a controllable tide;
    • Static requirements: Composition, architectural form, and materials must hold up on their own;
    • Dynamic requirements: The tide cannot be just a blue plane moving up and down—boats, waterline marks, and plaza flooding must all respond to the water level;
    • Technical constraints: Native WebGL2 only, no external images, models, or third-party libraries.

    This test case is effective because it simultaneously stress-tests three capabilities: artistic judgment (composition and prioritization), engineering skill (zero-dependency low-level implementation), and systems thinking (cross-element state coupling). After comparing multiple generation rounds, a stable pattern emerges: the gap in first-glance impression is mainly determined by how the scene is organized under the default camera; whether the code has long-term value depends on the architecture beneath the water’s surface.

    2. Prompt Design: Translating Aesthetic Demands into Engineering Constraints

    Most people stop their prompt at “make a water gate scene,” and the result is typically a pile of geometry, a mediocre default view, and perfunctory animation. To reliably push generated output past the bar, the prompt needs to unfold across three layers:

    Static layer (determines first impression)

    • Specify composition strategy: use the ring-shaped gate as the visual anchor, placed at the geometric center or a rule-of-thirds intersection;
    • Specify depth layers: foreground is water surface and boats, midground is the gate, background is the terraced sea city skyline;
    • Specify material tone: low-to-medium saturation stone palette, with one accent color (e.g., the metal color of the gate).

    Dynamic layer (determines believability)

    • Make clear that “water level is the sole driver”: water surface height, boat draft, building wet marks, and plaza flooding are all derived from the same water level parameter;
    • Make visible feedback explicit: at high tide, shallow water reflections first appear at the plaza edge; after the tide recedes, a gradually drying wet-mark band remains on the stone surface.

    Constraint layer (determines deliverability)

    • Tech stack: native WebGL2, single file, zero external resources;
    • Performance budget: stable frame rate on typical devices;
    • Structural requirements: rendering, simulation, and interaction organized as separate modules for easy modification.

    A useful rule of thumb: every abstract descriptor in the prompt (“must be stunning,” “must be realistic”) should be translated into a verifiable, concrete constraint (“gate metal color contrasts warm against stone walls,” “wet-mark height changes in real time with water level”). The more verifiable the constraints, the more stable the output.

    3. The Nature of First Impressions: Organizing Priority Under the Default Camera

    What truly separates visual quality is usually not modeling precision but the composition of the very first frame when the page opens. The same pile of geometry, organized differently, can look an order of magnitude better or worse. There are four core techniques:

    1. Front-load the visual anchor: A ring structure naturally has centripetal guiding force. Place the gate at the focal point of the default camera, and the viewer’s gaze gets “pulled” into the structure rather than wandering the scene without a landing point.
    2. Three-tier depth of field: Foreground (near water surface, floating boats) provides detail and motion; midground (the gate) carries the main narrative; background (terraced sea city) provides mass and depth. Remove any one, and the image goes “flat.”
    3. Disciplined color restraint: Keep overall saturation low, reserve only one accent color. Comparing multiple generation rounds reveals that versions with vibrant, cluttered default palettes consistently have a noticeably weaker first impression—not because there aren’t enough colors, but because the information isn’t focused.
    4. A single dominant light direction: A clear light direction “for free” sculpts volume on all geometry. Lighting from all sides looks flashy but actually flattens structural relief.

    In one sentence: first impressions aren’t built by addition—they’re “let” into existence by choosing what to prioritize and what to cut.

    4. The Tidal System: Making Water Level the Scene’s Single Source of Truth

    This is the real watershed of the test case. In a naive implementation, the tide is just a blue plane’s Y coordinate moving up and down. In a competent implementation, water level is a global state, and every water-related behavior is derived from it:

    1. const tide = {
    2. level: 0.0, // current water level
    3. target: 1.2, // target water level
    4. rate: 0.15, // rate of change (meters/second)
    5. update(dt) {
    6. const diff = this.target - this.level;
    7. this.level += Math.sign(diff) * Math.min(Math.abs(diff), this.rate * dt);
    8. return this.level;
    9. }
    10. };

    With water level as the source, at least four categories of behavior must be coupled:

    1. Boat bobbing

    A boat’s vertical position is no longer a fixed value but “water level + draft,” with a slight sway layered on top, and the floating feel immediately holds:

    1. function updateBoats(boats, waterLevel, t) {
    2. for (const b of boats) {
    3. b.y = waterLevel + b.draft;
    4. b.pitch = Math.sin(t * 1.3 + b.phase) * 0.02;
    5. b.roll = Math.cos(t * 0.9 + b.phase) * 0.03;
    6. }
    7. }

    2. Building waterline marks

    In the fragment shader, compare world-space height against the water level to form a wet-mark band that moves in real time with the water level:

    1. #version 300 es
    2. precision mediump float;
    3. in vec3 vWorldPos;
    4. uniform float uWaterLevel;
    5. uniform vec3 uDryColor;
    6. uniform vec3 uWetColor;
    7. out vec4 fragColor;
    8. void main() {
    9. // Below water level is wet; smooth transition within 0.05 above water level
    10. float wetness = 1.0 - smoothstep(uWaterLevel - 0.05,
    11. uWaterLevel + 0.05, vWorldPos.y);
    12. fragColor = vec4(mix(uDryColor, uWetColor, wetness), 1.0);
    13. }

    3. Plaza flooding state

    Plaza areas below the water level switch to a shallow-water material: darker color, stronger reflection, and overlaid high-frequency ripples. This can be determined per-height in the shader or switched per mesh tile on the CPU, depending on the performance budget.

    4. Gate logic coupling

    Gate opening can be tied to the water-level difference: when the water level is below the sea city’s datum, the gate slowly opens to release water; when above the datum, it closes to block the tide. This way, the dynamics are no longer a “performance” but a self-consistent small system.

    Once all four couplings are implemented, the scene upgrades from “a moving image” to “a world with state”—which is exactly the hidden test embedded in the dynamic requirements.

    5. Engineering Essentials of a Zero-Dependency Single File

    Giving up a ready-made rendering library means handling matrix math, geometry generation, and material lighting yourself. A feasible and controllable minimal set looks like this:

    • Math: Implement construction and multiplication of perspective projection, view, and model matrices—about a hundred lines covers it;
    • Geometry: Favor procedural generation. The ring-shaped gate body uses a swept circular segment, and the terraced sea city uses a height function layered by distance:
    1. function terraceHeight(x, z, step = 6.0, rise = 1.5) {
    2. const dist = Math.hypot(x, z);
    3. return Math.floor(dist / step) * rise;
    4. }
    • Materials: An approximation with Lambert diffuse plus single-light specular is enough to distinguish stone from metal;
    • Loop: Drive by delta time; define tidal rate in “meters/second” rather than “meters/frame” to avoid speed varying across devices with different frame rates.

    Two performance notes: generate geometry once at initialization and merge batches to avoid rebuilding buffers every frame; push per-pixel determinations like wet marks and flooding down to the shader rather than looping per-vertex on the CPU.

    6. Evaluation Dimensions: After First Impressions, the Real Test Is the “Backend”

    First impressions are the first few seconds after opening the page; engineering depth determines whether this code can continue to evolve three months later. When evaluating AI-generated 3D scene code, check five things in order:

    1. Is state centralized? Is water level the single source of truth? If the water surface, boats, and wet marks each maintain their own “water level,” inconsistency is already baked in;
    2. Are parameters externalized? Are gate radius, tidal period, and flooding threshold hardcoded and scattered, or centralized into configuration? The former means every adjustment requires reading the whole file;
    3. Are modules decoupled? Are rendering, simulation, and interaction layered? Can you swap the tidal curve without touching rendering code?
    4. Is performance robust? Does frame rate stay stable over long runs, is there memory growth, does it drop frames on low-end devices?
    5. Is extension convenient? Adding fog, a day-night cycle, or click picking—is it a small change or a refactor?

    Interestingly, these five items map exactly onto what traditional software engineering defines as “backend capability”—data consistency, configuration management, separation of concerns, resource governance, and evolvability. Front-end visuals can be quickly elevated with composition tricks, but these capabilities beneath the surface are what separate a “one-off demo” from a “deliverable asset.” This is especially true with AI-generated code: models have made undeniable progress in shaping first impressions, but turning generated output into an asset still requires developers to hold the line on architecture.

    7. Practical Checklist

    Compress the above into a directly usable checklist:

    • Prompt trio: Static constraints (composition/architecture/materials), dynamic constraints (state coupling), technical constraints (tech stack/file form/performance);
    • Composition four questions: Where is the visual anchor? Are foreground, midground, and background all present? Is there only one accent color? Is there a single dominant light direction?
    • Coupling four checks: Boat draft, building wet marks, plaza flooding, gate logic—are they all driven by the same water level?
    • Engineering five reviews: Centralized state, externalized parameters, decoupled modules, robust performance, convenient extension.

    Conclusion

    “First impressions are easy, engineering depth is hard” is not a dismissal of AI-generated code but a calibration of evaluation perspective: a stunning composition determines whether a piece of code is worth a second look, while a water-level-driven state architecture, layered module organization, and restrained performance budget determine whether it is worth keeping. Shifting the evaluation standard from “does it look like a demo” to “can it be delivered” is a fairer and more effective ruler—for both people and tools.