...

What We Think

Blog

Keep up with the latest in technological advancements and business strategies, with thought leadership articles contributed by our staff.
TECH

December 2, 2025

How to create a Calendar event in Gmail

As a programmer, we are probably too familiar with handling sending emails for our application.
How you can send a meeting invite from your own application that works perfectly with Google Calendar, Outlook, and Apple Calendar?
Today I will introduce about sending emails to invite to events and that event will be added to your calendar. We'll break down what iCalendar and .ics files are, how they work, and how you can use Node.js to send your own calendar invitations that show up with those professional "Yes / No / Maybe" buttons.

I. What is iCalendar?

iCalendar is a standard format for sharing calendar information between different applications. You may have used Google Calendar, Outlook, or Apple Calendar before — iCalendar is what helps these apps “speak” to each other when sharing event details. The format is widely used because it follows a consistent structure that all calendar software can understand.
The iCalendar format makes it easy to share event data like meetings, appointments, birthdays, or even reminders. For example, when you receive an event invitation in your email and click “Add to Calendar,” that’s usually an iCalendar file at work. This file contains all the event details such as date, time, title, and location, allowing your calendar app to automatically add the event to your schedule. The iCalendar format uses a .ics file extension — short for “iCalendar file.” It is human-readable and simple to create or modify, making it very useful for developers who want to add calendar features to their applications.

II. What is an ICS File?

An ICS file is a plain text file that follows the iCalendar format. It contains all the information needed for calendar events. You can open it with a text editor to see its content or import it into any calendar app.
When working with an ICS file, there are several key components you’ll usually find:
  • BEGIN:VCALENDAR and END:VCALENDAR: These mark the start and end of the calendar file.
  • VERSION: This indicates the version of iCalendar being used (commonly “2.0”).
  • PRODID: Identifies the application that created the ICS file.
  • BEGIN:VEVENT and END:VEVENT: These mark the start and end of an event block.
  • UID: A unique identifier for the event. It helps distinguish one event from another.
  • DTSTAMP: The date and time when the event file was created or last modified.
  • DTSTART and DTEND: Define the start and end times of the event.
  • SUMMARY: The title or short description of the event.
  • LOCATION: The place where the event will happen.
  • STATUS: Shows whether the event is confirmed, tentative, or cancelled.
  • DESCRIPTION: More details about the event.
  • ORGANIZER and ATTENDEE: Information about who is organizing the event and who is invited.

    Example of an ICS event:

    BEGIN:VCALENDAR
    VERSION:2.0
    PRODID:-//IVC System//Meeting Scheduler//EN
    CALSCALE:GREGORIAN
    METHOD:REQUEST
    BEGIN:VEVENT
    UID:20251124T183309Z
    DTSTAMP:20251124T113309Z
    DTSTART:20251124T114000Z
    DTEND:20251124T121000Z
    SUMMARY:Team meeting
    DESCRIPTION:Monthly team meeting to discuss progress and goals.
    LOCATION:Meeting Room 2
    SEQUENCE:0
    STATUS:CONFIRMED
    ORGANIZER;CN="admin@example.com":mailto:admin@example.com
    ATTENDEE;PARTSTAT=ACCEPTED;RSVP=FALSE;CN=user1@example.com:mailto:user1@example.com
    END:VEVENT
    END:VCALENDAR

III. Points to note when working with ICS:

Always Use UTC Time: Notice the Z at the end of all the timestamps (e.g., ...T100000Z)? This signifies UTC (Coordinated Universal Time). This is a critical best practice. Don't worry about timezones; just provide the event time in UTC. The user's calendar application (Google, Outlook) will automatically and correctly translate it to their local timezone.
UID is Forever: The UID is the event's permanent ID. If you send 10 emails with 10 different .ics files but they all have the same UID, the calendar app will just update the one event.

IV. How to create a new event

To create a new event, you generate an .ics file with:
  • A brand new, unique UID that has never been used before.
  • A SEQUENCE: 0 property.

V. How to update an Event

This is where UID and SEQUENCE are crucial. Imagine you need to move the meeting from 2:00 PM to 3:00 PM. You would send a new .ics file via a new email, but inside the file, you would:
Use the exact same UID as the original event (12345-abc-67890@my-domain.com).
Increment the SEQUENCE number (e.g., SEQUENCE:1).
Update the changed fields (e.g., DTSTART:20251126T150000Z and DTEND:20251126T160000Z).
Update the DTSTAMP to the current time.
When the user's calendar receives this, it sees the UID, finds the event it already has, and checks the SEQUENCE. Since 1 is greater than 0, it knows this is an update and applies the changes. If you send an update with the same SEQUENCE number, it will be ignored as a duplicate.

VI. Sending ICS Mail with Node.js

Manually writing .ics files is a pain. Luckily, we can use libraries to do the hard work. Here’s how to generate an event and email it as a real invitation (with the "Yes/No/Maybe" buttons) using two popular npm packages: ics and nodemailer.
First, install the libraries:
npm install ics nodemailer
Now, let's write the Node.js script.
constnodemailer=require("nodemailer");

 

consttransporter=nodemailer.createTransport({
    service:"gmail",
    auth: {
        user:"your_email@gmail.com",
        pass:"your_password"
    }
});

 

consticsContent=`
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//IVC System//Meeting Scheduler//EN
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VEVENT
UID:20251124T183309Z
DTSTAMP:20251124T113309Z
DTSTART:20251124T114000Z
DTEND:20251124T121000Z
SUMMARY:Team meeting
DESCRIPTION:Monthly team meeting to discuss progress and goals.
LOCATION:Meeting Room 2
SEQUENCE:0
STATUS:CONFIRMED
ORGANIZER;CN="admin@example.com":mailto:admin@example.com
ATTENDEE;PARTSTAT=ACCEPTED;RSVP=FALSE;CN=user1@example.com:mailto:user1@example.com
END:VEVENT
END:VCALENDAR
`;

 

constmailOptions= {
    from:"your_email@gmail.com",
    to:"recipient@example.com",
    subject:"Meeting Invitation",
    text:"Please find the meeting invitation attached.",
    alternatives: [
        {
            contentType:"text/calendar; charset=\"utf-8\"; method=REQUEST",
            content:icsContent
        }
    ]
};

 

transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
        console.log(error);
    } else {
        console.log("Email sent: "+info.response);
    }
});

VII. Conclusion

Working with ICS files is a simple yet powerful way to integrate calendar functionality into your applications. By understanding the basic structure of iCalendar and how an ICS file works, you can easily create, update, and share events between users. When combined with email tools like Nodemailer in Node.js, sending meeting invitations becomes automatic and seamless.
This feature is especially useful for apps that schedule appointments, meetings, or events — such as booking systems, team collaboration tools, and online learning platforms.
In short, iCalendar and ICS make it possible for different platforms and users to stay connected and organized, regardless of which calendar service they use. With just a bit of code, you can help users save time and never miss an important event again.
Whether you need scalable software solutions, expert IT outsourcing, or a long-term development partner, ISB Vietnam is here to deliver. Let's build something great together- reach out to us today. Or click here to explore more ISB Vietnam's case studies
[References]
View More
TECH

December 1, 2025

Integrating Social Login with Amazon Cognito

Social login (via Google, Facebook, Apple, etc.) is one of the easiest ways to boost user adoption and simplify onboarding. Instead of asking users to remember another password, you let them sign in using identities they already trust. Amazon Cognito makes this process straightforward by handling OAuth2 and identity federation behind the scenes — all you need to do is configure it correctly and plug it into your app. This post walks you through setting up Social Login in AWS Cognito, integrating it into your app, and handling the OAuth2 callback + token exchange using Node.js.

