Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /** * Sprite « anneau » — équivalent 3D du contour de sélection du graphe 2D * (`strokeWidth 2.5`, couleur slate-900) et du repère de pivot de la caméra. * * Rendu dans un canvas hors écran, comme les libellés, pour rester testable * sans WebGL. */ import * as THREE from 'three'; const TEXTURE_SIZE = 128; /** * @param {string} [color] couleur du trait (hex) * @param {{ opacity?: number, thickness?: number, scale?: number }} [options] * `scale` = diamètre du sprite en unités monde * @returns {THREE.Sprite|null} */ export function makeRingSprite( color = '#0f172a', { opacity = 0.95, thickness = 5, scale = 12 } = {}, ) { try { const canvas = document.createElement('canvas'); canvas.width = canvas.height = TEXTURE_SIZE; const ctx = canvas.getContext('2d'); if (!ctx) return null; const half = TEXTURE_SIZE / 2; const radius = half - thickness - 2; ctx.strokeStyle = color; ctx.globalAlpha = opacity; ctx.lineWidth = thickness; ctx.beginPath(); ctx.arc(half, half, radius, 0, 2 * Math.PI); ctx.stroke(); const texture = new THREE.CanvasTexture(canvas); texture.colorSpace = THREE.SRGBColorSpace; texture.needsUpdate = true; const sprite = new THREE.Sprite( new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, depthWrite: false, }), ); sprite.scale.set(scale, scale, 1); sprite.renderOrder = 2; return sprite; } catch { return null; } } |