blender まとめ20260821
# =============================================================================
# Blender 5.x ONLY
# Generic Addon Base - Stable Core Template (Ver 1.8)
# =============================================================================
import bpy
import webbrowser
import re
# =============================================================================
# 01. 【USER CONFIG】 接頭辞・名称・リンク設定
# =============================================================================
# 1. 内部ID用:必ず「英文字」から開始し、英数字とアンダースコア(_)のみを使用してください。
ADDON_PREFIX = "CAM_SPHERE"
# 2. アドオンの表示名(Preferences / アドオン一覧に表示される名前)
PREF_DISPLAY_NAME = "Cam Sphere Links Master"
# 3. サイドバーのタブ名(3Dビュー Nパネルのタブ名)
SIDEBAR_TAB_NAME = "Cam Sphere"
# 4. リンク定義(名前, URL)
LINKS = (
("背後霊カメラ 最新版リンク", "<https://app.notion.com/p/Cam-blender-39f347b3454a806490a6f0107c2347dd>"),
("posfie", "<https://posfie.com/@timekagura/t/zionad2022?sort=0>"),
("zionadchat", "<https://x.com/zionadchat>"),
)
# 5. 動作スイッチ
AUTO_OPEN_N_PANEL = True
AUTO_MATERIAL_PREVIEW = True
# =============================================================================
# 02. 【STABLE CORE LOGIC】 内部IDの自動生成と検証
# =============================================================================
_unregistered_flag = False
if not re.fullmatch(r"[A-Za-z][A-Za-z0-9_]*", ADDON_PREFIX):
raise ValueError(
f"[{PREF_DISPLAY_NAME}] ADDON_PREFIX は「英文字」から開始し、"
f"英数字とアンダースコアのみ使用してください。現在の値: '{ADDON_PREFIX}'"
)
_ID_VAL = ADDON_PREFIX.upper()
_ID_LOW = ADDON_PREFIX.lower()
OP_ID_URL = f"wm.{_ID_LOW}_open_url"
OP_ID_REMOVE = f"wm.{_ID_LOW}_remove_addon"
OP_ID_FOCUS = f"view3d.{_ID_LOW}_focus_selected"
PN_ID_MAIN = f"{_ID_VAL}_PT_main"
PN_ID_ADMIN = f"{_ID_VAL}_PT_admin"
# =============================================================================
# 03. アドオン情報 (bl_info)
# =============================================================================
bl_info = {
"name": PREF_DISPLAY_NAME,
"author": "Your Name",
"version": (1, 8),
"blender": (5, 0, 0),
"location": "View3D > Sidebar (Nパネル)",
"description": "フォーカス機能・リンク集・高安定タイマーを搭載したテンプレート",
"category": "3D View",
}
# =============================================================================
# 04. Operators
# =============================================================================
class OT_focus_selected(bpy.types.Operator):
"""選択オブジェクトを画面中央に表示(フォーカス)"""
bl_idname = OP_ID_FOCUS
bl_label = "選択オブジェクトを中央に表示"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
if context.active_object or context.selected_objects:
bpy.ops.view3d.view_selected()
return {'FINISHED'}
else:
self.report({'WARNING'}, "オブジェクトが選択されていません。")
return {'CANCELLED'}
class OT_open_url(bpy.types.Operator):
"""URLを検証してブラウザで開く"""
bl_idname = OP_ID_URL
bl_label = "リンクを開く"
url: bpy.props.StringProperty()
def execute(self, context):
u = self.url.strip()
if not u or not u.startswith(("http://", "https://")):
self.report({'WARNING'}, f"有効なURLではありません: {u}")
return {'CANCELLED'}
webbrowser.open(u)
return {'FINISHED'}
class OT_remove_addon(bpy.types.Operator):
"""安全な遅延解除タイマーを予約する"""
bl_idname = OP_ID_REMOVE
bl_label = "アドオン登録解除"
def execute(self, context):
if not bpy.app.timers.is_registered(delayed_unregister_timer):
bpy.app.timers.register(delayed_unregister_timer, first_interval=0.1)
return {'FINISHED'}
# =============================================================================
# 05. Panels
# =============================================================================
class PT_main(bpy.types.Panel):
"""メイン機能パネル:フォーカスボタンとリンク集"""
bl_label = "Main Tools & Links"
bl_idname = PN_ID_MAIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = SIDEBAR_TAB_NAME
def draw(self, context):
layout = self.layout
# フォーカスボタンを最上部に配置
col = layout.column(align=True)
col.scale_y = 1.2
col.operator(OP_ID_FOCUS, icon='ZOOM_SELECTED')
layout.separator()
# リンク集
box = layout.box()
box.label(text="Links", icon='URL')
for name, url in LINKS:
if name and url:
box.operator(OP_ID_URL, text=name, icon='EXTERNAL_DRIVE').url = url
class PT_admin(bpy.types.Panel):
"""アドオン管理パネル"""
bl_label = "Admin"
bl_idname = PN_ID_ADMIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = SIDEBAR_TAB_NAME
def draw(self, context):
layout = self.layout
layout.operator(OP_ID_REMOVE, icon='CANCEL')
# =============================================================================
# 06. Timer Logic
# =============================================================================
def initialize_viewport():
"""初期化:Nパネル展開とシェーディング設定"""
wm = bpy.context.window_manager
if wm is None: return 0.2
for window in wm.windows:
screen = window.screen
if screen is None: continue
for area in screen.areas:
if area.type != 'VIEW_3D': continue
space = area.spaces.active
if space is None: continue
if AUTO_OPEN_N_PANEL: space.show_region_ui = True
if AUTO_MATERIAL_PREVIEW: space.shading.type = 'MATERIAL'
return None
def delayed_unregister_timer():
"""Operator終了後に安全に解除を実行"""
global _unregistered_flag
if _unregistered_flag:
return None
unregister()
return None
# =============================================================================
# 07. Register / Unregister
# =============================================================================
classes = (OT_focus_selected, OT_open_url, OT_remove_addon, PT_main, PT_admin)
def register():
global _unregistered_flag
_unregistered_flag = False
for cls in classes:
bpy.utils.register_class(cls)
if not bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.register(initialize_viewport, first_interval=0.2)
def unregister():
global _unregistered_flag
if _unregistered_flag:
return
_unregistered_flag = True
if bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.unregister(initialize_viewport)
for cls in reversed(classes):
try:
bpy.utils.unregister_class(cls)
except RuntimeError:
pass
if __name__ == "__main__":
try: unregister()
except RuntimeError: pass
register()
# =============================================================================
# PROMPT LOG:
# アドオンの有効化と同時に以下の機能を自動実行するBlender 5.x専用コードを作成。
# 1. 「サイドパネル(Nパネル)が自動で開く」
# 2. 「3Dビューがマテリアルプレビューに自動で切り替わる」
# 3. アドオン最上部に「選択オブジェクトを画面中央に表示(フォーカス)」するボタンを配置。
# 元の「リンクパネル(LINKS)」の構成を維持し、安定性の高いタイマー処理を組み込み。
# =============================================================================
# =============================================================================
# Blender 5.x ONLY
# Generic Addon Base - Stable Core Template (Ver 1.8)
# =============================================================================
import bpy
import webbrowser
import re
# =============================================================================
# 01. 【USER CONFIG】 接頭辞・名称・リンク設定
# =============================================================================
# 1. 内部ID用:必ず「英文字」から開始し、英数字とアンダースコア(_)のみを使用してください。
ADDON_PREFIX = "CAM_SPHERE"
# 2. アドオンの表示名(Preferences / アドオン一覧に表示される名前)
PREF_DISPLAY_NAME = "Cam Sphere Links Master"
# 3. サイドバーのタブ名(3Dビュー Nパネルのタブ名)
SIDEBAR_TAB_NAME = "Cam Sphere"
# 4. リンク定義(名前, URL)
LINKS = (
("背後霊カメラ 最新版リンク", "<https://app.notion.com/p/Cam-blender-39f347b3454a806490a6f0107c2347dd>"),
("posfie", "<https://posfie.com/@timekagura/t/zionad2022?sort=0>"),
("zionadchat", "<https://x.com/zionadchat>"),
)
# 5. 動作スイッチ
AUTO_OPEN_N_PANEL = True
AUTO_MATERIAL_PREVIEW = True
# =============================================================================
# 02. 【STABLE CORE LOGIC】 内部IDの自動生成と検証
# =============================================================================
_unregistered_flag = False
if not re.fullmatch(r"[A-Za-z][A-Za-z0-9_]*", ADDON_PREFIX):
raise ValueError(
f"[{PREF_DISPLAY_NAME}] ADDON_PREFIX は「英文字」から開始し、"
f"英数字とアンダースコアのみ使用してください。現在の値: '{ADDON_PREFIX}'"
)
_ID_VAL = ADDON_PREFIX.upper()
_ID_LOW = ADDON_PREFIX.lower()
OP_ID_URL = f"wm.{_ID_LOW}_open_url"
OP_ID_REMOVE = f"wm.{_ID_LOW}_remove_addon"
OP_ID_FOCUS = f"view3d.{_ID_LOW}_focus_selected"
PN_ID_MAIN = f"{_ID_VAL}_PT_main"
PN_ID_ADMIN = f"{_ID_VAL}_PT_admin"
# =============================================================================
# 03. アドオン情報 (bl_info)
# =============================================================================
bl_info = {
"name": PREF_DISPLAY_NAME,
"author": "Your Name",
"version": (1, 8),
"blender": (5, 0, 0),
"location": "View3D > Sidebar (Nパネル)",
"description": "フォーカス機能・リンク集・高安定タイマーを搭載したテンプレート",
"category": "3D View",
}
# =============================================================================
# 04. Operators
# =============================================================================
class OT_focus_selected(bpy.types.Operator):
"""選択オブジェクトを画面中央に表示(フォーカス)"""
bl_idname = OP_ID_FOCUS
bl_label = "選択オブジェクトを中央に表示"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
if context.active_object or context.selected_objects:
bpy.ops.view3d.view_selected()
return {'FINISHED'}
else:
self.report({'WARNING'}, "オブジェクトが選択されていません。")
return {'CANCELLED'}
class OT_open_url(bpy.types.Operator):
"""URLを検証してブラウザで開く"""
bl_idname = OP_ID_URL
bl_label = "リンクを開く"
url: bpy.props.StringProperty()
def execute(self, context):
u = self.url.strip()
if not u or not u.startswith(("http://", "https://")):
self.report({'WARNING'}, f"有効なURLではありません: {u}")
return {'CANCELLED'}
webbrowser.open(u)
return {'FINISHED'}
class OT_remove_addon(bpy.types.Operator):
"""安全な遅延解除タイマーを予約する"""
bl_idname = OP_ID_REMOVE
bl_label = "アドオン登録解除"
def execute(self, context):
if not bpy.app.timers.is_registered(delayed_unregister_timer):
bpy.app.timers.register(delayed_unregister_timer, first_interval=0.1)
return {'FINISHED'}
# =============================================================================
# 05. Panels
# =============================================================================
class PT_main(bpy.types.Panel):
"""メイン機能パネル:フォーカスボタンとリンク集"""
bl_label = "Main Tools & Links"
bl_idname = PN_ID_MAIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = SIDEBAR_TAB_NAME
def draw(self, context):
layout = self.layout
# フォーカスボタンを最上部に配置
col = layout.column(align=True)
col.scale_y = 1.2
col.operator(OP_ID_FOCUS, icon='ZOOM_SELECTED')
layout.separator()
# リンク集
box = layout.box()
box.label(text="Links", icon='URL')
for name, url in LINKS:
if name and url:
box.operator(OP_ID_URL, text=name, icon='EXTERNAL_DRIVE').url = url
class PT_admin(bpy.types.Panel):
"""アドオン管理パネル"""
bl_label = "Admin"
bl_idname = PN_ID_ADMIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = SIDEBAR_TAB_NAME
def draw(self, context):
layout = self.layout
layout.operator(OP_ID_REMOVE, icon='CANCEL')
# =============================================================================
# 06. Timer Logic
# =============================================================================
def initialize_viewport():
"""初期化:Nパネル展開とシェーディング設定"""
wm = bpy.context.window_manager
if wm is None: return 0.2
for window in wm.windows:
screen = window.screen
if screen is None: continue
for area in screen.areas:
if area.type != 'VIEW_3D': continue
space = area.spaces.active
if space is None: continue
if AUTO_OPEN_N_PANEL: space.show_region_ui = True
if AUTO_MATERIAL_PREVIEW: space.shading.type = 'MATERIAL'
return None
def delayed_unregister_timer():
"""Operator終了後に安全に解除を実行"""
global _unregistered_flag
if _unregistered_flag:
return None
unregister()
return None
# =============================================================================
# 07. Register / Unregister
# =============================================================================
classes = (OT_focus_selected, OT_open_url, OT_remove_addon, PT_main, PT_admin)
def register():
global _unregistered_flag
_unregistered_flag = False
for cls in classes:
bpy.utils.register_class(cls)
if not bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.register(initialize_viewport, first_interval=0.2)
def unregister():
global _unregistered_flag
if _unregistered_flag:
return
_unregistered_flag = True
if bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.unregister(initialize_viewport)
for cls in reversed(classes):
try:
bpy.utils.unregister_class(cls)
except RuntimeError:
pass
if __name__ == "__main__":
try: unregister()
except RuntimeError: pass
register()
# =============================================================================
# PROMPT LOG:
# アドオンの有効化と同時に以下の機能を自動実行するBlender 5.x専用コードを作成。
# 1. 「サイドパネル(Nパネル)が自動で開く」
# 2. 「3Dビューがマテリアルプレビューに自動で切り替わる」
# 3. アドオン最上部に「選択オブジェクトを画面中央に表示(フォーカス)」するボタンを配置。
# 元の「リンクパネル(LINKS)」の構成を維持し、安定性の高いタイマー処理を組み込み。
# =============================================================================
# =============================================================================
# Blender 5.x ONLY
# Generic Addon Base - Ultimate Stability Template (Ver 1.6)
# =============================================================================
import bpy
import webbrowser
import re
# =============================================================================
# 01. 【ここだけ変更】接頭辞・名称設定
# =============================================================================
# 内部ID用:必ず英数字とアンダースコア(_)のみを使用してください。
ADDON_PREFIX = "CAM_SPHERE"
# 1. アドオンの表示名(設定画面 / Preferences の一覧に表示される名前)
PREF_DISPLAY_NAME = "Cam Sphere Links Master"
# 2. サイドバーのタブ名(3DビューのNパネルに表示される名前)
SIDEBAR_TAB_NAME = "Cam Sphere"
# --- 厳格なPREFIX検証 (不正な文字がある場合はロード時にエラーを出して停止) ---
if not re.fullmatch(r"[A-Za-z0-9_]+", ADDON_PREFIX):
raise ValueError(
f"[{PREF_DISPLAY_NAME}] ADDON_PREFIX は英数字とアンダースコアのみ使用してください。 "
f"現在の値: '{ADDON_PREFIX}'"
)
# =============================================================================
# 02. アドオン情報 (bl_info)
# =============================================================================
bl_info = {
"name": PREF_DISPLAY_NAME,
"author": "Your Name",
"version": (1, 6),
"blender": (5, 0, 0),
"location": "View3D > Sidebar (Nパネル)",
"description": "専用リンク集および管理ツール(究極安定性テンプレート)",
"category": "3D View",
}
# =============================================================================
# 03. 内部IDの自動生成
# =============================================================================
_ID_VAL = ADDON_PREFIX.upper()
_ID_LOW = ADDON_PREFIX.lower()
# 内部識別子
OP_ID_URL = f"wm.{_ID_LOW}_open_url"
OP_ID_REMOVE = f"wm.{_ID_LOW}_remove_addon"
PN_ID_LINKS = f"{_ID_VAL}_PT_links"
PN_ID_ADMIN = f"{_ID_VAL}_PT_admin"
# =============================================================================
# 04. Links定義 & 動作スイッチ
# =============================================================================
LINKS = (
("背後霊カメラ 最新版リンク", "<https://app.notion.com/p/Cam-blender-39f347b3454a806490a6f0107c2347dd>"),
("posfie", "<https://posfie.com/@timekagura/t/zionad2022?sort=0>"),
("zionadchat", "<https://x.com/zionadchat>"),
)
AUTO_OPEN_N_PANEL = True
AUTO_MATERIAL_PREVIEW = True
# =============================================================================
# 05. Operators
# =============================================================================
class OT_open_url(bpy.types.Operator):
"""URLを検証してブラウザで開く"""
bl_idname = OP_ID_URL
bl_label = "リンクを開く"
url: bpy.props.StringProperty()
def execute(self, context):
u = self.url.strip()
if not u or not u.startswith(("http://", "https://")):
self.report({'WARNING'}, f"有効なURLではありません: {u}")
return {'CANCELLED'}
webbrowser.open(u)
return {'FINISHED'}
class OT_remove_addon(bpy.types.Operator):
"""安全な遅延解除タイマーを予約する"""
bl_idname = OP_ID_REMOVE
bl_label = "アドオン登録解除"
def execute(self, context):
if not bpy.app.timers.is_registered(delayed_unregister_timer):
bpy.app.timers.register(delayed_unregister_timer, first_interval=0.1)
return {'FINISHED'}
# =============================================================================
# 06. Panels
# =============================================================================
class PT_links(bpy.types.Panel):
bl_label = "Links"
bl_idname = PN_ID_LINKS
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = SIDEBAR_TAB_NAME # 正しくタブ名に紐付け
def draw(self, context):
layout = self.layout
for name, url in LINKS:
if name and url:
layout.operator(OP_ID_URL, text=name, icon='URL').url = url
class PT_admin(bpy.types.Panel):
bl_label = "Admin"
bl_idname = PN_ID_ADMIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = SIDEBAR_TAB_NAME # 正しくタブ名に紐付け
def draw(self, context):
layout = self.layout
layout.operator(OP_ID_REMOVE, icon='CANCEL')
# =============================================================================
# 07. Timer Logic
# =============================================================================
def initialize_viewport():
wm = bpy.context.window_manager
if wm is None: return 0.2
for window in wm.windows:
screen = window.screen
if screen is None: continue
for area in screen.areas:
if area.type != 'VIEW_3D': continue
space = area.spaces.active
if space is None: continue
if AUTO_OPEN_N_PANEL: space.show_region_ui = True
if AUTO_MATERIAL_PREVIEW: space.shading.type = 'MATERIAL'
return None
def delayed_unregister_timer():
unregister()
return None
# =============================================================================
# 08. Register / Unregister
# =============================================================================
classes = (OT_open_url, OT_remove_addon, PT_links, PT_admin)
def register():
for cls in classes:
bpy.utils.register_class(cls)
if not bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.register(initialize_viewport, first_interval=0.2)
def unregister():
if bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.unregister(initialize_viewport)
for cls in reversed(classes):
try: bpy.utils.unregister_class(cls)
except RuntimeError: pass
if __name__ == "__main__":
try: unregister()
except RuntimeError: pass
register()
# =============================================================================
# 【他AI向け HTML化 完全指示プロンプト】
#
# 1. 厳格なカラー設定(CSS変数):
# --blog-background-color: #060505; /* ページ背景(黒) */
# --article-background-color: #0c120d; /* 記事背景(深緑) */
# --article-text-color: #ffffff; /* 本文文字(白) */
# --heading-text-color: #ffffff; /* 見出し文字(白) */
# --quote-bar-color: #ffd1d1; /* 引用バー(パステル赤) */
# --quote-text-color: #cdf4d3; /* 引用文字(パステル緑) */
#
# 2. 機能要件:
# - PDF資料の内容を勝手に要約・改変せず、すべて一言一句そのまま出力せよ。
# - 先頭に「読みやすさ重視(改行多め)」と「資料重視(そのまま)」の切替ボタンを設置せよ。
# - 全ての句点(。)の後に <span class="period-break"></span> を挿入せよ。
# =============================================================================
# =============================================================================
# Blender 5.x ONLY
# Generic Addon Base - Ultimate Stability Template (Ver 1.5)
# =============================================================================
import bpy
import webbrowser
import re
# =============================================================================
# 01. 【ここだけ変更】接頭辞・名称設定
# =============================================================================
# 接頭辞:英数字とアンダースコアのみ使用可能です。
# 他のアドオンと競合しない一意な名前を付けてください(例: "MY_TOOLS_V1")
ADDON_PREFIX = "CAM_SPHERE"
# アドオンの表示名
ADDON_TITLE = "Cam Sphere"
# Nパネルのタブ名
ADDON_CATEGORY = "Cam Sphere"
# --- 厳格なPREFIX検証 (不正な文字がある場合はロード時にエラーを出す) ---
if not re.fullmatch(r"[A-Za-z0-9_]+", ADDON_PREFIX):
raise ValueError(
f"[{ADDON_TITLE}] ADDON_PREFIX は英数字とアンダースコアのみ使用してください。 "
f"現在の値: '{ADDON_PREFIX}'"
)
# =============================================================================
# 02. アドオン情報 (bl_info)
# =============================================================================
bl_info = {
"name": f"{ADDON_TITLE} Links Master",
"author": "Your Name",
"version": (1, 5),
"blender": (5, 0, 0),
"location": "View3D > Sidebar (Nパネル)",
"description": "専用リンク集および管理ツール(究極安定性テンプレート)",
"category": "3D View",
}
# =============================================================================
# 03. 内部IDの自動生成 (これ以降のコードは原則変更不要)
# =============================================================================
_ID_VAL = ADDON_PREFIX.upper()
_ID_LOW = ADDON_PREFIX.lower()
# クラスで使用する共通ID
OP_ID_URL = f"wm.{_ID_LOW}_open_url"
OP_ID_REMOVE = f"wm.{_ID_LOW}_remove_addon"
PN_ID_LINKS = f"{_ID_VAL}_PT_links"
PN_ID_ADMIN = f"{_ID_VAL}_PT_admin"
# =============================================================================
# 04. Links定義 & 動作設定
# =============================================================================
LINKS = (
("背後霊カメラ 最新版リンク", "<https://app.notion.com/p/Cam-blender-39f347b3454a806490a6f0107c2347dd>"),
("posfie", "<https://posfie.com/@timekagura/t/zionad2022?sort=0>"),
("zionadchat", "<https://x.com/zionadchat>"),
)
AUTO_OPEN_N_PANEL = True
AUTO_MATERIAL_PREVIEW = True
# =============================================================================
# 05. Operators
# =============================================================================
class OT_open_url(bpy.types.Operator):
"""URLを検証してブラウザで開く"""
bl_idname = OP_ID_URL
bl_label = "リンクを開く"
url: bpy.props.StringProperty()
def execute(self, context):
u = self.url.strip()
# URLの妥当性チェック
if not u or not u.startswith(("http://", "https://")):
self.report({'WARNING'}, f"有効なURLではありません: {u}")
return {'CANCELLED'}
webbrowser.open(u)
return {'FINISHED'}
class OT_remove_addon(bpy.types.Operator):
"""安全な遅延解除タイマーを予約する"""
bl_idname = OP_ID_REMOVE
bl_label = "アドオン登録解除"
bl_description = "現在ロードされているアドオンの登録を安全に解除します"
def execute(self, context):
# 二重登録を防止してタイマーを開始
if not bpy.app.timers.is_registered(delayed_unregister_timer):
bpy.app.timers.register(delayed_unregister_timer, first_interval=0.1)
return {'FINISHED'}
# =============================================================================
# 06. Panels
# =============================================================================
class PT_links(bpy.types.Panel):
bl_label = "Links"
bl_idname = PN_ID_LINKS
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = ADDON_CATEGORY
def draw(self, context):
layout = self.layout
for name, url in LINKS:
if name and url:
layout.operator(OP_ID_URL, text=name, icon='URL').url = url
class PT_admin(bpy.types.Panel):
bl_label = "Admin"
bl_idname = PN_ID_ADMIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = ADDON_CATEGORY
def draw(self, context):
layout = self.layout
layout.operator(OP_ID_REMOVE, icon='CANCEL')
# =============================================================================
# 07. Timer Logic
# =============================================================================
def initialize_viewport():
"""初期化処理:Nパネル展開とマテリアルプレビュー設定"""
wm = bpy.context.window_manager
if wm is None: return 0.2
for window in wm.windows:
screen = window.screen
if screen is None: continue
for area in screen.areas:
if area.type != 'VIEW_3D': continue
space = area.spaces.active
if space is None: continue
if AUTO_OPEN_N_PANEL:
space.show_region_ui = True
if AUTO_MATERIAL_PREVIEW:
space.shading.type = 'MATERIAL'
return None
def delayed_unregister_timer():
"""Operator終了後に安全に解除を実行 (TimerはNoneを返すと自動解除される)"""
unregister()
return None
# =============================================================================
# 08. Register / Unregister
# =============================================================================
classes = (OT_open_url, OT_remove_addon, PT_links, PT_admin)
def register():
for cls in classes:
bpy.utils.register_class(cls)
if not bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.register(initialize_viewport, first_interval=0.2)
def unregister():
# 初期化タイマーの解除
if bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.unregister(initialize_viewport)
# 【改善】delayed_unregister_timerの自己解除チェックを廃止
# Timer自身がNoneを返して終了する設計に任せ、
# ここではクラス登録解除のみを確実に行う
for cls in reversed(classes):
try:
bpy.utils.unregister_class(cls)
except RuntimeError:
# すでに解除されている場合は無視
pass
if __name__ == "__main__":
try:
unregister()
except RuntimeError:
pass
register()
# =============================================================================
# 【他AI向け HTML化 完全指示プロンプト】
#
# このアドオンをHTML化する場合は、以下の【要件】を完全厳守せよ。
#
# 1. 厳格なカラー設定(CSS変数):
# --blog-background-color: #060505; /* ページ背景(黒) */
# --article-background-color: #0c120d; /* 記事背景(深緑) */
# --article-text-color: #ffffff; /* 本文文字(白) */
# --heading-text-color: #ffffff; /* 見出し文字(白) */
# --quote-bar-color: #ffd1d1; /* 引用バー(パステル赤) */
# --quote-text-color: #cdf4d3; /* 引用文字(パステル緑) */
#
# 2. 機能要件:
# - PDF資料の内容を勝手に要約・改変せず、すべて一言一句そのまま出力せよ。
# - 先頭に「読みやすさ重視(改行多め)」と「資料重視(そのまま)」の切替ボタンを設置せよ。
# - 全ての句点(。)の後に <span class="period-break"></span> を挿入せよ。
# =============================================================================
# =============================================================================
# Blender 5.x ONLY
# Generic Addon Base - Prefix Configurable Template (Ver 1.4)
# =============================================================================
bl_info = {
"name": "Cam Sphere Links Master",
"author": "Your Name",
"version": (1, 4),
"blender": (5, 0, 0),
"location": "View3D > Sidebar (Nパネル)",
"description": "専用リンク集および管理ツール(先頭Prefix変更モデル)",
"category": "3D View",
}
import bpy
import webbrowser
# =============================================================================
# 01. 【ここだけ変更】接頭辞設定
# =============================================================================
# この値を変更するだけで、内部の全てのIDが衝突しないように自動変更されます
# (英数字とアンダースコアのみ使用してください)
ADDON_PREFIX = "CAM_SPHERE"
# パネルに表示される名称
ADDON_TITLE = "Cam Sphere"
# Nパネルのタブ名
ADDON_CATEGORY = "Cam Sphere"
# =============================================================================
# 02. 内部IDの自動生成(これ以降のコードは変更不要です)
# =============================================================================
_ID_CLEAN = ADDON_PREFIX.strip().replace(" ", "_").replace("-", "_")
_ID_VAL = _ID_CLEAN.upper()
_ID_LOW = _ID_CLEAN.lower()
# クラスで使用する共通ID定義
OP_ID_URL = f"wm.{_ID_LOW}_open_url"
OP_ID_REMOVE = f"wm.{_ID_LOW}_remove_addon"
PN_ID_LINKS = f"{_ID_VAL}_PT_links"
PN_ID_ADMIN = f"{_ID_VAL}_PT_admin"
# =============================================================================
# 03. Links定義
# =============================================================================
LINKS = (
("背後霊カメラ 最新版リンク", "<https://app.notion.com/p/Cam-blender-39f347b3454a806490a6f0107c2347dd>"),
("posfie", "<https://posfie.com/@timekagura/t/zionad2022?sort=0>"),
("zionadchat", "<https://x.com/zionadchat>"),
)
# =============================================================================
# 04. 動作スイッチ
# =============================================================================
AUTO_OPEN_N_PANEL = True
AUTO_MATERIAL_PREVIEW = True
# =============================================================================
# 05. Operators
# =============================================================================
class OT_open_url(bpy.types.Operator):
bl_idname = OP_ID_URL
bl_label = "リンクを開く"
url: bpy.props.StringProperty()
def execute(self, context):
u = self.url.strip()
if u and u.startswith(("http://", "https://")):
webbrowser.open(u)
return {'FINISHED'}
class OT_remove_addon(bpy.types.Operator):
bl_idname = OP_ID_REMOVE
bl_label = "アドオン登録解除"
def execute(self, context):
if not bpy.app.timers.is_registered(delayed_unregister_timer):
bpy.app.timers.register(delayed_unregister_timer, first_interval=0.1)
return {'FINISHED'}
# =============================================================================
# 06. Panels
# =============================================================================
class PT_links(bpy.types.Panel):
bl_label = "Links"
bl_idname = PN_ID_LINKS
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = ADDON_CATEGORY
def draw(self, context):
layout = self.layout
for name, url in LINKS:
if name and url:
layout.operator(OP_ID_URL, text=name, icon='URL').url = url
class PT_admin(bpy.types.Panel):
bl_label = "Admin"
bl_idname = PN_ID_ADMIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = ADDON_CATEGORY
def draw(self, context):
layout = self.layout
layout.operator(OP_ID_REMOVE, icon='CANCEL')
# =============================================================================
# 07. Timer Logic
# =============================================================================
def initialize_viewport():
wm = bpy.context.window_manager
if wm is None: return 0.2
for window in wm.windows:
screen = window.screen
if screen is None: continue
for area in screen.areas:
if area.type != 'VIEW_3D': continue
space = area.spaces.active
if space is None: continue
if AUTO_OPEN_N_PANEL: space.show_region_ui = True
if AUTO_MATERIAL_PREVIEW: space.shading.type = 'MATERIAL'
return None
def delayed_unregister_timer():
unregister()
return None
# =============================================================================
# 08. Register / Unregister
# =============================================================================
classes = (OT_open_url, OT_remove_addon, PT_links, PT_admin)
def register():
for cls in classes:
bpy.utils.register_class(cls)
if not bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.register(initialize_viewport, first_interval=0.2)
def unregister():
if bpy.app.timers.is_registered(delayed_unregister_timer):
bpy.app.timers.unregister(delayed_unregister_timer)
if bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.unregister(initialize_viewport)
for cls in reversed(classes):
try: bpy.utils.unregister_class(cls)
except RuntimeError: pass
if __name__ == "__main__":
try: unregister()
except RuntimeError: pass
register()
# =============================================================================
# 【他AI向け HTML化 完全指示プロンプト】
#
# このアドオンをHTML化する場合は、以下の【要件】を完全厳守せよ。
#
# 1. 厳格なカラー設定(CSS変数):
# --blog-background-color: #060505; /* ページ背景(黒) */
# --article-background-color: #0c120d; /* 記事背景(深緑) */
# --article-text-color: #ffffff; /* 本文文字(白) */
# --heading-text-color: #ffffff; /* 見出し文字(白) */
# --quote-bar-color: #ffd1d1; /* 引用バー(パステル赤) */
# --quote-text-color: #cdf4d3; /* 引用文字(パステル緑) */
#
# 2. 機能要件:
# - PDF資料の内容を勝手に要約・改変せず、すべて一言一句そのまま出力せよ。
# - 先頭に「読みやすさ重視(改行多め)」と「資料重視(そのまま)」の切替ボタンを設置せよ。
# - 全ての句点(。)の後に <span class="period-break"></span> を挿入せよ。
# =============================================================================
# =============================================================================
# Blender 5.x ONLY
# Generic Addon Base - Ultimate Stability Template (Ver 1.3)
# =============================================================================
bl_info = {
"name": "Cam Sphere Links Master",
"author": "Your Name",
"version": (1, 3),
"blender": (5, 0, 0),
"location": "View3D > Sidebar (Nパネル)",
"description": "専用リンク集および管理ツール(究極安定性テンプレート)",
"category": "3D View",
}
import bpy
import webbrowser
# =============================================================================
# 01. 基本設定(定義セクション)
# =============================================================================
# 【ルール】PREFIXは必ず英数字とアンダースコア(_)のみを使用してください
PREFIX = "CAM_SPHERE"
ADDON_TITLE = "Cam Sphere"
ADDON_CATEGORY = "Cam Sphere"
# =============================================================================
# 02. IDの動的生成(内部識別子の一貫性確保)
# =============================================================================
# 安全のため、記号をアンダースコアに置換する処理を追加
PREFIX_CLEAN = PREFIX.strip().replace(" ", "_").replace("-", "_")
PREFIX_VAL = PREFIX_CLEAN.upper()
PREFIX_ID = PREFIX_CLEAN.lower()
# Operator / Panel IDs
BL_ID_OPEN_URL = f"wm.{PREFIX_ID}_open_url"
BL_ID_REMOVE_ADDON = f"wm.{PREFIX_ID}_remove_addon"
PANEL_ID_LINKS = f"{PREFIX_VAL}_PT_links"
PANEL_ID_ADMIN = f"{PREFIX_VAL}_PT_admin"
# =============================================================================
# 03. Links定義
# =============================================================================
LINKS = (
("背後霊カメラ 最新版リンク", "<https://app.notion.com/p/Cam-blender-39f347b3454a806490a6f0107c2347dd>"),
("posfie", "<https://posfie.com/@timekagura/t/zionad2022?sort=0>"),
("zionadchat", "<https://x.com/zionadchat>"),
)
# =============================================================================
# 04. 動作スイッチ
# =============================================================================
AUTO_OPEN_N_PANEL = True
AUTO_MATERIAL_PREVIEW = True
# =============================================================================
# 05. Operators
# =============================================================================
class OT_open_url(bpy.types.Operator):
"""URLを検証してブラウザで開く"""
bl_idname = BL_ID_OPEN_URL
bl_label = "リンクを開く"
url: bpy.props.StringProperty()
def execute(self, context):
url = self.url.strip()
if not url or not url.startswith(("http://", "https://")):
self.report({'WARNING'}, "無効なURLです。")
return {'CANCELLED'}
webbrowser.open(url)
return {'FINISHED'}
class OT_remove_addon(bpy.types.Operator):
"""Timerを介して安全にアドオンを登録解除する"""
bl_idname = BL_ID_REMOVE_ADDON
bl_label = "アドオン登録解除"
bl_description = "現在ロードされているアドオンの登録を安全に解除します"
def execute(self, context):
# 【改善1】解除Timerの多重登録を防止
if not bpy.app.timers.is_registered(delayed_unregister_timer):
bpy.app.timers.register(delayed_unregister_timer, first_interval=0.1)
return {'FINISHED'}
# =============================================================================
# 06. Panels
# =============================================================================
class PT_links(bpy.types.Panel):
bl_label = "Links"
bl_idname = PANEL_ID_LINKS
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = ADDON_CATEGORY
def draw(self, context):
layout = self.layout
for name, url in LINKS:
if name and url:
layout.operator(BL_ID_OPEN_URL, text=name, icon='URL').url = url
class PT_admin(bpy.types.Panel):
bl_label = "Admin"
bl_idname = PANEL_ID_ADMIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = ADDON_CATEGORY
def draw(self, context):
layout = self.layout
layout.operator(BL_ID_REMOVE_ADDON, icon='CANCEL')
# =============================================================================
# 07. Timer Logic (初期化と遅延解除)
# =============================================================================
def initialize_viewport():
"""3D Viewの状態を初期化する(WindowManagerの準備が整うまで再試行)"""
wm = bpy.context.window_manager
if wm is None: return 0.2
for window in wm.windows:
screen = window.screen
if screen is None: continue
for area in screen.areas:
if area.type != 'VIEW_3D': continue
space = area.spaces.active
if space is None: continue
if AUTO_OPEN_N_PANEL: space.show_region_ui = True
if AUTO_MATERIAL_PREVIEW: space.shading.type = 'MATERIAL'
return None
def delayed_unregister_timer():
"""Operator終了後に安全に解除を実行する"""
unregister()
return None
# =============================================================================
# 08. Register / Unregister (究極安定版ロジック)
# =============================================================================
classes = (
OT_open_url,
OT_remove_addon,
PT_links,
PT_admin,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
if not bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.register(initialize_viewport, first_interval=0.2)
def unregister():
# 【改善2】解除Timer自体の登録も、unregister時に確実にクリアする
if bpy.app.timers.is_registered(delayed_unregister_timer):
bpy.app.timers.unregister(delayed_unregister_timer)
if bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.unregister(initialize_viewport)
for cls in reversed(classes):
try:
bpy.utils.unregister_class(cls)
except RuntimeError:
pass
if __name__ == "__main__":
# 【改善3】例外処理をRuntimeErrorに限定し、信頼性を向上
try:
unregister()
except RuntimeError:
pass
register()
# =============================================================================
# 【他AI向け HTML化・PDF内容厳守プロンプト】
#
# このアドオンの説明をHTML化する場合は、以下の【指示】を最優先せよ。
#
# 1. 配色(CSS変数):
# --blog-background-color: #060505;
# --article-background-color: #0c120d;
# --article-text-color: #ffffff;
# --heading-text-color: #ffffff;
# --quote-bar-color: #ffd1d1;
# --quote-text-color: #cdf4d3;
#
# 2. コンテンツ(PDF内容厳守):
# 提供された資料の内容を一切要約・省略・改変せず、すべてそのままHTML化せよ。
# 改行のON/OFF切り替えボタン(読みやすさ重視/資料重視)を必ず実装せよ。
# 文章内の全ての句点(。)の直後に <span class="period-break"></span> を挿入せよ。
# =============================================================================
# =============================================================================
# Blender 5.x ONLY
# Generic Addon Base - High Stability Template
# =============================================================================
bl_info = {
"name": "Cam Sphere Links Master",
"author": "Your Name",
"version": (1, 2),
"blender": (5, 0, 0),
"location": "View3D > Sidebar (Nパネル)",
"description": "専用リンク集および管理ツール(高安定性テンプレート)",
"category": "3D View",
}
import bpy
import webbrowser
# =============================================================================
# 01. 基本設定(ここを変更するだけで独立した別アドオンになります)
# =============================================================================
PREFIX = "CAM_SPHERE" # 内部データ用の一意な接頭辞
ADDON_TITLE = "Cam Sphere" # パネル等に表示される名前
ADDON_CATEGORY = "Cam Sphere" # Nパネルのタブ名
# =============================================================================
# 02. IDの動的生成(Operator IDやPanel IDにのみ利用)
# =============================================================================
PREFIX_VAL = PREFIX.upper().strip().replace(" ", "_")
PREFIX_ID = PREFIX.lower().strip().replace(" ", "_")
# Operator IDs
BL_ID_OPEN_URL = f"wm.{PREFIX_ID}_open_url"
BL_ID_REMOVE_ADDON = f"wm.{PREFIX_ID}_remove_addon"
# Panel IDs
PANEL_ID_LINKS = f"{PREFIX_VAL}_PT_links"
PANEL_ID_ADMIN = f"{PREFIX_VAL}_PT_admin"
# =============================================================================
# 03. Links定義(一本化管理)
# =============================================================================
LINKS = (
("背後霊カメラ 最新版リンク", "<https://app.notion.com/p/Cam-blender-39f347b3454a806490a6f0107c2347dd>"),
("posfie", "<https://posfie.com/@timekagura/t/zionad2022?sort=0>"),
("zionadchat", "<https://x.com/zionadchat>"),
# ("名前", "URL"), # 追加が必要な場合はここに追記
)
# =============================================================================
# 04. 動作スイッチ
# =============================================================================
AUTO_OPEN_N_PANEL = True
AUTO_MATERIAL_PREVIEW = True
# =============================================================================
# 05. Operators
# =============================================================================
class OT_open_url(bpy.types.Operator):
"""URLを検証してブラウザで開く"""
bl_idname = BL_ID_OPEN_URL
bl_label = "リンクを開く"
url: bpy.props.StringProperty()
def execute(self, context):
url = self.url.strip()
if not url or not url.startswith(("http://", "https://")):
self.report({'WARNING'}, "有効なURLではありません。")
return {'CANCELLED'}
webbrowser.open(url)
return {'FINISHED'}
class OT_remove_addon(bpy.types.Operator):
"""Timerを介して安全にアドオンを登録解除する"""
bl_idname = BL_ID_REMOVE_ADDON
bl_label = "アドオン登録解除"
bl_description = "現在ロードされているアドオンの登録を安全に解除します"
def execute(self, context):
# 自分自身のOperator実行終了後にunregisterを呼び出すためTimerを使用
bpy.app.timers.register(delayed_unregister_timer, first_interval=0.1)
return {'FINISHED'}
# =============================================================================
# 06. Panels
# =============================================================================
class PT_links(bpy.types.Panel):
bl_label = "Links"
bl_idname = PANEL_ID_LINKS
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = ADDON_CATEGORY
def draw(self, context):
layout = self.layout
for name, url in LINKS:
if name and url:
layout.operator(BL_ID_OPEN_URL, text=name, icon='URL').url = url
class PT_admin(bpy.types.Panel):
bl_label = "Admin"
bl_idname = PANEL_ID_ADMIN
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = ADDON_CATEGORY
def draw(self, context):
layout = self.layout
# 名称を「登録解除」に変更して正確性を向上
layout.operator(BL_ID_REMOVE_ADDON, text="アドオン登録解除", icon='CANCEL')
# =============================================================================
# 07. Timer Logic (初期化と遅延解除)
# =============================================================================
def initialize_viewport():
"""3D Viewの状態を初期化する(WindowManagerの準備が整うまで再試行)"""
wm = bpy.context.window_manager
if wm is None:
return 0.2 # WindowManagerがない場合は0.2秒後に再試行
for window in wm.windows:
screen = window.screen
if screen is None: continue
for area in screen.areas:
if area.type != 'VIEW_3D': continue
space = area.spaces.active
if space is None: continue
if AUTO_OPEN_N_PANEL:
space.show_region_ui = True
if AUTO_MATERIAL_PREVIEW:
space.shading.type = 'MATERIAL'
return None # 成功した場合はTimerを終了
def delayed_unregister_timer():
"""Operator終了後に安全に解除を実行する"""
unregister()
return None
# =============================================================================
# 08. Register / Unregister (安定版ロジック)
# =============================================================================
classes = (
OT_open_url,
OT_remove_addon,
PT_links,
PT_admin,
)
def register():
# クラス名書き換えを廃止し、標準的な登録を行う
for cls in classes:
bpy.utils.register_class(cls)
# 二重登録を防止してTimerを登録
if not bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.register(initialize_viewport, first_interval=0.2)
def unregister():
# 初期化Timerの登録解除
if bpy.app.timers.is_registered(initialize_viewport):
bpy.app.timers.unregister(initialize_viewport)
# クラスの登録解除(逆順、想定されるRuntimeErrorのみ無視)
for cls in reversed(classes):
try:
bpy.utils.unregister_class(cls)
except RuntimeError:
pass
if __name__ == "__main__":
# テキストエディタからの実行時は一度解除を試みてから登録
try: unregister()
except: pass
register()
# =============================================================================
# 【他AI向け HTML化・PDF内容厳守プロンプト】
#
# このコードの説明をHTML化する場合は、以下の指示を最優先せよ。
#
# 1. 配色(CSS変数):
# --blog-background-color: #060505;
# --article-background-color: #0c120d;
# --article-text-color: #ffffff;
# --quote-bar-color: #ffd1d1;
# --quote-text-color: #cdf4d3;
#
# 2. コンテンツ:
# PDF資料の内容を一切要約・省略せず、すべてそのままHTML化せよ。
# 改行のON/OFF切り替えボタンを必ず実装し、句点(。)の後に
# <span class="period-break"></span> を挿入せよ。
# =============================================================================