What Is Amazon Cognito?

Amazon Cognito has two main components:
  • User Pools – Handle user management (sign up, sign in, MFA, password policies, etc.)
  • Identity Pools (Federated Identities) – Allow access to AWS resources using federated identities from external providers.
When you enable federated sign-in, Cognito links the user’s social identity (from Google, Facebook, etc.) to a Cognito user in your User Pool.

Step 1: Create a Cognito User Pool

  1. Open AWS Console → Cognito → Create user pool
  2. Name it (e.g., myapp-user-pool)
  3. In Sign-in experience, enable Federated sign-in
  4. Add the social providers you want to support

Step 2: Configure a Social Identity Provider (Google Example)

  1. Go to your User Pool → Federation → Identity providers
  2. Select Google
  3. Paste your Client ID and Client Secret from Google Cloud Console
  4. Save changes
Then, under App client integration → App client settings, enable Google as a sign-in provider for your app client.

Step 3: Set Callback and Logout URLs

In App client settings, add:
  • Callback URL(s) → where Cognito redirects users after successful login e.g., https://myapp.com/callback
  • Sign-out URL(s) → where Cognito redirects after logout e.g., https://myapp.com/logout
Click Save changes.

Step 4: Using the Hosted UI

Cognito offers a Hosted UI that handles login and redirects back to your app automatically. Your users visit a URL like this:

https://<your-domain>.auth.<region>.amazoncognito.com/login?client_id=&response_type=code&scope=email+openid+profile&redirect_uri=https://myapp.com/callback

Step 5: Handling the Callback and Exchanging Tokens

Let’s write the backend code that receives that code and exchanges it for tokens (ID token, access token, refresh token). Example: Node.js + Express

1. Install dependencies

npm install express axios qs dotenv

2. Create .env

COGNITO_DOMAIN=https://your-domain.auth.ap-southeast-1.amazoncognito.com
COGNITO_CLIENT_ID=xxxxxxxxxxxxxxx
COGNITO_CLIENT_SECRET=yyyyyyyyyyyyyyyy
COGNITO_REDIRECT_URI=https://myapp.com/callback

3. Create server.js


import express from "express";
import axios from "axios";
import qs from "qs";
import dotenv from "dotenv";
dotenv.config();

const app = express();

app.get("/callback", async (req, res) => {
  const code = req.query.code;
  if (!code) return res.status(400).send("Missing authorization code");

  try {
    const tokenUrl = `${process.env.COGNITO_DOMAIN}/oauth2/token`;

    const data = qs.stringify({
      grant_type: "authorization_code",
      client_id: process.env.COGNITO_CLIENT_ID,
      code,
      redirect_uri: process.env.COGNITO_REDIRECT_URI,
    });

    // Cognito expects Basic Auth header with client_id and client_secret
    const authHeader = Buffer.from(
      `${process.env.COGNITO_CLIENT_ID}:${process.env.COGNITO_CLIENT_SECRET}`
    ).toString("base64");

    const response = await axios.post(tokenUrl, data, {
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Authorization: `Basic ${authHeader}`,
      },
    });

    const { id_token, access_token, refresh_token } = response.data;

    // Decode the JWT ID token (you can also verify signature later)
    const userInfo = JSON.parse(
      Buffer.from(id_token.split(".")[1], "base64").toString("utf-8")
    );

    res.send(`Login successful!`);
  } catch (err) {
    console.error(err);
    res.status(500).send("Token exchange failed");
  }
});

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

How It Works

  1. Cognito redirects the user back to /callback with a code.
  2. You exchange that code for tokens via the /oauth2/token endpoint.
  3. You decode the id_token (JWT) to extract user info like email, sub, and name.

Conclusion

That’s it — you’ve now wired up Social Login with AWS Cognito, including the full OAuth2 token exchange flow. With Cognito handling the heavy lifting (OAuth, token issuance, identity federation), you can focus on building the actual app instead of managing auth complexity.
Whether you need scalable software solutions, expert IT outsourcing, or a long-term development partner, ISB Vietnam is here to deliver. Let’s build something great together—reach out to us today. Or click here to explore more ISB Vietnam's case studies.

 

Cover image from freepik.com

View More
TECH

December 1, 2025

MinIO: Open Source, S3 Compatible Object Storage Solution for Developers

In the modern world of application development, the management and storage of unstructured data such as images, videos, log files, etc. plays an increasingly important role. Amazon S3 (Simple Storage Service) has become a standard for cloud object storage services due to its stability, scalability, and ease of use.

However, when developing and testing applications locally, interacting directly with S3 sometimes causes certain inconveniences in terms of cost, latency, and resource management. That's why MinIO was born — an open-source, high-performance object storage solution designed to be fully compatible with the Amazon S3 API.

What is MinIO?

  • MinIO is an object storage server built on Go. It features the following:
    S3 Compatibility: MinIO implements nearly the entire Amazon S3 API, allowing applications that are already designed to work with S3 to easily integrate with MinIO without significant code changes.
  • High Performance: Optimized for performance, MinIO can achieve impressive read/write speeds, suitable for bandwidth-intensive workloads such as AI/ML, data analytics, and backup.
  • Scalability: MinIO supports a distributed mode architecture, allowing you to easily expand storage capacity and performance by adding new nodes to the cluster.
  • Lightweight and Easy to Deploy: With its compact size and ability to run on multiple platforms (Linux, macOS, Windows) as well as in Docker containers, MinIO is convenient for local development, testing, and deployment across different environments.
  • Open Source: Released under the Apache License v2.0, MinIO offers high flexibility and customizability to users.

Why should programmers use MinIO to emulate S3?

  • Easy local development and testing: You can quickly set up a simulated S3 environment on your PC or development server.
  • Cost savings: Avoid the overhead of constantly interacting with real S3 during development and testing.
  • Full control of the environment: You have complete control over MinIO's data and configuration, making it easy to reproduce failure scenarios and test.
  • Speed ​​up development: Accessing data locally is often faster than connecting to a remote cloud service, speeding up development and testing.

Instructions for installing MinIO using Docker Compose

