import html as html_lib
from ..rendering.personnage_data import resolve_personnage_idle_frame
def render_scene_object(obj):
"""HTML d'un objet de scène — positionnement en PIXELS ABSOLUS (pas de
% fluide, voir ensure_scene_schema.py), mirror volontairement plus
simple que render_element_html.py (pas d'arbre de nesting, pas de
palette de widgets à gérer) : juste kind="personnage" (réutilise
resolve_personnage_idle_frame, même _personnage_data que le widget
"personnage" de l'éditeur document) ou kind="decor" (image fixe,
attributes.src). data-object-id/data-personnage jouent le même rôle
que data-element-id/data-personnage côté DOM (voir
static/js/screen_edit/personnage-preview.js, static/js/play/actions.js)."""
style = (
f"position:absolute; left:{obj['x']}px; top:{obj['y']}px; "
f"width:{obj['width']}px; height:{obj['height']}px; z-index:{obj['z_index']};"
)
# data-element-id (en plus de data-object-id) : réutilise TELS QUELS
# tous les sélecteurs [data-element-id=...] déjà écrits pour l'éditeur
# document (collision, animation de sprites, "Modifier un élément") —
# voir static/js/play/actions.js/conditions.js. Sans risque de
# collision d'id : un jeu est ENTIÈREMENT "document" (_screen_elements)
# OU "jeu_2d" (_scene_objects), jamais les deux à la fois.
# data-anim-target (Timeline d'animation, Bug corrigé) : applyAnimationClip()
# (static/js/play/screens.js) et son équivalent d'aperçu éditeur
# (animation-timeline.js) sélectionnent TOUJOURS leur cible via
# [data-anim-target=...] (jamais data-element-id/data-object-id, posé
# sur .canvasElement/.playElement pour le DOM, voir visible_attrs.py) —
# un objet de scène n'ayant pas de wrapper équivalent, cet attribut est
# posé directement sur son
: SANS lui, aucun clip de Timeline (ni
# même une action de flow "Jouer une animation") ne trouvait jamais sa
# cible pour un objet de scène, quel que soit son type d'animation.
# class="sceneObjectSprite" (object-fit:contain, voir static/style.css) :
# les frames CraftPix (screens/labels/animal_sprite_library.py) sont de
# GRANDS canevas très paddés (~788×504 px, très différent des sprites
# Kenney déjà bien recadrés, ~96×128 px) — sans object-fit, l'image
# remplirait quand même son cadre (width/height:100%, voir la règle
# `.canvasElementInner > img` dans scene_edit.html) mais DÉFORMÉE,
# rendant le personnage minuscule/écrasé dans sa boîte de sélection.
if obj["kind"] == "personnage":
src = resolve_personnage_idle_frame(obj)
src_attr = f' src="{html_lib.escape(src)}"' if src else ""
return (f'
')
src = (obj.get("attributes") or {}).get("src", "")
src_attr = f' src="{html_lib.escape(src)}"' if src else ""
# "fond" (voir add_scene_object.py) : même image fixe que "decor",
# seule la classe change — .sceneBackground (static/style.css) la
# rend insensible au clic (pointer-events:none), pour qu'elle ne
# bloque jamais un clic destiné à un objet posé par-dessus, même
# étendue sur tout le "monde" (voir personnage-controller.js, la
# caméra qui la suit en défilant).
css_class = "sceneObjectSprite sceneBackground" if obj["kind"] == "fond" else "sceneObjectSprite"
return (f'
')