Gessa Docs
Recipes

Recipe

Juice and polish pass the presentation phase after the playtest proof

The loop already WORKS. world_playtest_scenario proved the player can act, the score changes, and the win phase fires (see playtest-verification-loop). The game is playable and plain: flat lighting, primitive-gray meshes, a functional but unframed camera, silence, no impact on contact. Polish is the next phase, and it is a distinct phase on purpose. Run it AFTER the proof so you are decorating a
engine v1.0.234since world-build-operation-catalog.v1, material-semantic-patch ai_safe.v1, action-catalog.v1.0.232, rendering.v1, camera.v1, audio.v1, generation.v1Copy for LLM

Use this for

the NAMED phase after a game verifiably plays; lifting a working-but-plain loop to a finished look and feel; lighting rig and sky, material palette, camera hero frame, world-text labels, audio, transient impact cues, and generated hero models as one ordered pass

Not for

the gameplay loop itself (see game-loop-assembly); the deep mechanics of one system (see the topic playbook); proving the loop works (see playtest-verification-loop, which runs BEFORE this pass)

Pairs with: Game loop assembly entities scripts HUD win shippable loop, Playtest verification loop proving gameplay executed evidence, Atmosphere sky lighting fog and time of day, Materials and looks PBR surfaces color metalness and textures, Camera feel field of view smoothing tone mapping and post, Game feel juice hit flash camera kick and impact, Audio sound effects music and positional feedback, Particles explosions and visual effects, Asset to instances model prefab instance authoring chain

When to use

The loop already WORKS. world_playtest_scenario proved the player can act, the score changes, and the win phase fires (see playtest-verification-loop). The game is playable and plain: flat lighting, primitive-gray meshes, a functional but unframed camera, silence, no impact on contact. Polish is the next phase, and it is a distinct phase on purpose. Run it AFTER the proof so you are decorating a real loop, not painting a scene that might still change shape.

Everything below is a real op verified in the tree. Where a juice idea has no authorable op yet (screen shake, hitstop, squash), the honest gap is named in game-feel-and-juice and in the roadmap, not faked here.

The polish pass, in order