Step 1: Install Docker and Docker Compose (if you haven't already)
If you haven't installed Docker, visit the official page https://www.docker.com/get-started/ to download and install it for your operating system.

Step 2: Create a docker-compose.yaml file
Create a file named docker-compose.yaml with the following content:

version: "3.8"

services:
    minio:
        image: minio/minio
        volumes:
            - ./minio-data:/data
        ports:
            - "9000:9000" # S3 API port
            - "9001:9001" # MinIO Console interface port
        environment:
            MINIO_ACCESS_KEY: "your_access_key" # Replace with your access key
            MINIO_SECRET_KEY: "your_secret_key" # Replace with your security secret key
        command: server --console-address ":9001" /data
        volumes:
            - ./minio-data:/data # Store data permanently in local directory

Step 3: Launch MinIO
Open a terminal and run the following command in the directory containing docker-compose.yaml:

docker-compose up -d

Step 4: Access the browser using the following link: http://localhost:9001
Use the accesskey and secretkey you set in step 2 to log in.

Step 5: Create an access key and secret key to be able to connect from the web to Minio.
Please save the access key and secret key as they are only visible when you create them.

Step 6: Create a bucket.

After creating the bucket, Minio also allows you to customize the policy, similar to S3.
Select custom and customize according to your needs.

So, you have installed Minio to simulate the S3 environment, now you can perform interactions with Minio similar to operations with S3 to perform development and testing.

Conclusion

MinIO is a powerful and flexible tool for developers who want to emulate a local Amazon S3 environment. Installing and using MinIO with Docker Compose simplifies the setup process while ensuring that data is persistent and easy to maintain. Hopefully, this guide will help you get started exploring and making the most of the features MinIO offers in your software development.

Whether you need scalable software solutions, expert IT outsourcing, or a long-term development partner, ISB Vietnam is here to deliver. Let’s build something great together—reach out to us today. Or click here to explore more ISB Vietnam's case studies.

[References]

View More
TECH

December 1, 2025

How to Send Email with SendGrid in Spring Boot

In modern web applications, sending email is a fundamental function—from account confirmation emails and password resets to system notifications. However, if you try to send emails via a regular SMTP server, you often encounter problems such as:

  • Emails being marked as spam
  • Difficulty in tracking delivery status
  • Sending rate limits

The solution? SendGrid—a professional, stable, and easy-to-integrate email service. In this article, we'll learn how to integrate SendGrid into a Spring Boot application to send emails quickly and securely.

I. What is SendGrid?

SendGrid (owned by Twilio) is a well-known cloud-based email delivery service that supports:

  • Sending transactional emails
  • Sending marketing emails
  • Managing recipient lists and email templates
  • Tracking open rates, bounce rates, and click tracking

SendGrid offers a free plan that allows sending 100 emails/day, which is perfect for testing or small projects.

II. Create an Account and Get an API Key

  • Go to https://sendgrid.com
  • Click Start for Free to register an account.
  • After verifying your email, log in to the dashboard.
  • Navigate to Settings → API Keys.
  • Click Create API Key.
  • Set a name (e.g., springboot-mail-key) and choose Full Access permissions.
  • Save the API Key (Important: It is only displayed once).

III. Add the Dependency to pom.xml

Add the official SendGrid Java library to your project's pom.xml:

XML

<dependency>
    <groupId>com.sendgrid</groupId>
    <artifactId>sendgrid-java</artifactId>
    <version>4.10.1</version>
</dependency>

 

IV. Configure the API Key

Add your SendGrid API key and default sender email to your application.properties file:

Properties

sendgrid.api.key=SG.xxxxxxxx_your_key_here
sendgrid.sender.email=no-reply@yourdomain.com

 

V. Create the SendGridService to Send Email

Next, create a service class that will handle the email sending logic. This class will read the configuration values using @Value and use the SendGrid library to make the API call.

Java

package com.example.mail.service;

import com.sendgrid.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;

@Service
public class SendGridService {

    @Value("${sendgrid.api.key}")
    private String sendGridApiKey;

    @Value("${sendgrid.sender.email}")
    private String senderEmail;

    public void sendEmail(String to, String subject, String contentHtml) throws IOException {
        Email from = new Email(senderEmail);
        Email recipient = new Email(to);
        Content content = new Content("text/html", contentHtml);
        Mail mail = new Mail(from, subject, recipient, content);

        SendGrid sg = new SendGrid(sendGridApiKey);
        Request request = new Request();

        try {
             request.setMethod(Method.POST);
             request.setEndpoint("mail/send");
             request.setBody(mail.build());
             Response response = sg.api(request);

             // Log the response
             System.out.println("Status Code: " + response.getStatusCode());
             System.out.println("Body: " + response.getBody());
             System.out.println("Headers: " + response.getHeaders());

        } catch (IOException ex) {
             // Handle the exception (e.g., log it)
             throw ex;
         }
    }
}

 

Conclusion

With just a few configuration steps, you can now:

  • Create a SendGrid API key
  • Integrate the SendGrid SDK into Spring Boot
  • Send professional HTML emails
  • Track the delivery status on the SendGrid Dashboard

SendGrid is an excellent choice if you want reliable email delivery, to avoid spam filters, and have flexible scalability for your application.

Whether you need scalable software solutions, expert IT outsourcing, or a long-term development partner, ISB Vietnam is here to deliver. Let’s build something great together—reach out to us today. Or click here to explore more ISB Vietnam's case studies.

[References]

View More
TECH

December 1, 2025

CASL – Flexible Authorization for Node.js / React Applications

In modern applications, especially admin dashboards and SaaS systems, detailed role-based access control is essential. If you've ever scattered if (user.role === 'admin') { ... } all over your code, you'll love CASL.

What is CASL?

CASL (Code Access Security Layer) is a JavaScript library for managing authorization in a declarative, maintainable way.

With CASL, you can:

  • Define what users can do on specific resources

  • Use it on both frontend (React/Vue) and backend (Node.js, NestJS)

  • Avoid role-checking spaghetti code

Install CASL in Node.js

yarn add @casl/ability

Define Abilities

Example: a regular user can read products, while an admin can manage everything.

import { AbilityBuilder, Ability } from '@casl/ability';

function defineAbilitiesFor(user) {
    const { can, cannot, build } = new AbilityBuilder(Ability);

    if (user.role === 'admin') {
        can('manage', 'all'); // full access
    } else {
        can('read', 'Product');
        cannot('delete', 'Product');
    }

    return build();
}

Check Permissions with CASL

Create an "ability" object based on the current user's roles/permissions

const ability = defineAbilitiesFor(currentUser);

// Check if the user has permission to "delete" a "Product"

if (ability.can('delete', 'Product')) {
    // allow action
} else {
    // deny access
}

In an Express middleware, this logic is often used to protect routes:

// Middleware to check permissions based on action and subject

function authorize(action, subject) {
    return (req, res, next) => {

        // Create ability based on the logged-in user
        const ability = defineAbilitiesFor(req.user); 
        if (ability.can(action, subject)) {

            // If allowed, proceed to the next middleware or route handler 
            return next();
        }
        res.status(403).send('Forbidden');
    };
}

Why CASL?

  • Clear semantic permission rules (can/cannot)
  • Works on both frontend and backend
  • Easily supports complex conditions (field-level access, ownership, etc.)
  • Keeps business logic clean and centralized

Conclusion

If you're building a system with multiple roles or complex permission rules, give CASL a try.
It helps you write clean, understandable, and reusable access control logic.

If you're seeking a reliable, long-term partner who values collaboration and shared growth, feel free to reach out to us here: Contact ISB Vietnam

[References]

https://casl.js.org/v6/en/


View More
TECH

December 1, 2025

Integration vbs processing with a bat file

I. Overview of Batch and VBScript

Batch file
Batch file (.bat or .cmd): A text file containing Command Prompt (CMD) commands executed sequentially to automate tasks on Windows. Batch can invoke programs, scripts, or execute system commands.

VBScript file (.vbs)
VBScript file (.vbs): A file containing script code written in the VBScript language, commonly used to automate tasks on Windows, such as manipulating files, the registry, or COM applications (e.g., Excel). VBScript is executed via Windows Script Host (wscript.exe or cscript.exe).

A Batch file can call a VBS file to leverage VBScript's advanced processing capabilities, particularly when interacting with COM objects or performing tasks that CMD does not support effectively.

II. Methods to Call a VBS File from a Batch File

There are several ways to call a VBS file from a Batch file, depending on the purpose and how you want the script to run (with a visible interface, in the background, or via the command line). Below are the main methods:

1. Using wscript.exe or cscript.exe
Windows Script Host provides two tools for running VBScript:

wscript.exe
wscript.exe: Executes VBScript in a graphical environment, typically used for scripts with a user interface (e.g., displaying MsgBox).

cscript.exe
cscript.exe: Executes VBScript in a command-line environment, suitable for printing output to the console or running in the background.

Basic Syntax in Batch:


wscript.exe "path_to_vbs_file" [parameter_1] [parameter_2] …
cscript.exe //Nologo "path_to_vbs_file" [parameter_1] [parameter_2] …


//Nologo: Suppresses version and copyright information of cscript.exe, resulting in cleaner output.
[parameter_1] [parameter_2] ...: Parameters passed to the VBS file, accessible in VBScript via WScript.Arguments.

2. Run a VBS file without displaying the Command Prompt window.
If you don’t want the CMD window to appear when running a Batch file (especially when using Task Scheduler), you can use an intermediate VBScript to call the Batch file or hide the window.

Example: Intermediate VBS file (quietrun.vbs) to run a Batch file silently:


' quietrun.vbs
If WScript.Arguments.Count >= 1 Then
ReDim Args(WScript.Arguments.Count - 1)
For i = 0 To WScript.Arguments.Count - 1
Arg = WScript.Arguments(i)
If InStr(Arg, " ") > 0 Then Arg = """" & Arg & """"
Args(i) = Arg
Next
CreateObject("WScript.Shell").Run Join(Args), 0, True
End If


Batch file to call a VBS file to run another VBS file (run_hidden.bat):


@echo off
cscript.exe //Nologo "quietrun.vbs" "test.vbs"


Effectiveness: The test.vbs file runs without displaying the CMD window.
Note: Ensure quietrun.vbs and test.vbs are in the same directory or specify the full path.

Result:

3. Call a VBS script using Task Scheduler

To enable automation, Task Scheduler can be used to execute a batch file. However, it is important to configure the task properly to avoid issues such as COM automation failures.

Task Scheduler Configuration:
1. Open Task Scheduler and create a new task.
2. In the “Actions” tab, add a new action:
Action: Start a program
Program/script: cscript.exe
Add arguments: //Nologo "path\to\test.vbs"
Alternatively, to run via batch file:
Program/script: path\to\run_vbs.bat
3. In the “General” tab, configure the following options:
Run whether user is logged on or not
Run with highest privileges (especially if the VBS requires admin rights)
Note:
If the VBS script interacts with Excel (e.g., opens a workbook), make sure the account running the task has proper COM access permissions. You may need to configure DCOM settings via dcomcnfg.exe.
Always check Task Scheduler history for errors.
Exit code 0x0 indicates success, but you should still verify the actual execution result to ensure the task behaves as expected.

Result:

III. Specific examples

Example 1: Simple VBS file call


' test.vbs
WScript.Echo "Hello from VBScript!"


Batch file (run_vbs.bat) to call it:


@echo off
cscript.exe //Nologo "test.vbs"
pause


Result: Prints "Hello from VBScript!" in the console.
@echo off: hides batch commands for cleaner output.

Example 2: Passing parameters


' test_args.vbs
If WScript.Arguments.Count > 0 Then
WScript.Echo "Argument 1: " & WScript.Arguments(0)
Else
WScript.Echo "No arguments provided."
End If"


batch file:


@echo off
cscript.exe //Nologo "test_args.vbs" "MyParameter"
pause"


Ressult: Prints "Argument 1: MyParameter"

Example 3:
Purpose: Batch file calls a VBS file to:
Retrieve the computer name.
Get free disk space of a specified drive (e.g., C:).
Write the information into a file named system_info.txt.
Requirements:
The batch file passes the drive letter as a parameter (e.g., "C:").
The VBScript returns results and handles errors.
Runs silently (no visible CMD window).
Suitable for automation using Task Scheduler.

1. VBScript File (get_system_info.vbs)
This VBS file retrieves system information and writes it to a text file.


' get_system_info.vbs
Option Explicit

Dim WShell, FSO, ComputerName, DriveLetter, FreeSpace, OutputFile
Dim OutStream, ErrMsg

' Initialize objects
Set WShell = CreateObject("WScript.Shell")
Set FSO = CreateObject("Scripting.FileSystemObject")

' Check arguments
If WScript.Arguments.Count < 2 Then
WScript.StdErr.WriteLine "Error: Missing arguments. Usage: get_system_info.vbs <DriveLetter> <OutputFile>"
WScript.Quit 1
End If

DriveLetter = WScript.Arguments(0) ' Exp: "C:"
OutputFile = WScript.Arguments(1)  ' Exp: "system_info.txt"

' Get computer name
On Error Resume Next
ComputerName = WShell.ExpandEnvironmentStrings("%COMPUTERNAME%")
If Err.Number <> 0 Then
ErrMsg = "Error getting Computer Name: " & Err.Description
WScript.StdErr.WriteLine ErrMsg
WScript.Quit 2
End If
On Error GoTo 0

' Get free space of the drive
On Error Resume Next
Dim Drive
Set Drive = FSO.GetDrive(DriveLetter)
If Err.Number = 0 Then
FreeSpace = Drive.FreeSpace / (1024^3) ' Convert to GB
FreeSpace = FormatNumber(FreeSpace, 2) ' Round to 2 decimal places
Else
ErrMsg = "Error accessing drive " & DriveLetter & ": " & Err.Description
WScript.StdErr.WriteLine ErrMsg
WScript.Quit 3
End If
On Error GoTo 0

' Write results to file
On Error Resume Next
Set OutStream = FSO.CreateTextFile(OutputFile, True)
If Err.Number = 0 Then
OutStream.WriteLine "Computer Name: " & ComputerName
OutStream.WriteLine "Free Space on " & DriveLetter & ": " & FreeSpace & " GB"
OutStream.Close
WScript.Echo "Successfully wrote to " & OutputFile
Else
ErrMsg = "Error writing to " & OutputFile & ": " & Err.Description
WScript.StdErr.WriteLine ErrMsg
WScript.Quit 4
End If
On Error GoTo 0


2. Batch File (run_system_info.bat)
Batch file calls the VBS script and handles the result.


@echo off
setlocal EnableDelayedExpansion

:: Define variables
set "VBS_FILE=get_system_info.vbs"
set "DRIVE=C:"
set "OUTPUT_FILE=system_info.txt"

:: Check if the VBS file exists
if not exist "%VBS_FILE%" (
echo Error: VBS file "%VBS_FILE%" not found.
exit /b 1
)

:: Call the VBS file
echo Calling VBS to collect system info...
cscript.exe //Nologo "%VBS_FILE%" "%DRIVE%" "%OUTPUT_FILE%" > output.txt 2> error.txt
set "EXIT_CODE=%ERRORLEVEL%"

:: Check the result
if %EXIT_CODE% equ 0 (
echo VBS executed successfully.
type output.txt
echo Contents of %OUTPUT_FILE%:
type "%OUTPUT_FILE%"
) else (
echo Error occurred. Exit code: %EXIT_CODE%
type error.txt
)

:: Clean up temporary files
del output.txt error.txt 2>nul

:: End
echo.
echo Done.
pause


Explanation:

Variables:      
VBS_FILE: Name of the VBS file.
DRIVE: Drive to check.
OUTPUT_FILE: Output file.
File Check: Ensure the VBS file exists before calling it.
Calling VBS:
Use cscript.exe //Nologo to run the VBS script.
Redirect standard output (StdOut) to output.txt and standard error (StdErr) to error.txt.
Error Checking: Use %ERRORLEVEL% to determine execution status (0 = success).
Displaying Results:
If successful, display messages from output.txt and the contents of system_info.txt.
If there is an error, display the error code and contents of error.txt.
Cleanup: Delete temporary files output.txt and error.txt

Result:

Cover image created by www.bing.com

Whether you need scalable software solutions, expert IT outsourcing, or a long-term development partner, ISB Vietnam is here to deliver. Let’s build something great together—reach out to us today. Or click here to explore more ISB Vietnam's case studies.

View More
TECH

December 1, 2025

Static Analysis in CakePHP with PHP CodeSniffer

When working on a large CakePHP project with multiple developers, code style can easily become inconsistent. As a result, maintaining a clean and consistent codebase can be challenging. Fortunately, PHP CodeSniffer (PHPCS) is a simple yet powerful static analysis tool that checks whether your code follows a chosen coding standard.

1. Key Features

  • Detects coding standard violations such as wrong indentation, missing spaces, or incorrect naming.
  • Supports popular standards like PSR-2, PSR-12, and CakePHP style.
  • Generates detailed reports about which files and lines need attention.
  • Lightweight and fast — scans text files without executing code.
  • Easily integrates into CI/CD pipelines for automated style checks before merge.

2. Benefits of Using PHPCS

  • Ensures consistent code style across the team.
  • Detects formatting issues early, before they reach production.
  • Makes code reviews faster by focusing reviewers on logic instead of style.
  • Works well with legacy code — issues can be fixed gradually.
  • Encourages good coding discipline and long-term maintainability.

3. How to Use

Step 1: Install PHPCS

composer require --dev "squizlabs/php_codesniffer=*"

Step 2: Run the Check

vendor/bin/phpcs --standard=CakePHP src/

Step 3: Output Results to a File

vendor/bin/phpcs --standard=CakePHP src/ > phpcs-report.txt

  • Optional: Use a bash script for convenience:
    #!/bin/bash
    echo "Running PHP CodeSniffer..."
    vendor/bin/phpcs --standard=CakePHP src/ > phpcs-report.txt
    echo "Done! Report saved to phpcs-report.txt"

4. Review the Output

The generated phpcs-report.txt will look like:
--------------------------------------------------------------------------------
FOUND 4 ERRORS AFFECTING 3 LINES
--------------------------------------------------------------------------------
15 | ERROR | Expected 1 space after FUNCTION keyword; 0 found
20 | ERROR | Line exceeds 120 characters; contains 134 characters
45 | ERROR | Missing doc comment for function getUserList()
--------------------------------------------------------------------------------

5. Conclusion

PHP CodeSniffer is a lightweight and effective static analysis tool for PHP projects, including CakePHP.
It helps you detect coding standard violations early, improves team consistency, and keeps your codebase clean and maintainable.

Even without auto-fix features, PHPCS is invaluable for:

  • Keeping code style consistent across the team
  • Reducing noise during code reviews
  • Maintaining high-quality, readable, and maintainable CakePHP projects

Whether you need scalable software solutions, expert IT outsourcing, or a long-term development partner, ISB Vietnam is here to deliver. Let’s build something great together—reach out to us today. Or click here to explore more ISB Vietnam's case studies.

[References]

https://github.com/squizlabs/PHP_CodeSnifferPHP CodeSniffer (GitHub)

https://book.cakephp.org/4/en/development/coding-standards.htmlCakePHP Coding Standards

https://www.php-fig.org/psr/psr-12/PSR-12 Coding StandardPSR-12 Coding Standard

https://surl.li/pmofsk (Image)

View More
TECH

November 28, 2025

Composition API & Options API in Vue 3. Which should we choose?

In Vue 3, there are two main approaches for creating and managing components: Composition API and Options API. Each approach has its own advantages and disadvantages, and choosing between them depends on project requirements and the development team's programming style.

Options API

The Options API is the traditional approach in Vue. It focuses on defining the parts of a component through objects such as data, methods, computed, watch, and props. This approach was introduced in Vue 2.x and is still widely used in Vue 3 for maintaining compatibility and simplicity.

Features of the Options API

- Simple to manage: The parts of the component are organized into separate options (data, methods, computed, etc.), making it easy to read and understand, especially for newcomers to Vue.

- Clear and structured: The component structure is very clear, and it’s easy to separate and maintain in smaller projects.

- Compatibility with Vue 2.x: The Options API was the main way to define components in Vue 2.x and is still fully supported in Vue 3. This makes it easier for developers transitioning from Vue 2 to Vue 3.

Example with Options API:

<template>
<div>
<h1>{{ message }}</h1>
<button @click="updateMessage">Update Message</button>
</div>
</template>

<script>
export default {
 data() {
   return {
   message: "Hello from Options API"
   };
 },
 methods: {
  updateMessage() {
  this.message = "Message Updated!";
  }
 }
};
</script>

Composition API

The Composition API was introduced in Vue 3, allowing developers to break down component logic in a more flexible, function-based manner instead of using objects like in the Options API. This approach helps improve code reuse, flexibility, and maintainability, especially in large applications.

Features of the Composition API

- Easier code reuse: Logic in components can be reused easily through functions, making the codebase cleaner and easier to maintain.

- Flexibility: Composition API allows you to organize your code based on related functionality, rather than being confined to predefined options like data, methods, computed, etc.

- Ideal for large projects: Especially in complex components and managing multiple states, Composition API provides a more efficient approach.

Example with Composition API:

<template>
<div>
<h1>{{ message }}</h1>
<button @click="updateMessage">Update Message</button>
</div>
</template>

<script>
import { ref } from 'vue';

 export default {
  setup() {
  const message = ref("Hello from Composition API");

  const updateMessage = () => {
  message.value = "Message Updated!";
 };

 return {
  message,
  updateMessage
  };
 }
};
</script>

Comparison Between Composition API and Options API

Feature Options API Composition API
Approach Uses objects like data, methods, computed, etc. Breaks down logic into separate functions in setup().
Logic Reusability Harder to reuse logic across components. Easier to reuse logic across components through functions.
Complexity Simple and easy to apply in small projects. Ideal for complex projects and better for large codebases.
Code Readability Easy to read and understand for beginners. Can be harder to understand, especially in large components.
State Management Easy state management with data and methods. More flexible state management with ref and reactive.
Upgrade Vue 2.x uses Options API, and migration is straightforward. Composition API is a Vue 3 enhancement, encouraged in Vue 3.
Lifecycle Management Uses lifecycle hooks like mounted, created, etc. Uses lifecycle hooks inside setup() with a more flexible syntax.

 

Which should we use?

The Options API should be used for:

- Small Projects: When you have a small or simple application, the Options API is easy to use and doesn’t require much organization.

- For beginners with Vue: Those new to Vue will find the Options API easier to grasp due to its clear structure.

- Vue 2.x Compatibility: Since the Options API was the standard in Vue 2.x, it’s the best choice when migrating a Vue 2 project to Vue 3, as it’s fully supported in Vue 3.

The Composition API should be used for:

- Large and Complex Projects: The Composition API is great for large-scale applications where you need to manage complex components and states.

- Logic Reusability: When you need to reuse logic across different components, the Composition API offers a more efficient way to share code.

- Typescript Support: It is more in line with TypeScript features and flexibility than the Options API.

Conclusion

- Options API: easy to use and best suited for smaller applications or when you’re just starting with Vue. It provides a clear and structured way to organize code and is compatible with Vue 2.x, making it ideal for projects migrating from Vue 2 to Vue 3.

- Composition API: offers more flexibility, better code reuse, and scalability, making it ideal for larger applications or when working with complex components. It also works very well with TypeScript, making it the preferred choice for projects that require strong typing and better code organization.

Although Vue 3 encourages using the Composition API, you can still mix both approaches in a project, depending on the specific situation and needs of your components.

References

https://vueschool.io/articles/vuejs-tutorials/options-api-vs-composition-api/

https://blog.logrocket.com/comparing-vue-3-options-api-composition-api/

Image source: https://www.freepik.com/free-photo/php-programming-html-coding-cyberspace-concept_17105500.htm

Ready to get started?

Contact IVC for a free consultation and discover how we can help your business grow online.

Contact IVC for a Free Consultation
View More
TECH

November 28, 2025

From AR to XR: A Developer-Friendly Tour (with a Qt Quick 3D XR Example)

From AR to XR: A Developer-Friendly Tour

Extended Reality (XR) has quietly gone from science fiction to “just another platform” we target alongside web and mobile. If you’re already building with Qt and curious how your skills fit into AR/VR/XR, this post walks through:

  • What AR and XR actually mean (and where they came from)
  • How AR and XR differ
  • Today’s mainstream XR devices
  • Common domains where XR is used
  • Where XR is going next
  • Programming languages & engines behind XR apps
  • A small Qt Quick 3D XR sample, with explanation of each QML type

AR & XR: Definitions and a Short History

What is Augmented Reality (AR)?

Augmented Reality overlays digital content onto the physical world, in real time, and in the correct 3D position. Classic examples are:

  • Visual instructions overlaid on machinery
  • Filters and effects in mobile apps
  • Navigation arrows painted onto streets or dashboards

A commonly used definition describes AR as systems that (1) combine real and virtual content, (2) run in real time, and (3) register virtual objects in 3D with the real world. Wikipedia

Key historical milestones:

  • 1968 – Ivan Sutherland’s head-mounted display (often cited as the first AR/VR HMD). G2
  • 1990 – Tim Caudell at Boeing coins the term “augmented reality”. G2
  • 2000s – HUDs(Head Up Display), industrial AR, early marker-based mobile AR. Wikipedia
  • 2010s – ARKit (Apple), ARCore (Google) take AR to mainstream phones.
  • 2020s – Mixed reality(MR) headsets with color passthrough blur AR/VR (Meta Quest 3, Apple Vision Pro).

What is Extended Reality (XR)?

Extended Reality (XR) is an umbrella term that covers VR, AR and MR, plus anything in between. More formally, XR refers to technologies that combine or interpolate between purely virtual and purely real environments, often using a “digital twin” of the physical world. Wikipedia

Think of XR as the whole spectrum:

  • VR – fully virtual world
  • MR – real world plus interactive virtual objects anchored in space
  • AR – lightweight overlays, often through phones or glasses

XR lets us talk about all of these together without obsessing over the exact label.

AR vs XR: What’s Actually Different?

Short answer: AR is one point on the XR spectrum.

  • Scope
    • AR is a specific technique: augmenting reality with digital overlays.
    • XR is the category that includes AR, VR, and MR—and sometimes even “beyond human senses” visualizations (e.g., seeing radio waves or air quality as graphics). Wikipedia
  • Devices
    • AR often runs on phones/tablets (ARKit/ARCore) or see-through glasses.
    • XR includes fully immersive headsets (VR), mixed-reality HMDs with passthrough cameras, and more experimental smart glasses.
  • Interaction
    • AR apps may only track a surface or image target.
    • XR apps typically track head pose, hands, controllers, depth, and the room itself, supporting room-scale experiences and precise spatial interaction.

So when you build a Quest 3 or Vision Pro app with both passthrough and fully immersive modes, you’re squarely in XR. When you ship an iOS app that puts a virtual sofa on a real floor via ARKit, that’s “just” AR.

Today’s XR Device Landscape

The hardware scene changes fast, but as of now, several product families dominate:

Meta Quest line

Meta’s Quest devices (Quest 3, Quest 3S, and special bundles like the Xbox Edition) are the most widely used consumer XR headsets, offering standalone VR with color passthrough MR. The Quest 3 is a standalone headset with a Snapdragon XR2 Gen 2, high-resolution displays, and color passthrough to mix virtual objects with the real world. VRcompare+1

Apple Vision Pro

Apple Vision Pro is positioned as a “spatial computer” rather than a VR headset. It uses high-resolution micro-OLED displays, precise eye/hand tracking, and an external “EyeSight” display to show the user’s eyes to people nearby. It runs visionOS, built on iPadOS frameworks, and heavily uses ARKit and spatial UI concepts. Apple+2Wikipedia+2

Samsung Galaxy XR & Android XR Ecosystem

Samsung and Google have introduced the Galaxy XR headset, powered by Android XR and Snapdragon XR2+ Gen 2, targeting both entertainment and enterprise. It supports passthrough AR, PC VR streaming, and AI-enhanced experiences via Google Gemini. WIRED+1

PC VR & Others

  • Valve’s long-running Index headset is being sunset in favor of a new device called Steam Frame, with higher resolution and standalone capability. The Verge
  • HTC Vive, Pico headsets, and enterprise-focused devices (HoloLens, Varjo) cover specific niches like simulation and industrial training.

Where XR Is Used Today

XR is no longer just for games. Some of the most active domains include:

  • Gaming & Entertainment – Immersive games, spatial cinema, location-based experiences, and festivals like Venice Immersive that blend film and XR storytelling. The Guardian+1
  • Training & Simulation – Flight simulators, manufacturing procedures, emergency response training. AR is used to overlay procedures on equipment; XR puts trainees in lifelike scenarios. Wikipedia+1
  • Healthcare – Surgical planning, medical training, anatomy visualization, rehab exercises, and AR overlays during surgery. Wikipedia
  • Architecture, Construction & Real Estate – Walk through buildings before they exist, overlay BIM models on construction sites, or show clients “digital twins” of spaces. Wikipedia+1
  • Remote Collaboration & Productivity – Spatial whiteboards, multi-screen virtual desktops (e.g., Windows 11 remote desktop in Quest 3), and 3D data exploration. The Verge+1

If you’re already building remote monitoring, control panels, or dashboards on PC and XR (which you are!), you’re essentially working in this “spatial productivity” space.

The Future of XR Applications

XR’s near-future trajectory looks something like this:

  • More Mixed Reality, Less “Blind VR”
    Color passthrough and room understanding (depth, spatial mapping) make headsets usable as AR devices at home and at work. Quest 3, Vision Pro, and Galaxy XR are all designed for everyday passthrough use. VRcompare+2Apple+2
  • Slimmer Hardware & Smart Glasses
    Research devices and early smart-glasses prototypes (including Android XR-powered glasses) hint at lighter, glasses-like form factors for notifications, translation, and contextual help. WIRED+1
  • AI-Powered Spatial Experiences
    On-device AI (Gemini, Apple’s on-device models, etc.) will turn XR into an always-on assistant that understands your environment: recognizing objects, transcribing conversations, summarizing documents pinned in space, and more. WIRED+1
  • Deeper Vertical Integration
    Expect more specialized XR apps: surgical guidance, industrial digital twins, spatial cinema, and educational content with strong domain knowledge, not just generic demos. Wikipedia+1

The devices are finally good enough that the bottleneck is shifting from hardware to content and UX—which is where frameworks like Qt, Unity, and Unreal come in.

Programming Languages & Engines for XR

XR apps usually sit on top of an engine or framework. Under the hood, several languages dominate: Index.dev+1

  • C#
    • Primary language for Unity, historically the most popular engine for VR/AR games and experiences.
    • Widely used for Quest, PC VR, mobile AR (via AR Foundation), and many indie XR projects.
  • C++
    • Core language of Unreal Engine and many in-house engines.
    • Used when you need maximum performance or deep engine customization.
    • Also the foundation for many XR runtimes (OpenXR implementations, device SDKs).
  • Swift / Objective-C
    • For iOS, iPadOS, and visionOS apps using ARKit and RealityKit / Reality Composer Pro.
    • Swift + SwiftUI / RealityKit is the primary stack for Apple Vision Pro.
  • Java / Kotlin
    • For Android-level XR / ARCore integrations, especially when you need tight control over camera, sensors, or Android services.
  • JavaScript / TypeScript
    • For WebXR in browsers and frameworks like three.js, Babylon.js, and A-Frame.
    • Great for lightweight experiences or quick prototypes.
  • C++/QML (Qt)
    • With Qt Quick 3D XR, you can write cross-platform XR apps in QML with C++ backends, reusing your existing Qt skills. felgo.com+1
  • Python, Lua, etc.
    • Common in tooling, content generation, prototyping, and scripting inside some engines.

Given your current stack, Qt + C++/QML is a natural fit for XR dashboards, remote monitoring tools, and 3D control panels.

A Minimal Qt Quick 3D XR Example

Let’s finish with a simple, self-contained Qt Quick 3D XR scene that you can adapt.

Goal: Show how to:

  • Use XrView as the root (instead of Window + View3D)
  • Define a floor-based reference space
  • Place a cube for a table in front of the user
  • Visualize one controller as a cylinder for a ray stick and handle that follows the user’s hand

This follows the structure recommended in Qt’s own XR examples but is simplified for clarity. doc.qt.io+1

main.qml

// main.qml

// Minimal Qt Quick 3D XR scene

import QtQuick
import QtQuick.Controls

import QtQuick3D
import QtQuick3D.Helpers
import QtQuick3D.Xr

XrView {
        id: xrView

        xrOrigin: theOrigin

        environment: SceneEnvironment {
              id: sceneEnvironment
              lightProbe: Texture {
                    textureData: ProceduralSkyTextureData {
                    }
              }
              antialiasingMode: SceneEnvironment.MSAA
              antialiasingQuality: SceneEnvironment.High
              backgroundMode: SceneEnvironment.Color
              clearColor: "skyblue"
              probeHorizon: 0.5
        }

        DirectionalLight {
              eulerRotation.x: -30
              eulerRotation.y: -70
        }

        XrOrigin {
              id: theOrigin
              z: 100

              XrController {
                    id: rightController
                    controller: XrController.ControllerRight
                    poseSpace: XrController.AimPose

                    Node {
                          id: rayStick
                          property real length: 50

                          z: -length/2
                          Model {
                                eulerRotation.x: 90
                                scale: Qt.vector3d(0.02, rayStick.length/100, 0.02)
                                source: "#Cylinder"
                                materials: PrincipledMaterial { baseColor: "green"}
                                opacity: 0.5
                          }
                    }

                    Node {
                          id: rayHandle
                          z: 5
                          Model {
                                eulerRotation.x: 90
                                scale: Qt.vector3d(0.05, 0.10, 0.05)
                                source: "#Cylinder"
                                materials: PrincipledMaterial {
                                      baseColor: "black"
                                      roughness: 0.2
                                }
                          }
                    }
              }
        }

        Model {
              id: floor
              source: "#Rectangle"
              eulerRotation.x: -90
              scale: Qt.vector3d(5,5,5)
              materials: [ PrincipledMaterial {
                          baseColor: "green"
                    }
              ]
        }

        Model {
              id: table
              property real height: 70
              position: Qt.vector3d(0, height / 2, 0)
              source: "#Cube"
              scale: Qt.vector3d(3, height / 100, 1)
              materials: PrincipledMaterial {
                    baseColor: "#554433" //"brown" color
              }
        }
}

Output of above sample looks like below image:

What each piece does

  • XrView
    • Replaces View3D as the entry point for XR scenes.
    • Handles connection to the XR runtime (OpenXR, visionOS, etc.), head tracking, and multi-view rendering. doc.qt.io+1
  • SceneEnvironment
    • Controls background, lighting model, tonemapping, etc.
    • A procedural sky (ProceduralSkyTextureData) is used as a light probe, so the lighting looks more natural. We're setting "skyblue" as sky's color.
    • MSAA antialiasing improves edge quality.
    • Background is a solid sky blue color.
    • probeHorizon adjusts how the sky lighting fades near the horizon.
  • XrOrigin
    • Defines the origin of tracked space; controllers and hands are positioned relative to this.
    • In typical room-scale setups, the origin is near the center of the play area at floor height. felgo.com
    • Setting z: 100 means: the player’s origin is 100 units “forward” (along +Z) relative to your global coordinates (or vice versa, depending on how you think about your scene).
  • DirectionalLight
    • Simple “sunlight”. The eulerRotation angles position the light above and in front of the user.
  • Model for floor & cube
    • #Plane and #Cube are built-in primitive meshes from Qt Quick 3D Helpers.
    • We scale and rotate the plane to act as a floor, and we place a 30 cm cube 1 m in front of the user’s head.
  • XrController: representing the right-hand controller & the ray
    • Represents a tracked controller or hand pose in 3D.
    • controller: XrController.ControllerRight selects the right-hand device; poseSpace: XrController.AimPose tracks the “aim” ray used for pointing. felgo.com+1
    • Because XrController inherits from Node, the child Model (ray stick as Cylinder) automatically follows the controller’s position and orientation, acting as a visual marker for your hand/controller.
      • rayStick is a helper Node that draws a long, thin cylinder to visualize the pointing ray.
      • length controls how long the ray should be in front of the controller.
      • The Model:
        • Uses the built-in #Cylinder mesh.
        • Is rotated 90° in X so it extends along local Z.
        • Is scaled to be very thin and long; length sets its size.
        • Semi-transparent green → a typical laser pointer look.
      • z: -length/2 shifts the cylinder so its base sits near the controller and extends forward.
  • Floor and table: static world geometry
      • These are not children of XrOrigin, so they’re placed in world coordinates.
      • Uses a built-in #Rectangle mesh.
      • Rotated -90° in X so it lies flat in the XZ plane (Y up).
      • Scaled to make a larger floor (5×5).
      • Simple green(for floor), like brown(for table) material.

        From here, it’s a small step to what you’re already doing in your project: attaching QML panels, ray-picking boards, and synchronizing transforms across multiple devices.

        Conclusion: XR Is Just Another Platform You Can Own

        AR and XR can sound buzzword-heavy, but at this point they’re really just another runtime environment for the same core skills you already use: 3D thinking, good UX, and solid engineering.

        We saw how:

        • AR sits in the real world, overlaying digital content on reality.
        • XR is the bigger spectrum that includes AR, VR, and mixed-reality in between.
        • Today’s devices (Quest, Vision Pro, Galaxy XR, PC VR, etc.) are powerful enough that the hardware is no longer the main bottleneck—content and UX
        • XR is already transforming domains like training, healthcare, architecture, remote collaboration, and productivity, not just games.

        On the tooling side, engines like Unity and Unreal dominate classical game-style XR, but they’re not the only option. If you come from the Qt world, Qt Quick 3D XR lets you reuse your C++/QML skills to build spatial apps: control panels, dashboards, visualizations, multi-screen workspaces, and “serious” tools that live in 3D space. The small sample we walked through—XrView, XrOrigin, controllers, simple models—is already enough to:

        • Render 3D content in a headset
        • Track the user’s head and hands/controllers
        • Start experimenting with interaction, locomotion, and UI panels in 3D

        The big shift isn’t so much technical as mental: instead of “windows and tabs”, you’re placing objects, information, and tools in a room around the user. Once you accept that, all your existing experience with state management, networking, UI architecture, and performance suddenly becomes extremely valuable in XR.

        If you’re already comfortable with Qt and 3D, you’re closer to XR than you might think. Start with a tiny scene, add one or two interactive elements, and iterate. The step from “Qt desktop app” to “Qt XR app” is no longer a leap—it’s just your next branch

        Ready to get started?

        Contact IVC for a free consultation and discover how we can help your business grow online.

        Contact IVC for a Free Consultation

        References:

        https://en.wikipedia.org/wiki/Augmented_reality?

        https://www.g2.com/articles/history-of-augmented-reality?

        https://en.wikipedia.org/wiki/Extended_reality?

        https://vr-compare.com/headset/metaquest3?

        https://www.apple.com/newsroom/2023/06/introducing-apple-vision-pro/?

        https://www.wired.com/story/samsung-galaxy-xr-gemini-android-xr-mixed-reality-headset?

        https://www.theguardian.com/film/2025/aug/27/venice-film-festival-extended-reality-cinema-vr?

        https://www.index.dev/blog/top-programming-languages-ar-vr-game-development?

        https://felgo.com/doc/qt/qt-quick-3d-xr/?

        https://doc.qt.io/qt-6/qtquick3d-xr-simple-example.html?

         Image source:

        https://www.ourfriday.co.uk/image/cache/catalog/Oculus/oculus-3-7-800x800w.jpg

        https://media.wired.com/photos/647e2a2040f1b0ff578445a2/3:2/w_1920,c_limit/Apple-Vision-Pro-Gear.jpg

        https://www.ourfriday.co.uk/image/cache/catalog/Oculus/oculus-3-3-800x800.jpg

        https://e3.365dm.com/23/06/1600x900/skynews-apple-headset_6179275.jpg?20230605202646

        View More
        TECH

        November 28, 2025

        On C++26's Reflection

        On C++26's Reflection

        Table of Contents

        Introduction

        The C++26 standard is adding compile-time reflection to the language. This new feature enables C++ programs to inspect types, data members, and other program entities during compilation. As a result, developers can write more generic and less repetitive code for tasks such as serialization, validation, and code generation.

        This article provides an overview of C++26 reflection, as currently supported in Clang’s experimental branches, and presents a practical example: serializing templated structures to JSON with minimal boilerplate.

        What is Reflection?

        Reflection refers to a language feature that allows a program to inspect or manipulate its own structure—such as types, data members, functions, or other entities—during program execution or compilation. This capability is widely available in languages like Java and C#, where programs can query and interact with type information at runtime (runtime reflection).

        Historically, standard C++ has not provided built-in reflection. Developers have often relied on macros, manual coding, or third-party libraries to work around this limitation. As a result, tasks like serialization, validation, and automatic code generation have typically required repetitive boilerplate or external tools.

        C++26 introduces compile-time reflection, which provides access to type and member information while the code is being compiled, with no runtime overhead. This approach enables the generation of highly generic and maintainable code for a wide range of metaprogramming scenarios.

        The feature was introduced in paper P2996R13 and was voted into C++26 on June 25, 2025.

        Using C++26 Reflection with Clang

        At the time of writing, C++26 reflection is available in experimental branches of Clang, for example, Bloomberg's clang-p2996.

        The core syntax involves:

        • Including <experimental/meta>.
        • Using the ^^ operator to reflect on a type.
        • Enumerating members with utilities like nonstatic_data_members_of.
        • "Splicing" members into code with obj.[:m:] syntax.

        Example 1: Enumerating member names and values with reflection

        Suppose we have the following two structures and wish to print their members’ names and values:

        struct Point { int x = 1; int y = 2; };
        struct Person { std::string name = "Bob"; int age = 30; };
        

        Without reflection, one would probably have to write:

        #include <iostream>
        #include <string>
        struct Point { int x = 1; int y = 2; };
        struct Person { std::string name = "Bob"; int age = 30; };
        
        int main() {
            Point pt;
            Person person;
        
            std::cout << "x: " << pt.x << std::endl;
            std::cout << "y: " << pt.y << std::endl;
        
            std::cout << "name: " << person.name << std::endl;
            std::cout << "age: " << person.age << std::endl;
        }
        

        With reflection, it is possible to write a generic print_members() that works for any struct - no manual edits are needed if you add, remove, or change fields.

        #include <experimental/meta>
        #include <iostream>
        #include <string>
        
        template <typename T>
        void print_members(const T& obj) {
            constexpr auto ctx = std::meta::access_context::current();
            template for (constexpr auto member :
                std::define_static_array(nonstatic_data_members_of(^^T, ctx))) {
                std::cout << identifier_of(member) << ": " << obj.[:member:] << std::endl;
            }
        }
        
        struct Point { int x = 1; int y = 2; };
        struct Person { std::string name = "Bob"; int age = 30; };
        
        int main() {
            Point pt;
            Person person;
        
            print_members(pt);
            print_members(person);
        }
        

        The above code yields:

        x: 1
        y: 2
        name: Bob
        age: 30
        

        Example 2: JSON Serialization of Structures

        Below is a single-file example using Clang’s <experimental/meta> extension for C++26 reflection. The code provides a function to serialize any struct (with appropriate members) to a JSON string.

        The function is then called on several different structures, including the two structure types (Point and Person) in the previous section and an additional User struct with two public and one private field

        #include <experimental/meta>
        #include <iostream>
        #include <string>
        #include <type_traits>
        
        template <typename T>
        std::string generate_json_str(const T& obj) {
            std::string json = "{";
            constexpr auto ctx = std::meta::access_context::current();
            bool first = true;
        
            template for (constexpr auto m :
                std::define_static_array(nonstatic_data_members_of(^^T, ctx))) {
                if (!first) json += ", ";
                first = false;
                json += "\"";
                json += identifier_of(m);
                json += "\": ";
                // Add quotes for string members
                if constexpr (std::is_same_v<decltype(obj.[:m:]), std::string>) {
                    json += "\"";
                    json += obj.[:m:];
                    json += "\"";
                } else {
                    json += std::to_string(obj.[:m:]);
                }
            }
            json += "}";
            return json;
        }
        
        struct Point { int x = 1; int y = 2; };
        struct Person { std::string name = "Bob"; int age = 30; };
        
        struct User {
            int id;
            std::string name;
        private:
            double balance;
        public:
            User(int i, std::string n, double b)
                : id(i), name(std::move(n)), balance(b) {}
        };
        
        int main() {
            Point point;
            Person person;
            User user{1, "Alice", 123.45};
        
            std::cout << "JSON of point: " << generate_json_str(point) << std::endl;
            std::cout << "JSON of person: " << generate_json_str(person) << std::endl;
            std::cout << "JSON of user: " << generate_json_str(user) << std::endl;
        }
        

        Outputs:

        JSON of point: {"x": 1, "y": 2}
        JSON of person: {"name": "Bob", "age": 30}
        JSON of user: {"id": 1, "name": "Alice"}
        

        Outro

        This article has demonstrated only a small subset of the potential applications for C++26’s reflection facilities. The key takeaway is that compile-time reflection enables the creation of efficient and reusable code, with strong type safety enforced at compile time. Although some of the new syntax may appear complex at first glance, its use quickly becomes practical with familiarity.

        As compiler and library support matures, compile-time reflection is likely to simplify and streamline many codebases and tooling workflows in the C++ ecosystem.

        References

        Ready to get started?

        Contact IVC for a free consultation and discover how we can help your business grow online.

        Contact IVC for a Free Consultation
        View More
        1 3 4 5 6 7 23
        Let's explore a Partnership Opportunity

        CONTACT US



        At ISB Vietnam, we are always open to exploring new partnership opportunities.

        If you're seeking a reliable, long-term partner who values collaboration and shared growth, we'd be happy to connect and discuss how we can work together.

        Add the attachment *Up to 10MB