Blog

  • NetBeans 26 Advanced Editor Review

    NetBeans 26 Advanced Editor Review

    NetBeans 26 Review: A Comprehensive Deep Dive 🚀

    Overview

    Apache NetBeans 26, released on May 19, 2025, arrives with support for JDKs 17, 21, and the latest JDK 24, broadening its appeal to developers targeting modern Java platforms. The IDE continues its open-source, Apache-licensed tradition, extending support for languages like Java, JavaFX, C/C++, PHP, JavaScript, HTML5, and more.

    What’s New & Enhanced

    • Smart & Contextual Coding: Fast, semantic-aware code completion with real-time error detection. NetBeans’ “Smart Code Editing” significantly reduces coding friction.
    • Debugger & Visual Tools: Enhanced visual debugger enables GUI snapshots and component inspection—a major plus for Swing/JavaFX developers.
    • Database & Static Analysis Integration: Built-in database explorer, SQL editor, and static analysis tools like FindBugs bolster the developer toolkit.
    • Remote & Profiling Support: Full remote C/C++ development support and a powerful bundled Profiler, essential for performance tuning.

    Requirements For Programming Text Editor

    Glossary:

    Code Editor

    Designed for writing and editing source code.

    IDE

    Integrated Development Environment combines various tools need for software development.

    Plugin

    Software component that adds specific functionality.

    Theme

    Preset package containing graphical appearance to customize look and feel.

    Open source

    Freely available for possible modification and redistribution.

    SCM

    Source code management use to manage and track modifications to a source code repository.

    Test Tools

    Test System
    Name Description
    CPU Intel(R) i7 2600 @ 3.40GHz.
    Memory 16GB DDR3.
    Operating System Fedora Linux Workstation 42.
    Desktop Environment Gnome 48.
    Name Description

    Test Suite
    Name Description
    Large File 1GB human-readable text.
    Regex File Text with word “Netbeans” repeated..
    Syntax File PHP file containing HTML, CSS & JavaScript.
    Media File Smiley face or Tux Linux JPEG file.
    Java Version OpenJDK 21.0.7.
    PHP Version OpenJDK 8.4.8.
    Python Version OpenJDK 3.13.3.
    Netbeans Version 26.
    Name Description

    Test Scoring

    1. Each feature has two parts.
    2. Score of zero indicates a missing feature.
    3. A part of a feature is work a score of 0.5.

    Three bias elimination steps were utilized. The editor was used for at least three years on different platforms. Attempts were made to get stable plug-ins for missing features. The same editor was compared between the one in the repository, the developers website, and the compiled version if applicable.

    Selecting Editor Version

    For this review, Netbeans was downloaded from the developers website and it did not require additional plugins.

    Features

    1. The theme can be native for the editor in terms of the background, and the dark theme did not need tweaks for source code management. Netbeans comes with dark and light themes and others can be created or downloaded. The score for the theme was 1.0.
    2. Dragging and dropping a text file into the editor opens a new tab. It is still not possible to specify the tab location during the drag and drop operation. The score for drag and drop into editor was 0.5.
    3. Opening a very large text file did not crash Netbeans. An out of memory window was shown and it was not possible to edit the large file. The score for opening a large file was 0.5.
    4. Multiple documents can opened in multiple tabs. Tear-off tabs work by opening a new Netbeans editor instances which is handy for multiple monitors. The score for multiple documents was a perfect 1.0.
    5. Multiple editors can be opened as new tabs with drag options. Every new editor tab can be split vertically or horizontally. The score for multiple editor view was a perfect 1.0.
    6. Creating non-project files is possible by dragging the folder into the workspace. Non-project files can be opened by the drag and drop operation. The score for creating non-project files was a perfect 1.0.
    7. Soft word wrap can be enabled in the editor settings. Automatic soft wrap for documents is available for Netbeans. The score for word wrap was a perfect 1.0.
    8. Spell check works as words are typed. Spelling errors are shown in opened documents. The score for spell check was a perfect 1.0.
    9. Word count is not available for Netbeans. Selection word count is not available. The score for word count was 0.0.
    10. Go to line can jump to a specified line. It is possible to jump to either the first or last line. The score for go to line was a perfect 1.0.
    11. Indentation can default to user-defined tab stops. Children are automatically indented. The score for indentation was a perfect 1.0
    12. Fonts can be dynamically scaled. The system font can be bypassed and a new editor font and size can be set. The score for fonts was a perfect 1.0.
    13. Find and replace using regular expressions can be utilized for all open documents in the current session. Find and replace will work for the current document or a selection in the current document. The score for find and replacing using regular expressions was 1.0.
    14. Multiple language syntax highlighting in one file is enabled if the language plug-ins are installed. Each language has code-sensitive syntax colors which can be modified. The score for multiple language syntax highlighting was a perfect 1.0.
    15. Code folding works for markup languages such as HTML. Code folding also works for programming languages such as Java and PHP. The score for code folding was 1.0.
    16. Selecting rectangular block per column works via a toggle or CTRL-SHIFT-R on Linux. Rectangular block selections work with word wrap enabled. The score for selecting rectangular block was a perfect 1.0.
    17. Multiple selection works using the shortcut CTRL-SHIFT-LMB or CMD-SHIFT-LMB on Macs. Search multiple selection is not available. The score for multiple selection was 0.5.
    18. Distraction-free mode to hide panes works. Line numbers can be toggled to improve distraction-free mode. The score for distraction-free was a perfect 1.0.
    19. The file manager can create and delete folders. Media files can be dragged and dropped into the file manager pane. The score for file manager was a perfect 1.0.
    20. Terminal is integrated into Netbeans. The terminal can follow folder. Terminal can execute system commands. The score for terminal was 1.0.

    Results

    Netbeans is a very powerful IDE. By default, the Netbeans editor is no longer missing required features which can be installed by using extensions. For my required features, the Netbeans editor scored 77.5% or 7.75 out of 10.

    Netbeans 26 Split View
    Apache Netbeans 26 Multiple Editor Split View

    Netbeans 26 Plugins View
    Apache Netbeans 26 Installed Plugins View

    🎥 Live Screencast Tour

    Take a guided walk-through of some of NetBeans 26’s best new features—from database tools to testing frameworks:

    Apache Netbeans 26 Tour And Review

    Verdict: NetBeans 26 is a robust, mature IDE great for Java, web, and C/C++ development. Its extensive feature set and strong debugging/database tooling make it ideal for both beginners and seasoned developers. The only downsides? Slightly dated UI and bit of heaviness on older systems.

    One-on-One NetBeans & Programming Tutorials

    Looking to level up? I offer personalized online tutoring sessions to help you master:

    • NetBeans full setup & advanced features
    • Java (SE, EE, JavaFX), C/C++, Python, PHP/HTML/CSS/JavaScript
    • GUI development, debugging, remote builds, database access
    • Build tools, integration, best practices

    Session styles include:

    • Short term (code review, targeted topic)
    • Long term (structured curriculum)
    • Project-focused (develop your app with guidance)

    Why pick me?

    • Professionally experienced, patient, and supportive
    • Flexible scheduling across time zones
    • Personalized roadmap & resource recommendations

    Next step: reply with your goals & level, and I’ll tailor a free session outline for you or contact me via the Ojambo Services.

    Getting Started with NetBeans 26

    1. Install: Grab the appropriate installer (bundled with JDK) from the Apache site and follow the setup wizard.
    2. Launch: Use the Welcome screen to create or import a project.
    3. Try Debugging: Use Ctrl+F5/⌘+F5 for GUI apps; snap components and trace back to source code.
    4. Explore Database Tools: Connect to MySQL or other DBs, explore tables, write queries & view history.
    5. Run Screencasts: Visit the official NetBeans tutorials for extras like TestNG, Java EE, and JavaFX tours.

    TL;DR

    NetBeans 26 excels as a free, full-featured multi-language IDE. Ideal for full-stack devs, GUI designers, database work, and C/C++ needs. If you’re after speed or UI modernity, consider alternatives—but NetBeans offers unmatched reliability and features at zero cost.

    Like this article?
    Subscribe for future IDE comparisons, coding tips, and updates. Want a walkthrough in NetBeans? Book your one-on-one session today!

  • Review Generative AI Phi3 14B Model

    Review Generative AI Phi3 14B Model

    🔍 Reviewing Phi-3 LLM on Linux Using Alpaca & Ollama

    In this article, I’ll walk you through my experience using Phi-3, a lightweight large language model (LLM) developed by Microsoft, running locally on Linux via Alpaca, a user-friendly front-end for Ollama packaged conveniently as a Flatpak.

    Whether you’re exploring on-device AI, seeking open-source alternatives to cloud-based LLMs, or want an affordable and private way to run AI locally, Phi-3 is a great place to start. Let’s dive into the setup, performance, and practical use cases of Phi-3 through Alpaca.

    💡 What is Phi-3?

    Phi-3 is part of Microsoft’s compact LLM family optimized for speed and memory efficiency. Despite its small size (ranging from 1.3B to 7B parameters), it’s surprisingly capable in reasoning, summarization, and Q&A tasks.

    Phi-3 models are released under an MIT license, which makes them ideal for developers, hobbyists, educators, and small businesses looking for unrestricted usage.

    🐪 Why Use Alpaca (Ollama) on Linux?

    Alpaca is a modern GUI client for Ollama, a framework for running LLMs locally with one command. The Flatpak version makes it easy to install and sandbox on any Linux distribution without dependency conflicts.

    🔧 Installation Steps

    1. Install Alpaca via Flatpak:
      flatpak install flathub com.jeffser.Alpaca
    2. Launch Alpaca and select Phi-3 model:
    3. From Alpaca’s UI, you can configure temperature, and other model parameters with ease.

    📷 Screenshots

    Phi-3 14B answered question about the Mayor
    Alpaca With Phi-3 14B Answered Mayor Of Toronto Request.

    Phi-3 14B answered question about PHP code
    Alpaca With Phi-3 14B Answered PHP Code Request.

    Netbeans running Phi-3 14B PHP code
    Apache Netbeans Running Alpaca With Phi-3 14B Generated PHP Code.

    Phi-3 14B answered question about screenshot
    Alpaca With Phi-3 14B Answered Gnome Desktop Screenshot Request.

    Phi-3 14B answered question about Kotlin
    Alpaca With Phi-3 14B Answered Kotlin Code Request.

    Phi-3 14B answered request for Blender Blend File
    Alpaca With Phi-3 14B Answered Blender Blend File Request.

    ▶️ Live Demo Screencast

    Watch my real-time demo of Phi-3 running inside Alpaca on Linux:

    Video Displaying Whole Process From Setup To Running Your First Prompt

    Results:

    Who is the mayor of Toronto?

    Produced inaccurate outdated answer to Olivia Chow as the mayor of Toronto.

    I need a PHP code snippet to connect to a MySQL database.

    Produced accurate syntax PHP code snippet to connect to a MySQL database.

    I need a 1080p screenshot of the gnome desktop environment.

    Produced elaborate answer to generate a 1080p screenshot of Gnome desktop environment because it is a text-based AI lacking ability.

    I need a kotlin code snippet to open the camera using Camera2 API and place the camera view on a TextureView.

    Produced incomplete Kotlin code snippet to open the camera using Camera2 API.

    I need a blender blend file for fire animation.

    Produced elaborate answer to generate a fire animation, but not a Blender Blend file because it is a text-based AI lacking ability.

    💼 Hire Me: LLM Installation & AI Tutoring

    Want to run LLMs like Phi-3 on your own machine? Need help understanding how AI works or integrating it into your workflow?

    I offer:

    • ✅ One-on-one tutoring on local AI and prompt engineering
    • ✅ Remote setup and configuration of Ollama, Alpaca, and models
    • ✅ Lightweight model recommendations for your hardware
    • ✅ Ongoing support and training for your team

    👉 Contact me here or via the form to schedule a session!

    📚 Conclusion

    Running Phi-3 on Linux through Alpaca is an empowering experience. It’s fast, efficient, and respects your privacy. Whether you’re an AI enthusiast or a small business owner, local models like Phi-3 offer real value without the overhead of the cloud.

    Let me know in the comments what models you’re experimenting with, or reach out if you’d like help setting one up!

  • Use Git Commit-Msg Hook With PHP Projects

    Use Git Commit-Msg Hook With PHP Projects

    🚀 How to Use the Git commit-msg Hook with PHP Projects

    If you’re new to Git and PHP development, learning to automate and enforce commit standards is a great skill. In this article, you’ll learn how to use a Git commit-msg hook to validate your commit messages, making your Git history cleaner and more professional – especially useful when working on a team or contributing to open source.

    💡 What is a commit-msg Hook?

    Git hooks are scripts that run at various points in the Git lifecycle. The commit-msg hook is triggered after you enter a commit message, but before the commit is finalized.

    With it, you can:

    • Enforce a specific format for commit messages
    • Block empty or meaningless commits
    • Require ticket numbers or prefixes (e.g. “FEATURE:”, “BUGFIX:”)

    🔬 Example: Require Commit Messages to Start with FEATURE:, BUGFIX:, or DOC:

    Create a commit-msg hook in your project:

    
    
    
    touch .git/hooks/commit-msg
    chmod +x .git/hooks/commit-msg
    
    

    Paste the following into .git/hooks/commit-msg:

    
    
    
    #!/bin/sh
    
    COMMIT_MSG_FILE=$1
    COMMIT_MSG=$(head -n1 "$COMMIT_MSG_FILE")
    
    case "$COMMIT_MSG" in
      FEATURE:*|BUGFIX:*|DOC:*)
        echo "✅ Commit message format OK"
        ;;
      *)
        echo "❌ Commit message must start with 'FEATURE:', 'BUGFIX:', or 'DOC:'"
        exit 1
        ;;
    esac
    
    

    Now try committing:

    git commit -m "Refactored login"

    You’ll see:

    ❌ Commit message must start with 'FEATURE:', 'BUGFIX:', or 'DOC:'

    Try again:

    git commit -m "FEATURE: Refactored login"

    Now it works ✅

    📷 Screenshots

    Git Commit-Msg Hook
    Screenshot Of .git/hooks/commit-msg File

    Git Commit Blocked And Accepted
    Terminal Showing Commit Being Blocked And Accepted

    🎥 Screencast: Watch It in Action

    📚 Want to Learn More PHP?

    This tutorial is just one piece of the puzzle. If you’re serious about becoming a professional PHP developer, check out my full course and book:

    🎓 Course: Learning PHP

    📖 Book: Learning PHP

    You’ll go from beginner to confident developer with step-by-step tutorials, projects, and real-world examples.

    👨‍🎓 Need Help? I Offer One-on-One Coaching & Consulting

    If you’re stuck, want code reviewed, or need help setting up a real-world PHP project, I’m available for one-on-one online tutorials and consulting.

    📩 Contact me here or schedule a session.

    ✅ Final Thoughts

    Git hooks are a hidden gem in the developer workflow. Starting with commit-msg is a smart way to build good habits and prevent bad commits. Give it a try, and level up your Git game – your teammates will thank you!

  • Remote Desktop Collaboration with Rustdesk

    Remote Desktop Collaboration with Rustdesk

    🔧 Secure Remote Desktop with Rustdesk: Self-Hosted Server + Client Setup (Podman)

    Remote desktop access is a vital tool for many of us — whether for tech support, accessing your home computer, or working remotely. Rustdesk is a fantastic open-source alternative to TeamViewer and AnyDesk that puts you in control by allowing self-hosted servers. In this post, we’ll walk through setting up the Rustdesk server using Podman and installing the client, so you can get secure remote access without relying on third-party cloud services.

    📌 What is Rustdesk?

    Rustdesk is an open-source remote desktop software written in Rust. It provides features like:

    • End-to-end encrypted communication
    • Cross-platform clients (Windows, macOS, Linux, Android, iOS)
    • Self-hosted relay and rendezvous servers
    • Simple installation and usage

    Official site: https://rustdesk.com

    📦 Part 1: Install Rustdesk Server Using Podman

    Rustdesk’s server consists of two components:

    • hbbs (the relay server)
    • hbbr (the rendezvous server)

    Here’s how to run both using Podman on your own machine or server.

    📝 Step-by-Step Guide:

    Create a directory for your Rustdesk server config:

    
    
    
          mkdir -p ~/rustdesk-server/data
          cd ~/rustdesk-server
          
    

    Run Rustdesk containers (hbbs + hbbr):

    
    
    
          # Run the relay server
          podman run -d --name hbbs \
            -p 21115:21115 \
            -p 21116:21116 \
            -p 21116:21116/udp \
            -p 21118:21118 \
            -v ./data:/root \
            rustdesk/rustdesk-server hbbs -r your.public.ip
          # Run the rendezvous server
          podman run -d --name hbbr \
            -p 21117:21117 \
            -v ./data:/root \
            rustdesk/rustdesk-server hbbr</code></pre>
          
    

    🔒 Note: Replace your.public.ip with your server’s public IP address. Make sure ports 21115–21118 are open on your firewall.

    🔬 Check if it’s working:

    You can check logs with:

    1. podman logs hbbs
    2. podman logs hbbr

    If both are running fine, your server is ready!

    💻 Part 2: Install the Rustdesk Client

    🧩 Download and install:

    Head to the official download page and install Rustdesk for your platform.

    ⚙️ Configuration:

    Once installed, go to Settings > ID/Relay Server and enter:

    • Relay Server IP: your.public.ip
    • Key: (leave blank unless configured)
    • Use Custom Server: enabled

    You’ll now be connecting via your own server infrastructure — fully private.

    📷 Part 3: Screenshots

    Rustdesk Client
    Rustdesk Client Default Screen

    Rustdesk Client Settings
    Rustdesk Client Settings Screen

    Rustdesk Client Connection
    Rustdesk Client Connection Screen

    Rustdesk Client Connection Password
    Rustdesk Client Connection Password Screen

    Rustdesk Client Wayland Notice
    Rustdesk Client Connection Wayland Notice Screen

    Rustdesk Client Remote Control
    Rustdesk Client Controlling Remote Desktop

    Rustdesk Client Remote Web Browser
    Rustdesk Client Controlling Remote Desktop Web Browser

    Rustdesk Client Remote Terminal
    Rustdesk Client Controlling Remote Desktop Terminal Application

    Rustdesk Client Remote Overview
    Rustdesk Client Controlling Remote Desktop Gnome Shell Overview

    Rustdesk Client Remote Closed
    Rustdesk Client Controlling Remote Desktop Closed

    🎬 Part 4: Live YouTube Screencast

    Video Displaying The Installation And Use Of RustDesk In Container

    🤝 Need Help Installing Rustdesk?

    If you’d like help setting up your Rustdesk server, I offer:

    • 1-on-1 installation support
    • Custom configuration (SSL, domain names, NAT/firewall issues)
    • Troubleshooting connectivity and client issues

    ➡️ Contact me via the Contact page or leave a comment below, and I’ll get in touch!

    💬 Conclusion

    Rustdesk is a powerful, lightweight, and private alternative to commercial remote desktop solutions. By self-hosting your Rustdesk server, you maintain full control over your remote connections — no third-party tracking, no compromises.

    Happy remoting!

  • PHP Web Framework Mezzio

    PHP Web Framework Mezzio


    Getting Started with Mezzio: A Modern Middleware Framework for PHP

    Mezzio is an open-source microframework developed by the Laminas Project. It provides a middleware-based architecture that is perfect for building scalable and maintainable web applications in PHP. If you’re looking for a modern alternative to traditional MVC frameworks, Mezzio offers flexibility, performance, and the backing of a strong PHP community.

    What is Mezzio?

    Mezzio is built around the concept of middleware, giving developers the ability to compose applications from reusable components. It’s PSR-7 and PSR-15 compliant, which means it works seamlessly with modern PHP standards for HTTP message interfaces and middleware.

    • Middleware architecture for clean and modular code
    • Support for multiple routing, templating, and dependency injection containers
    • PSR-compliant, interoperable with a wide range of PHP libraries
    • Ideal for REST APIs and microservices

    Installing Mezzio

    To get started, you’ll need PHP 8.1 or higher, Composer, and a web server such as Apache or Nginx.

    
    
    
    composer create-project mezzio/mezzio-skeleton my-app
    cd my-app
    composer serve
      
    

    The installer will prompt you to select your preferred container, router, and template engine. Once complete, your application will be accessible at http://localhost:8080.

    Building a Simple Database Application with Mezzio and PDO

    In this section, we’ll build a basic Mezzio middleware that connects to an existing MySQL database using PDO and returns data from a table in JSON format.

    Step 1: Configure the Database Connection

    
    
    
    return [
        'db' => [
            'dsn'      => 'mysql:host=localhost;dbname=my_database;charset=utf8mb4',
            'username' => 'my_user',
            'password' => 'my_password',
        ],
    ];
      
    

    Step 2: Create a PDO Service Factory

    
    
    
    namespace App\Factory;
    
    use Psr\Container\ContainerInterface;
    use PDO;
    
    class PdoFactory
    {
        public function __invoke(ContainerInterface $container): PDO
        {
            $config = $container->get('config')['db'];
    
            return new PDO(
                $config['dsn'],
                $config['username'],
                $config['password'],
                [
                    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                ]
            );
        }
    }
      
    

    Step 3: Register the PDO Service

    
    
    
    return [
        'dependencies' => [
            'factories' => [
                PDO::class => \App\Factory\PdoFactory::class,
            ],
        ],
    ];
      
    

    Step 4: Create Middleware to Fetch Data

    
    
    
    namespace App\Handler;
    
    use PDO;
    use Psr\Http\Server\RequestHandlerInterface;
    use Psr\Http\Message\ServerRequestInterface;
    use Psr\Http\Message\ResponseInterface;
    use Laminas\Diactoros\Response\JsonResponse;
    
    class UserListHandler implements RequestHandlerInterface
    {
        private PDO $pdo;
    
        public function __construct(PDO $pdo)
        {
            $this->pdo = $pdo;
        }
    
        public function handle(ServerRequestInterface $request): ResponseInterface
        {
            $stmt = $this->pdo->query('SELECT id, name, email FROM users');
            $users = $stmt->fetchAll();
    
            return new JsonResponse($users);
        }
    }
      
    

    Step 5: Register the Route

    
    
    
    use App\Handler\UserListHandler;
    
    $app->get('/users', UserListHandler::class, 'users.list');
      
    

    Visit /users to see the user list output as JSON.

    Screenshots

    Mezzio Installation
    Composer Installing Sample Mezzio Application

    Mezzio Server
    Mezzio Web Server Running

    Mezzio Twig Template
    Web Browser Displaying Custom Mezzio Twig Template Page

    Watch the Live Screencast

    Watch the full step-by-step Mezzio installation and configuration process

    Go Deeper with the Learning PHP Course

    Want to master PHP from the ground up? Enroll in my course “Learning PHP”, designed for beginners and intermediate developers. It covers everything from syntax to building full applications, including Mezzio projects like the one above.

    The book version of Learning PHP is also available and includes code walkthroughs, diagrams, and exercises to reinforce your understanding.

    Enroll in the course or buy the book.

    Book a One-on-One PHP or Mezzio Tutorial

    If you’d prefer a more personalized approach, I offer one-on-one coaching sessions. Whether you’re just getting started or working on a Mezzio project, I can help you gain clarity and confidence.

    Contact me to schedule your session.

    Conclusion

    Mezzio provides a modern and efficient framework for PHP developers who want more control and flexibility in building web applications. From middleware composition to dependency injection and database integration with PDO, it’s a framework that grows with your needs.

    Explore the screencast, try the code examples, and check out the Learning PHP course to deepen your skills.

  • Textured Triangle Rotation Animation Using Blender Python

    Textured Triangle Rotation Animation Using Blender Python

    Textured Triangle with Noise & Rotation Animation Using Blender Python

    A Sample Project from “Mastering Blender Python API”

    If you’re exploring the powerful world of Blender’s Python API, this tutorial offers a small yet visually engaging example that blends geometry creation, material scripting, and animation—all programmatically. This is a preview of one of the practical projects featured in my book “Mastering Blender Python API.”

    Whether you’re a beginner or an intermediate user, this project shows how to:

    • Create a custom triangle mesh
    • Apply noise-based procedural textures to each face
    • Animate a rotation to showcase all sides

    Step 1: Create the Triangle Mesh

    We’ll begin by using bpy to create a simple triangle in the 3D viewport.

    
    
    
    import bpy
    
    # Clear the scene
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)
    
    # Create mesh and object
    mesh = bpy.data.meshes.new(name="TriangleMesh")
    obj = bpy.data.objects.new("Triangle", mesh)
    bpy.context.collection.objects.link(obj)
    
    # Define vertices and one triangular face
    verts = [(1, 0, 0), (-1, 0, 0), (0, 1, 0)]
    faces = [(0, 1, 2)]
    mesh.from_pydata(verts, [], faces)
    mesh.update()
    
    

    Step 2: Apply Unique Noise Textures to Each Face

    We’ll create materials programmatically and use Blender’s noise texture nodes for variety.

    
    
    
    # Create and assign three materials with unique noise textures
    for i in range(3):
        mat = bpy.data.materials.new(name=f"NoiseMaterial_{i}")
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        links = mat.node_tree.links
    
        noise = nodes.new('ShaderNodeTexNoise')
        bsdf = nodes.get("Principled BSDF")
        links.new(noise.outputs['Color'], bsdf.inputs['Base Color'])
    
        obj.data.materials.append(mat)
    
    # Assign material to the triangle face
    obj.data.polygons[0].material_index = 0
    
    

    This ensures the one face has a rich, randomized pattern. For more faces, you’d assign a unique material index per face.

    Step 3: Animate Rotation to View All Sides

    Now let’s spin the triangle to see all sides using keyframes:

    
    
    
    from math import radians
    
    # Animate Z-axis rotation over 120 frames
    for frame in range(0, 121, 40):
        obj.rotation_euler[2] = radians(frame)
        obj.keyframe_insert(data_path="rotation_euler", index=2, frame=frame)
    
    

    You can preview the animation with the timeline or render it as an MP4/GIF to showcase.

    Screenshots and Screencast

    Below are some visual results from the final Blender project:

    Triangle in Blender viewport
    Blender Scripting Tab Displaying Triangle In Blender Viewport

    Rendered triangle with noise textures
    Blender Rendered Output Displaying Triangle With Noise Textures

    Animated Screencast For Blender Python API Textured Triangle Mesh

    About the Book: “Mastering Blender Python API”

    This example is just a taste of what you’ll learn in “Mastering Blender Python API”—a comprehensive guide covering:

    • Mesh generation
    • Materials and shaders
    • Node automation
    • Rigging and animation
    • Scripting best practices

    📖 Click here to learn more or purchase the book

    Need Help or a Custom Tutorial?

    If you’d like personal help with Blender scripting or Python development, I offer private 1-on-1 tutorials and custom project guidance.

    ✉ Contact Me:

  • JavaScript Image Rotation CAPTCHA

    JavaScript Image Rotation CAPTCHA


    Image Rotation CAPTCHA: A Fun Way to Prevent Bots

    Captchas are an essential tool for preventing bots and malicious scripts from interacting with your website or service. Traditional CAPTCHA methods, such as distorted text or simple math problems, can be frustrating for users and often fail to keep up with increasingly sophisticated bots.

    A more engaging and user-friendly alternative is the Image Rotation CAPTCHA, where users are required to rotate a piece of an image back to its correct orientation. This CAPTCHA type provides both security and a more intuitive, interactive experience for users.

    Verification Form

    CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) involves challenges such as identifying distorted text or selecting images.

    The CAPTCHA is used on web forms to prevent spam, malicious bots and other automated attacks.

    A CAPTCHA presents a challenge that is relatively easy for humans to complete but difficult for bots to replicate.

    In this tutorial, the rotation image-based CAPTCHA will be generated that users must type in the input box. An bitmap image will be split and the split portion of the image will need to be rotated.

    How Does the Image Rotation CAPTCHA Work?

    In a typical Image Rotation CAPTCHA, the process is simple yet effective:

    • Split the Image: An image is divided into several pieces.
    • Rotate One Piece: A random piece of the image is rotated by a certain angle.
    • Rotate Back: The user is tasked with rotating the piece back to its original position using a drag-to-rotate feature.
    • Validation: If the user rotates the piece correctly, the CAPTCHA is solved successfully. The system checks if the rotation is within a small tolerance (typically around 5 degrees).

    This form of CAPTCHA is not only effective at blocking bots but also more engaging for users, as it involves an action (rotating an image) rather than a simple click or text input.

    Why Choose Image Rotation CAPTCHA?

    1. User-Friendly Interaction
    Unlike text-based CAPTCHAs, which can often be misinterpreted by users or bots, the Image Rotation CAPTCHA offers a more intuitive approach. Rotating an image is a natural action that most users are familiar with, making it easier to complete.

    2. Security
    Since it requires real-time interaction (rotating a part of an image), it adds a layer of complexity that traditional CAPTCHA methods don’t offer. Bots that can easily solve text or simple math CAPTCHAs might struggle with rotating an image correctly, especially when it’s randomly rotated.

    3. Visually Appealing
    The Image Rotation CAPTCHA is visually engaging, providing a seamless and interactive experience that can be more aesthetically pleasing compared to traditional methods. It can enhance the user experience while adding an extra layer of security.

    How to Implement an Image Rotation CAPTCHA

    Implementing an Image Rotation CAPTCHA on your website is easier than you might think. Below is a simple example that you can customize to suit your needs. This implementation uses HTML, CSS, and JavaScript to create the interactive image rotation puzzle.

    HTML CAPTCHA Form

    
    
    
    <form class="image-captcha">
       <h3 class="middle">Form Image Rotation CAPTCHA</h3>
       <div class="middle captcha-container">
          <!-- Image pieces will be inserted here dynamically -->
       </div>
       <div class="captcha-buttons">
          <input type="submit" value="Submit" />
          <input type="reset" value="Reset" />
       </div>
       <output></output>
    </form>
    <script></script>
    
    

    CSS CAPTCHA Form

    
    
    
    .captcha-container {
        width: 300px;
        height: 300px;
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-template-rows: 1fr 1fr;
        gap: 2px;
        position: relative;
        border: 2px solid #ccc;
        overflow: hidden;
        background-color: #fff;
    }
    
    .captcha-piece {
        width: 100%;
        height: 100%;
        background-size: 200%;
        background-position: center;
        cursor: pointer;
        transition: transform 0.2s ease-in-out;
        user-select: none;  /* Disable text selection */
    }
    
    

    Rotated Image CAPTCHA Validator

    
    
    
             (() => {
                let captchaContainer = document.querySelector('.captcha-container');
                let output = document.querySelector('output');
                let imageUrl = 'Tux_05.avif'; // Replace with your image URL
                let rows = 2;
                let cols = 2;
                let pieces = [];
                let rotatedPieceIndex = Math.floor(Math.random() * (rows * cols)); // Randomly select a piece to rotate
                let isDragging = false;
                let initialAngle = 0;
                let currentAngle = 0;
                let initialX = 0;
                let initialY = 0;
                let draggedPiece = null;
                let tolerance = 5;
                let createPieces = () => {
                    let pieceWidth = 300 / cols;
                    let pieceHeight = 300 / rows;
    
                    for (let row = 0; row < rows; row++) {
                        for (let col = 0; col < cols; col++) {
                            let piece = document.createElement('div');
                            piece.classList.add('captcha-piece');
                            piece.style.backgroundImage = `url(${imageUrl})`;
                            piece.style.backgroundPosition = `-${col * pieceWidth}px -${row * pieceHeight}px`;
                            piece.style.transform = `rotate(0deg)`; // Initial rotation is 0deg
                            piece.dataset.index = row * cols + col; // Store the piece index
                            piece.dataset.row = row;
                            piece.dataset.col = col;
    
                            // Add event listener to drag and rotate the piece
                            piece.addEventListener('mousedown', startDrag);
    
                            captchaContainer.appendChild(piece);
                            pieces.push(piece);
                        }
                    }
    
                    // Rotate the selected random piece by a random amount
                    rotateRandomPiece();
                };
                let rotateRandomPiece = () => {
                    let selectedPiece = pieces[rotatedPieceIndex];
                    let randomRotation = (Math.random() * 180) + 45; // Random rotation between 45 and 180 degrees
                    selectedPiece.style.transform = `rotate(${randomRotation}deg)`;
                    selectedPiece.dataset.rotation = randomRotation;
                };
                let startDrag = (event) => {
                    draggedPiece = event.target;
                    isDragging = true;
    
                    // Get initial mouse position and current rotation
                    initialX = event.clientX;
                    initialY = event.clientY;
    
                    // Get current rotation angle of the piece
                    initialAngle = getRotationAngle(draggedPiece);
    
                    // Prevent text selection and default drag behavior
                    event.preventDefault();
    
                    // Add mousemove and mouseup listeners
                    document.addEventListener('mousemove', dragPiece);
                    document.addEventListener('mouseup', stopDrag);
                };
                let dragPiece = (event) => {
                    if (!isDragging) return;
    
                    // Get the movement of the mouse
                    let deltaX = event.clientX - initialX;
                    let deltaY = event.clientY - initialY;
    
                    // Calculate the angle based on mouse movement
                    let angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
    
                    // Update the current rotation angle
                    currentAngle = initialAngle + angle;
    
                    // Apply the new rotation
                    draggedPiece.style.transform = `rotate(${currentAngle}deg)`;
                };
                let stopDrag = () => {
                    isDragging = false;
    
                    // Remove mousemove and mouseup listeners
                    document.removeEventListener('mousemove', dragPiece);
                    document.removeEventListener('mouseup', stopDrag);
    
                    // Update the rotation in the dataset
                    draggedPiece.dataset.rotation = currentAngle;
    
                    // Check if the piece is in the correct rotation
                    let targetRotation = parseFloat(draggedPiece.dataset.rotation);
                    if (Math.abs(currentAngle - targetRotation) <= tolerance) {
                        draggedPiece.style.border = '2px solid green'; // Mark as correctly rotated
                    } else {
                        draggedPiece.style.border = '2px solid red'; // Incorrect rotation
                    }
                };
                let getRotationAngle = (element) => {
                    let matrix = window.getComputedStyle(element).transform;
                    if (matrix === 'none') return 0;
    
                    let values = matrix.split('(')[1].split(')')[0].split(',');
                    let a = parseFloat(values[0]);
                    let b = parseFloat(values[1]);
                    let angle = Math.atan2(b, a) * (180 / Math.PI);
                    return angle;
                };
                let ckCode = () => {
                   isCorrect = true;
                   pieces.forEach((piece) => {
                      if ( piece.hasAttribute('data-rotation') && !(Math.abs(parseFloat(piece.dataset.rotation)) <= tolerance) ) {
                         isCorrect = false;
                      }
                   });
                   if ( isCorrect ) {
                   output.innerHTML = `<em class="pass">Validated</em>`;
                   } else {
                      output.innerHTML = `<em class="fail">Failed</em>`;
                   }
                };
                document.querySelector('form.captcha-validator').addEventListener('submit', (evt) => {
                   evt.preventDefault();
                   ckCode();
                });
    
                // Initialize the CAPTCHA
                createPieces();
    
             })();
    
    

    This example splits the image into smaller pieces, rotates one piece randomly, and allows the user to rotate it back into place by dragging.

    Screenshots

    Image Rotation CAPTCHA Fail
    Image Rotation CAPTCHA Failed Screenshot

    Image Rotation CAPTCHA Pass
    Image Rotation CAPTCHA Passed Screenshot

    Screencast

    Image Rotation CAPTCHA in action

    Offering Programming Help for Implementation

    If you need assistance with implementing an Image Rotation CAPTCHA on your website or application, I’m here to help! Whether you’re looking for a simple integration or a more advanced custom CAPTCHA solution, I can provide guidance on the following:

    • Custom CAPTCHA Designs: Tailoring the CAPTCHA to match your website’s theme and design.
    • Advanced Features: Adding additional layers of security, such as custom rotation angles or multi-step verifications.
    • Cross-Browser Support: Ensuring the CAPTCHA works flawlessly across all browsers and devices.
    • Backend Integration: Setting up server-side validation to confirm that the CAPTCHA was solved correctly before allowing form submissions.

    Contact me for more information and a personalized quote!