Aspect | Synchronous Data Parallelism | Asynchronous Data Parallelism |
---|---|---|
How it works | All workers do each step together, then sync | Workers work at their own pace, no syncing |
Updates | The model is updated only after all workers finish the step | The model is updated as soon as a worker finishes |
Speed bottleneck | Slowed by the slowest (straggler) worker | Not slowed by any single worker |
Model consistency | All model copies stay identical | Model copies may be slightly different |
Stability | More stable, easier to tune and debug | Can be less stable, needs careful tuning |
Communication | Uses “all-reduce” (direct worker-to-worker) | Uses “parameter server” (central coordinator) |
Common use cases | Most deep learning frameworks (e.g., DDP, Horovod) | Edge devices, unreliable or mixed-speed clusters |
When to use | When you need accuracy and consistency | When speed and hardware utilization are critical |
Pros | Cons |
---|---|
Speed-Up and Efficiency Tasks complete faster by dividing work over multiple processors. For large workloads, data parallelism can achieve near-linear speed-up as resources increase. | Memory Overhead Each worker holds a full copy of the model or data, causing duplicated memory usage and limiting scalability for very large models. |
Simplicity of Replication The same code or model runs on each worker; frameworks handle splitting and merging, so you usually don’t need major code changes. | Communication Overhead Combining results (like synchronizing gradients) adds network traffic, which can become a bottleneck as model or cluster size grows. |
Scalability Easy to handle more data or bigger models by adding more workers; widely used for scaling to hundreds or thousands of machines. | Synchronization Penalty In synchronous setups, the fastest workers must wait for the slowest, making performance sensitive to hardware imbalance or stragglers. |
Fault Isolation If one worker fails, only its portion of the data is lost. With checkpointing, work can resume with minimal loss, improving reliability. | Diminishing Returns Adding more workers eventually yields less benefit due to communication and merge overhead, and can affect ML model quality if batches become too large. |
Balanced Workload Splitting by data often naturally balances the work (assuming data complexity is uniform), keeping all processors equally busy. | Applicability Not all problems split easily by data; tasks with strong dependencies or that require global state need different parallelization strategies. |
import torch
import torch.nn as nn
# DataParallel usage (single machine, multiple GPUs)
model = nn.DataParallel(MyModel())
output = model(input)
# DistributedDataParallel usage (scalable, multi-GPU)
import torch.distributed as dist
dist.init_process_group(backend="nccl")
model = nn.parallel.DistributedDataParallel(
MyModel().to(local_rank), device_ids=[local_rank]
)
The code wraps a model for parallel execution. With DataParallel, the model splits the input batch and computes results on each device. DistributedDataParallel synchronizes gradients across multiple processes.import tensorflow as tf
# Example: Synchronous multi-GPU training
strategy = tf.distribute.MirroredStrategy()
with strategy.scope():
model = build_model(...)
model.fit(dataset, epochs=..., ...)
This code will automatically split batches and aggregate gradients behind the scenes.import horovod.torch as hvd
hvd.init()
model = MyModel().to(hvd.local_rank())
optimizer = optim.Adam(model.parameters(), lr=0.001 * hvd.size())
# Wrap the optimizer with Horovod DistributedOptimizer
optimizer = hvd.DistributedOptimizer(optimizer, named_parameters=model.named_parameters())
# Synchronize model parameters across workers
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
The code snippet initializes Horovod for distributed training, where the optimizer’s learning rate is scaled by the number of workers. It also synchronizes the model parameters across all processes. Horovod’s DistributedOptimizer handles gradient averaging and update synchronization across multiple GPUs or nodes efficiently.pip install ray
import ray
import numpy as np
# Initialize Ray
ray.init()
# Dummy training function to simulate model training on a data shard
@ray.remote
def train_worker(data_shard):
# Initialize model weights randomly
weights = np.random.rand(10)
# Dummy "training": update weights with mean of the data shard
for batch in data_shard:
weights += batch.mean(axis=0) * 0.01
return weights
# Generate dummy data and split into shards
num_workers = 4
data = [np.random.rand(100, 10) for _ in range(num_workers)] # 4 shards of data
# Launch training jobs in parallel
results = [train_worker.remote(shard) for shard in data]
# Collect the results (trained weights) from all workers
trained_weights = ray.get(results)
# Aggregate weights (simple average)
final_weights = np.mean(trained_weights, axis=0)
print("Aggregated model weights:", final_weights)
How it works:Thank god they started pre-washing and boxing salad otherwise I’d never eat the stuff … very important to douse greens with salad gravy (yes, a Gaffiganism) and my salad dressing of choice is Briannas (no apostrophe) Blush Wine Vinaigrette. I have tried every salad dressing on planet Earth and this is the best stuff (I can get at Wegmans) by a mile. Try it and let me know how right I am!
In the 2023-2024 academic year, the number of international students studying in the United States was at an all-time high.Open Doors
Comparing robotaxi operations: Waymo leads in the United States; Baidu dominates in China.Recode China AI
While Waymo pioneered the robotaxi, nearly every other company providing regular public road service is Chinese. It mirrors the global electric vehicle market where, aside from Tesla, Chinese carmakers like BYD dominate the top ranks.
With backing from Toyota, Pony.ai is aiming to produce 1,000 of its robotaxis this year.Pony.ai
Pony.ai, backed by Toyota and co-founded by ex-Baidu executive James Peng and coding prodigy Tiancheng Lou, operates 270 robotaxis. By year end, they aim to scale production to 1,000 of their seventh-generation robotaxis, co-developed with Toyota and two local Chinese automakers. Pony.ai has not disclosed its robotaxi order numbers but claims an impressive 1-to-20 ratio of remote safety operators to vehicles and says its operational footprint is roughly 20 times the size of Waymo’s service area in San Francisco.
Since its NASDAQ debut, Pony.ai has attracted significant attention, including a partnership with Uber and rumored discussions involving Uber’s controversial founder, Travis Kalanick, who was supposedly interested in acquiring the company’s U.S. operations.
WeRide, another company founded by Baidu’s veterans, overcame early turmoil when its co-founder, former Baidu executive Wang Jing, stepped down amid a lawsuit alleging trade-secret misappropriation. CTO Tony Han stepped in, steering WeRide to success with a 500-robotaxi fleet and diversified offerings including robo-buses and autonomous street sweepers. WeRide also collaborates with Bosch, the German technology giant and WeRide’s major investor, on ADAS development, though major commercial clients remain elusive.
WeRide launched the Middle East’s first robotaxi service in Abu Dhabi this year. WeRide
Now these firms are turning outward, eyeing overseas expansion in Southeast Asia, Europe, and the Middle East—racing to claim global robotaxi territory ahead of American competitors. Early this year, Baidu expanded into Dubai and Abu Dhabi after securing road‑test permits and reportedly plans to enter Singapore, Malaysia, and Switzerland. Pony.ai signed an agreement with Dubai’s transit authority, aiming for fully driverless operations by 2026 and maintains test operations in South Korea and Luxembourg. WeRide partnered with Uber for pilot operations in Abu Dhabi, becoming the Middle East’s first fully driverless robotaxi service and plans expansion into 15 more cities globally over the next five years.
Tesla launched its robotaxi service in Austin, Texas, with a handful of vehicles in limited areas of the city. Tim Goessman/Bloomberg/Getty Images
Their software is a combination of AI models and rule-based code, designed to interpret traffic patterns, predict behaviors, and execute driving decisions. All three Chinese robotaxi firms now boast “end-to-end” systems—a term popularized by Tesla that refers to AI models capable of processing raw sensor data and directly outputting driving actions.
Unlike Waymo’s early suburban testing in Phoenix, Chinese robotaxis are trained in the dense, chaotic streets of Beijing and Guangzhou, where roads are often packed with motorbikes, bicycles, and street vendors. The ability to operate in such conditions could arguably make their systems more adaptable.
Waymo operates more than 1,500 robotaxis in the metropolitan areas of four U.S. cities.Craig F. Walker/The Boston Globe/Getty Images
Social issues also loom large. Apollo Go’s expansion in Wuhan last year sparked protests from local taxi drivers who feared for their livelihoods. In response, the Wuhan Transportation Bureau clarified that Apollo Go operates only 400 robotaxis in the city. Baidu CEO Robin Li acknowledged the concerns, emphasizing that scaling robotaxi operations will be a gradual process that may take many years.
Profitability is another challenge for all robotaxi firms. Despite growing ride volumes and improving hardware economics, none of the players have yet reached break-even. Most services remain heavily subsidized, especially during pilot phases. Pony.ai has set the goal of turning profitable by 2029.
Another strategic dependency is chips. Most Chinese robotaxi fleets are currently powered by Nvidia chips, particularly the widely used Orin system-on-chip. These chips handle the bulk of sensor fusion, perception, and path-planning workloads. The reliance on a U.S. supplier poses geopolitical and supply chain risks. Recent export restrictions and rising tensions between the United States and China have prompted some Chinese firms to explore domestic alternatives, but so far, no local chipmaker has matched Nvidia’s AV computing capabilities.
A test wafer made with CDimension’s process sits underneath a microscope.CDimension
The latter might be 2D semiconductor’s first industrial entry. “We’re showing the possibilities with silicon plus 2D material,” Zhu says. “But 2D material might be used for the highly scaled logic devices as well. That can be the next step.”
Chipmakers like Intel, Samsung, and TSMC reported research aimed at replacing silicon nanosheets in their future transistors with MoS2 and other 2D semiconductors at the IEEE International Electron Device Meeting in December 2024. At the same conference, Zhu and his colleagues from the MIT laboratories of IEEE Fellow Tomás Palacios and Jing Kong showed that the low-temperature synthesis could produce MoS2 transistors with multiple stacked channels, akin to nanosheet transistors. (Palacios is a strategic advisor to CDimension.) By scaling down the device, the team predicted that such devices could meet and exceed the requirements of the future 10A (1-nanometer) node in terms of power consumption, performance, and the area they occupy.
A big motivation to go with 2D semiconductors is to reduce power consumption, says Zhu. Power is lost in transistors both when they are on (dynamic power) and when they are off (static power). Because it’s just over 0.6 nm thick, 2D transistors have qualities that could let them operate using about half the voltage of today’s silicon devices, saving dynamic power. When they are off, it’s leakage current you have to worry about most. But MoS2 has a bandgap that’s more than twice the value of silicon’s, meaning it takes much more energy for charge to leak across the device. Zhu says devices made using CDimension’s materials consumed as little as one-thousandth the energy of silicon devices.
In addition to MoS2, which is an electron-conducting (n-type) semiconductor, the startup also provides tungsten diselenide, a p-type semiconductor, as well as 2D insulating films, such as hexagonal boron nitride. The whole combination will be needed if 2D semiconductors are to ever take over in future CMOS chips.
Decisions are rarely one-and-done affairs. Leading a team, managing a project, allocating resources, and undertaking a design all require regular interactions with others, with initial decisions adjusted regularly over time.
The same applies to mental models for human decision-making. Monitoring normal day-to-day operations of an organization or a project likely would not provide information of a high enough signal-to-noise ratio for mental models to be reliably updated.
Instead, special tasks and situations can be instrumental in achieving the goal. For example, a manager could give a challenging task to a team member primarily to improve the manager’s mental model of the employee, rather than to address a pressing organizational need. The improved mental model can help the leader determine the best role for the employee when an actual challenging situation arises.
Regardless of effort, mental models will never be perfect. There will always be uncertainty. So, one crucial lesson for decision-makers to keep in mind is that whatever you know, you only think you know. Resist the temptation to believe you really know the truth.
As a decision-maker, the objects of your mental models include your organization, other stakeholders, and the external environment. But they also include your self-model. You need to have a clear understanding of your own capabilities, preferences, and circumstances. Examples include your workload, the pace at which you work best, your flexibility in light of other priorities, and what motivates you. And, of course, you need to appreciate that your self-models are uncertain, too.
People often don’t know themselves as well as they think they do. Be honest with yourself, and ask for feedback from trusted colleagues and friends. Don’t react defensively; listen to the feedback, then reflect. Doing so can strengthen your understanding of yourself.
Columbia University researchers introduce a process that allows machines to “grow” physically by integrating parts from their surroundings or from other robots, demonstrating a step toward self-sustaining robot ecologies.
[Robot Metabolism] via [Columbia]We challenged ourselves to see just how far we could push Digit’s ability to stabilize itself in response to a disturbance. Utilizing state-of-the-art AI technology and robust physical intelligence, Digit can adapt to substantial disruptions, all without the use of visual perception.We are presenting the Figure 03 (F.03) battery—a significant advancement in our core humanoid robot technology roadmap.
The effort that was put into safety for this battery is impressive. But I would note two things: The battery life is “5 hours of run time at peak performance” without saying what “peak performance” actually means, and 2-kilowatt fast charge still means over an hour to fully charge.
[Figure]Well this is a nifty idea.
[UBTECH]PAPRLE is a plug-and-play robotic limb environment for flexible configuration and control of robotic limbs across applications. With PAPRLE, users can use diverse configurations of leader-follower pair for teleoperation. In the video, we show several teleoperation examples supported by PAPRLE.
[PAPRLE]
Thanks, Joohyung!Always nice to see a robot with a carefully thought-out commercial use case in which it can just do robot stuff like a robot.
[Cohesive Robotics]
Thanks, David!We are interested in deploying autonomous legged robots in diverse environments, such as industrial facilities and forests. As part of the DigiForest project, we are working on new systems to autonomously build forest inventories with legged platforms, which we have deployed in the UK, Finland, and Switzerland.
[Oxford]
Thanks, Matias!In this research we introduce a self-healing, biocompatible strain sensor using Galinstan and a Diels-Alder polymer, capable of restoring both mechanical and sensing functions after repeated damage. This highly stretchable and conductive sensor demonstrates strong performance metrics—including 80% mechanical healing efficiency and 105% gauge factor recovery—making it suitable for smart wearable applications.
[Paper]
Thanks, Bram!The “Amazing Hand” from Pollen Robotics costs less than $250.
[Pollen]Welcome to our Unboxing Day! After months of waiting, our humanoid robot has finally arrived at Fraunhofer IPA in Stuttgart.
I used to take stretching classes from a woman who could do this backwards in 5.43 seconds.
[Fraunhofer]At the Changchun stop of the VOYAGEX Music Festival on July 12, PNDbotics’ full-sized humanoid robot Adam took the stage as a keytar player with the famous Chinese musician Hu Yutong’s band.Material movement is the invisible infrastructure of hospitals, airports, cities–everyday life. We build robots that support the people doing this essential, often overlooked work. Watch our CEO Brad Porter reflect on what inspired Cobot.
[Cobot]Yes please.
[ Pollen ]I think I could get to the point of being okay with this living in my bathroom.
[Paper]Thanks to its social perception, high expressiveness, and out-of-the-box integration, TIAGo Head offers the ultimate human-robot interaction experience.Sneak peek: Our No Manning Required Ship (NOMARS) Defiant unmanned surface vessel is designed to operate for up to a year at sea without human intervention. In-water testing is preparing it for an extended at-sea demonstration of reliability and endurance.
Excellent name for any ship.
[DARPA]At the 22nd International Conference on Ubiquitous Robots (UR2025), high school student and robotics researcher Ethan Hong was honored as a Special Invited Speaker for the conference banquet and “Robots With Us” panel. In this heartfelt and inspiring talk, Ethan shares the story behind Food Angel—a food delivery robot he designed and built to support people experiencing homelessness in Los Angeles. Motivated by the growing crises of homelessness and food insecurity, Ethan asked a simple but profound question: “Why not use robots to help the unhoused?”
[UR2025]
app.css
and add the following styles at the end of the file:.landing-container {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 5%;
position: absolute;
top: 0;
width: 100%;
z-index: 20;
background: #171B20;
width: 100vw;
}
.top-row{
padding-left: 0;
}
.top-row{
background: #26b050;
}
.logo {
width: 50px;
height: 50px;
}
.nav-links {
display: flex;
gap: 20px;
align-items: center;
}
.nav-link {
text-decoration: none;
color: white;
font-size: 16px;
transition: color 0.3s;
}
.nav-link:hover {
color: #6c72e8;
}
.hero-section {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
padding: 5%;
background: url('assets/images/background/dots.svg') center/cover no-repeat;
}
.hero-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(180deg, rgba(24,27,32,0.9) 30%, rgba(0,0,0,0.25) 65%);
z-index: -1;
}
.hero-title {
font-size: 48px;
font-weight: bold;
text-transform: uppercase;
margin: 0;
background: linear-gradient(93deg, rgba(233,92,255,1) 12%, rgba(210,125,255,1) 49%, rgba(159,121,255,1) 93%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.hero-subtitle {
font-size: 18px;
margin-top: 20px;
max-width: 450px;
}
.hero-buttons {
margin-top: 20px;
display: flex;
gap: 20px;
justify-content: center;
}
.dashboard-container {
margin-top: 40px;
}
.dashboard-image {
width: 100%;
max-width: 950px;
min-height: 450px;
border-radius: 16px;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}
.section {
padding: 60px 5%;
text-align: center;
}
.pricing-cards {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
}
.pricing-card {
width: 380px;
margin: 20px;
padding: 20px;
background-color: #1d2127;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}
.footer {
display: flex;
justify-content: space-around;
padding: 40px 5%;
background-color: #111;
}
.footer-column {
max-width: 250px;
}
.footer-column h2 {
font-size: 24px;
margin-bottom: 20px;
}
.footer-link {
color: white;
text-decoration: none;
display: block;
margin-bottom: 10px;
transition: color 0.3s;
}
.footer-link:hover {
color: #483cf4;
}
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
.item {
background: #121418;
color: rgba(255, 255, 255, .8);
font: 36px/200px sans-serif;
text-align: center;
margin: 0;
border: none;
position: absolute;
text-shadow: 1px 1px 2px rgba(0, 0, 0, .8);
border-width: 0px;
}
.k-scrollview {
margin: 0 auto;
border: none;
border-width: 0px;
}
.carousel-style {
border: none !important;
}
.carousel-style .k-scrollview-nav .k-link {
background-color: #4B0082;
}
.carousel-style .k-scrollview-nav .k-link.k-primary {
background-color: #3F51B5;
}
.k-form-label,
.k-form-hint,
.k-label {
color: #ffffff !important;
}
.k-input,
.k-textbox,
.k-dropdown,
.k-multiselect {
color: #ffffff !important;
}
.k-validation-message {
color: #ffffff !important;
}
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
margin: 0;
background-color: #181B20;
color: white;
}
...
.content {
font-family: "Poppins", sans-serif;
}
App.razor
and add the following line in the Head
section:<head>
...
<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
<ImportMap />
...
</head>
With the previous steps completed, we are ready to create the landing page.LandingPage.razor
. We will modify this component by adding an @page
directive to turn it into a page and assign it as the initial route of the application. Finally, we will specify the rendermode
as InteractiveServer
:@page "/"
@rendermode InteractiveServer
<h3>LandingPage</h3>
@code {
}
To avoid issues with routes, you should change the @page
directive of the Home.razor
page to a different value, such as:@page "/Home"
If you run the application at this point, you will see the newly created page displayed on the screen:MainLayout.razor
file, which, if you examine, includes elements such as a sidebar.EmptyLayout.razor
with the following content:@inherits LayoutComponentBase
<TelerikRootComponent>
<main>
<article class="content">
@Body
</article>
</main>
</TelerikRootComponent>
With this, we are using @Body
to render the content while removing unnecessary elements like the sidebar. The next step is to go to LandingPage.razor
and specify that we want to use the new layout via the @layout
directive:@using LandingPageBlazor.Components.Layout
@page "/"
@layout EmptyLayout
<h3>LandingPage</h3>
@code {
}
When you run the application, you will see that the page now occupies the full available space:<TelerikAppBar ThemeColor="dark">
<AppBarSection>
<img src="assets/logo/logo.png" alt="Logo" class="logo" />
</AppBarSection>
<AppBarSpacer></AppBarSpacer>
<AppBarSection>
<a href="#about" class="nav-link">About Us</a>
</AppBarSection>
<AppBarSeparator></AppBarSeparator>
<AppBarSection>
<a href="#pricing" class="nav-link">Pricing</a>
</AppBarSection>
<AppBarSeparator></AppBarSeparator>
<AppBarSection>
<a href="#features" class="nav-link">Features</a>
</AppBarSection>
<AppBarSeparator></AppBarSeparator>
<AppBarSection>
<a href="#company" class="nav-link">Company</a>
</AppBarSection>
<AppBarSeparator></AppBarSeparator>
<AppBarSection>
<TelerikButton OnClick="@(() => {})">Get Started <i class="bi bi-arrow-right"></i></TelerikButton>
</AppBarSection>
<AppBarSeparator></AppBarSeparator>
</TelerikAppBar>
In the code above, we use the TelerikAppBar
component, to which we add sections using the AppBarSection
tag. This allows us to include HTML code with the desired content. You can see that in my case, I use links and even a TelerikButton
to execute a C# method if needed. The AppBarSpacer
and AppBarSeparator
tags allow you to add space between the elements of the TelerikAppBar
, resulting in a final design that looks like this:TelerikCarousel
control, which provides an easy and quick way to implement carousels not only of images but also of any custom content you need.TelerikCarousel
control works by defining a data source with a set of properties that we will display in the carousel. In my case, since I only need to display images, I will add a class with the properties ID
and ImagePath
, in addition to creating a list with five objects of the created model:@code {
public IEnumerable<CarouselModel> CarouselData = Enumerable.Range(1, 5).Select(x => new CarouselModel
{
ID = x,
ImagePath = "assets/images/home/dashboard.png"
});
public class CarouselModel
{
public int ID { get; set; }
public string ImagePath { get; set; }
}
}
The hero section looks as follows:<!-- HERO SECTION -->
<section id="hero-section" class="hero-section">
<div class="hero-bg"></div>
<h1 class="hero-title">
AI Powered<br />Coding Simplified
</h1>
<p class="hero-subtitle">
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Error adipisci corrupti accusamus reiciendis similique assumenda nostrum fuga dicta vitae ipsum.
</p>
<div class="hero-buttons">
<TelerikButton OnClick="@(() => {})" Size="lg" ThemeColor="info">Get Started</TelerikButton>
<TelerikButton OnClick="@(() => {})" Size="lg" Class="secondary" ThemeColor="light">Learn More</TelerikButton>
</div>
<div class="dashboard-container">
<TelerikCarousel Data="@CarouselData" Width="950px" Height="450px" Class="carousel-style">
<Template>
<div class="item">
<img src="assets/images/home/dashboard.png" alt="Dashboard" class="dashboard-image" />
</div>
</Template>
</TelerikCarousel>
</div>
</section>
When running the application, you’ll see how the slider with images is displayed within the application:<!-- Trusted Brands Section -->
<section class="section" id="mySection">
<h2>Trusted by Brands You Know</h2>
<div style="overflow: hidden; white-space: nowrap; max-width: 800px; margin: 0 auto;">
<TelerikAnimationContainer @ref="animationContainer"
AnimationType="AnimationType.ZoomIn"
AnimationDuration="1000"
Width="800px">
<div style="display: inline-block; animation: scroll 10s linear infinite;">
<img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/author-images/progress-blog-default-logo-transparent.png" alt="Progress" style="height:50px; width:50px; margin: 0 20px;" />
<img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/author-images/progress-blog-default-logo-transparent.png" alt="Progress" style="height:50px; width:150px; margin: 0 20px;" />
<img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/author-images/progress-blog-default-logo-transparent.png" alt="Progress" style="height:50px; width:150px; margin: 0 20px;" />
<img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/author-images/progress-blog-default-logo-transparent.png" alt="Progress" style="height:50px; width:150px; margin: 0 20px;" />
<img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/author-images/progress-blog-default-logo-transparent.png" alt="Progress" style="height:50px; width:150px; margin: 0 20px;" />
<img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/author-images/progress-blog-default-logo-transparent.png" alt="Progress" style="height:50px; width:150px; margin: 0 20px;" />
</div>
</TelerikAnimationContainer>
</div>
</section>
In the code above, you can see that a series of logo images (representing company logos) are nested within a div
. Additionally, we have configured the TelerikAnimationContainer
control with an AnimationType
, an AnimationDuration
, a Width
and a @ref
, which is used to control the animation effect. This setup is necessary as TelerikAnimationContainer
can be reused for displaying other types of content as needed.@code {
private TelerikAnimationContainer animationContainer;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await animationContainer.ShowAsync();
}
}
...
}
However, the above code has an issue for our specific use case. The problem is that, if the user starts by viewing the navigation menu and the hero section, they might miss the logo animation since it executes immediately after the page renders. Ideally, we should see the animation only when the user scrolls to that section. This can be fixed with these steps:App.razor
file and add a <script>
tag at the end of the <body>
tag with the following content:<body>
...
<script>
window.observeElement = (elementId, dotNetHelper) => {
const element = document.getElementById(elementId);
if (!element) {
console.error("Element with id: " + elementId + " was not found");
return;
}
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
dotNetHelper.invokeMethodAsync('OnSectionVisible');
observer.unobserve(entry.target);
}
});
});
observer.observe(element);
};
</script>
</body>
LandingPage.razor
, add the following directive:@inject IJSRuntime JS
LandingPage.razor
, modify the OnAfterRenderAsync
method and add the OnSectionVisible
method:protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// await animationContainer.ShowAsync();
await JS.InvokeVoidAsync("observeElement", "mySection", DotNetObjectReference.Create(this));
}
}
[JSInvokable]
public async Task OnSectionVisible()
{
await animationContainer.ShowAsync();
}
The above code enables the animation to execute only when the user scrolls to the corresponding section, as shown below:GridLayoutRows
) and columns (GridLayoutColumns
), and then place the elements in their corresponding positions. Below is an example of its usage:<!-- Features Section -->
<section class="section" id="features" style="width: 1420px; margin: 0 auto;">
<TelerikGridLayout ColumnSpacing="120px" VerticalAlign="GridLayoutVerticalAlign.Center">
<GridLayoutColumns>
<GridLayoutColumn Width="850px"></GridLayoutColumn>
<GridLayoutColumn Width="450px"></GridLayoutColumn>
</GridLayoutColumns>
<GridLayoutRows>
<GridLayoutRow Height="auto"></GridLayoutRow>
</GridLayoutRows>
<GridLayoutItems>
<GridLayoutItem Column="1" Row="1">
<img src="assets/images/home/coding.png" alt="Coding" style="width: 100%; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.2);" />
</GridLayoutItem>
<GridLayoutItem Column="2" Row="1">
<h3>Streamlined Coding</h3>
<div>
<h4><i class="bi bi-check-all"></i> AI Powered</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</div>
<div>
<h4><i class="bi bi-check-all"></i> Locally Run</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</div>
</GridLayoutItem>
</GridLayoutItems>
</TelerikGridLayout>
</section>
The code above will render the content into two columns and one row:CardHeader
), body (CardBody
) and footer (CardFooter
). As an advantage, we can combine the card’s content with HTML code or add other components, as shown in the following example:<!-- Pricing Section -->
<section class="section" id="pricing">
<h3>Simple Pricing</h3>
<div class="pricing-cards">
<TelerikCard Class="pricing-card">
<CardHeader>
<h3>
<span style="font-size: 32px; font-weight: bold;">$9</span>
<span style="font-size: 24px; color: #ccc;">/mo</span>
</h3>
</CardHeader>
<CardBody>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab, explicabo!
</p>
<hr />
<ul style="list-style: none; padding: 0;">
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem, ipsum.</li>
<li>Lorem, ipsum dolor.</li>
<li>Lorem ipsum dolor sit.</li>
</ul>
</CardBody>
<CardFooter>
<TelerikButton OnClick="@(() => {})">Get Now</TelerikButton>
</CardFooter>
</TelerikCard>
<TelerikCard Class="pricing-card">
<CardHeader>
<h3>
<span style="font-size: 32px; font-weight: bold;">$19</span>
<span style="font-size: 24px; color: #ccc;">/mo</span>
</h3>
</CardHeader>
<CardBody>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab, explicabo!
</p>
<hr />
<ul style="list-style: none; padding: 0;">
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem, ipsum.</li>
<li>Lorem, ipsum dolor.</li>
<li>Lorem ipsum dolor sit.</li>
</ul>
</CardBody>
<CardFooter>
<TelerikButton OnClick="@(() => {})">Get Now</TelerikButton>
</CardFooter>
</TelerikCard>
<TelerikCard Class="pricing-card">
<CardHeader>
<h3>
<span style="font-size: 32px; font-weight: bold;">$49</span>
<span style="font-size: 24px; color: #ccc;">/mo</span>
</h3>
</CardHeader>
<CardBody>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab, explicabo!
</p>
<hr />
<ul style="list-style: none; padding: 0;">
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem, ipsum.</li>
<li>Lorem, ipsum dolor.</li>
<li>Lorem ipsum dolor sit.</li>
</ul>
</CardBody>
<CardFooter>
<TelerikButton OnClick="@(() => {})">Get Now</TelerikButton>
</CardFooter>
</TelerikCard>
</div>
</section>
The previous code will display three cards with subscription options, which look great:private Contact contact = new Contact();
public class Contact
{
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; }
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Enter a valid email address")]
public string Email { get; set; }
// Optional field
public string Phone { get; set; }
[Required(ErrorMessage = "Subject is required")]
public string Subject { get; set; }
[Required(ErrorMessage = "Message is required")]
public string Message { get; set; }
}
private void HandleSubmit()
{
}
Next, in the Razor section of the code, we define the form using a TelerikForm
, with FormItems
configured according to the type of input data, along with a TelerikButton
to handle the submission of information, as shown in the following example:<section class="section" id="contact" style="display: flex; flex-direction: column; align-items: center;">
<h3>Contact Us</h3>
<div>
<TelerikForm Model="@contact" Width="500px" OnSubmit="@HandleSubmit">
<FormValidation>
<DataAnnotationsValidator />
</FormValidation>
<FormItems>
<FormItem Field="@nameof(Contact.Name)" LabelText="Name" Hint="Enter your name" />
<FormItem Field="@nameof(Contact.Email)" LabelText="Email" Hint="Enter your email address" />
<FormItem Field="@nameof(Contact.Phone)" LabelText="Phone" Hint="Enter your phone number (optional)" />
<FormItem Field="@nameof(Contact.Subject)" LabelText="Subject" Hint="Enter the subject of your inquiry" />
<FormItem Field="@nameof(Contact.Message)" LabelText="Message" Hint="Enter your inquiry or comment" EditorType="@FormEditorType.TextArea" />
</FormItems>
<FormButtons>
<TelerikButton ButtonType="ButtonType.Submit">
Send
</TelerikButton>
</FormButtons>
</TelerikForm>
</div>
</section>
The result of the execution with the updated code looks like this:Is a password alone enough to secure their access and account details?
If it’s not enough, how do you want to incorporate two-factor authentication (2FA) or multifactor authentication (MFA) into the process to enhance security?
There are a variety of authentication methods you can include when developing the login procedure for your website or app. In this post, we’re going to look at how multifactor authentication works, when to implement it and when to choose 2FA over MFA.