├── .gitignore ├── .gitattributes ├── py └── CYBERPUNKHT.py ├── LICENSE ├── __init__.py ├── js ├── cyberpunk-image.js ├── Cyberpunk.html ├── cyberpunk-noto.js ├── cyberpunk-i18n.js ├── cyberpunkht.js └── cyberpunklink.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | __pycache__/ 3 | .DS_Store 4 | Thumbs.db 5 | *.log 6 | 7 | *.tmp 8 | *.cache 9 | *.bak 10 | *~ 11 | node_modules/ 12 | 13 | .vscode/ 14 | .idea/ 15 | *.swp 16 | *.swo 17 | 18 | # Documentation images (stored externally) 19 | images/ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | images/*.gif filter=lfs diff=lfs merge=lfs -text 3 | images/*.jpg filter=lfs diff=lfs merge=lfs -text 4 | images/*.png filter=lfs diff=lfs merge=lfs -text 5 | images/*.jpeg filter=lfs diff=lfs merge=lfs -text 6 | *.gif filter=lfs diff=lfs merge=lfs -text 7 | *.jpg filter=lfs diff=lfs merge=lfs -text 8 | *.png filter=lfs diff=lfs merge=lfs -text 9 | *.jpeg filter=lfs diff=lfs merge=lfs -text 10 | *.mp4 filter=lfs diff=lfs merge=lfs -text 11 | *.avi filter=lfs diff=lfs merge=lfs -text 12 | *.mov filter=lfs diff=lfs merge=lfs -text 13 | *.zip filter=lfs diff=lfs merge=lfs -text 14 | *.tar.gz filter=lfs diff=lfs merge=lfs -text -------------------------------------------------------------------------------- /py/CYBERPUNKHT.py: -------------------------------------------------------------------------------- 1 | class AnyType(str): 2 | def __ne__(self, __value: object) -> bool: 3 | return False 4 | any_type = AnyType("*") 5 | class CYBERPUNKHT: 6 | @classmethod 7 | def INPUT_TYPES(s): 8 | return {"required": { 9 | "Float": ("FLOAT", { 10 | "default": 1, 11 | "min": -999999, 12 | "max": 999999, 13 | "step": 0.01, 14 | "display": "slider" 15 | }), 16 | }, 17 | "optional": {}, 18 | "hidden": { 19 | "output_type": (["float", "int"], {"default": "float"}), 20 | } 21 | } 22 | RETURN_TYPES = (any_type,) 23 | FUNCTION = "run" 24 | CATEGORY = "2🐕/CYBERPUNK" 25 | INPUT_IS_LIST = False 26 | OUTPUT_IS_LIST = (False,) 27 | def run(self, Float, output_type="float"): 28 | processed_value = round(Float, 10) 29 | print(f"CYBERPUNKHT: Float={Float}, output_type={output_type}, processed_value={processed_value}") 30 | if output_type == "int": 31 | scaled_number = int(round(processed_value)) 32 | print(f"CYBERPUNKHT: Converting to int: {scaled_number}") 33 | else: 34 | scaled_number = float(processed_value) 35 | print(f"CYBERPUNKHT: Keeping as float: {scaled_number}") 36 | return (scaled_number,) 37 | NODE_CLASS_MAPPINGS = { 38 | "CYBERPUNKHT": CYBERPUNKHT 39 | } 40 | NODE_DISPLAY_NAME_MAPPINGS = { 41 | "CYBERPUNKHT": "CYBERPUNKHT" 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CYBERPUNK-STYLE-DIY License 2 | 3 | Copyright (c) 2025 CYBERPUNK-STYLE-DIY 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to use 9 | the Software in its original form, subject to the following conditions: 10 | 11 | PERMITTED: 12 | ✅ Use - You may use the Software for personal and commercial purposes 13 | ✅ Distribution - You may distribute the original, unmodified Software 14 | ✅ Display - You may publicly display the Software 15 | 16 | PROHIBITED: 17 | ❌ Modification - You may NOT modify, alter, or create derivative works 18 | ❌ Reverse Engineering - You may NOT reverse engineer or decompile 19 | ❌ Redistribution of Modified Versions - You may NOT distribute modified versions 20 | ❌ Claim of Authorship - You may NOT claim authorship of this work 21 | 22 | CONDITIONS: 23 | 📋 The above copyright notice and this permission notice shall be included in all copies 24 | 📋 You must retain all original credits and attribution 25 | 📋 Any distribution must include this complete license text 26 | 📋 You must clearly indicate that the Software is provided "as-is" from the original author 27 | 28 | DISCLAIMER: 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. 36 | 37 | For any questions regarding this license, please contact the original author. 38 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import importlib 4 | python = sys.executable 5 | file_directory = os.path.dirname(os.path.abspath(__file__)) 6 | WEB_DIRECTORY = file_directory + "/js" 7 | def print_cyberpunk_logo(): 8 | logo = [ 9 | "\033[38;5;201m ██████╗\033[38;5;165m██╗ ██╗\033[38;5;129m██████╗ \033[38;5;93m███████╗\033[38;5;57m██████╗ \033[38;5;21m██████╗ \033[38;5;27m██╗ ██╗\033[38;5;33m███╗ ██╗\033[38;5;39m██╗ ██╗\033[0m", 10 | "\033[38;5;201m██╔════╝\033[38;5;165m╚██╗ ██╔╝\033[38;5;129m██╔══██╗\033[38;5;93m██╔════╝\033[38;5;57m██╔══██╗\033[38;5;21m██╔══██╗\033[38;5;27m██║ ██║\033[38;5;33m████╗ ██║\033[38;5;39m██║ ██╔╝\033[0m", 11 | "\033[38;5;201m██║ \033[38;5;165m ╚████╔╝ \033[38;5;129m██████╔╝\033[38;5;93m█████╗ \033[38;5;57m██████╔╝\033[38;5;21m██████╔╝\033[38;5;27m██║ ██║\033[38;5;33m██╔██╗ ██║\033[38;5;39m█████╔╝ \033[0m", 12 | "\033[38;5;201m██║ \033[38;5;165m ╚██╔╝ \033[38;5;129m██╔══██╗\033[38;5;93m██╔══╝ \033[38;5;57m██╔═══╝ \033[38;5;21m██╔═══╝ \033[38;5;27m██║ ██║\033[38;5;33m██║╚██╗██║\033[38;5;39m██╔═██╗ \033[0m", 13 | "\033[38;5;201m╚██████╗\033[38;5;165m ██║ \033[38;5;129m██████╔╝\033[38;5;93m███████╗\033[38;5;57m██║ \033[38;5;21m██║ \033[38;5;27m╚██████╔╝\033[38;5;33m██║ ╚████║\033[38;5;39m██║ ██╗\033[0m", 14 | "\033[38;5;201m ╚═════╝\033[38;5;165m ╚═╝ \033[38;5;129m╚═════╝ \033[38;5;93m╚══════╝\033[38;5;57m╚═╝ \033[38;5;21m╚═╝ \033[38;5;27m ╚═════╝ \033[38;5;33m╚═╝ ╚═══╝\033[38;5;39m╚═╝ ╚═╝\033[0m" 15 | ] 16 | print() 17 | for line in logo: 18 | print(line) 19 | print() 20 | print("\033[38;5;51m🚀 CYBERPUNK-STYLE-DIY Custom Nodes Loaded! 🚀\033[0m") 21 | print() 22 | print_cyberpunk_logo() 23 | NODE_CLASS_MAPPINGS = {} 24 | NODE_DISPLAY_NAME_MAPPINGS = {} 25 | def load_nodes(): 26 | py_dir = os.path.join(file_directory, "py") 27 | if os.path.exists(py_dir): 28 | if py_dir not in sys.path: 29 | sys.path.insert(0, py_dir) 30 | for filename in os.listdir(py_dir): 31 | if filename.endswith(".py") and filename != "__init__.py": 32 | module_name = filename[:-3] 33 | try: 34 | module = importlib.import_module(module_name) 35 | if hasattr(module, "NODE_CLASS_MAPPINGS"): 36 | NODE_CLASS_MAPPINGS.update(module.NODE_CLASS_MAPPINGS) 37 | if hasattr(module, "NODE_DISPLAY_NAME_MAPPINGS"): 38 | NODE_DISPLAY_NAME_MAPPINGS.update(module.NODE_DISPLAY_NAME_MAPPINGS) 39 | except: 40 | pass 41 | load_nodes() 42 | __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"] -------------------------------------------------------------------------------- /js/cyberpunk-image.js: -------------------------------------------------------------------------------- 1 | import{app as e}from"../../scripts/app.js";class t extends LGraphNode{constructor(e){super(e),this.title=e,this.serialize_widgets=!0,this.isVirtualNode=!0,this.class_type=this.constructor.type,this.type=this.constructor.type,this.pos=[0,0]}static setUp(){this.registered||(LiteGraph.registerNodeType(this.type,this),this.registered=!0)}configure(e){e.properties&&Object.assign(this.properties,e.properties),e.pos&&(this.pos=e.pos),e.size&&(this.size=e.size),e.flags&&(this.flags=e.flags)}serialize(){const e=super.serialize();return!e.id&&this.id&&(e.id=this.id),e.order||void 0===this.order||(e.order=this.order),e.mode||void 0===this.mode||(e.mode=this.mode),e.properties={...this.properties},!e.pos&&this.pos&&(e.pos=[...this.pos]),!e.size&&this.size&&(e.size=[...this.size]),!e.flags&&this.flags&&(e.flags={...this.flags}),e}}class i extends t{constructor(t=i.title){super(t),this.flags=this.flags||{},this.flags.allow_interaction=!this.flags.pinned,this.properties={imageUrl:"",previewSize:256,fontSize:12,fontFamily:"Arial",fontColor:"#ffffff",backgroundColor:"#333333",backgroundAlpha:.8,borderRadius:8,padding:8,waitingText:"等待图像链接或Base64...",loadingText:"加载中..."},this.img=new Image,this.img.onload=()=>{!this.hasBeenResized&&256===this.size[0]&&this.size[1],e.graph.setDirtyCanvas(!0)},this.resizable=!0,this.size=[256,256],this.imageLoaded=!1,this.color="#fff0",this.bgcolor="#fff0",this.loadError=null,this.hasBeenResized=!1}onDrawBackground(e){if(!this.imageLoaded&&this.properties.imageUrl){const e=this.properties.imageUrl.trim();if(e.startsWith("http://")||e.startsWith("https://"))this.img.src=e;else try{let t=e;e.includes("base64,")?this.img.src=e:(t=t.replace(/[\n\r]/g,""),this.img.src="data:image/png;base64,"+t)}catch(e){console.error("Base64解码失败:",e),this.loadError="Base64解码失败"}this.imageLoaded=!0}const t=this.properties.borderRadius,i=(this.properties.padding,this.properties.backgroundColor),s=this.properties.backgroundAlpha;if(s>0){const r=e.fillStyle;e.fillStyle=this.hexToRGBA(i,s),t>0?(e.beginPath(),e.moveTo(t,0),e.lineTo(this.size[0]-t,0),e.quadraticCurveTo(this.size[0],0,this.size[0],t),e.lineTo(this.size[0],this.size[1]-t),e.quadraticCurveTo(this.size[0],this.size[1],this.size[0]-t,this.size[1]),e.lineTo(t,this.size[1]),e.quadraticCurveTo(0,this.size[1],0,this.size[1]-t),e.lineTo(0,t),e.quadraticCurveTo(0,0,t,0),e.closePath(),e.fill()):e.fillRect(0,0,this.size[0],this.size[1]),e.fillStyle=r}if(this.img.complete&&0!==this.img.naturalWidth){const t=e.globalAlpha,i=e.globalCompositeOperation,s=this.properties.previewSize,r=this.img.naturalWidth,o=this.img.naturalHeight;let a;a=r>=o?s/r:s/o;const l=r*a,n=o*a,p=(this.size[0]-l)/2,h=(this.size[1]-n)/2;try{l>0&&n>0?(e.globalAlpha=1,e.globalCompositeOperation="source-over",e.drawImage(this.img,p,h,l,n),e.globalAlpha=t,e.globalCompositeOperation=i):console.warn("图像绘制参数异常:",{x:p,y:h,drawWidth:l,drawHeight:n,nodeSize:this.size,scale:a,targetSize:s})}catch(s){console.error("图像绘制失败:",s),e.globalAlpha=t,e.globalCompositeOperation=i}}else{const t=e.fillStyle,i=e.font,s=e.textAlign;e.fillStyle=this.properties.fontColor,e.font=this.properties.fontSize+"px "+this.properties.fontFamily,e.textAlign="center",e.fillText(this.loadError||(this.properties.imageUrl?this.properties.loadingText:this.properties.waitingText),this.size[0]/2,this.size[1]/2),e.fillStyle=t,e.font=i,e.textAlign=s}}hexToRGBA(e,t){return"rgba("+parseInt(e.slice(1,3),16)+", "+parseInt(e.slice(3,5),16)+", "+parseInt(e.slice(5,7),16)+", "+t+")"}onPropertyChanged(t,i){"imageUrl"===t?(this.imageLoaded=!1,this.img.src="",this.loadError=null,e.graph.setDirtyCanvas(!0)):e.graph.setDirtyCanvas(!0)}onDblClick(e,t,i){LGraphCanvas.active_canvas.showShowNodePanel(this)}onResize(t){t&&Array.isArray(t)&&t.length>=2&&(this.size[0]=Math.max(t[0],50),this.size[1]=Math.max(t[1],50),this.hasBeenResized=!0,e.graph.setDirtyCanvas(!0))}getExtraMenuOptions(e,t){t.unshift({content:"设置预览大小",submenu:{options:[{content:"128x128",callback:()=>{this.properties.previewSize=128,this.onPropertyChanged("previewSize",128)}},{content:"256x256",callback:()=>{this.properties.previewSize=256,this.onPropertyChanged("previewSize",256)}},{content:"512x512",callback:()=>{this.properties.previewSize=512,this.onPropertyChanged("previewSize",512)}}]}}),t.push({content:"固定节点",callback:()=>{this.flags.pinned=!this.flags.pinned,this.flags.allow_interaction=!this.flags.pinned}})}onShowCustomPanelInfo(e){var t,i;null===(t=e.querySelector('div.property[data-property="Mode"]'))||void 0===t||t.remove(),null===(i=e.querySelector('div.property[data-property="Color"]'))||void 0===i||i.remove()}draw(e){this.flags=this.flags||{},this.flags.allow_interaction=!this.flags.pinned}}i.type="2🐕/CYBERPUNK",i.title="图像链接预览",i.title_mode=LiteGraph.NO_TITLE,i.collapsable=!1,i["@imageUrl"]={type:"string",title:"图像链接"},i["@previewSize"]={type:"number",title:"预览大小",default:256,min:64,max:1024,step:1},i["@fontSize"]={type:"number",title:"字体大小",default:12,min:8,max:32,step:1},i["@fontFamily"]={type:"string",title:"字体",default:"Arial"},i["@fontColor"]={type:"color",title:"字体颜色",default:"#ffffff"},i["@backgroundColor"]={type:"color",title:"背景颜色",default:"#333333"},i["@backgroundAlpha"]={type:"number",title:"背景透明度",default:0,min:0,max:1,step:.1},i["@borderRadius"]={type:"number",title:"圆角大小",default:8,min:0,max:50,step:1},i["@padding"]={type:"number",title:"内边距",default:8,min:0,max:50,step:1},i["@waitingText"]={type:"string",title:"等待提示文字",default:"等待图像链接或Base64..."},i["@loadingText"]={type:"string",title:"加载提示文字",default:"加载中..."};const s=LGraphCanvas.prototype.drawNode;LGraphCanvas.prototype.drawNode=function(e,t){if(e.constructor===i){e.bgcolor="transparent",e.color="#666666";const i=s.apply(this,arguments);return e.onDrawBackground(t),i}return s.apply(this,arguments)};const r={processingMouseDown:!1,lastMouseEvent:null,lastClickTime:0},o=LGraph.prototype.getNodeOnPos;LGraph.prototype.getNodeOnPos=function(e,t,s,a){if(s){const e=LiteGraph.getTime()-LGraphCanvas.active_canvas.last_mouseclick<300;r.processingMouseDown&&r.lastMouseEvent&&r.lastMouseEvent.type.includes("down")&&1===r.lastMouseEvent.which&&!e&&(s=[...s].filter((e=>!(e instanceof i&&e.flags.pinned))))}return o.apply(this,[e,t,s,a])},document.addEventListener("mousedown",(function(e){r.processingMouseDown=!0,r.lastMouseEvent=e}),!0),document.addEventListener("mouseup",(function(){r.processingMouseDown=!1}),!0),e.registerExtension({name:"2🐕.URLPreview",registerCustomNodes(){i.setUp()}}); -------------------------------------------------------------------------------- /js/Cyberpunk.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |titleImages.js 文件中点击按钮选择文件或拖拽PNG图像到此处
174 | 177 | 178 |为转换的图像指定自定义主题名称
182 |