Run these as one pass. Earlier steps set the frame the later steps read (a material palette reads better under a real lighting rig; a hero frame composes the lit, textured scene).

  1. LIGHTING AND SKY. Land a lighting rig and an atmosphere as world-build ops in the same document transaction (world_build_apply_semantic_operations): lighting.rig.apply for a sun-plus-fill rig, and the world-build operation environment.sky_atmosphere.apply (or environment.atmosphere.apply) for the sky and fog mood. Deep control of individual lights and local fog is on LightComponent and LocalEnvironmentVolumeComponent (see atmosphere-sky-and-lighting). A lit scene is the single biggest step up from plain.

  2. MATERIAL PALETTE. Give the world a coherent look with material.palette.apply (world-build), then refine specific hero surfaces with the twelve ai_safe PBR ops through apply_material_semantic_patch (project.material.patch.apply): base color, metallic, roughness, emissive, alpha, texture slots (see materials-and-looks). Set a material once and reuse it across meshes so the palette stays coherent.

  3. CAMERA HERO FRAME AND POST LOOK. Compose the shot with camera.hero_frame.set (or camera.frame_target to point at the objective). Tune the feel on CameraComponent directly: fov, follow smoothing, toneMapping, exposure, and the postProcessing block (depthOfField, motionBlur) (see camera-feel). Apply a global renderer grade with renderer.visual_profile.apply (MCP tool world_apply_visual_profile). Post settings are clamped by one policy authority against live backend capabilities, so a profile that the running backend cannot honor degrades safely rather than crashing.

  4. WORLD-TEXT LABELS. Anchor readable labels to entities with a TextRenderableComponent: enemy nameplates, floating values, item labels, and quest markers, rendered through the MSDF atlas so they stay crisp at any distance. This is the diegetic-UI layer that a HUD panel (layer 4 of assembly) does not cover. A player's own name over their character is not this layer: it comes from the character policy nameplate setting, which stamps a server-written NameplateComponent (see player-characters-and-spawns), so do not hand-author a player name plate.

  5. AUDIO. Audio is LIVE in production Play. The audio subsystem is mounted above the present-path branch (main-thread, serving both the Worker and main-thread present paths), so AudioEmitterComponent beds and ctx.audio one-shots are audible in a real session, not just a test fixture. Add looping ambience and background music with ctx.audio.setBackgroundMusic / an AudioEmitterComponent, and event stingers (a pickup chime, a hit thud) with ctx.audio.play / playSpatial, pitched and leveled per event (see audio-feedback). Need a bespoke stinger the catalog lacks? Generate one with generation_create_job (the audio_generator kind), import it as a project asset, and reference it from the emitter (credit-metered, see step 7).

  6. IMPACT CUES (the juice moment). On a contact or score moment, fire the transient presentation cues through the script fx host: particleBurst for a one-shot spark or poof and decal for a scorch or paint mark (the Fx.particleBurst and Fx.decal script nodes). These ride the wired presentation cue lane (audience-scoped, replayed byte-identically from the cue id, never leaked to a non-recipient), and they are cosmetic by construction so they never mutate the authoritative sim. Layer them with a HighlightComponent flash pulse and a small ctx.camera.addLookInput kick to assemble a punchy hit (see game-feel-and-juice). Persistent effects (a torch's fire, a continuous stream) stay on ParticleEmitterComponent (see particles-and-visual-effects); the cue is for the one-shot.

  7. HERO MODELS (replace the placeholders). The loop was proven with primitive placeholders (a gray box is a chest, a capsule is an enemy). For the HERO objects the player looks at, replace the placeholder with a generated 3D model: generation_create_job with a model capability (model_generator; providers include hunyuan3d21, trellis, sf3d) and target.importOnSuccess: true finalizes a variant-bearing project asset, which you then reference from a RenderableComponent shape mesh assetId and instance through the asset-to-instances corridor. COST NOTE: generation is an async, credit-metered job (quote it first with generation_quote_job when budget matters). Spend it on the few hero objects, not every prop; keep primitives or catalog reuse for background fill (see asset-acquisition-strategy).

    DISCLOSURE NORM: primitive placeholders and marker stand-ins (the asset.placeholder.request billboard, a cone-for-a-tree, a gray box for a chest) are legitimate mid-build state, but they are NOT finished fidelity. If any HERO object is still a placeholder when you hand back a scenery or look-and-feel brief, SAY SO in your summary by name: which objects remain primitives or markers, and that they await a generated or catalog mesh. The failure this prevents is reporting a scene as "polished" or "done" while the player would see cones and boxes. An honest summary names the remaining placeholders; it never lets structure being present read as fidelity being achieved.

Why this is a separate phase, and its order

  • Polish decorates a proven loop. If you light and texture before the loop is proven, a gameplay change that moves or deletes entities orphans the work. The playtest is the gate; polish comes after it.
  • Lighting before materials: a palette is judged under the rig that will ship, not under flat default light.
  • The camera hero frame after lighting and materials: you are framing the lit, textured scene, not a gray one.
  • Generation (step 7) is last and selective because it is the one step that costs credits and runs asynchronously; everything above is synchronous authored state.

What is NOT available (do not fake it)

  • No native screenShake, hitstop, squash, or transform-tween op. Approximate a shake with an oscillating ctx.camera.addLookInput kick and a hitstop with a state-gated pause; these are approximations, not one-call effects (see game-feel-and-juice). Naming these as done is the failure mode this playbook exists to prevent.
  • No transient full-screen post pulse (a damage vignette flash) as a cue; renderer.visual_profile.apply and the CameraComponent post fields are durable global writes, not one-shot pulses.

Verify

  • Reload the world and confirm it MOUNTS and renders the lit, textured, framed scene (a backend 200 is not proof; load the SPA).
  • Trigger a contact moment in a playtest and confirm the particle burst fires, the sound plays, and the highlight flashes.
  • project_get_graph_snapshot: the palette, camera, lighting, and any TextRenderableComponent labels and generated hero assets are present on the entities you expect.
  • LOOK before you claim fidelity: a snapshot proves structure, not appearance. Frame the hero objects with world_observe_entity_view (see scenery-composition) to confirm they render as real meshes, not placeholders. If any hero is still a primitive or marker, or the render came back unavailable, disclose that in the summary rather than calling the scene done.
Was this helpful?Report an issueContact support

On this page